[
  {
    "path": ".gitignore",
    "content": "# IDE\nnbproject/\n\n# Android\nplatforms/android/bin/\nplatforms/android/gen/\nplatforms/android/build/\n\n# iOS\nplatforms/ios/build/\nplatforms/ios/CordovaLib/build/\nplatforms/ios/www\nplatforms/ios/MyPace/config.xml\nplatforms/ios/.staging\n\n# Browser\nplatforms/browser/build/\n\n# Emulator logs\nplatforms/ios/cordova/console.log\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "PRIVACY.MD",
    "content": "# Pi-hole Droid - Privacy\n\n### Why does Pi-hole Droid request permission to access my camera?\nThe app could scan the QR Code of your Pi-hole to obtain the token to connect to it. This function is available on the \"App settings\" page.\n\n### Does Pi-hole Droid collect informations?\nThe app will **locally** store the IP and the token of your Pi-hole for the only purpose of connecting to it.\n"
  },
  {
    "path": "README.md",
    "content": "# Pi-hole Droid\n\n![App Logo](www/assets/mipmap-hdpi/ic_launcher.png?raw=true)\n\nPi-hole Droid is an *unofficial* client that connects to your [Pi-hole](https://github.com/pi-hole/pi-hole) to show charts and statistics.\n\nIt requires the new *Pi-hole 3.0 FTL* (released on 2 May 2017). Please update your Pi-hole!\n\nThis is the repository of the Pi-hole Droid's opensource application available on [Google Play Store](https://play.google.com/store/apps/details?id=friimaind.piholedroid).\n\n**What is Pi-hole?**\n\n> Pi-hole is the multi-platform, network-wide ad blocker which blocks ads for all your devices without the need to install client-side software.\n\nPi-hole Droid makes use of [Pi-hole API](https://github.com/pi-hole/AdminLTE) to obtain all the data. The credentials is **locally stored** on your device through localStorage.\n\n## Download\n\n<a href=\"#/\"><img src=\"https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png\" height=\"60\"></a>\n\n*Please note:* Google Play Store is temporary unavailable, in the meantime you can **get the latest APK** directly from [here](https://github.com/friimaind/pi-hole-droid/releases/latest) or [F-Droid repository](https://f-droid.org/en/packages/friimaind.piholedroid/)\n\n## Screenshots\n![Homepage](screenshots/home.png?raw=true \"Homepage\") \n![Menu](screenshots/menu.png?raw=true \"Menu\") \n\n![Charts](screenshots/charts.png?raw=true \"Charts\")\n![Settings](screenshots/settings.png?raw=true \"Settings\")\n\n![Toggle On](screenshots/toggle_on.png?raw=true \"Toggle On\")\n![Toggle Off](screenshots/toggle_off.png?raw=true \"Toggle Off\")\n\n![Home Landscape](screenshots/home-landscape.png?raw=true \"Home Landscape\")\n\n![Landscape](screenshots/landscape.png?raw=true \"Landscape\")\n\n![Landscape2](screenshots/landscape-2.png?raw=true \"Landscape2\")\n\n![Query Log](screenshots/query-log.png?raw=true \"Query Log\")\n\n## Built With\n\n* [Apache Cordova](https://cordova.apache.org/)\n* [MDL Material Design Lite](https://getmdl.io)\n* [jQuery](https://jquery.com)\n* [Chartist JS](https://gionkunz.github.io/chartist-js)\n* [DataTables](https://datatables.net)\n* [Hammer.js](http://hammerjs.github.io)\n* [BarcodeScanner](https://github.com/phonegap/phonegap-plugin-barcodescanner)\n\n## Upcoming releases\nI'm working on these tasks for the next releases:\n\n* Improvements on UI (loading icons on table views, better UI on Query Log page primarily)\n* Improvements on landscape view (better use of space)\n* Query Log: highlight blocked queries\n* Auto update toggle on Query Log's page\n* Dark theme\n\nDo you have a feature request? Please, [write an issue](https://github.com/friimaind/pi-hole-droid/issues).\n\n## Oh no! I found a bug!\n\nPlease, [write an issue](https://github.com/friimaind/pi-hole-droid/issues).\n\n## Authors\n\n* **Massimiliano Monaro** - [blog.friimaind.it](https://blog.friimaind.it)\n\n## Contributing\n\nIf you want to contribute to this project and make it better, your help is very welcome! :)\n\n## App permissions\n\nThe app could scan the QR Code of your Pi-hole to retrieve the token. This function uses the camera of your smartphone so this is the reason why the app needs the **camera permission**.\n\n## License\n\nThis project is licensed under the terms of the [GNU General Public License v2.0](LICENSE).\n"
  },
  {
    "path": "config.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<widget id=\"friimaind.piholedroid\" version=\"1.0.5\" xmlns=\"http://www.w3.org/ns/widgets\" xmlns:cdv=\"http://cordova.apache.org/ns/1.0\">\n    <name>Pi-hole Droid</name>\n    <description>\n        Monitor your Pi-hole with your Android smartphone\n    </description>\n    <author email=\"massimiliano.monaro@gmail.com\" href=\"https://blog.friimaind.it\">\n        Massimiliano Monaro\n    </author>\n    <content src=\"index.html\" />\n    <plugin name=\"cordova-plugin-whitelist\" spec=\"1\" />\n    <access origin=\"*\" />\n    <allow-intent href=\"http://*/*\" />\n    <allow-intent href=\"https://*/*\" />\n    <allow-intent href=\"tel:*\" />\n    <allow-intent href=\"sms:*\" />\n    <allow-intent href=\"mailto:*\" />\n    <allow-intent href=\"geo:*\" />\n    <preference name=\"Fullscreen\" value=\"false\" />\n    <preference name=\"SplashScreenDelay\" value=\"2000\" />\n    <preference name=\"SplashScreen\" value=\"screen\"/>\n    <preference name=\"SplashMaintainAspectRatio\" value=\"true\" />\n    <preference name=\"ShowSplashScreenSpinner\" value=\"false\" />\n    <platform name=\"android\">\n        <icon src=\"www/assets/mipmap-ldpi/ic_launcher.png\" density=\"ldpi\" />\n        <icon src=\"www/assets/mipmap-mdpi/ic_launcher.png\" density=\"mdpi\" />\n        <icon src=\"www/assets/mipmap-hdpi/ic_launcher.png\" density=\"hdpi\" />\n        <icon src=\"www/assets/mipmap-xhdpi/ic_launcher.png\" density=\"xhdpi\" />\n        <allow-intent href=\"market:*\" />\n    </platform>\n</widget>\n"
  },
  {
    "path": "hooks/README.md",
    "content": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#  KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n#\n-->\n# Cordova Hooks\n\nCordova Hooks represent special scripts which could be added by application and plugin developers or even by your own build system  to customize cordova commands. See Hooks Guide for more details:  http://cordova.apache.org/docs/en/edge/guide_appdev_hooks_index.md.html#Hooks%20Guide.\n"
  },
  {
    "path": "platforms/android/.gitignore",
    "content": "# Non-project-specific build files:\nbuild.xml\nlocal.properties\n/gradlew\n/gradlew.bat\n/gradle\n# Ant builds\nant-build\nant-gen\n# Eclipse builds\ngen\nout\n# Gradle builds\n/build\n"
  },
  {
    "path": "platforms/android/AndroidManifest.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<manifest android:hardwareAccelerated=\"true\" android:versionCode=\"10005\" android:versionName=\"1.0.5\" package=\"friimaind.piholedroid\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <supports-screens android:anyDensity=\"true\" android:largeScreens=\"true\" android:normalScreens=\"true\" android:resizeable=\"true\" android:smallScreens=\"true\" android:xlargeScreens=\"true\" />\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <application android:hardwareAccelerated=\"true\" android:icon=\"@mipmap/icon\" android:label=\"@string/app_name\" android:supportsRtl=\"true\">\n        <activity android:configChanges=\"orientation|keyboardHidden|keyboard|screenSize|locale\" android:label=\"@string/activity_name\" android:launchMode=\"singleTop\" android:name=\"MainActivity\" android:theme=\"@android:style/Theme.DeviceDefault.NoActionBar\" android:windowSoftInputMode=\"adjustResize\">\n            <intent-filter android:label=\"@string/launcher_name\">\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity android:clearTaskOnLaunch=\"true\" android:configChanges=\"orientation|keyboardHidden|screenSize\" android:exported=\"false\" android:name=\"com.google.zxing.client.android.CaptureActivity\" android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\" android:windowSoftInputMode=\"stateAlwaysHidden\" />\n        <activity android:label=\"Share\" android:name=\"com.google.zxing.client.android.encode.EncodeActivity\" />\n    </application>\n    <uses-sdk android:minSdkVersion=\"16\" android:targetSdkVersion=\"25\" />\n    <uses-permission android:name=\"android.permission.CAMERA\" />\n    <uses-permission android:name=\"android.permission.FLASHLIGHT\" />\n    <uses-feature android:name=\"android.hardware.camera\" android:required=\"true\" />\n</manifest>\n"
  },
  {
    "path": "platforms/android/CordovaLib/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n-->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n      package=\"org.apache.cordova\" android:versionName=\"1.0\" android:versionCode=\"1\">\n    <uses-sdk android:minSdkVersion=\"14\" />\n</manifest>\n"
  },
  {
    "path": "platforms/android/CordovaLib/build/generated/source/buildConfig/debug/org/apache/cordova/BuildConfig.java",
    "content": "/**\n * Automatically generated file. DO NOT MODIFY\n */\npackage org.apache.cordova;\n\npublic final class BuildConfig {\n  public static final boolean DEBUG = Boolean.parseBoolean(\"true\");\n  public static final String APPLICATION_ID = \"org.apache.cordova\";\n  public static final String BUILD_TYPE = \"debug\";\n  public static final String FLAVOR = \"\";\n  public static final int VERSION_CODE = 1;\n  public static final String VERSION_NAME = \"1.0\";\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/build/generated/source/buildConfig/release/org/apache/cordova/BuildConfig.java",
    "content": "/**\n * Automatically generated file. DO NOT MODIFY\n */\npackage org.apache.cordova;\n\npublic final class BuildConfig {\n  public static final boolean DEBUG = false;\n  public static final String APPLICATION_ID = \"org.apache.cordova\";\n  public static final String BUILD_TYPE = \"release\";\n  public static final String FLAVOR = \"\";\n  public static final int VERSION_CODE = 1;\n  public static final String VERSION_NAME = \"1.0\";\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/bundles/debug/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n-->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"org.apache.cordova\"\n    android:versionCode=\"1\"\n    android:versionName=\"1.0\" >\n\n    <uses-sdk android:minSdkVersion=\"14\" />\n\n</manifest>"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/bundles/release/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n-->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"org.apache.cordova\"\n    android:versionCode=\"1\"\n    android:versionName=\"1.0\" >\n\n    <uses-sdk android:minSdkVersion=\"14\" />\n\n</manifest>"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/incremental/mergeDebugAssets/merger.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<merger version=\"3\"><dataSet config=\"main\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/assets\"/><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/build/generated/assets/shaders/debug\"/></dataSet><dataSet config=\"debug\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/debug/assets\"/></dataSet></merger>"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<merger version=\"3\"><dataSet config=\"main\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/main/jniLibs\"/></dataSet><dataSet config=\"debug\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/debug/jniLibs\"/></dataSet></merger>"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/incremental/mergeDebugShaders/merger.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<merger version=\"3\"><dataSet config=\"main\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/main/shaders\"/></dataSet><dataSet config=\"debug\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/debug/shaders\"/></dataSet></merger>"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/incremental/mergeReleaseAssets/merger.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<merger version=\"3\"><dataSet config=\"main\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/assets\"/><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/build/generated/assets/shaders/release\"/></dataSet><dataSet config=\"release\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/release/assets\"/></dataSet></merger>"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<merger version=\"3\"><dataSet config=\"main\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/main/jniLibs\"/></dataSet><dataSet config=\"release\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/release/jniLibs\"/></dataSet></merger>"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/incremental/mergeReleaseShaders/merger.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<merger version=\"3\"><dataSet config=\"main\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/main/shaders\"/></dataSet><dataSet config=\"release\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/release/shaders\"/></dataSet></merger>"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/incremental/packageDebugResources/compile-file-map.properties",
    "content": "#Sun Apr 23 15:43:32 CEST 2017\n"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/incremental/packageDebugResources/merger.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<merger version=\"3\"><dataSet config=\"main$Generated\" generated=\"true\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/res\"/><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/build/generated/res/rs/debug\"/><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/build/generated/res/resValues/debug\"/></dataSet><dataSet config=\"debug$Generated\" generated=\"true\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/debug/res\"/></dataSet><dataSet config=\"main\" generated-set=\"main$Generated\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/res\"/><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/build/generated/res/rs/debug\"/><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/build/generated/res/resValues/debug\"/></dataSet><dataSet config=\"debug\" generated-set=\"debug$Generated\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/debug/res\"/></dataSet><mergedItems/></merger>"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/incremental/packageReleaseResources/compile-file-map.properties",
    "content": "#Sun Apr 23 15:43:32 CEST 2017\n"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/incremental/packageReleaseResources/merger.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<merger version=\"3\"><dataSet config=\"main$Generated\" generated=\"true\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/res\"/><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/build/generated/res/rs/release\"/><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/build/generated/res/resValues/release\"/></dataSet><dataSet config=\"release$Generated\" generated=\"true\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/release/res\"/></dataSet><dataSet config=\"main\" generated-set=\"main$Generated\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/res\"/><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/build/generated/res/rs/release\"/><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/build/generated/res/resValues/release\"/></dataSet><dataSet config=\"release\" generated-set=\"release$Generated\"><source path=\"/home/massimiliano/cordova/piholeApp/platforms/android/CordovaLib/src/release/res\"/></dataSet><mergedItems/></merger>"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/incremental-safeguard/debug/tag.txt",
    "content": "incremental task execution"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/incremental-safeguard/release/tag.txt",
    "content": "incremental task execution"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/manifests/aapt/debug/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n-->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"org.apache.cordova\"\n    android:versionCode=\"1\"\n    android:versionName=\"1.0\" >\n\n    <uses-sdk android:minSdkVersion=\"14\" />\n\n</manifest>"
  },
  {
    "path": "platforms/android/CordovaLib/build/intermediates/manifests/aapt/release/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n-->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"org.apache.cordova\"\n    android:versionCode=\"1\"\n    android:versionName=\"1.0\" >\n\n    <uses-sdk android:minSdkVersion=\"14\" />\n\n</manifest>"
  },
  {
    "path": "platforms/android/CordovaLib/build.gradle",
    "content": "/* Licensed to the Apache Software Foundation (ASF) under one\n   or more contributor license agreements.  See the NOTICE file\n   distributed with this work for additional information\n   regarding copyright ownership.  The ASF licenses this file\n   to you under the Apache License, Version 2.0 (the\n   \"License\"); you may not use this file except in compliance\n   with the License.  You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing,\n   software distributed under the License is distributed on an\n   \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n   KIND, either express or implied.  See the License for the\n   specific language governing permissions and limitations\n   under the License.\n*/\n\next {\n    apply from: 'cordova.gradle'\n    cdvCompileSdkVersion = privateHelpers.getProjectTarget()\n    cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()\n}\n\nbuildscript {\n    repositories {\n        mavenCentral()\n        jcenter()\n    }\n\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.2.3'\n        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'\n        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'\n    }\n}\n\napply plugin: 'com.android.library'\napply plugin: 'com.github.dcendents.android-maven'\napply plugin: 'com.jfrog.bintray'\n\ngroup = 'org.apache.cordova'\nversion = '6.2.0'\n\nandroid {\n    compileSdkVersion cdvCompileSdkVersion\n    buildToolsVersion cdvBuildToolsVersion\n    publishNonDefault true\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_6\n        targetCompatibility JavaVersion.VERSION_1_6\n    }\n\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['src']\n            aidl.srcDirs = ['src']\n            renderscript.srcDirs = ['src']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n        }\n    }\n\n    packagingOptions {\n        exclude 'META-INF/LICENSE'\n        exclude 'META-INF/LICENSE.txt'\n        exclude 'META-INF/DEPENDENCIES'\n        exclude 'META-INF/NOTICE'\n    }\n}\n\ninstall {\n    repositories.mavenInstaller {\n        pom {\n            project {\n                packaging 'aar'\n                name 'Cordova'\n                url 'https://cordova.apache.org'\n                licenses {\n                    license {\n                        name 'The Apache Software License, Version 2.0'\n                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                    }\n                }\n                developers {\n                    developer {\n                        id 'stevengill'\n                        name 'Steve Gill'\n                    }\n                }\n                scm {\n                    connection 'https://git-wip-us.apache.org/repos/asf?p=cordova-android.git'\n                    developerConnection 'https://git-wip-us.apache.org/repos/asf?p=cordova-android.git'\n                    url 'https://git-wip-us.apache.org/repos/asf?p=cordova-android'\n\n                }\n            }\n        }\n    }\n}\n\ntask sourcesJar(type: Jar) {\n    from android.sourceSets.main.java.srcDirs\n    classifier = 'sources'\n}\n\nartifacts {\n    archives sourcesJar\n}\n\nbintray {\n    user = System.getenv('BINTRAY_USER')\n    key = System.getenv('BINTRAY_KEY')\n    configurations = ['archives']\n    pkg {\n        repo = 'maven'\n        name = 'cordova-android'\n        userOrg = 'cordova'\n        licenses = ['Apache-2.0']\n        vcsUrl = 'https://git-wip-us.apache.org/repos/asf?p=cordova-android.git'\n        websiteUrl = 'https://cordova.apache.org'\n        issueTrackerUrl = 'https://issues.apache.org/jira/browse/CB'\n        publicDownloadNumbers = true\n        licenses = ['Apache-2.0']\n        labels = ['android', 'cordova', 'phonegap']\n        version {\n            name = version\n            released  = new Date()\n            vcsTag = version\n        }\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/cordova.gradle",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nimport java.util.regex.Pattern\nimport groovy.swing.SwingBuilder\n\nString doEnsureValueExists(filePath, props, key) {\n    if (props.get(key) == null) {\n        throw new GradleException(filePath + ': Missing key required \"' + key + '\"')\n    }\n    return props.get(key)\n}\n\nString doGetProjectTarget() {\n    def props = new Properties()\n    file('project.properties').withReader { reader ->\n        props.load(reader)\n    }\n    return doEnsureValueExists('project.properties', props, 'target')\n}\n\nString[] getAvailableBuildTools() {\n    def buildToolsDir = new File(getAndroidSdkDir(), \"build-tools\")\n    buildToolsDir.list()\n        .findAll { it ==~ /[0-9.]+/ }\n        .sort { a, b -> compareVersions(b, a) }\n}\n\nString doFindLatestInstalledBuildTools(String minBuildToolsVersion) {\n    def availableBuildToolsVersions\n    try {\n        availableBuildToolsVersions = getAvailableBuildTools()\n    } catch (e) {\n        println \"An exception occurred while trying to find the Android build tools.\"\n        throw e\n    }\n    if (availableBuildToolsVersions.length > 0) {\n        def highestBuildToolsVersion = availableBuildToolsVersions[0]\n        if (compareVersions(highestBuildToolsVersion, minBuildToolsVersion) < 0) {\n            throw new RuntimeException(\n                \"No usable Android build tools found. Highest installed version is \" +\n                highestBuildToolsVersion + \"; minimum version required is \" +\n                minBuildToolsVersion + \".\")\n        }\n        highestBuildToolsVersion\n    } else {\n        throw new RuntimeException(\n            \"No installed build tools found. Install the Android build tools version \" +\n            minBuildToolsVersion + \" or higher.\")\n    }\n}\n\n// Return the first non-zero result of subtracting version list elements\n// pairwise. If they are all identical, return the difference in length of\n// the two lists.\nint compareVersionList(Collection aParts, Collection bParts) {\n    def pairs = ([aParts, bParts]).transpose()\n    pairs.findResult(aParts.size()-bParts.size()) {it[0] - it[1] != 0 ? it[0] - it[1] : null}\n}\n\n// Compare two version strings, such as \"19.0.0\" and \"18.1.1.0\". If all matched\n// elements are identical, the longer version is the largest by this method.\n// Examples:\n//   \"19.0.0\" > \"19\"\n//   \"19.0.1\" > \"19.0.0\"\n//   \"19.1.0\" > \"19.0.1\"\n//   \"19\" > \"18.999.999\"\nint compareVersions(String a, String b) {\n    def aParts = a.tokenize('.').collect {it.toInteger()}\n    def bParts = b.tokenize('.').collect {it.toInteger()}\n    compareVersionList(aParts, bParts)\n}\n\nString getAndroidSdkDir() {\n    def rootDir = project.rootDir\n    def androidSdkDir = null\n    String envVar = System.getenv(\"ANDROID_HOME\")\n    def localProperties = new File(rootDir, 'local.properties')\n    String systemProperty = System.getProperty(\"android.home\")\n    if (envVar != null) {\n        androidSdkDir = envVar\n    } else if (localProperties.exists()) {\n        Properties properties = new Properties()\n        localProperties.withInputStream { instr ->\n            properties.load(instr)\n        }\n        def sdkDirProp = properties.getProperty('sdk.dir')\n        if (sdkDirProp != null) {\n            androidSdkDir = sdkDirProp\n        } else {\n            sdkDirProp = properties.getProperty('android.dir')\n            if (sdkDirProp != null) {\n                androidSdkDir = (new File(rootDir, sdkDirProp)).getAbsolutePath()\n            }\n        }\n    }\n    if (androidSdkDir == null && systemProperty != null) {\n        androidSdkDir = systemProperty\n    }\n    if (androidSdkDir == null) {\n        throw new RuntimeException(\n            \"Unable to determine Android SDK directory.\")\n    }\n    androidSdkDir\n}\n\ndef doExtractIntFromManifest(name) {\n    def manifestFile = file(android.sourceSets.main.manifest.srcFile)\n    def pattern = Pattern.compile(name + \"=\\\"(\\\\d+)\\\"\")\n    def matcher = pattern.matcher(manifestFile.getText())\n    matcher.find()\n    return new BigInteger(matcher.group(1))\n}\n\ndef doExtractStringFromManifest(name) {\n    def manifestFile = file(android.sourceSets.main.manifest.srcFile)\n    def pattern = Pattern.compile(name + \"=\\\"(\\\\S+)\\\"\")\n    def matcher = pattern.matcher(manifestFile.getText())\n    matcher.find()\n    return matcher.group(1)\n}\n\ndef doPromptForPassword(msg) {\n    if (System.console() == null) {\n        def ret = null\n        new SwingBuilder().edt {\n            dialog(modal: true, title: 'Enter password', alwaysOnTop: true, resizable: false, locationRelativeTo: null, pack: true, show: true) {\n                vbox {\n                    label(text: msg)\n                    def input = passwordField()\n                    button(defaultButton: true, text: 'OK', actionPerformed: {\n                        ret = input.password;\n                        dispose();\n                    })\n                }\n            }\n        }\n        if (!ret) {\n            throw new GradleException('User canceled build')\n        }\n        return new String(ret)\n    } else {\n        return System.console().readPassword('\\n' + msg);\n    }\n}\n\ndef doGetConfigXml() {\n    def xml = file(\"res/xml/config.xml\").getText()\n    // Disable namespace awareness since Cordova doesn't use them properly\n    return new XmlParser(false, false).parseText(xml)\n}\n\ndef doGetConfigPreference(name, defaultValue) {\n    name = name.toLowerCase()\n    def root = doGetConfigXml()\n\n    def ret = defaultValue\n    root.preference.each { it ->\n        def attrName = it.attribute(\"name\")\n        if (attrName && attrName.toLowerCase() == name) {\n            ret = it.attribute(\"value\")\n        }\n    }\n    return ret\n}\n\n// Properties exported here are visible to all plugins.\next {\n    // These helpers are shared, but are not guaranteed to be stable / unchanged.\n    privateHelpers = {}\n    privateHelpers.getProjectTarget = { doGetProjectTarget() }\n    privateHelpers.findLatestInstalledBuildTools = { doFindLatestInstalledBuildTools('19.1.0') }\n    privateHelpers.extractIntFromManifest = { name -> doExtractIntFromManifest(name) }\n    privateHelpers.extractStringFromManifest = { name -> doExtractStringFromManifest(name) }\n    privateHelpers.promptForPassword = { msg -> doPromptForPassword(msg) }\n    privateHelpers.ensureValueExists = { filePath, props, key -> doEnsureValueExists(filePath, props, key) }\n\n    // These helpers can be used by plugins / projects and will not change.\n    cdvHelpers = {}\n    // Returns a XmlParser for the config.xml. Added in 4.1.0.\n    cdvHelpers.getConfigXml = { doGetConfigXml() }\n    // Returns the value for the desired <preference>. Added in 4.1.0.\n    cdvHelpers.getConfigPreference = { name, defaultValue -> doGetConfigPreference(name, defaultValue) }\n}\n\n"
  },
  {
    "path": "platforms/android/CordovaLib/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system use,\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n\n# Indicates whether an apk should be generated for each density.\nsplit.density=false\n# Project target.\ntarget=android-25\napk-configurations=\nrenderscript.opt.level=O0\nandroid.library=true\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/AuthenticationToken.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\n/**\n * The Class AuthenticationToken defines the userName and password to be used for authenticating a web resource\n */\npublic class AuthenticationToken {\n    private String userName;\n    private String password;\n\n    /**\n     * Gets the user name.\n     *\n     * @return the user name\n     */\n    public String getUserName() {\n        return userName;\n    }\n\n    /**\n     * Sets the user name.\n     *\n     * @param userName\n     *            the new user name\n     */\n    public void setUserName(String userName) {\n        this.userName = userName;\n    }\n\n    /**\n     * Gets the password.\n     *\n     * @return the password\n     */\n    public String getPassword() {\n        return password;\n    }\n\n    /**\n     * Sets the password.\n     *\n     * @param password\n     *            the new password\n     */\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CallbackContext.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport org.json.JSONArray;\n\nimport org.apache.cordova.CordovaWebView;\nimport org.apache.cordova.PluginResult;\nimport org.json.JSONObject;\n\npublic class CallbackContext {\n    private static final String LOG_TAG = \"CordovaPlugin\";\n\n    private String callbackId;\n    private CordovaWebView webView;\n    protected boolean finished;\n    private int changingThreads;\n\n    public CallbackContext(String callbackId, CordovaWebView webView) {\n        this.callbackId = callbackId;\n        this.webView = webView;\n    }\n\n    public boolean isFinished() {\n        return finished;\n    }\n\n    public boolean isChangingThreads() {\n        return changingThreads > 0;\n    }\n\n    public String getCallbackId() {\n        return callbackId;\n    }\n\n    public void sendPluginResult(PluginResult pluginResult) {\n        synchronized (this) {\n            if (finished) {\n                LOG.w(LOG_TAG, \"Attempted to send a second callback for ID: \" + callbackId + \"\\nResult was: \" + pluginResult.getMessage());\n                return;\n            } else {\n                finished = !pluginResult.getKeepCallback();\n            }\n        }\n        webView.sendPluginResult(pluginResult, callbackId);\n    }\n\n    /**\n     * Helper for success callbacks that just returns the Status.OK by default\n     *\n     * @param message           The message to add to the success result.\n     */\n    public void success(JSONObject message) {\n        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));\n    }\n\n    /**\n     * Helper for success callbacks that just returns the Status.OK by default\n     *\n     * @param message           The message to add to the success result.\n     */\n    public void success(String message) {\n        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));\n    }\n\n    /**\n     * Helper for success callbacks that just returns the Status.OK by default\n     *\n     * @param message           The message to add to the success result.\n     */\n    public void success(JSONArray message) {\n        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));\n    }\n\n    /**\n     * Helper for success callbacks that just returns the Status.OK by default\n     *\n     * @param message           The message to add to the success result.\n     */\n    public void success(byte[] message) {\n        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));\n    }\n\n    /**\n     * Helper for success callbacks that just returns the Status.OK by default\n     *\n     * @param message           The message to add to the success result.\n     */\n    public void success(int message) {\n        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));\n    }\n\n    /**\n     * Helper for success callbacks that just returns the Status.OK by default\n     */\n    public void success() {\n        sendPluginResult(new PluginResult(PluginResult.Status.OK));\n    }\n\n    /**\n     * Helper for error callbacks that just returns the Status.ERROR by default\n     *\n     * @param message           The message to add to the error result.\n     */\n    public void error(JSONObject message) {\n        sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message));\n    }\n\n    /**\n     * Helper for error callbacks that just returns the Status.ERROR by default\n     *\n     * @param message           The message to add to the error result.\n     */\n    public void error(String message) {\n        sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message));\n    }\n\n    /**\n     * Helper for error callbacks that just returns the Status.ERROR by default\n     *\n     * @param message           The message to add to the error result.\n     */\n    public void error(int message) {\n        sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message));\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CallbackMap.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport android.util.Pair;\nimport android.util.SparseArray;\n\n/**\n * Provides a collection that maps unique request codes to CordovaPlugins and Integers.\n * Used to ensure that when plugins make requests for runtime permissions, those requests do not\n * collide with requests from other plugins that use the same request code value.\n */\npublic class CallbackMap {\n    private int currentCallbackId = 0;\n    private SparseArray<Pair<CordovaPlugin, Integer>> callbacks;\n\n    public CallbackMap() {\n        this.callbacks = new SparseArray<Pair<CordovaPlugin, Integer>>();\n    }\n\n    /**\n     * Stores a CordovaPlugin and request code and returns a new unique request code to use\n     * in a permission request.\n     *\n     * @param receiver      The plugin that is making the request\n     * @param requestCode   The original request code used by the plugin\n     * @return              A unique request code that can be used to retrieve this callback\n     *                      with getAndRemoveCallback()\n     */\n    public synchronized int registerCallback(CordovaPlugin receiver, int requestCode) {\n        int mappedId = this.currentCallbackId++;\n        callbacks.put(mappedId, new Pair<CordovaPlugin, Integer>(receiver, requestCode));\n        return mappedId;\n    }\n\n    /**\n     * Retrieves and removes a callback stored in the map using the mapped request code\n     * obtained from registerCallback()\n     *\n     * @param mappedId      The request code obtained from registerCallback()\n     * @return              The CordovaPlugin and orignal request code that correspond to the\n     *                      given mappedCode\n     */\n    public synchronized Pair<CordovaPlugin, Integer> getAndRemoveCallback(int mappedId) {\n        Pair<CordovaPlugin, Integer> callback = callbacks.get(mappedId);\n        callbacks.remove(mappedId);\n        return callback;\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/Config.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova;\n\nimport java.util.List;\n\nimport android.app.Activity;\n\n@Deprecated // Use Whitelist, CordovaPrefences, etc. directly.\npublic class Config {\n    private static final String TAG = \"Config\";\n\n    static ConfigXmlParser parser;\n\n    private Config() {\n    }\n\n    public static void init(Activity action) {\n        parser = new ConfigXmlParser();\n        parser.parse(action);\n        //TODO: Add feature to bring this back.  Some preferences should be overridden by intents, but not all\n        parser.getPreferences().setPreferencesBundle(action.getIntent().getExtras());\n    }\n\n    // Intended to be used for testing only; creates an empty configuration.\n    public static void init() {\n        if (parser == null) {\n            parser = new ConfigXmlParser();\n        }\n    }\n\n    public static String getStartUrl() {\n        if (parser == null) {\n            return \"file:///android_asset/www/index.html\";\n        }\n        return parser.getLaunchUrl();\n    }\n\n    public static String getErrorUrl() {\n        return parser.getPreferences().getString(\"errorurl\", null);\n    }\n\n    public static List<PluginEntry> getPluginEntries() {\n        return parser.getPluginEntries();\n    }\n\n    public static CordovaPreferences getPreferences() {\n        return parser.getPreferences();\n    }\n\n    public static boolean isInitialized() {\n        return parser != null;\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Locale;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport android.content.Context;\n\npublic class ConfigXmlParser {\n    private static String TAG = \"ConfigXmlParser\";\n\n    private String launchUrl = \"file:///android_asset/www/index.html\";\n    private CordovaPreferences prefs = new CordovaPreferences();\n    private ArrayList<PluginEntry> pluginEntries = new ArrayList<PluginEntry>(20);\n\n    public CordovaPreferences getPreferences() {\n        return prefs;\n    }\n\n    public ArrayList<PluginEntry> getPluginEntries() {\n        return pluginEntries;\n    }\n\n    public String getLaunchUrl() {\n        return launchUrl;\n    }\n\n    public void parse(Context action) {\n        // First checking the class namespace for config.xml\n        int id = action.getResources().getIdentifier(\"config\", \"xml\", action.getClass().getPackage().getName());\n        if (id == 0) {\n            // If we couldn't find config.xml there, we'll look in the namespace from AndroidManifest.xml\n            id = action.getResources().getIdentifier(\"config\", \"xml\", action.getPackageName());\n            if (id == 0) {\n                LOG.e(TAG, \"res/xml/config.xml is missing!\");\n                return;\n            }\n        }\n        parse(action.getResources().getXml(id));\n    }\n\n    boolean insideFeature = false;\n    String service = \"\", pluginClass = \"\", paramType = \"\";\n    boolean onload = false;\n\n    public void parse(XmlPullParser xml) {\n        int eventType = -1;\n\n        while (eventType != XmlPullParser.END_DOCUMENT) {\n            if (eventType == XmlPullParser.START_TAG) {\n                handleStartTag(xml);\n            }\n            else if (eventType == XmlPullParser.END_TAG)\n            {\n                handleEndTag(xml);\n            }\n            try {\n                eventType = xml.next();\n            } catch (XmlPullParserException e) {\n                e.printStackTrace();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public void handleStartTag(XmlPullParser xml) {\n        String strNode = xml.getName();\n        if (strNode.equals(\"feature\")) {\n            //Check for supported feature sets  aka. plugins (Accelerometer, Geolocation, etc)\n            //Set the bit for reading params\n            insideFeature = true;\n            service = xml.getAttributeValue(null, \"name\");\n        }\n        else if (insideFeature && strNode.equals(\"param\")) {\n            paramType = xml.getAttributeValue(null, \"name\");\n            if (paramType.equals(\"service\")) // check if it is using the older service param\n                service = xml.getAttributeValue(null, \"value\");\n            else if (paramType.equals(\"package\") || paramType.equals(\"android-package\"))\n                pluginClass = xml.getAttributeValue(null,\"value\");\n            else if (paramType.equals(\"onload\"))\n                onload = \"true\".equals(xml.getAttributeValue(null, \"value\"));\n        }\n        else if (strNode.equals(\"preference\")) {\n            String name = xml.getAttributeValue(null, \"name\").toLowerCase(Locale.ENGLISH);\n            String value = xml.getAttributeValue(null, \"value\");\n            prefs.set(name, value);\n        }\n        else if (strNode.equals(\"content\")) {\n            String src = xml.getAttributeValue(null, \"src\");\n            if (src != null) {\n                setStartUrl(src);\n            }\n        }\n    }\n\n    public void handleEndTag(XmlPullParser xml) {\n        String strNode = xml.getName();\n        if (strNode.equals(\"feature\")) {\n            pluginEntries.add(new PluginEntry(service, pluginClass, onload));\n\n            service = \"\";\n            pluginClass = \"\";\n            insideFeature = false;\n            onload = false;\n        }\n    }\n\n    private void setStartUrl(String src) {\n        Pattern schemeRegex = Pattern.compile(\"^[a-z-]+://\");\n        Matcher matcher = schemeRegex.matcher(src);\n        if (matcher.find()) {\n            launchUrl = src;\n        } else {\n            if (src.charAt(0) == '/') {\n                src = src.substring(1);\n            }\n            launchUrl = \"file:///android_asset/www/\" + src;\n        }\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport java.util.ArrayList;\nimport java.util.Locale;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.annotation.SuppressLint;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.res.Configuration;\nimport android.graphics.Color;\nimport android.media.AudioManager;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.Window;\nimport android.view.WindowManager;\nimport android.webkit.WebViewClient;\nimport android.widget.FrameLayout;\n\n/**\n * This class is the main Android activity that represents the Cordova\n * application. It should be extended by the user to load the specific\n * html file that contains the application.\n *\n * As an example:\n *\n * <pre>\n *     package org.apache.cordova.examples;\n *\n *     import android.os.Bundle;\n *     import org.apache.cordova.*;\n *\n *     public class Example extends CordovaActivity {\n *       &#64;Override\n *       public void onCreate(Bundle savedInstanceState) {\n *         super.onCreate(savedInstanceState);\n *         super.init();\n *         // Load your application\n *         loadUrl(launchUrl);\n *       }\n *     }\n * </pre>\n *\n * Cordova xml configuration: Cordova uses a configuration file at\n * res/xml/config.xml to specify its settings. See \"The config.xml File\"\n * guide in cordova-docs at http://cordova.apache.org/docs for the documentation\n * for the configuration. The use of the set*Property() methods is\n * deprecated in favor of the config.xml file.\n *\n */\npublic class CordovaActivity extends Activity {\n    public static String TAG = \"CordovaActivity\";\n\n    // The webview for our app\n    protected CordovaWebView appView;\n\n    private static int ACTIVITY_STARTING = 0;\n    private static int ACTIVITY_RUNNING = 1;\n    private static int ACTIVITY_EXITING = 2;\n\n    // Keep app running when pause is received. (default = true)\n    // If true, then the JavaScript and native code continue to run in the background\n    // when another application (activity) is started.\n    protected boolean keepRunning = true;\n\n    // Flag to keep immersive mode if set to fullscreen\n    protected boolean immersiveMode;\n\n    // Read from config.xml:\n    protected CordovaPreferences preferences;\n    protected String launchUrl;\n    protected ArrayList<PluginEntry> pluginEntries;\n    protected CordovaInterfaceImpl cordovaInterface;\n\n    /**\n     * Called when the activity is first created.\n     */\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        // need to activate preferences before super.onCreate to avoid \"requestFeature() must be called before adding content\" exception\n        loadConfig();\n\n        String logLevel = preferences.getString(\"loglevel\", \"ERROR\");\n        LOG.setLogLevel(logLevel);\n\n        LOG.i(TAG, \"Apache Cordova native platform version \" + CordovaWebView.CORDOVA_VERSION + \" is starting\");\n        LOG.d(TAG, \"CordovaActivity.onCreate()\");\n\n        if (!preferences.getBoolean(\"ShowTitle\", false)) {\n            getWindow().requestFeature(Window.FEATURE_NO_TITLE);\n        }\n\n        if (preferences.getBoolean(\"SetFullscreen\", false)) {\n            LOG.d(TAG, \"The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version.\");\n            preferences.set(\"Fullscreen\", true);\n        }\n        if (preferences.getBoolean(\"Fullscreen\", false)) {\n            // NOTE: use the FullscreenNotImmersive configuration key to set the activity in a REAL full screen\n            // (as was the case in previous cordova versions)\n            if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) && !preferences.getBoolean(\"FullscreenNotImmersive\", false)) {\n                immersiveMode = true;\n            } else {\n                getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,\n                        WindowManager.LayoutParams.FLAG_FULLSCREEN);\n            }\n        } else {\n            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,\n                    WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);\n        }\n\n        super.onCreate(savedInstanceState);\n\n        cordovaInterface = makeCordovaInterface();\n        if (savedInstanceState != null) {\n            cordovaInterface.restoreInstanceState(savedInstanceState);\n        }\n    }\n\n    protected void init() {\n        appView = makeWebView();\n        createViews();\n        if (!appView.isInitialized()) {\n            appView.init(cordovaInterface, pluginEntries, preferences);\n        }\n        cordovaInterface.onCordovaInit(appView.getPluginManager());\n\n        // Wire the hardware volume controls to control media if desired.\n        String volumePref = preferences.getString(\"DefaultVolumeStream\", \"\");\n        if (\"media\".equals(volumePref.toLowerCase(Locale.ENGLISH))) {\n            setVolumeControlStream(AudioManager.STREAM_MUSIC);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    protected void loadConfig() {\n        ConfigXmlParser parser = new ConfigXmlParser();\n        parser.parse(this);\n        preferences = parser.getPreferences();\n        preferences.setPreferencesBundle(getIntent().getExtras());\n        launchUrl = parser.getLaunchUrl();\n        pluginEntries = parser.getPluginEntries();\n        Config.parser = parser;\n    }\n\n    //Suppressing warnings in AndroidStudio\n    @SuppressWarnings({\"deprecation\", \"ResourceType\"})\n    protected void createViews() {\n        //Why are we setting a constant as the ID? This should be investigated\n        appView.getView().setId(100);\n        appView.getView().setLayoutParams(new FrameLayout.LayoutParams(\n                ViewGroup.LayoutParams.MATCH_PARENT,\n                ViewGroup.LayoutParams.MATCH_PARENT));\n\n        setContentView(appView.getView());\n\n        if (preferences.contains(\"BackgroundColor\")) {\n            try {\n                int backgroundColor = preferences.getInteger(\"BackgroundColor\", Color.BLACK);\n                // Background of activity:\n                appView.getView().setBackgroundColor(backgroundColor);\n            }\n            catch (NumberFormatException e){\n                e.printStackTrace();\n            }\n        }\n\n        appView.getView().requestFocusFromTouch();\n    }\n\n    /**\n     * Construct the default web view object.\n     * <p/>\n     * Override this to customize the webview that is used.\n     */\n    protected CordovaWebView makeWebView() {\n        return new CordovaWebViewImpl(makeWebViewEngine());\n    }\n\n    protected CordovaWebViewEngine makeWebViewEngine() {\n        return CordovaWebViewImpl.createEngine(this, preferences);\n    }\n\n    protected CordovaInterfaceImpl makeCordovaInterface() {\n        return new CordovaInterfaceImpl(this) {\n            @Override\n            public Object onMessage(String id, Object data) {\n                // Plumb this to CordovaActivity.onMessage for backwards compatibility\n                return CordovaActivity.this.onMessage(id, data);\n            }\n        };\n    }\n\n    /**\n     * Load the url into the webview.\n     */\n    public void loadUrl(String url) {\n        if (appView == null) {\n            init();\n        }\n\n        // If keepRunning\n        this.keepRunning = preferences.getBoolean(\"KeepRunning\", true);\n\n        appView.loadUrlIntoView(url, true);\n    }\n\n    /**\n     * Called when the system is about to start resuming a previous activity.\n     */\n    @Override\n    protected void onPause() {\n        super.onPause();\n        LOG.d(TAG, \"Paused the activity.\");\n\n        if (this.appView != null) {\n            // CB-9382 If there is an activity that started for result and main activity is waiting for callback\n            // result, we shoudn't stop WebView Javascript timers, as activity for result might be using them\n            boolean keepRunning = this.keepRunning || this.cordovaInterface.activityResultCallback != null;\n            this.appView.handlePause(keepRunning);\n        }\n    }\n\n    /**\n     * Called when the activity receives a new intent\n     */\n    @Override\n    protected void onNewIntent(Intent intent) {\n        super.onNewIntent(intent);\n        //Forward to plugins\n        if (this.appView != null)\n            this.appView.onNewIntent(intent);\n    }\n\n    /**\n     * Called when the activity will start interacting with the user.\n     */\n    @Override\n    protected void onResume() {\n        super.onResume();\n        LOG.d(TAG, \"Resumed the activity.\");\n\n        if (this.appView == null) {\n            return;\n        }\n        // Force window to have focus, so application always\n        // receive user input. Workaround for some devices (Samsung Galaxy Note 3 at least)\n        this.getWindow().getDecorView().requestFocus();\n\n        this.appView.handleResume(this.keepRunning);\n    }\n\n    /**\n     * Called when the activity is no longer visible to the user.\n     */\n    @Override\n    protected void onStop() {\n        super.onStop();\n        LOG.d(TAG, \"Stopped the activity.\");\n\n        if (this.appView == null) {\n            return;\n        }\n        this.appView.handleStop();\n    }\n\n    /**\n     * Called when the activity is becoming visible to the user.\n     */\n    @Override\n    protected void onStart() {\n        super.onStart();\n        LOG.d(TAG, \"Started the activity.\");\n\n        if (this.appView == null) {\n            return;\n        }\n        this.appView.handleStart();\n    }\n\n    /**\n     * The final call you receive before your activity is destroyed.\n     */\n    @Override\n    public void onDestroy() {\n        LOG.d(TAG, \"CordovaActivity.onDestroy()\");\n        super.onDestroy();\n\n        if (this.appView != null) {\n            appView.handleDestroy();\n        }\n    }\n\n    /**\n     * Called when view focus is changed\n     */\n    @Override\n    public void onWindowFocusChanged(boolean hasFocus) {\n        super.onWindowFocusChanged(hasFocus);\n        if (hasFocus && immersiveMode) {\n            final int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE\n                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION\n                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN\n                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION\n                    | View.SYSTEM_UI_FLAG_FULLSCREEN\n                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;\n\n            getWindow().getDecorView().setSystemUiVisibility(uiOptions);\n        }\n    }\n\n    @SuppressLint(\"NewApi\")\n    @Override\n    public void startActivityForResult(Intent intent, int requestCode, Bundle options) {\n        // Capture requestCode here so that it is captured in the setActivityResultCallback() case.\n        cordovaInterface.setActivityResultRequestCode(requestCode);\n        super.startActivityForResult(intent, requestCode, options);\n    }\n\n    /**\n     * Called when an activity you launched exits, giving you the requestCode you started it with,\n     * the resultCode it returned, and any additional data from it.\n     *\n     * @param requestCode The request code originally supplied to startActivityForResult(),\n     *                    allowing you to identify who this result came from.\n     * @param resultCode  The integer result code returned by the child activity through its setResult().\n     * @param intent      An Intent, which can return result data to the caller (various data can be attached to Intent \"extras\").\n     */\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {\n        LOG.d(TAG, \"Incoming Result. Request code = \" + requestCode);\n        super.onActivityResult(requestCode, resultCode, intent);\n        cordovaInterface.onActivityResult(requestCode, resultCode, intent);\n    }\n\n    /**\n     * Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable).\n     * The errorCode parameter corresponds to one of the ERROR_* constants.\n     *\n     * @param errorCode   The error code corresponding to an ERROR_* value.\n     * @param description A String describing the error.\n     * @param failingUrl  The url that failed to load.\n     */\n    public void onReceivedError(final int errorCode, final String description, final String failingUrl) {\n        final CordovaActivity me = this;\n\n        // If errorUrl specified, then load it\n        final String errorUrl = preferences.getString(\"errorUrl\", null);\n        if ((errorUrl != null) && (!failingUrl.equals(errorUrl)) && (appView != null)) {\n            // Load URL on UI thread\n            me.runOnUiThread(new Runnable() {\n                public void run() {\n                    me.appView.showWebPage(errorUrl, false, true, null);\n                }\n            });\n        }\n        // If not, then display error dialog\n        else {\n            final boolean exit = !(errorCode == WebViewClient.ERROR_HOST_LOOKUP);\n            me.runOnUiThread(new Runnable() {\n                public void run() {\n                    if (exit) {\n                        me.appView.getView().setVisibility(View.GONE);\n                        me.displayError(\"Application Error\", description + \" (\" + failingUrl + \")\", \"OK\", exit);\n                    }\n                }\n            });\n        }\n    }\n\n    /**\n     * Display an error dialog and optionally exit application.\n     */\n    public void displayError(final String title, final String message, final String button, final boolean exit) {\n        final CordovaActivity me = this;\n        me.runOnUiThread(new Runnable() {\n            public void run() {\n                try {\n                    AlertDialog.Builder dlg = new AlertDialog.Builder(me);\n                    dlg.setMessage(message);\n                    dlg.setTitle(title);\n                    dlg.setCancelable(false);\n                    dlg.setPositiveButton(button,\n                            new AlertDialog.OnClickListener() {\n                                public void onClick(DialogInterface dialog, int which) {\n                                    dialog.dismiss();\n                                    if (exit) {\n                                        finish();\n                                    }\n                                }\n                            });\n                    dlg.create();\n                    dlg.show();\n                } catch (Exception e) {\n                    finish();\n                }\n            }\n        });\n    }\n\n    /*\n     * Hook in Cordova for menu plugins\n     */\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        if (appView != null) {\n            appView.getPluginManager().postMessage(\"onCreateOptionsMenu\", menu);\n        }\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(Menu menu) {\n        if (appView != null) {\n            appView.getPluginManager().postMessage(\"onPrepareOptionsMenu\", menu);\n        }\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        if (appView != null) {\n            appView.getPluginManager().postMessage(\"onOptionsItemSelected\", item);\n        }\n        return true;\n    }\n\n    /**\n     * Called when a message is sent to plugin.\n     *\n     * @param id   The message id\n     * @param data The message data\n     * @return Object or null\n     */\n    public Object onMessage(String id, Object data) {\n        if (\"onReceivedError\".equals(id)) {\n            JSONObject d = (JSONObject) data;\n            try {\n                this.onReceivedError(d.getInt(\"errorCode\"), d.getString(\"description\"), d.getString(\"url\"));\n            } catch (JSONException e) {\n                e.printStackTrace();\n            }\n        } else if (\"exit\".equals(id)) {\n            finish();\n        }\n        return null;\n    }\n\n    protected void onSaveInstanceState(Bundle outState) {\n        cordovaInterface.onSaveInstanceState(outState);\n        super.onSaveInstanceState(outState);\n    }\n\n    /**\n     * Called by the system when the device configuration changes while your activity is running.\n     *\n     * @param newConfig The new device configuration\n     */\n    @Override\n    public void onConfigurationChanged(Configuration newConfig) {\n        super.onConfigurationChanged(newConfig);\n        if (this.appView == null) {\n            return;\n        }\n        PluginManager pm = this.appView.getPluginManager();\n        if (pm != null) {\n            pm.onConfigurationChanged(newConfig);\n        }\n    }\n\n    /**\n     * Called by the system when the user grants permissions\n     *\n     * @param requestCode\n     * @param permissions\n     * @param grantResults\n     */\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String permissions[],\n                                           int[] grantResults) {\n        try\n        {\n            cordovaInterface.onRequestPermissionResult(requestCode, permissions, grantResults);\n        }\n        catch (JSONException e)\n        {\n            LOG.d(TAG, \"JSONException: Parameters fed into the method are not valid\");\n            e.printStackTrace();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaArgs.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport android.util.Base64;\n\npublic class CordovaArgs {\n    private JSONArray baseArgs;\n\n    public CordovaArgs(JSONArray args) {\n        this.baseArgs = args;\n    }\n\n\n    // Pass through the basics to the base args.\n    public Object get(int index) throws JSONException {\n        return baseArgs.get(index);\n    }\n\n    public boolean getBoolean(int index) throws JSONException {\n        return baseArgs.getBoolean(index);\n    }\n\n    public double getDouble(int index) throws JSONException {\n        return baseArgs.getDouble(index);\n    }\n\n    public int getInt(int index) throws JSONException {\n        return baseArgs.getInt(index);\n    }\n\n    public JSONArray getJSONArray(int index) throws JSONException {\n        return baseArgs.getJSONArray(index);\n    }\n\n    public JSONObject getJSONObject(int index) throws JSONException {\n        return baseArgs.getJSONObject(index);\n    }\n\n    public long getLong(int index) throws JSONException {\n        return baseArgs.getLong(index);\n    }\n\n    public String getString(int index) throws JSONException {\n        return baseArgs.getString(index);\n    }\n\n\n    public Object opt(int index) {\n        return baseArgs.opt(index);\n    }\n\n    public boolean optBoolean(int index) {\n        return baseArgs.optBoolean(index);\n    }\n\n    public double optDouble(int index) {\n        return baseArgs.optDouble(index);\n    }\n\n    public int optInt(int index) {\n        return baseArgs.optInt(index);\n    }\n\n    public JSONArray optJSONArray(int index) {\n        return baseArgs.optJSONArray(index);\n    }\n\n    public JSONObject optJSONObject(int index) {\n        return baseArgs.optJSONObject(index);\n    }\n\n    public long optLong(int index) {\n        return baseArgs.optLong(index);\n    }\n\n    public String optString(int index) {\n        return baseArgs.optString(index);\n    }\n\n    public boolean isNull(int index) {\n        return baseArgs.isNull(index);\n    }\n\n\n    // The interesting custom helpers.\n    public byte[] getArrayBuffer(int index) throws JSONException {\n        String encoded = baseArgs.getString(index);\n        return Base64.decode(encoded, Base64.DEFAULT);\n    }\n}\n\n\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaBridge.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport java.security.SecureRandom;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\n\n/**\n * Contains APIs that the JS can call. All functions in here should also have\n * an equivalent entry in CordovaChromeClient.java, and be added to\n * cordova-js/lib/android/plugin/android/promptbasednativeapi.js\n */\npublic class CordovaBridge {\n    private static final String LOG_TAG = \"CordovaBridge\";\n    private PluginManager pluginManager;\n    private NativeToJsMessageQueue jsMessageQueue;\n    private volatile int expectedBridgeSecret = -1; // written by UI thread, read by JS thread.\n\n    public CordovaBridge(PluginManager pluginManager, NativeToJsMessageQueue jsMessageQueue) {\n        this.pluginManager = pluginManager;\n        this.jsMessageQueue = jsMessageQueue;\n    }\n\n    public String jsExec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {\n        if (!verifySecret(\"exec()\", bridgeSecret)) {\n            return null;\n        }\n        // If the arguments weren't received, send a message back to JS.  It will switch bridge modes and try again.  See CB-2666.\n        // We send a message meant specifically for this case.  It starts with \"@\" so no other message can be encoded into the same string.\n        if (arguments == null) {\n            return \"@Null arguments.\";\n        }\n\n        jsMessageQueue.setPaused(true);\n        try {\n            // Tell the resourceApi what thread the JS is running on.\n            CordovaResourceApi.jsThread = Thread.currentThread();\n\n            pluginManager.exec(service, action, callbackId, arguments);\n            String ret = null;\n            if (!NativeToJsMessageQueue.DISABLE_EXEC_CHAINING) {\n                ret = jsMessageQueue.popAndEncode(false);\n            }\n            return ret;\n        } catch (Throwable e) {\n            e.printStackTrace();\n            return \"\";\n        } finally {\n            jsMessageQueue.setPaused(false);\n        }\n    }\n\n    public void jsSetNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {\n        if (!verifySecret(\"setNativeToJsBridgeMode()\", bridgeSecret)) {\n            return;\n        }\n        jsMessageQueue.setBridgeMode(value);\n    }\n\n    public String jsRetrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {\n        if (!verifySecret(\"retrieveJsMessages()\", bridgeSecret)) {\n            return null;\n        }\n        return jsMessageQueue.popAndEncode(fromOnlineEvent);\n    }\n\n    private boolean verifySecret(String action, int bridgeSecret) throws IllegalAccessException {\n        if (!jsMessageQueue.isBridgeEnabled()) {\n            if (bridgeSecret == -1) {\n                LOG.d(LOG_TAG, action + \" call made before bridge was enabled.\");\n            } else {\n                LOG.d(LOG_TAG, \"Ignoring \" + action + \" from previous page load.\");\n            }\n            return false;\n        }\n        // Bridge secret wrong and bridge not due to it being from the previous page.\n        if (expectedBridgeSecret < 0 || bridgeSecret != expectedBridgeSecret) {\n            LOG.e(LOG_TAG, \"Bridge access attempt with wrong secret token, possibly from malicious code. Disabling exec() bridge!\");\n            clearBridgeSecret();\n            throw new IllegalAccessException();\n        }\n        return true;\n    }\n\n    /** Called on page transitions */\n    void clearBridgeSecret() {\n        expectedBridgeSecret = -1;\n    }\n\n    public boolean isSecretEstablished() {\n        return expectedBridgeSecret != -1;\n    }\n\n    /** Called by cordova.js to initialize the bridge. */\n    int generateBridgeSecret() {\n        SecureRandom randGen = new SecureRandom();\n        expectedBridgeSecret = randGen.nextInt(Integer.MAX_VALUE);\n        return expectedBridgeSecret;\n    }\n\n    public void reset() {\n        jsMessageQueue.reset();\n        clearBridgeSecret();\n    }\n\n    public String promptOnJsPrompt(String origin, String message, String defaultValue) {\n        if (defaultValue != null && defaultValue.length() > 3 && defaultValue.startsWith(\"gap:\")) {\n            JSONArray array;\n            try {\n                array = new JSONArray(defaultValue.substring(4));\n                int bridgeSecret = array.getInt(0);\n                String service = array.getString(1);\n                String action = array.getString(2);\n                String callbackId = array.getString(3);\n                String r = jsExec(bridgeSecret, service, action, callbackId, message);\n                return r == null ? \"\" : r;\n            } catch (JSONException e) {\n                e.printStackTrace();\n            } catch (IllegalAccessException e) {\n                e.printStackTrace();\n            }\n            return \"\";\n        }\n        // Sets the native->JS bridge mode.\n        else if (defaultValue != null && defaultValue.startsWith(\"gap_bridge_mode:\")) {\n            try {\n                int bridgeSecret = Integer.parseInt(defaultValue.substring(16));\n                jsSetNativeToJsBridgeMode(bridgeSecret, Integer.parseInt(message));\n            } catch (NumberFormatException e){\n                e.printStackTrace();\n            } catch (IllegalAccessException e) {\n                e.printStackTrace();\n            }\n            return \"\";\n        }\n        // Polling for JavaScript messages\n        else if (defaultValue != null && defaultValue.startsWith(\"gap_poll:\")) {\n            int bridgeSecret = Integer.parseInt(defaultValue.substring(9));\n            try {\n                String r = jsRetrieveJsMessages(bridgeSecret, \"1\".equals(message));\n                return r == null ? \"\" : r;\n            } catch (IllegalAccessException e) {\n                e.printStackTrace();\n            }\n            return \"\";\n        }\n        else if (defaultValue != null && defaultValue.startsWith(\"gap_init:\")) {\n            // Protect against random iframes being able to talk through the bridge.\n            // Trust only pages which the app would have been allowed to navigate to anyway.\n            if (pluginManager.shouldAllowBridgeAccess(origin)) {\n                // Enable the bridge\n                int bridgeMode = Integer.parseInt(defaultValue.substring(9));\n                jsMessageQueue.setBridgeMode(bridgeMode);\n                // Tell JS the bridge secret.\n                int secret = generateBridgeSecret();\n                return \"\"+secret;\n            } else {\n                LOG.e(LOG_TAG, \"gap_init called from restricted origin: \" + origin);\n            }\n            return \"\";\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaClientCertRequest.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport java.security.Principal;\nimport java.security.PrivateKey;\nimport java.security.cert.X509Certificate;\n\nimport android.webkit.ClientCertRequest;\n\n/**\n * Implementation of the ICordovaClientCertRequest for Android WebView.\n */\npublic class CordovaClientCertRequest implements ICordovaClientCertRequest {\n\n    private final ClientCertRequest request;\n\n    public CordovaClientCertRequest(ClientCertRequest request) {\n        this.request = request;\n    }\n    \n    /**\n     * Cancel this request\n     */\n    public void cancel()\n    {\n        request.cancel();\n    }\n    \n    /*\n     * Returns the host name of the server requesting the certificate.\n     */\n    public String getHost()\n    {\n        return request.getHost();\n    }\n    \n    /*\n     * Returns the acceptable types of asymmetric keys (can be null).\n     */\n    public String[] getKeyTypes()\n    {\n        return request.getKeyTypes();\n    }\n    \n    /*\n     * Returns the port number of the server requesting the certificate.\n     */\n    public int getPort()\n    {\n        return request.getPort();\n    }\n    \n    /*\n     * Returns the acceptable certificate issuers for the certificate matching the private key (can be null).\n     */\n    public Principal[] getPrincipals()\n    {\n        return request.getPrincipals();\n    }\n    \n    /*\n     * Ignore the request for now. Do not remember user's choice.\n     */\n    public void ignore()\n    {\n        request.ignore();\n    }\n    \n    /*\n     * Proceed with the specified private key and client certificate chain. Remember the user's positive choice and use it for future requests.\n     * \n     * @param privateKey The privateKey\n     * @param chain The certificate chain \n     */\n    public void proceed(PrivateKey privateKey, X509Certificate[] chain)\n    {\n        request.proceed(privateKey, chain);\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaDialogsHelper.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.view.KeyEvent;\nimport android.widget.EditText;\n\n/**\n * Helper class for WebViews to implement prompt(), alert(), confirm() dialogs.\n */\npublic class CordovaDialogsHelper {\n    private final Context context;\n    private AlertDialog lastHandledDialog;\n\n    public CordovaDialogsHelper(Context context) {\n        this.context = context;\n    }\n\n    public void showAlert(String message, final Result result) {\n        AlertDialog.Builder dlg = new AlertDialog.Builder(context);\n        dlg.setMessage(message);\n        dlg.setTitle(\"Alert\");\n        //Don't let alerts break the back button\n        dlg.setCancelable(true);\n        dlg.setPositiveButton(android.R.string.ok,\n                new AlertDialog.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        result.gotResult(true, null);\n                    }\n                });\n        dlg.setOnCancelListener(\n                new DialogInterface.OnCancelListener() {\n                    public void onCancel(DialogInterface dialog) {\n                        result.gotResult(false, null);\n                    }\n                });\n        dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {\n            //DO NOTHING\n            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {\n                if (keyCode == KeyEvent.KEYCODE_BACK)\n                {\n                    result.gotResult(true, null);\n                    return false;\n                }\n                else\n                    return true;\n            }\n        });\n        lastHandledDialog = dlg.show();\n    }\n\n    public void showConfirm(String message, final Result result) {\n        AlertDialog.Builder dlg = new AlertDialog.Builder(context);\n        dlg.setMessage(message);\n        dlg.setTitle(\"Confirm\");\n        dlg.setCancelable(true);\n        dlg.setPositiveButton(android.R.string.ok,\n                new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        result.gotResult(true, null);\n                    }\n                });\n        dlg.setNegativeButton(android.R.string.cancel,\n                new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        result.gotResult(false, null);\n                    }\n                });\n        dlg.setOnCancelListener(\n                new DialogInterface.OnCancelListener() {\n                    public void onCancel(DialogInterface dialog) {\n                        result.gotResult(false, null);\n                    }\n                });\n        dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {\n            //DO NOTHING\n            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {\n                if (keyCode == KeyEvent.KEYCODE_BACK)\n                {\n                    result.gotResult(false, null);\n                    return false;\n                }\n                else\n                    return true;\n            }\n        });\n        lastHandledDialog = dlg.show();\n    }\n\n    /**\n     * Tell the client to display a prompt dialog to the user.\n     * If the client returns true, WebView will assume that the client will\n     * handle the prompt dialog and call the appropriate JsPromptResult method.\n     *\n     * Since we are hacking prompts for our own purposes, we should not be using them for\n     * this purpose, perhaps we should hack console.log to do this instead!\n     */\n    public void showPrompt(String message, String defaultValue, final Result result) {\n        // Returning false would also show a dialog, but the default one shows the origin (ugly).\n        AlertDialog.Builder dlg = new AlertDialog.Builder(context);\n        dlg.setMessage(message);\n        final EditText input = new EditText(context);\n        if (defaultValue != null) {\n            input.setText(defaultValue);\n        }\n        dlg.setView(input);\n        dlg.setCancelable(false);\n        dlg.setPositiveButton(android.R.string.ok,\n                new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        String userText = input.getText().toString();\n                        result.gotResult(true, userText);\n                    }\n                });\n        dlg.setNegativeButton(android.R.string.cancel,\n                new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        result.gotResult(false, null);\n                    }\n                });\n        lastHandledDialog = dlg.show();\n    }\n\n    public void destroyLastDialog(){\n        if (lastHandledDialog != null){\n            lastHandledDialog.cancel();\n        }\n    }\n\n    public interface Result {\n        public void gotResult(boolean success, String value);\n    }\n}"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaHttpAuthHandler.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport android.webkit.HttpAuthHandler;\n\n/**\n * Specifies interface for HTTP auth handler object which is used to handle auth requests and\n * specifying user credentials.\n */\npublic class CordovaHttpAuthHandler implements ICordovaHttpAuthHandler {\n\n    private final HttpAuthHandler handler;\n\n    public CordovaHttpAuthHandler(HttpAuthHandler handler) {\n        this.handler = handler;\n    }\n    \n    /**\n     * Instructs the WebView to cancel the authentication request.\n     */\n    public void cancel () {\n        this.handler.cancel();\n    }\n    \n    /**\n     * Instructs the WebView to proceed with the authentication with the given credentials.\n     * \n     * @param username\n     * @param password\n     */\n    public void proceed (String username, String password) {\n        this.handler.proceed(username, password);\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterface.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport android.app.Activity;\nimport android.content.Intent;\n\nimport org.apache.cordova.CordovaPlugin;\n\nimport java.util.concurrent.ExecutorService;\n\n/**\n * The Activity interface that is implemented by CordovaActivity.\n * It is used to isolate plugin development, and remove dependency on entire Cordova library.\n */\npublic interface CordovaInterface {\n\n    /**\n     * Launch an activity for which you would like a result when it finished. When this activity exits,\n     * your onActivityResult() method will be called.\n     *\n     * @param command     The command object\n     * @param intent      The intent to start\n     * @param requestCode   The request code that is passed to callback to identify the activity\n     */\n    abstract public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode);\n\n    /**\n     * Set the plugin to be called when a sub-activity exits.\n     *\n     * @param plugin      The plugin on which onActivityResult is to be called\n     */\n    abstract public void setActivityResultCallback(CordovaPlugin plugin);\n\n    /**\n     * Get the Android activity.\n     *\n     * @return the Activity\n     */\n    public abstract Activity getActivity();\n    \n\n    /**\n     * Called when a message is sent to plugin.\n     *\n     * @param id            The message id\n     * @param data          The message data\n     * @return              Object or null\n     */\n    public Object onMessage(String id, Object data);\n    \n    /**\n     * Returns a shared thread pool that can be used for background tasks.\n     */\n    public ExecutorService getThreadPool();\n\n    /**\n     * Sends a permission request to the activity for one permission.\n     */\n    public void requestPermission(CordovaPlugin plugin, int requestCode, String permission);\n\n    /**\n     * Sends a permission request to the activity for a group of permissions\n     */\n    public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions);\n\n    /**\n     * Check for a permission.  Returns true if the permission is granted, false otherwise.\n     */\n    public boolean hasPermission(String permission);\n\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterfaceImpl.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.util.Pair;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * Default implementation of CordovaInterface.\n */\npublic class CordovaInterfaceImpl implements CordovaInterface {\n    private static final String TAG = \"CordovaInterfaceImpl\";\n    protected Activity activity;\n    protected ExecutorService threadPool;\n    protected PluginManager pluginManager;\n\n    protected ActivityResultHolder savedResult;\n    protected CallbackMap permissionResultCallbacks;\n    protected CordovaPlugin activityResultCallback;\n    protected String initCallbackService;\n    protected int activityResultRequestCode;\n    protected boolean activityWasDestroyed = false;\n    protected Bundle savedPluginState;\n\n    public CordovaInterfaceImpl(Activity activity) {\n        this(activity, Executors.newCachedThreadPool());\n    }\n\n    public CordovaInterfaceImpl(Activity activity, ExecutorService threadPool) {\n        this.activity = activity;\n        this.threadPool = threadPool;\n        this.permissionResultCallbacks = new CallbackMap();\n    }\n\n    @Override\n    public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode) {\n        setActivityResultCallback(command);\n        try {\n            activity.startActivityForResult(intent, requestCode);\n        } catch (RuntimeException e) { // E.g.: ActivityNotFoundException\n            activityResultCallback = null;\n            throw e;\n        }\n    }\n\n    @Override\n    public void setActivityResultCallback(CordovaPlugin plugin) {\n        // Cancel any previously pending activity.\n        if (activityResultCallback != null) {\n            activityResultCallback.onActivityResult(activityResultRequestCode, Activity.RESULT_CANCELED, null);\n        }\n        activityResultCallback = plugin;\n    }\n\n    @Override\n    public Activity getActivity() {\n        return activity;\n    }\n\n    @Override\n    public Object onMessage(String id, Object data) {\n        if (\"exit\".equals(id)) {\n            activity.finish();\n        }\n        return null;\n    }\n\n    @Override\n    public ExecutorService getThreadPool() {\n        return threadPool;\n    }\n\n    /**\n     * Dispatches any pending onActivityResult callbacks and sends the resume event if the\n     * Activity was destroyed by the OS.\n     */\n    public void onCordovaInit(PluginManager pluginManager) {\n        this.pluginManager = pluginManager;\n        if (savedResult != null) {\n            onActivityResult(savedResult.requestCode, savedResult.resultCode, savedResult.intent);\n        } else if(activityWasDestroyed) {\n            // If there was no Activity result, we still need to send out the resume event if the\n            // Activity was destroyed by the OS\n            activityWasDestroyed = false;\n            if(pluginManager != null)\n            {\n                CoreAndroid appPlugin = (CoreAndroid) pluginManager.getPlugin(CoreAndroid.PLUGIN_NAME);\n                if(appPlugin != null) {\n                    JSONObject obj = new JSONObject();\n                    try {\n                        obj.put(\"action\", \"resume\");\n                    } catch (JSONException e) {\n                        LOG.e(TAG, \"Failed to create event message\", e);\n                    }\n                    appPlugin.sendResumeEvent(new PluginResult(PluginResult.Status.OK, obj));\n                }\n            }\n\n        }\n    }\n\n    /**\n     * Routes the result to the awaiting plugin. Returns false if no plugin was waiting.\n     */\n    public boolean onActivityResult(int requestCode, int resultCode, Intent intent) {\n        CordovaPlugin callback = activityResultCallback;\n        if(callback == null && initCallbackService != null) {\n            // The application was restarted, but had defined an initial callback\n            // before being shut down.\n            savedResult = new ActivityResultHolder(requestCode, resultCode, intent);\n            if (pluginManager != null) {\n                callback = pluginManager.getPlugin(initCallbackService);\n                if(callback != null) {\n                    callback.onRestoreStateForActivityResult(savedPluginState.getBundle(callback.getServiceName()),\n                            new ResumeCallback(callback.getServiceName(), pluginManager));\n                }\n            }\n        }\n        activityResultCallback = null;\n\n        if (callback != null) {\n            LOG.d(TAG, \"Sending activity result to plugin\");\n            initCallbackService = null;\n            savedResult = null;\n            callback.onActivityResult(requestCode, resultCode, intent);\n            return true;\n        }\n        LOG.w(TAG, \"Got an activity result, but no plugin was registered to receive it\" + (savedResult != null ? \" yet!\" : \".\"));\n        return false;\n    }\n\n    /**\n     * Call this from your startActivityForResult() overload. This is required to catch the case\n     * where plugins use Activity.startActivityForResult() + CordovaInterface.setActivityResultCallback()\n     * rather than CordovaInterface.startActivityForResult().\n     */\n    public void setActivityResultRequestCode(int requestCode) {\n        activityResultRequestCode = requestCode;\n    }\n\n    /**\n     * Saves parameters for startActivityForResult().\n     */\n    public void onSaveInstanceState(Bundle outState) {\n        if (activityResultCallback != null) {\n            String serviceName = activityResultCallback.getServiceName();\n            outState.putString(\"callbackService\", serviceName);\n        }\n        if(pluginManager != null){\n            outState.putBundle(\"plugin\", pluginManager.onSaveInstanceState());\n        }\n\n    }\n\n    /**\n     * Call this from onCreate() so that any saved startActivityForResult parameters will be restored.\n     */\n    public void restoreInstanceState(Bundle savedInstanceState) {\n        initCallbackService = savedInstanceState.getString(\"callbackService\");\n        savedPluginState = savedInstanceState.getBundle(\"plugin\");\n        activityWasDestroyed = true;\n    }\n\n    private static class ActivityResultHolder {\n        private int requestCode;\n        private int resultCode;\n        private Intent intent;\n\n        public ActivityResultHolder(int requestCode, int resultCode, Intent intent) {\n            this.requestCode = requestCode;\n            this.resultCode = resultCode;\n            this.intent = intent;\n        }\n    }\n\n    /**\n     * Called by the system when the user grants permissions\n     *\n     * @param requestCode\n     * @param permissions\n     * @param grantResults\n     */\n    public void onRequestPermissionResult(int requestCode, String[] permissions,\n                                          int[] grantResults) throws JSONException {\n        Pair<CordovaPlugin, Integer> callback = permissionResultCallbacks.getAndRemoveCallback(requestCode);\n        if(callback != null) {\n            callback.first.onRequestPermissionResult(callback.second, permissions, grantResults);\n        }\n    }\n\n    public void requestPermission(CordovaPlugin plugin, int requestCode, String permission) {\n        String[] permissions = new String [1];\n        permissions[0] = permission;\n        requestPermissions(plugin, requestCode, permissions);\n    }\n\n    public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions) {\n        int mappedRequestCode = permissionResultCallbacks.registerCallback(plugin, requestCode);\n        getActivity().requestPermissions(permissions, mappedRequestCode);\n    }\n\n    public boolean hasPermission(String permission)\n    {\n        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)\n        {\n            int result = activity.checkSelfPermission(permission);\n            return PackageManager.PERMISSION_GRANTED == result;\n        }\n        else\n        {\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaPlugin.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport org.apache.cordova.CordovaArgs;\nimport org.apache.cordova.CordovaWebView;\nimport org.apache.cordova.CordovaInterface;\nimport org.apache.cordova.CallbackContext;\nimport org.json.JSONArray;\nimport org.json.JSONException;\n\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.res.Configuration;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\n\n/**\n * Plugins must extend this class and override one of the execute methods.\n */\npublic class CordovaPlugin {\n    public CordovaWebView webView;\n    public CordovaInterface cordova;\n    protected CordovaPreferences preferences;\n    private String serviceName;\n\n    /**\n     * Call this after constructing to initialize the plugin.\n     * Final because we want to be able to change args without breaking plugins.\n     */\n    public final void privateInitialize(String serviceName, CordovaInterface cordova, CordovaWebView webView, CordovaPreferences preferences) {\n        assert this.cordova == null;\n        this.serviceName = serviceName;\n        this.cordova = cordova;\n        this.webView = webView;\n        this.preferences = preferences;\n        initialize(cordova, webView);\n        pluginInitialize();\n    }\n\n    /**\n     * Called after plugin construction and fields have been initialized.\n     * Prefer to use pluginInitialize instead since there is no value in\n     * having parameters on the initialize() function.\n     */\n    public void initialize(CordovaInterface cordova, CordovaWebView webView) {\n    }\n\n    /**\n     * Called after plugin construction and fields have been initialized.\n     */\n    protected void pluginInitialize() {\n    }\n\n    /**\n     * Returns the plugin's service name (what you'd use when calling pluginManger.getPlugin())\n     */\n    public String getServiceName() {\n        return serviceName;\n    }\n\n    /**\n     * Executes the request.\n     *\n     * This method is called from the WebView thread. To do a non-trivial amount of work, use:\n     *     cordova.getThreadPool().execute(runnable);\n     *\n     * To run on the UI thread, use:\n     *     cordova.getActivity().runOnUiThread(runnable);\n     *\n     * @param action          The action to execute.\n     * @param rawArgs         The exec() arguments in JSON form.\n     * @param callbackContext The callback context used when calling back into JavaScript.\n     * @return                Whether the action was valid.\n     */\n    public boolean execute(String action, String rawArgs, CallbackContext callbackContext) throws JSONException {\n        JSONArray args = new JSONArray(rawArgs);\n        return execute(action, args, callbackContext);\n    }\n\n    /**\n     * Executes the request.\n     *\n     * This method is called from the WebView thread. To do a non-trivial amount of work, use:\n     *     cordova.getThreadPool().execute(runnable);\n     *\n     * To run on the UI thread, use:\n     *     cordova.getActivity().runOnUiThread(runnable);\n     *\n     * @param action          The action to execute.\n     * @param args            The exec() arguments.\n     * @param callbackContext The callback context used when calling back into JavaScript.\n     * @return                Whether the action was valid.\n     */\n    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {\n        CordovaArgs cordovaArgs = new CordovaArgs(args);\n        return execute(action, cordovaArgs, callbackContext);\n    }\n\n    /**\n     * Executes the request.\n     *\n     * This method is called from the WebView thread. To do a non-trivial amount of work, use:\n     *     cordova.getThreadPool().execute(runnable);\n     *\n     * To run on the UI thread, use:\n     *     cordova.getActivity().runOnUiThread(runnable);\n     *\n     * @param action          The action to execute.\n     * @param args            The exec() arguments, wrapped with some Cordova helpers.\n     * @param callbackContext The callback context used when calling back into JavaScript.\n     * @return                Whether the action was valid.\n     */\n    public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) throws JSONException {\n        return false;\n    }\n\n    /**\n     * Called when the system is about to start resuming a previous activity.\n     *\n     * @param multitasking\t\tFlag indicating if multitasking is turned on for app\n     */\n    public void onPause(boolean multitasking) {\n    }\n\n    /**\n     * Called when the activity will start interacting with the user.\n     *\n     * @param multitasking\t\tFlag indicating if multitasking is turned on for app\n     */\n    public void onResume(boolean multitasking) {\n    }\n\n    /**\n     * Called when the activity is becoming visible to the user.\n     */\n    public void onStart() {\n    }\n\n    /**\n     * Called when the activity is no longer visible to the user.\n     */\n    public void onStop() {\n    }\n\n    /**\n     * Called when the activity receives a new intent.\n     */\n    public void onNewIntent(Intent intent) {\n    }\n\n    /**\n     * The final call you receive before your activity is destroyed.\n     */\n    public void onDestroy() {\n    }\n\n    /**\n     * Called when the Activity is being destroyed (e.g. if a plugin calls out to an external\n     * Activity and the OS kills the CordovaActivity in the background). The plugin should save its\n     * state in this method only if it is awaiting the result of an external Activity and needs\n     * to preserve some information so as to handle that result; onRestoreStateForActivityResult()\n     * will only be called if the plugin is the recipient of an Activity result\n     *\n     * @return  Bundle containing the state of the plugin or null if state does not need to be saved\n     */\n    public Bundle onSaveInstanceState() {\n        return null;\n    }\n\n    /**\n     * Called when a plugin is the recipient of an Activity result after the CordovaActivity has\n     * been destroyed. The Bundle will be the same as the one the plugin returned in\n     * onSaveInstanceState()\n     *\n     * @param state             Bundle containing the state of the plugin\n     * @param callbackContext   Replacement Context to return the plugin result to\n     */\n    public void onRestoreStateForActivityResult(Bundle state, CallbackContext callbackContext) {}\n\n    /**\n     * Called when a message is sent to plugin.\n     *\n     * @param id            The message id\n     * @param data          The message data\n     * @return              Object to stop propagation or null\n     */\n    public Object onMessage(String id, Object data) {\n        return null;\n    }\n\n    /**\n     * Called when an activity you launched exits, giving you the requestCode you started it with,\n     * the resultCode it returned, and any additional data from it.\n     *\n     * @param requestCode   The request code originally supplied to startActivityForResult(),\n     *                      allowing you to identify who this result came from.\n     * @param resultCode    The integer result code returned by the child activity through its setResult().\n     * @param intent        An Intent, which can return result data to the caller (various data can be\n     *                      attached to Intent \"extras\").\n     */\n    public void onActivityResult(int requestCode, int resultCode, Intent intent) {\n    }\n\n    /**\n     * Hook for blocking the loading of external resources.\n     *\n     * This will be called when the WebView's shouldInterceptRequest wants to\n     * know whether to open a connection to an external resource. Return false\n     * to block the request: if any plugin returns false, Cordova will block\n     * the request. If all plugins return null, the default policy will be\n     * enforced. If at least one plugin returns true, and no plugins return\n     * false, then the request will proceed.\n     *\n     * Note that this only affects resource requests which are routed through\n     * WebViewClient.shouldInterceptRequest, such as XMLHttpRequest requests and\n     * img tag loads. WebSockets and media requests (such as <video> and <audio>\n     * tags) are not affected by this method. Use CSP headers to control access\n     * to such resources.\n     */\n    public Boolean shouldAllowRequest(String url) {\n        return null;\n    }\n\n    /**\n     * Hook for blocking navigation by the Cordova WebView. This applies both to top-level and\n     * iframe navigations.\n     *\n     * This will be called when the WebView's needs to know whether to navigate\n     * to a new page. Return false to block the navigation: if any plugin\n     * returns false, Cordova will block the navigation. If all plugins return\n     * null, the default policy will be enforced. It at least one plugin returns\n     * true, and no plugins return false, then the navigation will proceed.\n     */\n    public Boolean shouldAllowNavigation(String url) {\n        return null;\n    }\n\n    /**\n     * Hook for allowing page to call exec(). By default, this returns the result of\n     * shouldAllowNavigation(). It's generally unsafe to allow untrusted content to be loaded\n     * into a CordovaWebView, even within an iframe, so it's best not to touch this.\n     */\n    public Boolean shouldAllowBridgeAccess(String url) {\n        return shouldAllowNavigation(url);\n    }\n\n    /**\n     * Hook for blocking the launching of Intents by the Cordova application.\n     *\n     * This will be called when the WebView will not navigate to a page, but\n     * could launch an intent to handle the URL. Return false to block this: if\n     * any plugin returns false, Cordova will block the navigation. If all\n     * plugins return null, the default policy will be enforced. If at least one\n     * plugin returns true, and no plugins return false, then the URL will be\n     * opened.\n     */\n    public Boolean shouldOpenExternalUrl(String url) {\n        return null;\n    }\n\n    /**\n     * Allows plugins to handle a link being clicked. Return true here to cancel the navigation.\n     *\n     * @param url           The URL that is trying to be loaded in the Cordova webview.\n     * @return              Return true to prevent the URL from loading. Default is false.\n     */\n    public boolean onOverrideUrlLoading(String url) {\n        return false;\n    }\n\n    /**\n     * Hook for redirecting requests. Applies to WebView requests as well as requests made by plugins.\n     * To handle the request directly, return a URI in the form:\n     *\n     *    cdvplugin://pluginId/...\n     *\n     * And implement handleOpenForRead().\n     * To make this easier, use the toPluginUri() and fromPluginUri() helpers:\n     *\n     *     public Uri remapUri(Uri uri) { return toPluginUri(uri); }\n     *\n     *     public CordovaResourceApi.OpenForReadResult handleOpenForRead(Uri uri) throws IOException {\n     *         Uri origUri = fromPluginUri(uri);\n     *         ...\n     *     }\n     */\n    public Uri remapUri(Uri uri) {\n        return null;\n    }\n\n    /**\n     * Called to handle CordovaResourceApi.openForRead() calls for a cdvplugin://pluginId/ URL.\n     * Should never return null.\n     * Added in cordova-android@4.0.0\n     */\n    public CordovaResourceApi.OpenForReadResult handleOpenForRead(Uri uri) throws IOException {\n        throw new FileNotFoundException(\"Plugin can't handle uri: \" + uri);\n    }\n\n    /**\n     * Refer to remapUri()\n     * Added in cordova-android@4.0.0\n     */\n    protected Uri toPluginUri(Uri origUri) {\n        return new Uri.Builder()\n            .scheme(CordovaResourceApi.PLUGIN_URI_SCHEME)\n            .authority(serviceName)\n            .appendQueryParameter(\"origUri\", origUri.toString())\n            .build();\n    }\n\n    /**\n     * Refer to remapUri()\n     * Added in cordova-android@4.0.0\n     */\n    protected Uri fromPluginUri(Uri pluginUri) {\n        return Uri.parse(pluginUri.getQueryParameter(\"origUri\"));\n    }\n\n    /**\n     * Called when the WebView does a top-level navigation or refreshes.\n     *\n     * Plugins should stop any long-running processes and clean up internal state.\n     *\n     * Does nothing by default.\n     */\n    public void onReset() {\n    }\n\n    /**\n     * Called when the system received an HTTP authentication request. Plugin can use\n     * the supplied HttpAuthHandler to process this auth challenge.\n     *\n     * @param view              The WebView that is initiating the callback\n     * @param handler           The HttpAuthHandler used to set the WebView's response\n     * @param host              The host requiring authentication\n     * @param realm             The realm for which authentication is required\n     *\n     * @return                  Returns True if plugin will resolve this auth challenge, otherwise False\n     *\n     */\n    public boolean onReceivedHttpAuthRequest(CordovaWebView view, ICordovaHttpAuthHandler handler, String host, String realm) {\n        return false;\n    }\n\n    /**\n     * Called when he system received an SSL client certificate request.  Plugin can use\n     * the supplied ClientCertRequest to process this certificate challenge.\n     *\n     * @param view              The WebView that is initiating the callback\n     * @param request           The client certificate request\n     *\n     * @return                  Returns True if plugin will resolve this auth challenge, otherwise False\n     *\n     */\n    public boolean onReceivedClientCertRequest(CordovaWebView view, ICordovaClientCertRequest request) {\n        return false;\n    }\n\n    /**\n     * Called by the system when the device configuration changes while your activity is running.\n     *\n     * @param newConfig\t\tThe new device configuration\n     */\n    public void onConfigurationChanged(Configuration newConfig) {\n    }\n\n    /**\n     * Called by the Plugin Manager when we need to actually request permissions\n     *\n     * @param requestCode   Passed to the activity to track the request\n     *\n     * @return              Returns the permission that was stored in the plugin\n     */\n\n    public void requestPermissions(int requestCode) {\n    }\n\n    /*\n     * Called by the WebView implementation to check for geolocation permissions, can be used\n     * by other Java methods in the event that a plugin is using this as a dependency.\n     *\n     * @return          Returns true if the plugin has all the permissions it needs to operate.\n     */\n\n    public boolean hasPermisssion() {\n        return true;\n    }\n\n    /**\n     * Called by the system when the user grants permissions\n     *\n     * @param requestCode\n     * @param permissions\n     * @param grantResults\n     */\n    public void onRequestPermissionResult(int requestCode, String[] permissions,\n                                          int[] grantResults) throws JSONException {\n\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaPreferences.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova;\n\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.apache.cordova.LOG;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n\npublic class CordovaPreferences {\n    private HashMap<String, String> prefs = new HashMap<String, String>(20);\n    private Bundle preferencesBundleExtras;\n\n    public void setPreferencesBundle(Bundle extras) {\n        preferencesBundleExtras = extras;\n    }\n\n    public void set(String name, String value) {\n        prefs.put(name.toLowerCase(Locale.ENGLISH), value);\n    }\n\n    public void set(String name, boolean value) {\n        set(name, \"\" + value);\n    }\n\n    public void set(String name, int value) {\n        set(name, \"\" + value);\n    }\n    \n    public void set(String name, double value) {\n        set(name, \"\" + value);\n    }\n    \n    public Map<String, String> getAll() {\n        return prefs;\n    }\n\n    public boolean getBoolean(String name, boolean defaultValue) {\n        name = name.toLowerCase(Locale.ENGLISH);\n        String value = prefs.get(name);\n        if (value != null) {\n            return Boolean.parseBoolean(value);\n        }\n        return defaultValue;\n    }\n\n    // Added in 4.0.0\n    public boolean contains(String name) {\n        return getString(name, null) != null;\n    }\n\n    public int getInteger(String name, int defaultValue) {\n        name = name.toLowerCase(Locale.ENGLISH);\n        String value = prefs.get(name);\n        if (value != null) {\n            // Use Integer.decode() can't handle it if the highest bit is set.\n            return (int)(long)Long.decode(value);\n        }\n        return defaultValue;\n    }\n\n    public double getDouble(String name, double defaultValue) {\n        name = name.toLowerCase(Locale.ENGLISH);\n        String value = prefs.get(name);\n        if (value != null) {\n            return Double.valueOf(value);\n        }\n        return defaultValue;\n    }\n\n    public String getString(String name, String defaultValue) {\n        name = name.toLowerCase(Locale.ENGLISH);\n        String value = prefs.get(name);\n        if (value != null) {\n            return value;\n        }\n        return defaultValue;\n    }\n\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaResourceApi.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n */\npackage org.apache.cordova;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.res.AssetFileDescriptor;\nimport android.content.res.AssetManager;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Looper;\nimport android.util.Base64;\nimport android.webkit.MimeTypeMap;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.nio.channels.FileChannel;\nimport java.util.Locale;\n\n/**\n * What this class provides:\n * 1. Helpers for reading & writing to URLs.\n *   - E.g. handles assets, resources, content providers, files, data URIs, http[s]\n *   - E.g. Can be used to query for mime-type & content length.\n *\n * 2. To allow plugins to redirect URLs (via remapUrl).\n *   - All plugins should call remapUrl() on URLs they receive from JS *before*\n *     passing the URL onto other utility functions in this class.\n *   - For an example usage of this, refer to the org.apache.cordova.file plugin.\n *\n * Future Work:\n *   - Consider using a Cursor to query content URLs for their size (like the file plugin does).\n *   - Allow plugins to remapUri to \"cdv-plugin://plugin-name/foo\", which CordovaResourceApi\n *     would then delegate to pluginManager.getPlugin(plugin-name).openForRead(url)\n *     - Currently, plugins *can* do this by remapping to a data: URL, but it's inefficient\n *       for large payloads.\n */\npublic class CordovaResourceApi {\n    @SuppressWarnings(\"unused\")\n    private static final String LOG_TAG = \"CordovaResourceApi\";\n\n    public static final int URI_TYPE_FILE = 0;\n    public static final int URI_TYPE_ASSET = 1;\n    public static final int URI_TYPE_CONTENT = 2;\n    public static final int URI_TYPE_RESOURCE = 3;\n    public static final int URI_TYPE_DATA = 4;\n    public static final int URI_TYPE_HTTP = 5;\n    public static final int URI_TYPE_HTTPS = 6;\n    public static final int URI_TYPE_PLUGIN = 7;\n    public static final int URI_TYPE_UNKNOWN = -1;\n\n    public static final String PLUGIN_URI_SCHEME = \"cdvplugin\";\n\n    private static final String[] LOCAL_FILE_PROJECTION = { \"_data\" };\n    \n    public static Thread jsThread;\n\n    private final AssetManager assetManager;\n    private final ContentResolver contentResolver;\n    private final PluginManager pluginManager;\n    private boolean threadCheckingEnabled = true;\n\n\n    public CordovaResourceApi(Context context, PluginManager pluginManager) {\n        this.contentResolver = context.getContentResolver();\n        this.assetManager = context.getAssets();\n        this.pluginManager = pluginManager;\n    }\n    \n    public void setThreadCheckingEnabled(boolean value) {\n        threadCheckingEnabled = value;\n    }\n\n    public boolean isThreadCheckingEnabled() {\n        return threadCheckingEnabled;\n    }\n    \n    \n    public static int getUriType(Uri uri) {\n        assertNonRelative(uri);\n        String scheme = uri.getScheme();\n        if (ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(scheme)) {\n            return URI_TYPE_CONTENT;\n        }\n        if (ContentResolver.SCHEME_ANDROID_RESOURCE.equalsIgnoreCase(scheme)) {\n            return URI_TYPE_RESOURCE;\n        }\n        if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(scheme)) {\n            if (uri.getPath().startsWith(\"/android_asset/\")) {\n                return URI_TYPE_ASSET;\n            }\n            return URI_TYPE_FILE;\n        }\n        if (\"data\".equalsIgnoreCase(scheme)) {\n            return URI_TYPE_DATA;\n        }\n        if (\"http\".equalsIgnoreCase(scheme)) {\n            return URI_TYPE_HTTP;\n        }\n        if (\"https\".equalsIgnoreCase(scheme)) {\n            return URI_TYPE_HTTPS;\n        }\n        if (PLUGIN_URI_SCHEME.equalsIgnoreCase(scheme)) {\n            return URI_TYPE_PLUGIN;\n        }\n        return URI_TYPE_UNKNOWN;\n    }\n    \n    public Uri remapUri(Uri uri) {\n        assertNonRelative(uri);\n        Uri pluginUri = pluginManager.remapUri(uri);\n        return pluginUri != null ? pluginUri : uri;\n    }\n\n    public String remapPath(String path) {\n        return remapUri(Uri.fromFile(new File(path))).getPath();\n    }\n    \n    /**\n     * Returns a File that points to the resource, or null if the resource\n     * is not on the local filesystem.\n     */\n    public File mapUriToFile(Uri uri) {\n        assertBackgroundThread();\n        switch (getUriType(uri)) {\n            case URI_TYPE_FILE:\n                return new File(uri.getPath());\n            case URI_TYPE_CONTENT: {\n                Cursor cursor = contentResolver.query(uri, LOCAL_FILE_PROJECTION, null, null, null);\n                if (cursor != null) {\n                    try {\n                        int columnIndex = cursor.getColumnIndex(LOCAL_FILE_PROJECTION[0]);\n                        if (columnIndex != -1 && cursor.getCount() > 0) {\n                            cursor.moveToFirst();\n                            String realPath = cursor.getString(columnIndex);\n                            if (realPath != null) {\n                                return new File(realPath);\n                            }\n                        }\n                    } finally {\n                        cursor.close();\n                    }\n                }\n            }\n        }\n        return null;\n    }\n    \n    public String getMimeType(Uri uri) {\n        switch (getUriType(uri)) {\n            case URI_TYPE_FILE:\n            case URI_TYPE_ASSET:\n                return getMimeTypeFromPath(uri.getPath());\n            case URI_TYPE_CONTENT:\n            case URI_TYPE_RESOURCE:\n                return contentResolver.getType(uri);\n            case URI_TYPE_DATA: {\n                return getDataUriMimeType(uri);\n            }\n            case URI_TYPE_HTTP:\n            case URI_TYPE_HTTPS: {\n                try {\n                    HttpURLConnection conn = (HttpURLConnection)new URL(uri.toString()).openConnection();\n                    conn.setDoInput(false);\n                    conn.setRequestMethod(\"HEAD\");\n                    String mimeType = conn.getHeaderField(\"Content-Type\");\n                    if (mimeType != null) {\n                        mimeType = mimeType.split(\";\")[0];\n                    }\n                    return mimeType;\n                } catch (IOException e) {\n                }\n            }\n        }\n        \n        return null;\n    }\n    \n    \n    //This already exists\n    private String getMimeTypeFromPath(String path) {\n        String extension = path;\n        int lastDot = extension.lastIndexOf('.');\n        if (lastDot != -1) {\n            extension = extension.substring(lastDot + 1);\n        }\n        // Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).\n        extension = extension.toLowerCase(Locale.getDefault());\n        if (extension.equals(\"3ga\")) {\n            return \"audio/3gpp\";\n        } else if (extension.equals(\"js\")) {\n            // Missing from the map :(.\n            return \"text/javascript\";\n        }\n        return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);\n    }\n    \n    /**\n     * Opens a stream to the given URI, also providing the MIME type & length.\n     * @return Never returns null.\n     * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be\n     *     resolved before being passed into this function.\n     * @throws Throws an IOException if the URI cannot be opened.\n     * @throws Throws an IllegalStateException if called on a foreground thread.\n     */\n    public OpenForReadResult openForRead(Uri uri) throws IOException {\n        return openForRead(uri, false);\n    }\n\n    /**\n     * Opens a stream to the given URI, also providing the MIME type & length.\n     * @return Never returns null.\n     * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be\n     *     resolved before being passed into this function.\n     * @throws Throws an IOException if the URI cannot be opened.\n     * @throws Throws an IllegalStateException if called on a foreground thread and skipThreadCheck is false.\n     */\n    public OpenForReadResult openForRead(Uri uri, boolean skipThreadCheck) throws IOException {\n        if (!skipThreadCheck) {\n            assertBackgroundThread();\n        }\n        switch (getUriType(uri)) {\n            case URI_TYPE_FILE: {\n                FileInputStream inputStream = new FileInputStream(uri.getPath());\n                String mimeType = getMimeTypeFromPath(uri.getPath());\n                long length = inputStream.getChannel().size();\n                return new OpenForReadResult(uri, inputStream, mimeType, length, null);\n            }\n            case URI_TYPE_ASSET: {\n                String assetPath = uri.getPath().substring(15);\n                AssetFileDescriptor assetFd = null;\n                InputStream inputStream;\n                long length = -1;\n                try {\n                    assetFd = assetManager.openFd(assetPath);\n                    inputStream = assetFd.createInputStream();\n                    length = assetFd.getLength();\n                } catch (FileNotFoundException e) {\n                    // Will occur if the file is compressed.\n                    inputStream = assetManager.open(assetPath);\n                }\n                String mimeType = getMimeTypeFromPath(assetPath);\n                return new OpenForReadResult(uri, inputStream, mimeType, length, assetFd);\n            }\n            case URI_TYPE_CONTENT:\n            case URI_TYPE_RESOURCE: {\n                String mimeType = contentResolver.getType(uri);\n                AssetFileDescriptor assetFd = contentResolver.openAssetFileDescriptor(uri, \"r\");\n                InputStream inputStream = assetFd.createInputStream();\n                long length = assetFd.getLength();\n                return new OpenForReadResult(uri, inputStream, mimeType, length, assetFd);\n            }\n            case URI_TYPE_DATA: {\n                OpenForReadResult ret = readDataUri(uri);\n                if (ret == null) {\n                    break;\n                }\n                return ret;\n            }\n            case URI_TYPE_HTTP:\n            case URI_TYPE_HTTPS: {\n                HttpURLConnection conn = (HttpURLConnection)new URL(uri.toString()).openConnection();\n                conn.setDoInput(true);\n                String mimeType = conn.getHeaderField(\"Content-Type\");\n                if (mimeType != null) {\n                    mimeType = mimeType.split(\";\")[0];\n                }\n                int length = conn.getContentLength();\n                InputStream inputStream = conn.getInputStream();\n                return new OpenForReadResult(uri, inputStream, mimeType, length, null);\n            }\n            case URI_TYPE_PLUGIN: {\n                String pluginId = uri.getHost();\n                CordovaPlugin plugin = pluginManager.getPlugin(pluginId);\n                if (plugin == null) {\n                    throw new FileNotFoundException(\"Invalid plugin ID in URI: \" + uri);\n                }\n                return plugin.handleOpenForRead(uri);\n            }\n        }\n        throw new FileNotFoundException(\"URI not supported by CordovaResourceApi: \" + uri);\n    }\n\n    public OutputStream openOutputStream(Uri uri) throws IOException {\n        return openOutputStream(uri, false);\n    }\n\n    /**\n     * Opens a stream to the given URI.\n     * @return Never returns null.\n     * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be\n     *     resolved before being passed into this function.\n     * @throws Throws an IOException if the URI cannot be opened.\n     */\n    public OutputStream openOutputStream(Uri uri, boolean append) throws IOException {\n        assertBackgroundThread();\n        switch (getUriType(uri)) {\n            case URI_TYPE_FILE: {\n                File localFile = new File(uri.getPath());\n                File parent = localFile.getParentFile();\n                if (parent != null) {\n                    parent.mkdirs();\n                }\n                return new FileOutputStream(localFile, append);\n            }\n            case URI_TYPE_CONTENT:\n            case URI_TYPE_RESOURCE: {\n                AssetFileDescriptor assetFd = contentResolver.openAssetFileDescriptor(uri, append ? \"wa\" : \"w\");\n                return assetFd.createOutputStream();\n            }\n        }\n        throw new FileNotFoundException(\"URI not supported by CordovaResourceApi: \" + uri);\n    }\n\n    public HttpURLConnection createHttpConnection(Uri uri) throws IOException {\n        assertBackgroundThread();\n        return (HttpURLConnection)new URL(uri.toString()).openConnection();\n    }\n    \n    // Copies the input to the output in the most efficient manner possible.\n    // Closes both streams.\n    public void copyResource(OpenForReadResult input, OutputStream outputStream) throws IOException {\n        assertBackgroundThread();\n        try {\n            InputStream inputStream = input.inputStream;\n            if (inputStream instanceof FileInputStream && outputStream instanceof FileOutputStream) {\n                FileChannel inChannel = ((FileInputStream)input.inputStream).getChannel();\n                FileChannel outChannel = ((FileOutputStream)outputStream).getChannel();\n                long offset = 0;\n                long length = input.length;\n                if (input.assetFd != null) {\n                    offset = input.assetFd.getStartOffset();\n                }\n                // transferFrom()'s 2nd arg is a relative position. Need to set the absolute\n                // position first.\n                inChannel.position(offset);\n                outChannel.transferFrom(inChannel, 0, length);\n            } else {\n                final int BUFFER_SIZE = 8192;\n                byte[] buffer = new byte[BUFFER_SIZE];\n                \n                for (;;) {\n                    int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE);\n                    \n                    if (bytesRead <= 0) {\n                        break;\n                    }\n                    outputStream.write(buffer, 0, bytesRead);\n                }\n            }            \n        } finally {\n            input.inputStream.close();\n            if (outputStream != null) {\n                outputStream.close();\n            }\n        }\n    }\n\n    public void copyResource(Uri sourceUri, OutputStream outputStream) throws IOException {\n        copyResource(openForRead(sourceUri), outputStream);\n    }\n\n    // Added in 3.5.0.\n    public void copyResource(Uri sourceUri, Uri dstUri) throws IOException {\n        copyResource(openForRead(sourceUri), openOutputStream(dstUri));\n    }\n    \n    private void assertBackgroundThread() {\n        if (threadCheckingEnabled) {\n            Thread curThread = Thread.currentThread();\n            if (curThread == Looper.getMainLooper().getThread()) {\n                throw new IllegalStateException(\"Do not perform IO operations on the UI thread. Use CordovaInterface.getThreadPool() instead.\");\n            }\n            if (curThread == jsThread) {\n                throw new IllegalStateException(\"Tried to perform an IO operation on the WebCore thread. Use CordovaInterface.getThreadPool() instead.\");\n            }\n        }\n    }\n    \n    private String getDataUriMimeType(Uri uri) {\n        String uriAsString = uri.getSchemeSpecificPart();\n        int commaPos = uriAsString.indexOf(',');\n        if (commaPos == -1) {\n            return null;\n        }\n        String[] mimeParts = uriAsString.substring(0, commaPos).split(\";\");\n        if (mimeParts.length > 0) {\n            return mimeParts[0];\n        }\n        return null;\n    }\n\n    private OpenForReadResult readDataUri(Uri uri) {\n        String uriAsString = uri.getSchemeSpecificPart();\n        int commaPos = uriAsString.indexOf(',');\n        if (commaPos == -1) {\n            return null;\n        }\n        String[] mimeParts = uriAsString.substring(0, commaPos).split(\";\");\n        String contentType = null;\n        boolean base64 = false;\n        if (mimeParts.length > 0) {\n            contentType = mimeParts[0];\n        }\n        for (int i = 1; i < mimeParts.length; ++i) {\n            if (\"base64\".equalsIgnoreCase(mimeParts[i])) {\n                base64 = true;\n            }\n        }\n        String dataPartAsString = uriAsString.substring(commaPos + 1);\n        byte[] data;\n        if (base64) {\n            data = Base64.decode(dataPartAsString, Base64.DEFAULT);\n        } else {\n            try {\n                data = dataPartAsString.getBytes(\"UTF-8\");\n            } catch (UnsupportedEncodingException e) {\n                data = dataPartAsString.getBytes();\n            }\n        }\n        InputStream inputStream = new ByteArrayInputStream(data);\n        return new OpenForReadResult(uri, inputStream, contentType, data.length, null);\n    }\n    \n    private static void assertNonRelative(Uri uri) {\n        if (!uri.isAbsolute()) {\n            throw new IllegalArgumentException(\"Relative URIs are not supported.\");\n        }\n    }\n    \n    public static final class OpenForReadResult {\n        public final Uri uri;\n        public final InputStream inputStream;\n        public final String mimeType;\n        public final long length;\n        public final AssetFileDescriptor assetFd;\n        \n        public OpenForReadResult(Uri uri, InputStream inputStream, String mimeType, long length, AssetFileDescriptor assetFd) {\n            this.uri = uri;\n            this.inputStream = inputStream;\n            this.mimeType = mimeType;\n            this.length = length;\n            this.assetFd = assetFd;\n        }\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n         http://www.apache.org/licenses/LICENSE-2.0\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.view.View;\nimport android.webkit.WebChromeClient.CustomViewCallback;\n\n/**\n * Main interface for interacting with a Cordova webview - implemented by CordovaWebViewImpl.\n * This is an interface so that it can be easily mocked in tests.\n * Methods may be added to this interface without a major version bump, as plugins & embedders\n * are not expected to implement it.\n */\npublic interface CordovaWebView {\n    public static final String CORDOVA_VERSION = \"6.2.1\";\n\n    void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences);\n\n    boolean isInitialized();\n\n    View getView();\n\n    void loadUrlIntoView(String url, boolean recreatePlugins);\n\n    void stopLoading();\n\n    boolean canGoBack();\n\n    void clearCache();\n\n    /** Use parameter-less overload */\n    @Deprecated\n    void clearCache(boolean b);\n\n    void clearHistory();\n\n    boolean backHistory();\n\n    void handlePause(boolean keepRunning);\n\n    void onNewIntent(Intent intent);\n\n    void handleResume(boolean keepRunning);\n\n    void handleStart();\n\n    void handleStop();\n\n    void handleDestroy();\n\n    /**\n     * Send JavaScript statement back to JavaScript.\n     *\n     * Deprecated (https://issues.apache.org/jira/browse/CB-6851)\n     * Instead of executing snippets of JS, you should use the exec bridge\n     * to create a Java->JS communication channel.\n     * To do this:\n     * 1. Within plugin.xml (to have your JS run before deviceready):\n     *    <js-module><runs/></js-module>\n     * 2. Within your .js (call exec on start-up):\n     *    require('cordova/channel').onCordovaReady.subscribe(function() {\n     *      require('cordova/exec')(win, null, 'Plugin', 'method', []);\n     *      function win(message) {\n     *        ... process message from java here ...\n     *      }\n     *    });\n     * 3. Within your .java:\n     *    PluginResult dataResult = new PluginResult(PluginResult.Status.OK, CODE);\n     *    dataResult.setKeepCallback(true);\n     *    savedCallbackContext.sendPluginResult(dataResult);\n     */\n    @Deprecated\n    void sendJavascript(String statememt);\n\n    /**\n     * Load the specified URL in the Cordova webview or a new browser instance.\n     *\n     * NOTE: If openExternal is false, only whitelisted URLs can be loaded.\n     *\n     * @param url           The url to load.\n     * @param openExternal  Load url in browser instead of Cordova webview.\n     * @param clearHistory  Clear the history stack, so new page becomes top of history\n     * @param params        Parameters for new app\n     */\n    void showWebPage(String url, boolean openExternal, boolean clearHistory, Map<String, Object> params);\n\n    /**\n     * Deprecated in 4.0.0. Use your own View-toggling logic.\n     */\n    @Deprecated\n    boolean isCustomViewShowing();\n\n    /**\n     * Deprecated in 4.0.0. Use your own View-toggling logic.\n     */\n    @Deprecated\n    void showCustomView(View view, CustomViewCallback callback);\n\n    /**\n     * Deprecated in 4.0.0. Use your own View-toggling logic.\n     */\n    @Deprecated\n    void hideCustomView();\n\n    CordovaResourceApi getResourceApi();\n\n    void setButtonPlumbedToJs(int keyCode, boolean override);\n    boolean isButtonPlumbedToJs(int keyCode);\n\n    void sendPluginResult(PluginResult cr, String callbackId);\n\n    PluginManager getPluginManager();\n    CordovaWebViewEngine getEngine();\n    CordovaPreferences getPreferences();\n    ICordovaCookieManager getCookieManager();\n\n    String getUrl();\n\n    // TODO: Work on deleting these by removing refs from plugins.\n    Context getContext();\n    void loadUrl(String url);\n    Object postMessage(String id, Object data);\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewEngine.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport android.view.KeyEvent;\nimport android.view.View;\nimport android.webkit.ValueCallback;\n\n/**\n * Interface for all Cordova engines.\n * No methods will be added to this class (in order to be compatible with existing engines).\n * Instead, we will create a new interface: e.g. CordovaWebViewEngineV2\n */\npublic interface CordovaWebViewEngine {\n    void init(CordovaWebView parentWebView, CordovaInterface cordova, Client client,\n              CordovaResourceApi resourceApi, PluginManager pluginManager,\n              NativeToJsMessageQueue nativeToJsMessageQueue);\n\n    CordovaWebView getCordovaWebView();\n    ICordovaCookieManager getCookieManager();\n    View getView();\n\n    void loadUrl(String url, boolean clearNavigationStack);\n\n    void stopLoading();\n\n    /** Return the currently loaded URL */\n    String getUrl();\n\n    void clearCache();\n\n    /** After calling clearHistory(), canGoBack() should be false. */\n    void clearHistory();\n\n    boolean canGoBack();\n\n    /** Returns whether a navigation occurred */\n    boolean goBack();\n\n    /** Pauses / resumes the WebView's event loop. */\n    void setPaused(boolean value);\n\n    /** Clean up all resources associated with the WebView. */\n    void destroy();\n\n    /** Add the evaulate Javascript method **/\n    void evaluateJavascript(String js, ValueCallback<String> callback);\n\n    /**\n     * Used to retrieve the associated CordovaWebView given a View without knowing the type of Engine.\n     * E.g. ((CordovaWebView.EngineView)activity.findViewById(android.R.id.webView)).getCordovaWebView();\n     */\n    public interface EngineView {\n        CordovaWebView getCordovaWebView();\n    }\n\n    /**\n     * Contains methods that an engine uses to communicate with the parent CordovaWebView.\n     * Methods may be added in future cordova versions, but never removed.\n     */\n    public interface Client {\n        Boolean onDispatchKeyEvent(KeyEvent event);\n        void clearLoadTimeoutTimer();\n        void onPageStarted(String newUrl);\n        void onReceivedError(int errorCode, String description, String failingUrl);\n        void onPageFinishedLoading(String url);\n        boolean onNavigationAttempt(String url);\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.view.Gravity;\nimport android.view.KeyEvent;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.webkit.WebChromeClient;\nimport android.widget.FrameLayout;\n\nimport org.apache.cordova.engine.SystemWebViewEngine;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.lang.reflect.Constructor;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Main class for interacting with a Cordova webview. Manages plugins, events, and a CordovaWebViewEngine.\n * Class uses two-phase initialization. You must call init() before calling any other methods.\n */\npublic class CordovaWebViewImpl implements CordovaWebView {\n\n    public static final String TAG = \"CordovaWebViewImpl\";\n\n    private PluginManager pluginManager;\n\n    protected final CordovaWebViewEngine engine;\n    private CordovaInterface cordova;\n\n    // Flag to track that a loadUrl timeout occurred\n    private int loadUrlTimeout = 0;\n\n    private CordovaResourceApi resourceApi;\n    private CordovaPreferences preferences;\n    private CoreAndroid appPlugin;\n    private NativeToJsMessageQueue nativeToJsMessageQueue;\n    private EngineClient engineClient = new EngineClient();\n    private boolean hasPausedEver;\n\n    // The URL passed to loadUrl(), not necessarily the URL of the current page.\n    String loadedUrl;\n\n    /** custom view created by the browser (a video player for example) */\n    private View mCustomView;\n    private WebChromeClient.CustomViewCallback mCustomViewCallback;\n\n    private Set<Integer> boundKeyCodes = new HashSet<Integer>();\n\n    public static CordovaWebViewEngine createEngine(Context context, CordovaPreferences preferences) {\n        String className = preferences.getString(\"webview\", SystemWebViewEngine.class.getCanonicalName());\n        try {\n            Class<?> webViewClass = Class.forName(className);\n            Constructor<?> constructor = webViewClass.getConstructor(Context.class, CordovaPreferences.class);\n            return (CordovaWebViewEngine) constructor.newInstance(context, preferences);\n        } catch (Exception e) {\n            throw new RuntimeException(\"Failed to create webview. \", e);\n        }\n    }\n\n    public CordovaWebViewImpl(CordovaWebViewEngine cordovaWebViewEngine) {\n        this.engine = cordovaWebViewEngine;\n    }\n\n    // Convenience method for when creating programmatically (not from Config.xml).\n    public void init(CordovaInterface cordova) {\n        init(cordova, new ArrayList<PluginEntry>(), new CordovaPreferences());\n    }\n\n    @Override\n    public void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences) {\n        if (this.cordova != null) {\n            throw new IllegalStateException();\n        }\n        this.cordova = cordova;\n        this.preferences = preferences;\n        pluginManager = new PluginManager(this, this.cordova, pluginEntries);\n        resourceApi = new CordovaResourceApi(engine.getView().getContext(), pluginManager);\n        nativeToJsMessageQueue = new NativeToJsMessageQueue();\n        nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.NoOpBridgeMode());\n        nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.LoadUrlBridgeMode(engine, cordova));\n\n        if (preferences.getBoolean(\"DisallowOverscroll\", false)) {\n            engine.getView().setOverScrollMode(View.OVER_SCROLL_NEVER);\n        }\n        engine.init(this, cordova, engineClient, resourceApi, pluginManager, nativeToJsMessageQueue);\n        // This isn't enforced by the compiler, so assert here.\n        assert engine.getView() instanceof CordovaWebViewEngine.EngineView;\n\n        pluginManager.addService(CoreAndroid.PLUGIN_NAME, \"org.apache.cordova.CoreAndroid\");\n        pluginManager.init();\n\n    }\n\n    @Override\n    public boolean isInitialized() {\n        return cordova != null;\n    }\n\n    @Override\n    public void loadUrlIntoView(final String url, boolean recreatePlugins) {\n        LOG.d(TAG, \">>> loadUrl(\" + url + \")\");\n        if (url.equals(\"about:blank\") || url.startsWith(\"javascript:\")) {\n            engine.loadUrl(url, false);\n            return;\n        }\n\n        recreatePlugins = recreatePlugins || (loadedUrl == null);\n\n        if (recreatePlugins) {\n            // Don't re-initialize on first load.\n            if (loadedUrl != null) {\n                appPlugin = null;\n                pluginManager.init();\n            }\n            loadedUrl = url;\n        }\n\n        // Create a timeout timer for loadUrl\n        final int currentLoadUrlTimeout = loadUrlTimeout;\n        final int loadUrlTimeoutValue = preferences.getInteger(\"LoadUrlTimeoutValue\", 20000);\n\n        // Timeout error method\n        final Runnable loadError = new Runnable() {\n            public void run() {\n                stopLoading();\n                LOG.e(TAG, \"CordovaWebView: TIMEOUT ERROR!\");\n\n                // Handle other errors by passing them to the webview in JS\n                JSONObject data = new JSONObject();\n                try {\n                    data.put(\"errorCode\", -6);\n                    data.put(\"description\", \"The connection to the server was unsuccessful.\");\n                    data.put(\"url\", url);\n                } catch (JSONException e) {\n                    // Will never happen.\n                }\n                pluginManager.postMessage(\"onReceivedError\", data);\n            }\n        };\n\n        // Timeout timer method\n        final Runnable timeoutCheck = new Runnable() {\n            public void run() {\n                try {\n                    synchronized (this) {\n                        wait(loadUrlTimeoutValue);\n                    }\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n\n                // If timeout, then stop loading and handle error\n                if (loadUrlTimeout == currentLoadUrlTimeout) {\n                    cordova.getActivity().runOnUiThread(loadError);\n                }\n            }\n        };\n\n        final boolean _recreatePlugins = recreatePlugins;\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            public void run() {\n                if (loadUrlTimeoutValue > 0) {\n                    cordova.getThreadPool().execute(timeoutCheck);\n                }\n                engine.loadUrl(url, _recreatePlugins);\n            }\n        });\n    }\n\n\n    @Override\n    public void loadUrl(String url) {\n        loadUrlIntoView(url, true);\n    }\n\n    @Override\n    public void showWebPage(String url, boolean openExternal, boolean clearHistory, Map<String, Object> params) {\n        LOG.d(TAG, \"showWebPage(%s, %b, %b, HashMap)\", url, openExternal, clearHistory);\n\n        // If clearing history\n        if (clearHistory) {\n            engine.clearHistory();\n        }\n\n        // If loading into our webview\n        if (!openExternal) {\n            // Make sure url is in whitelist\n            if (pluginManager.shouldAllowNavigation(url)) {\n                // TODO: What about params?\n                // Load new URL\n                loadUrlIntoView(url, true);\n            } else {\n                LOG.w(TAG, \"showWebPage: Refusing to load URL into webview since it is not in the <allow-navigation> whitelist. URL=\" + url);\n            }\n        }\n        if (!pluginManager.shouldOpenExternalUrl(url)) {\n            LOG.w(TAG, \"showWebPage: Refusing to send intent for URL since it is not in the <allow-intent> whitelist. URL=\" + url);\n            return;\n        }\n        try {\n            Intent intent = new Intent(Intent.ACTION_VIEW);\n            // To send an intent without CATEGORY_BROWSER, a custom plugin should be used.\n            intent.addCategory(Intent.CATEGORY_BROWSABLE);\n            Uri uri = Uri.parse(url);\n            // Omitting the MIME type for file: URLs causes \"No Activity found to handle Intent\".\n            // Adding the MIME type to http: URLs causes them to not be handled by the downloader.\n            if (\"file\".equals(uri.getScheme())) {\n                intent.setDataAndType(uri, resourceApi.getMimeType(uri));\n            } else {\n                intent.setData(uri);\n            }\n            cordova.getActivity().startActivity(intent);\n        } catch (android.content.ActivityNotFoundException e) {\n            LOG.e(TAG, \"Error loading url \" + url, e);\n        }\n    }\n\n    @Override\n    @Deprecated\n    public void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {\n        // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0\n        LOG.d(TAG, \"showing Custom View\");\n        // if a view already exists then immediately terminate the new one\n        if (mCustomView != null) {\n            callback.onCustomViewHidden();\n            return;\n        }\n\n        // Store the view and its callback for later (to kill it properly)\n        mCustomView = view;\n        mCustomViewCallback = callback;\n\n        // Add the custom view to its container.\n        ViewGroup parent = (ViewGroup) engine.getView().getParent();\n        parent.addView(view, new FrameLayout.LayoutParams(\n                ViewGroup.LayoutParams.MATCH_PARENT,\n                ViewGroup.LayoutParams.MATCH_PARENT,\n                Gravity.CENTER));\n\n        // Hide the content view.\n        engine.getView().setVisibility(View.GONE);\n\n        // Finally show the custom view container.\n        parent.setVisibility(View.VISIBLE);\n        parent.bringToFront();\n    }\n\n    @Override\n    @Deprecated\n    public void hideCustomView() {\n        // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0\n        if (mCustomView == null) return;\n        LOG.d(TAG, \"Hiding Custom View\");\n\n        // Hide the custom view.\n        mCustomView.setVisibility(View.GONE);\n\n        // Remove the custom view from its container.\n        ViewGroup parent = (ViewGroup) engine.getView().getParent();\n        parent.removeView(mCustomView);\n        mCustomView = null;\n        mCustomViewCallback.onCustomViewHidden();\n\n        // Show the content view.\n        engine.getView().setVisibility(View.VISIBLE);\n    }\n\n    @Override\n    @Deprecated\n    public boolean isCustomViewShowing() {\n        return mCustomView != null;\n    }\n\n    @Override\n    @Deprecated\n    public void sendJavascript(String statement) {\n        nativeToJsMessageQueue.addJavaScript(statement);\n    }\n\n    @Override\n    public void sendPluginResult(PluginResult cr, String callbackId) {\n        nativeToJsMessageQueue.addPluginResult(cr, callbackId);\n    }\n\n    @Override\n    public PluginManager getPluginManager() {\n        return pluginManager;\n    }\n    @Override\n    public CordovaPreferences getPreferences() {\n        return preferences;\n    }\n    @Override\n    public ICordovaCookieManager getCookieManager() {\n        return engine.getCookieManager();\n    }\n    @Override\n    public CordovaResourceApi getResourceApi() {\n        return resourceApi;\n    }\n    @Override\n    public CordovaWebViewEngine getEngine() {\n        return engine;\n    }\n    @Override\n    public View getView() {\n        return engine.getView();\n    }\n    @Override\n    public Context getContext() {\n        return engine.getView().getContext();\n    }\n\n    private void sendJavascriptEvent(String event) {\n        if (appPlugin == null) {\n            appPlugin = (CoreAndroid)pluginManager.getPlugin(CoreAndroid.PLUGIN_NAME);\n        }\n\n        if (appPlugin == null) {\n            LOG.w(TAG, \"Unable to fire event without existing plugin\");\n            return;\n        }\n        appPlugin.fireJavascriptEvent(event);\n    }\n\n    @Override\n    public void setButtonPlumbedToJs(int keyCode, boolean override) {\n        switch (keyCode) {\n            case KeyEvent.KEYCODE_VOLUME_DOWN:\n            case KeyEvent.KEYCODE_VOLUME_UP:\n            case KeyEvent.KEYCODE_BACK:\n            case KeyEvent.KEYCODE_MENU:\n                // TODO: Why are search and menu buttons handled separately?\n                if (override) {\n                    boundKeyCodes.add(keyCode);\n                } else {\n                    boundKeyCodes.remove(keyCode);\n                }\n                return;\n            default:\n                throw new IllegalArgumentException(\"Unsupported keycode: \" + keyCode);\n        }\n    }\n\n    @Override\n    public boolean isButtonPlumbedToJs(int keyCode) {\n        return boundKeyCodes.contains(keyCode);\n    }\n\n    @Override\n    public Object postMessage(String id, Object data) {\n        return pluginManager.postMessage(id, data);\n    }\n\n    // Engine method proxies:\n    @Override\n    public String getUrl() {\n        return engine.getUrl();\n    }\n\n    @Override\n    public void stopLoading() {\n        // Clear timeout flag\n        loadUrlTimeout++;\n    }\n\n    @Override\n    public boolean canGoBack() {\n        return engine.canGoBack();\n    }\n\n    @Override\n    public void clearCache() {\n        engine.clearCache();\n    }\n\n    @Override\n    @Deprecated\n    public void clearCache(boolean b) {\n        engine.clearCache();\n    }\n\n    @Override\n    public void clearHistory() {\n        engine.clearHistory();\n    }\n\n    @Override\n    public boolean backHistory() {\n        return engine.goBack();\n    }\n\n    /////// LifeCycle methods ///////\n    @Override\n    public void onNewIntent(Intent intent) {\n        if (this.pluginManager != null) {\n            this.pluginManager.onNewIntent(intent);\n        }\n    }\n    @Override\n    public void handlePause(boolean keepRunning) {\n        if (!isInitialized()) {\n            return;\n        }\n        hasPausedEver = true;\n        pluginManager.onPause(keepRunning);\n        sendJavascriptEvent(\"pause\");\n\n        // If app doesn't want to run in background\n        if (!keepRunning) {\n            // Pause JavaScript timers. This affects all webviews within the app!\n            engine.setPaused(true);\n        }\n    }\n    @Override\n    public void handleResume(boolean keepRunning) {\n        if (!isInitialized()) {\n            return;\n        }\n\n        // Resume JavaScript timers. This affects all webviews within the app!\n        engine.setPaused(false);\n        this.pluginManager.onResume(keepRunning);\n\n        // In order to match the behavior of the other platforms, we only send onResume after an\n        // onPause has occurred. The resume event might still be sent if the Activity was killed\n        // while waiting for the result of an external Activity once the result is obtained\n        if (hasPausedEver) {\n            sendJavascriptEvent(\"resume\");\n        }\n    }\n    @Override\n    public void handleStart() {\n        if (!isInitialized()) {\n            return;\n        }\n        pluginManager.onStart();\n    }\n    @Override\n    public void handleStop() {\n        if (!isInitialized()) {\n            return;\n        }\n        pluginManager.onStop();\n    }\n    @Override\n    public void handleDestroy() {\n        if (!isInitialized()) {\n            return;\n        }\n        // Cancel pending timeout timer.\n        loadUrlTimeout++;\n\n        // Forward to plugins\n        this.pluginManager.onDestroy();\n\n        // TODO: about:blank is a bit special (and the default URL for new frames)\n        // We should use a blank data: url instead so it's more obvious\n        this.loadUrl(\"about:blank\");\n\n        // TODO: Should not destroy webview until after about:blank is done loading.\n        engine.destroy();\n        hideCustomView();\n    }\n\n    protected class EngineClient implements CordovaWebViewEngine.Client {\n        @Override\n        public void clearLoadTimeoutTimer() {\n            loadUrlTimeout++;\n        }\n\n        @Override\n        public void onPageStarted(String newUrl) {\n            LOG.d(TAG, \"onPageDidNavigate(\" + newUrl + \")\");\n            boundKeyCodes.clear();\n            pluginManager.onReset();\n            pluginManager.postMessage(\"onPageStarted\", newUrl);\n        }\n\n        @Override\n        public void onReceivedError(int errorCode, String description, String failingUrl) {\n            clearLoadTimeoutTimer();\n            JSONObject data = new JSONObject();\n            try {\n                data.put(\"errorCode\", errorCode);\n                data.put(\"description\", description);\n                data.put(\"url\", failingUrl);\n            } catch (JSONException e) {\n                e.printStackTrace();\n            }\n            pluginManager.postMessage(\"onReceivedError\", data);\n        }\n\n        @Override\n        public void onPageFinishedLoading(String url) {\n            LOG.d(TAG, \"onPageFinished(\" + url + \")\");\n\n            clearLoadTimeoutTimer();\n\n            // Broadcast message that page has loaded\n            pluginManager.postMessage(\"onPageFinished\", url);\n\n            // Make app visible after 2 sec in case there was a JS error and Cordova JS never initialized correctly\n            if (engine.getView().getVisibility() != View.VISIBLE) {\n                Thread t = new Thread(new Runnable() {\n                    public void run() {\n                        try {\n                            Thread.sleep(2000);\n                            cordova.getActivity().runOnUiThread(new Runnable() {\n                                public void run() {\n                                    pluginManager.postMessage(\"spinner\", \"stop\");\n                                }\n                            });\n                        } catch (InterruptedException e) {\n                        }\n                    }\n                });\n                t.start();\n            }\n\n            // Shutdown if blank loaded\n            if (url.equals(\"about:blank\")) {\n                pluginManager.postMessage(\"exit\", null);\n            }\n        }\n\n        @Override\n        public Boolean onDispatchKeyEvent(KeyEvent event) {\n            int keyCode = event.getKeyCode();\n            boolean isBackButton = keyCode == KeyEvent.KEYCODE_BACK;\n            if (event.getAction() == KeyEvent.ACTION_DOWN) {\n                if (isBackButton && mCustomView != null) {\n                    return true;\n                } else if (boundKeyCodes.contains(keyCode)) {\n                    return true;\n                } else if (isBackButton) {\n                    return engine.canGoBack();\n                }\n            } else if (event.getAction() == KeyEvent.ACTION_UP) {\n                if (isBackButton && mCustomView != null) {\n                    hideCustomView();\n                    return true;\n                } else if (boundKeyCodes.contains(keyCode)) {\n                    String eventName = null;\n                    switch (keyCode) {\n                        case KeyEvent.KEYCODE_VOLUME_DOWN:\n                            eventName = \"volumedownbutton\";\n                            break;\n                        case KeyEvent.KEYCODE_VOLUME_UP:\n                            eventName = \"volumeupbutton\";\n                            break;\n                        case KeyEvent.KEYCODE_SEARCH:\n                            eventName = \"searchbutton\";\n                            break;\n                        case KeyEvent.KEYCODE_MENU:\n                            eventName = \"menubutton\";\n                            break;\n                        case KeyEvent.KEYCODE_BACK:\n                            eventName = \"backbutton\";\n                            break;\n                    }\n                    if (eventName != null) {\n                        sendJavascriptEvent(eventName);\n                        return true;\n                    }\n                } else if (isBackButton) {\n                    return engine.goBack();\n                }\n            }\n            return null;\n        }\n\n        @Override\n        public boolean onNavigationAttempt(String url) {\n            // Give plugins the chance to handle the url\n            if (pluginManager.onOverrideUrlLoading(url)) {\n                return true;\n            } else if (pluginManager.shouldAllowNavigation(url)) {\n                return false;\n            } else if (pluginManager.shouldOpenExternalUrl(url)) {\n                showWebPage(url, true, false, null);\n                return true;\n            }\n            LOG.w(TAG, \"Blocked (possibly sub-frame) navigation to non-allowed URL: \" + url);\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/CoreAndroid.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.telephony.TelephonyManager;\nimport android.view.KeyEvent;\n\nimport java.lang.reflect.Field;\nimport java.util.HashMap;\n\n/**\n * This class exposes methods in Cordova that can be called from JavaScript.\n */\npublic class CoreAndroid extends CordovaPlugin {\n\n    public static final String PLUGIN_NAME = \"CoreAndroid\";\n    protected static final String TAG = \"CordovaApp\";\n    private BroadcastReceiver telephonyReceiver;\n    private CallbackContext messageChannel;\n    private PluginResult pendingResume;\n    private final Object messageChannelLock = new Object();\n\n    /**\n     * Send an event to be fired on the Javascript side.\n     *\n     * @param action The name of the event to be fired\n     */\n    public void fireJavascriptEvent(String action) {\n        sendEventMessage(action);\n    }\n\n    /**\n     * Sets the context of the Command. This can then be used to do things like\n     * get file paths associated with the Activity.\n     */\n    @Override\n    public void pluginInitialize() {\n        this.initTelephonyReceiver();\n    }\n\n    /**\n     * Executes the request and returns PluginResult.\n     *\n     * @param action            The action to execute.\n     * @param args              JSONArry of arguments for the plugin.\n     * @param callbackContext   The callback context from which we were invoked.\n     * @return                  A PluginResult object with a status and message.\n     */\n    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {\n        PluginResult.Status status = PluginResult.Status.OK;\n        String result = \"\";\n\n        try {\n            if (action.equals(\"clearCache\")) {\n                this.clearCache();\n            }\n            else if (action.equals(\"show\")) {\n                // This gets called from JavaScript onCordovaReady to show the webview.\n                // I recommend we change the name of the Message as spinner/stop is not\n                // indicative of what this actually does (shows the webview).\n                cordova.getActivity().runOnUiThread(new Runnable() {\n                    public void run() {\n                        webView.getPluginManager().postMessage(\"spinner\", \"stop\");\n                    }\n                });\n            }\n            else if (action.equals(\"loadUrl\")) {\n                this.loadUrl(args.getString(0), args.optJSONObject(1));\n            }\n            else if (action.equals(\"cancelLoadUrl\")) {\n                //this.cancelLoadUrl();\n            }\n            else if (action.equals(\"clearHistory\")) {\n                this.clearHistory();\n            }\n            else if (action.equals(\"backHistory\")) {\n                this.backHistory();\n            }\n            else if (action.equals(\"overrideButton\")) {\n                this.overrideButton(args.getString(0), args.getBoolean(1));\n            }\n            else if (action.equals(\"overrideBackbutton\")) {\n                this.overrideBackbutton(args.getBoolean(0));\n            }\n            else if (action.equals(\"exitApp\")) {\n                this.exitApp();\n            }\n\t\t\telse if (action.equals(\"messageChannel\")) {\n                synchronized(messageChannelLock) {\n                    messageChannel = callbackContext;\n                    if (pendingResume != null) {\n                        sendEventMessage(pendingResume);\n                        pendingResume = null;\n                    }\n                }\n                return true;\n            }\n\n            callbackContext.sendPluginResult(new PluginResult(status, result));\n            return true;\n        } catch (JSONException e) {\n            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));\n            return false;\n        }\n    }\n\n    //--------------------------------------------------------------------------\n    // LOCAL METHODS\n    //--------------------------------------------------------------------------\n\n    /**\n     * Clear the resource cache.\n     */\n    public void clearCache() {\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            public void run() {\n                webView.clearCache(true);\n            }\n        });\n    }\n\n    /**\n     * Load the url into the webview.\n     *\n     * @param url\n     * @param props\t\t\tProperties that can be passed in to the Cordova activity (i.e. loadingDialog, wait, ...)\n     * @throws JSONException\n     */\n    public void loadUrl(String url, JSONObject props) throws JSONException {\n        LOG.d(\"App\", \"App.loadUrl(\"+url+\",\"+props+\")\");\n        int wait = 0;\n        boolean openExternal = false;\n        boolean clearHistory = false;\n\n        // If there are properties, then set them on the Activity\n        HashMap<String, Object> params = new HashMap<String, Object>();\n        if (props != null) {\n            JSONArray keys = props.names();\n            for (int i = 0; i < keys.length(); i++) {\n                String key = keys.getString(i);\n                if (key.equals(\"wait\")) {\n                    wait = props.getInt(key);\n                }\n                else if (key.equalsIgnoreCase(\"openexternal\")) {\n                    openExternal = props.getBoolean(key);\n                }\n                else if (key.equalsIgnoreCase(\"clearhistory\")) {\n                    clearHistory = props.getBoolean(key);\n                }\n                else {\n                    Object value = props.get(key);\n                    if (value == null) {\n\n                    }\n                    else if (value.getClass().equals(String.class)) {\n                        params.put(key, (String)value);\n                    }\n                    else if (value.getClass().equals(Boolean.class)) {\n                        params.put(key, (Boolean)value);\n                    }\n                    else if (value.getClass().equals(Integer.class)) {\n                        params.put(key, (Integer)value);\n                    }\n                }\n            }\n        }\n\n        // If wait property, then delay loading\n\n        if (wait > 0) {\n            try {\n                synchronized(this) {\n                    this.wait(wait);\n                }\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n        }\n        this.webView.showWebPage(url, openExternal, clearHistory, params);\n    }\n\n    /**\n     * Clear page history for the app.\n     */\n    public void clearHistory() {\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            public void run() {\n                webView.clearHistory();\n            }\n        });\n    }\n\n    /**\n     * Go to previous page displayed.\n     * This is the same as pressing the backbutton on Android device.\n     */\n    public void backHistory() {\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            public void run() {\n                webView.backHistory();\n            }\n        });\n    }\n\n    /**\n     * Override the default behavior of the Android back button.\n     * If overridden, when the back button is pressed, the \"backKeyDown\" JavaScript event will be fired.\n     *\n     * @param override\t\tT=override, F=cancel override\n     */\n    public void overrideBackbutton(boolean override) {\n        LOG.i(\"App\", \"WARNING: Back Button Default Behavior will be overridden.  The backbutton event will be fired!\");\n        webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, override);\n    }\n\n    /**\n     * Override the default behavior of the Android volume buttons.\n     * If overridden, when the volume button is pressed, the \"volume[up|down]button\" JavaScript event will be fired.\n     *\n     * @param button        volumeup, volumedown\n     * @param override      T=override, F=cancel override\n     */\n    public void overrideButton(String button, boolean override) {\n        LOG.i(\"App\", \"WARNING: Volume Button Default Behavior will be overridden.  The volume event will be fired!\");\n        if (button.equals(\"volumeup\")) {\n            webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override);\n        }\n        else if (button.equals(\"volumedown\")) {\n            webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override);\n        }\n        else if (button.equals(\"menubutton\")) {\n            webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_MENU, override);\n        }\n    }\n\n    /**\n     * Return whether the Android back button is overridden by the user.\n     *\n     * @return boolean\n     */\n    public boolean isBackbuttonOverridden() {\n        return webView.isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);\n    }\n\n    /**\n     * Exit the Android application.\n     */\n    public void exitApp() {\n        this.webView.getPluginManager().postMessage(\"exit\", null);\n    }\n\n\n    /**\n     * Listen for telephony events: RINGING, OFFHOOK and IDLE\n     * Send these events to all plugins using\n     *      CordovaActivity.onMessage(\"telephone\", \"ringing\" | \"offhook\" | \"idle\")\n     */\n    private void initTelephonyReceiver() {\n        IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);\n        //final CordovaInterface mycordova = this.cordova;\n        this.telephonyReceiver = new BroadcastReceiver() {\n\n            @Override\n            public void onReceive(Context context, Intent intent) {\n\n                // If state has changed\n                if ((intent != null) && intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {\n                    if (intent.hasExtra(TelephonyManager.EXTRA_STATE)) {\n                        String extraData = intent.getStringExtra(TelephonyManager.EXTRA_STATE);\n                        if (extraData.equals(TelephonyManager.EXTRA_STATE_RINGING)) {\n                            LOG.i(TAG, \"Telephone RINGING\");\n                            webView.getPluginManager().postMessage(\"telephone\", \"ringing\");\n                        }\n                        else if (extraData.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {\n                            LOG.i(TAG, \"Telephone OFFHOOK\");\n                            webView.getPluginManager().postMessage(\"telephone\", \"offhook\");\n                        }\n                        else if (extraData.equals(TelephonyManager.EXTRA_STATE_IDLE)) {\n                            LOG.i(TAG, \"Telephone IDLE\");\n                            webView.getPluginManager().postMessage(\"telephone\", \"idle\");\n                        }\n                    }\n                }\n            }\n        };\n\n        // Register the receiver\n        webView.getContext().registerReceiver(this.telephonyReceiver, intentFilter);\n    }\n\n    private void sendEventMessage(String action) {\n        JSONObject obj = new JSONObject();\n        try {\n            obj.put(\"action\", action);\n        } catch (JSONException e) {\n            LOG.e(TAG, \"Failed to create event message\", e);\n        }\n        sendEventMessage(new PluginResult(PluginResult.Status.OK, obj));\n    }\n\n    private void sendEventMessage(PluginResult payload) {\n        payload.setKeepCallback(true);\n        if (messageChannel != null) {\n            messageChannel.sendPluginResult(payload);\n        }\n    }\n\n    /*\n     * Unregister the receiver\n     *\n     */\n    public void onDestroy()\n    {\n        webView.getContext().unregisterReceiver(this.telephonyReceiver);\n    }\n\n    /**\n     * Used to send the resume event in the case that the Activity is destroyed by the OS\n     *\n     * @param resumeEvent PluginResult containing the payload for the resume event to be fired\n     */\n    public void sendResumeEvent(PluginResult resumeEvent) {\n        // This operation must be synchronized because plugin results that trigger resume\n        // events can be processed asynchronously\n        synchronized(messageChannelLock) {\n            if (messageChannel != null) {\n                sendEventMessage(resumeEvent);\n            } else {\n                // Might get called before the page loads, so we need to store it until the\n                // messageChannel gets created\n                this.pendingResume = resumeEvent;\n            }\n        }\n    }\n\n      /*\n     * This needs to be implemented if you wish to use the Camera Plugin or other plugins\n     * that read the Build Configuration.\n     *\n     * Thanks to Phil@Medtronic and Graham Borland for finding the answer and posting it to\n     * StackOverflow.  This is annoying as hell!\n     *\n     */\n\n    public static Object getBuildConfigValue(Context ctx, String key)\n    {\n        try\n        {\n            Class<?> clazz = Class.forName(ctx.getPackageName() + \".BuildConfig\");\n            Field field = clazz.getField(key);\n            return field.get(null);\n        } catch (ClassNotFoundException e) {\n            LOG.d(TAG, \"Unable to get the BuildConfig, is this built with ANT?\");\n            e.printStackTrace();\n        } catch (NoSuchFieldException e) {\n            LOG.d(TAG, key + \" is not a valid field. Check your build.gradle\");\n        } catch (IllegalAccessException e) {\n            LOG.d(TAG, \"Illegal Access Exception: Let's print a stack trace.\");\n            e.printStackTrace();\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/ExposedJsApi.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova;\n\nimport org.json.JSONException;\n\n/*\n * Any exposed Javascript API MUST implement these three things!\n */\npublic interface ExposedJsApi {\n    public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException;\n    public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException;\n    public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException;\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/ICordovaClientCertRequest.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport java.security.Principal;\nimport java.security.PrivateKey;\nimport java.security.cert.X509Certificate;\n\n/**\n * Specifies interface for handling certificate requests.\n */\npublic interface ICordovaClientCertRequest {\n    /**\n     * Cancel this request\n     */\n    public void cancel();\n    \n    /*\n     * Returns the host name of the server requesting the certificate.\n     */\n    public String getHost();\n    \n    /*\n     * Returns the acceptable types of asymmetric keys (can be null).\n     */\n    public String[] getKeyTypes();\n    \n    /*\n     * Returns the port number of the server requesting the certificate.\n     */\n    public int getPort();\n    \n    /*\n     * Returns the acceptable certificate issuers for the certificate matching the private key (can be null).\n     */\n    public Principal[] getPrincipals();\n    \n    /*\n     * Ignore the request for now. Do not remember user's choice.\n     */\n    public void ignore();\n    \n    /*\n     * Proceed with the specified private key and client certificate chain. Remember the user's positive choice and use it for future requests.\n     * \n     * @param privateKey The privateKey\n     * @param chain The certificate chain \n     */\n    public void proceed(PrivateKey privateKey, X509Certificate[] chain);\n}"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/ICordovaCookieManager.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova;\n\npublic interface ICordovaCookieManager {\n\n    public void setCookiesEnabled(boolean accept);\n\n    public void setCookie(final String url, final String value);\n\n    public String getCookie(final String url);\n\n    public void clearCookies();\n\n    public void flush();\n};\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/ICordovaHttpAuthHandler.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\n/**\n * Specifies interface for HTTP auth handler object which is used to handle auth requests and\n * specifying user credentials.\n */\n public interface ICordovaHttpAuthHandler {\n    /**\n     * Instructs the WebView to cancel the authentication request.\n     */\n    public void cancel ();\n    \n    /**\n     * Instructs the WebView to proceed with the authentication with the given credentials.\n     * \n     * @param username The user name\n     * @param password The password\n     */\n    public void proceed (String username, String password);\n}"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/LOG.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport android.util.Log;\n\n/**\n * Log to Android logging system.\n *\n * Log message can be a string or a printf formatted string with arguments.\n * See http://developer.android.com/reference/java/util/Formatter.html\n */\npublic class LOG {\n\n    public static final int VERBOSE = Log.VERBOSE;\n    public static final int DEBUG = Log.DEBUG;\n    public static final int INFO = Log.INFO;\n    public static final int WARN = Log.WARN;\n    public static final int ERROR = Log.ERROR;\n\n    // Current log level\n    public static int LOGLEVEL = Log.ERROR;\n\n    /**\n     * Set the current log level.\n     *\n     * @param logLevel\n     */\n    public static void setLogLevel(int logLevel) {\n        LOGLEVEL = logLevel;\n        Log.i(\"CordovaLog\", \"Changing log level to \" + logLevel);\n    }\n\n    /**\n     * Set the current log level.\n     *\n     * @param logLevel\n     */\n    public static void setLogLevel(String logLevel) {\n        if (\"VERBOSE\".equals(logLevel)) LOGLEVEL = VERBOSE;\n        else if (\"DEBUG\".equals(logLevel)) LOGLEVEL = DEBUG;\n        else if (\"INFO\".equals(logLevel)) LOGLEVEL = INFO;\n        else if (\"WARN\".equals(logLevel)) LOGLEVEL = WARN;\n        else if (\"ERROR\".equals(logLevel)) LOGLEVEL = ERROR;\n        Log.i(\"CordovaLog\", \"Changing log level to \" + logLevel + \"(\" + LOGLEVEL + \")\");\n    }\n\n    /**\n     * Determine if log level will be logged\n     *\n     * @param logLevel\n     * @return true if the parameter passed in is greater than or equal to the current log level\n     */\n    public static boolean isLoggable(int logLevel) {\n        return (logLevel >= LOGLEVEL);\n    }\n\n    /**\n     * Verbose log message.\n     *\n     * @param tag\n     * @param s\n     */\n    public static void v(String tag, String s) {\n        if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s);\n    }\n\n    /**\n     * Debug log message.\n     *\n     * @param tag\n     * @param s\n     */\n    public static void d(String tag, String s) {\n        if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s);\n    }\n\n    /**\n     * Info log message.\n     *\n     * @param tag\n     * @param s\n     */\n    public static void i(String tag, String s) {\n        if (LOG.INFO >= LOGLEVEL) Log.i(tag, s);\n    }\n\n    /**\n     * Warning log message.\n     *\n     * @param tag\n     * @param s\n     */\n    public static void w(String tag, String s) {\n        if (LOG.WARN >= LOGLEVEL) Log.w(tag, s);\n    }\n\n    /**\n     * Error log message.\n     *\n     * @param tag\n     * @param s\n     */\n    public static void e(String tag, String s) {\n        if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s);\n    }\n\n    /**\n     * Verbose log message.\n     *\n     * @param tag\n     * @param s\n     * @param e\n     */\n    public static void v(String tag, String s, Throwable e) {\n        if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s, e);\n    }\n\n    /**\n     * Debug log message.\n     *\n     * @param tag\n     * @param s\n     * @param e\n     */\n    public static void d(String tag, String s, Throwable e) {\n        if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s, e);\n    }\n\n    /**\n     * Info log message.\n     *\n     * @param tag\n     * @param s\n     * @param e\n     */\n    public static void i(String tag, String s, Throwable e) {\n        if (LOG.INFO >= LOGLEVEL) Log.i(tag, s, e);\n    }\n\n    /**\n     * Warning log message.\n     *\n     * @param tag\n     * @param e\n     */\n    public static void w(String tag, Throwable e) {\n        if (LOG.WARN >= LOGLEVEL) Log.w(tag, e);\n    }\n\n    /**\n     * Warning log message.\n     *\n     * @param tag\n     * @param s\n     * @param e\n     */\n    public static void w(String tag, String s, Throwable e) {\n        if (LOG.WARN >= LOGLEVEL) Log.w(tag, s, e);\n    }\n\n    /**\n     * Error log message.\n     *\n     * @param tag\n     * @param s\n     * @param e\n     */\n    public static void e(String tag, String s, Throwable e) {\n        if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s, e);\n    }\n\n    /**\n     * Verbose log message with printf formatting.\n     *\n     * @param tag\n     * @param s\n     * @param args\n     */\n    public static void v(String tag, String s, Object... args) {\n        if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, String.format(s, args));\n    }\n\n    /**\n     * Debug log message with printf formatting.\n     *\n     * @param tag\n     * @param s\n     * @param args\n     */\n    public static void d(String tag, String s, Object... args) {\n        if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, String.format(s, args));\n    }\n\n    /**\n     * Info log message with printf formatting.\n     *\n     * @param tag\n     * @param s\n     * @param args\n     */\n    public static void i(String tag, String s, Object... args) {\n        if (LOG.INFO >= LOGLEVEL) Log.i(tag, String.format(s, args));\n    }\n\n    /**\n     * Warning log message with printf formatting.\n     *\n     * @param tag\n     * @param s\n     * @param args\n     */\n    public static void w(String tag, String s, Object... args) {\n        if (LOG.WARN >= LOGLEVEL) Log.w(tag, String.format(s, args));\n    }\n\n    /**\n     * Error log message with printf formatting.\n     *\n     * @param tag\n     * @param s\n     * @param args\n     */\n    public static void e(String tag, String s, Object... args) {\n        if (LOG.ERROR >= LOGLEVEL) Log.e(tag, String.format(s, args));\n    }\n\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/NativeToJsMessageQueue.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport java.util.ArrayList;\nimport java.util.LinkedList;\n\n/**\n * Holds the list of messages to be sent to the WebView.\n */\npublic class NativeToJsMessageQueue {\n    private static final String LOG_TAG = \"JsMessageQueue\";\n\n    // Set this to true to force plugin results to be encoding as\n    // JS instead of the custom format (useful for benchmarking).\n    // Doesn't work for multipart messages.\n    private static final boolean FORCE_ENCODE_USING_EVAL = false;\n\n    // Disable sending back native->JS messages during an exec() when the active\n    // exec() is asynchronous. Set this to true when running bridge benchmarks.\n    static final boolean DISABLE_EXEC_CHAINING = false;\n\n    // Arbitrarily chosen upper limit for how much data to send to JS in one shot.\n    // This currently only chops up on message boundaries. It may be useful\n    // to allow it to break up messages.\n    private static int MAX_PAYLOAD_SIZE = 50 * 1024 * 10240;\n\n    /**\n     * When true, the active listener is not fired upon enqueue. When set to false,\n     * the active listener will be fired if the queue is non-empty.\n     */\n    private boolean paused;\n\n    /**\n     * The list of JavaScript statements to be sent to JavaScript.\n     */\n    private final LinkedList<JsMessage> queue = new LinkedList<JsMessage>();\n\n    /**\n     * The array of listeners that can be used to send messages to JS.\n     */\n    private ArrayList<BridgeMode> bridgeModes = new ArrayList<BridgeMode>();\n\n    /**\n     * When null, the bridge is disabled. This occurs during page transitions.\n     * When disabled, all callbacks are dropped since they are assumed to be\n     * relevant to the previous page.\n     */\n    private BridgeMode activeBridgeMode;\n\n    public void addBridgeMode(BridgeMode bridgeMode) {\n        bridgeModes.add(bridgeMode);\n    }\n\n    public boolean isBridgeEnabled() {\n        return activeBridgeMode != null;\n    }\n\n    public boolean isEmpty() {\n        return queue.isEmpty();\n    }\n\n    /**\n     * Changes the bridge mode.\n     */\n    public void setBridgeMode(int value) {\n        if (value < -1 || value >= bridgeModes.size()) {\n            LOG.d(LOG_TAG, \"Invalid NativeToJsBridgeMode: \" + value);\n        } else {\n            BridgeMode newMode = value < 0 ? null : bridgeModes.get(value);\n            if (newMode != activeBridgeMode) {\n                LOG.d(LOG_TAG, \"Set native->JS mode to \" + (newMode == null ? \"null\" : newMode.getClass().getSimpleName()));\n                synchronized (this) {\n                    activeBridgeMode = newMode;\n                    if (newMode != null) {\n                        newMode.reset();\n                        if (!paused && !queue.isEmpty()) {\n                            newMode.onNativeToJsMessageAvailable(this);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Clears all messages and resets to the default bridge mode.\n     */\n    public void reset() {\n        synchronized (this) {\n            queue.clear();\n            setBridgeMode(-1);\n        }\n    }\n\n    private int calculatePackedMessageLength(JsMessage message) {\n        int messageLen = message.calculateEncodedLength();\n        String messageLenStr = String.valueOf(messageLen);\n        return messageLenStr.length() + messageLen + 1;\n    }\n\n    private void packMessage(JsMessage message, StringBuilder sb) {\n        int len = message.calculateEncodedLength();\n        sb.append(len)\n          .append(' ');\n        message.encodeAsMessage(sb);\n    }\n\n    /**\n     * Combines and returns queued messages combined into a single string.\n     * Combines as many messages as possible, while staying under MAX_PAYLOAD_SIZE.\n     * Returns null if the queue is empty.\n     */\n    public String popAndEncode(boolean fromOnlineEvent) {\n        synchronized (this) {\n            if (activeBridgeMode == null) {\n                return null;\n            }\n            activeBridgeMode.notifyOfFlush(this, fromOnlineEvent);\n            if (queue.isEmpty()) {\n                return null;\n            }\n            int totalPayloadLen = 0;\n            int numMessagesToSend = 0;\n            for (JsMessage message : queue) {\n                int messageSize = calculatePackedMessageLength(message);\n                if (numMessagesToSend > 0 && totalPayloadLen + messageSize > MAX_PAYLOAD_SIZE && MAX_PAYLOAD_SIZE > 0) {\n                    break;\n                }\n                totalPayloadLen += messageSize;\n                numMessagesToSend += 1;\n            }\n\n            StringBuilder sb = new StringBuilder(totalPayloadLen);\n            for (int i = 0; i < numMessagesToSend; ++i) {\n                JsMessage message = queue.removeFirst();\n                packMessage(message, sb);\n            }\n\n            if (!queue.isEmpty()) {\n                // Attach a char to indicate that there are more messages pending.\n                sb.append('*');\n            }\n            String ret = sb.toString();\n            return ret;\n        }\n    }\n\n    /**\n     * Same as popAndEncode(), except encodes in a form that can be executed as JS.\n     */\n    public String popAndEncodeAsJs() {\n        synchronized (this) {\n            int length = queue.size();\n            if (length == 0) {\n                return null;\n            }\n            int totalPayloadLen = 0;\n            int numMessagesToSend = 0;\n            for (JsMessage message : queue) {\n                int messageSize = message.calculateEncodedLength() + 50; // overestimate.\n                if (numMessagesToSend > 0 && totalPayloadLen + messageSize > MAX_PAYLOAD_SIZE && MAX_PAYLOAD_SIZE > 0) {\n                    break;\n                }\n                totalPayloadLen += messageSize;\n                numMessagesToSend += 1;\n            }\n            boolean willSendAllMessages = numMessagesToSend == queue.size();\n            StringBuilder sb = new StringBuilder(totalPayloadLen + (willSendAllMessages ? 0 : 100));\n            // Wrap each statement in a try/finally so that if one throws it does\n            // not affect the next.\n            for (int i = 0; i < numMessagesToSend; ++i) {\n                JsMessage message = queue.removeFirst();\n                if (willSendAllMessages && (i + 1 == numMessagesToSend)) {\n                    message.encodeAsJsMessage(sb);\n                } else {\n                    sb.append(\"try{\");\n                    message.encodeAsJsMessage(sb);\n                    sb.append(\"}finally{\");\n                }\n            }\n            if (!willSendAllMessages) {\n                sb.append(\"window.setTimeout(function(){cordova.require('cordova/plugin/android/polling').pollOnce();},0);\");\n            }\n            for (int i = willSendAllMessages ? 1 : 0; i < numMessagesToSend; ++i) {\n                sb.append('}');\n            }\n            String ret = sb.toString();\n            return ret;\n        }\n    }\n\n    /**\n     * Add a JavaScript statement to the list.\n     */\n    public void addJavaScript(String statement) {\n        enqueueMessage(new JsMessage(statement));\n    }\n\n    /**\n     * Add a JavaScript statement to the list.\n     */\n    public void addPluginResult(PluginResult result, String callbackId) {\n        if (callbackId == null) {\n            LOG.e(LOG_TAG, \"Got plugin result with no callbackId\", new Throwable());\n            return;\n        }\n        // Don't send anything if there is no result and there is no need to\n        // clear the callbacks.\n        boolean noResult = result.getStatus() == PluginResult.Status.NO_RESULT.ordinal();\n        boolean keepCallback = result.getKeepCallback();\n        if (noResult && keepCallback) {\n            return;\n        }\n        JsMessage message = new JsMessage(result, callbackId);\n        if (FORCE_ENCODE_USING_EVAL) {\n            StringBuilder sb = new StringBuilder(message.calculateEncodedLength() + 50);\n            message.encodeAsJsMessage(sb);\n            message = new JsMessage(sb.toString());\n        }\n\n        enqueueMessage(message);\n    }\n\n    private void enqueueMessage(JsMessage message) {\n        synchronized (this) {\n            if (activeBridgeMode == null) {\n                LOG.d(LOG_TAG, \"Dropping Native->JS message due to disabled bridge\");\n                return;\n            }\n            queue.add(message);\n            if (!paused) {\n                activeBridgeMode.onNativeToJsMessageAvailable(this);\n            }\n        }\n    }\n\n    public void setPaused(boolean value) {\n        if (paused && value) {\n            // This should never happen. If a use-case for it comes up, we should\n            // change pause to be a counter.\n            LOG.e(LOG_TAG, \"nested call to setPaused detected.\", new Throwable());\n        }\n        paused = value;\n        if (!value) {\n            synchronized (this) {\n                if (!queue.isEmpty() && activeBridgeMode != null) {\n                    activeBridgeMode.onNativeToJsMessageAvailable(this);\n                }\n            }\n        }\n    }\n\n    public static abstract class BridgeMode {\n        public abstract void onNativeToJsMessageAvailable(NativeToJsMessageQueue queue);\n        public void notifyOfFlush(NativeToJsMessageQueue queue, boolean fromOnlineEvent) {}\n        public void reset() {}\n    }\n\n    /** Uses JS polls for messages on a timer.. */\n    public static class NoOpBridgeMode extends BridgeMode {\n        @Override public void onNativeToJsMessageAvailable(NativeToJsMessageQueue queue) {\n        }\n    }\n\n    /** Uses webView.loadUrl(\"javascript:\") to execute messages. */\n    public static class LoadUrlBridgeMode extends BridgeMode {\n        private final CordovaWebViewEngine engine;\n        private final CordovaInterface cordova;\n\n        public LoadUrlBridgeMode(CordovaWebViewEngine engine, CordovaInterface cordova) {\n            this.engine = engine;\n            this.cordova = cordova;\n        }\n\n        @Override\n        public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {\n            cordova.getActivity().runOnUiThread(new Runnable() {\n                public void run() {\n                    String js = queue.popAndEncodeAsJs();\n                    if (js != null) {\n                        engine.loadUrl(\"javascript:\" + js, false);\n                    }\n                }\n            });\n        }\n    }\n\n    /** Uses online/offline events to tell the JS when to poll for messages. */\n    public static class OnlineEventsBridgeMode extends BridgeMode {\n        private final OnlineEventsBridgeModeDelegate delegate;\n        private boolean online;\n        private boolean ignoreNextFlush;\n\n        public interface OnlineEventsBridgeModeDelegate {\n            void setNetworkAvailable(boolean value);\n            void runOnUiThread(Runnable r);\n        }\n\n        public OnlineEventsBridgeMode(OnlineEventsBridgeModeDelegate delegate) {\n            this.delegate = delegate;\n        }\n\n        @Override\n        public void reset() {\n            delegate.runOnUiThread(new Runnable() {\n                public void run() {\n                    online = false;\n                    // If the following call triggers a notifyOfFlush, then ignore it.\n                    ignoreNextFlush = true;\n                    delegate.setNetworkAvailable(true);\n                }\n            });\n        }\n\n        @Override\n        public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {\n            delegate.runOnUiThread(new Runnable() {\n                public void run() {\n                    if (!queue.isEmpty()) {\n                        ignoreNextFlush = false;\n                        delegate.setNetworkAvailable(online);\n                    }\n                }\n            });\n        }\n        // Track when online/offline events are fired so that we don't fire excess events.\n        @Override\n        public void notifyOfFlush(final NativeToJsMessageQueue queue, boolean fromOnlineEvent) {\n            if (fromOnlineEvent && !ignoreNextFlush) {\n                online = !online;\n            }\n        }\n    }\n\n    /** Uses webView.evaluateJavascript to execute messages. */\n    public static class EvalBridgeMode extends BridgeMode {\n        private final CordovaWebViewEngine engine;\n        private final CordovaInterface cordova;\n\n        public EvalBridgeMode(CordovaWebViewEngine engine, CordovaInterface cordova) {\n            this.engine = engine;\n            this.cordova = cordova;\n        }\n\n        @Override\n        public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {\n            cordova.getActivity().runOnUiThread(new Runnable() {\n                public void run() {\n                    String js = queue.popAndEncodeAsJs();\n                    if (js != null) {\n                        engine.evaluateJavascript(js, null);\n                    }\n                }\n            });\n        }\n    }\n\n\n\n    private static class JsMessage {\n        final String jsPayloadOrCallbackId;\n        final PluginResult pluginResult;\n        JsMessage(String js) {\n            if (js == null) {\n                throw new NullPointerException();\n            }\n            jsPayloadOrCallbackId = js;\n            pluginResult = null;\n        }\n        JsMessage(PluginResult pluginResult, String callbackId) {\n            if (callbackId == null || pluginResult == null) {\n                throw new NullPointerException();\n            }\n            jsPayloadOrCallbackId = callbackId;\n            this.pluginResult = pluginResult;\n        }\n\n        static int calculateEncodedLengthHelper(PluginResult pluginResult) {\n            switch (pluginResult.getMessageType()) {\n                case PluginResult.MESSAGE_TYPE_BOOLEAN: // f or t\n                case PluginResult.MESSAGE_TYPE_NULL: // N\n                    return 1;\n                case PluginResult.MESSAGE_TYPE_NUMBER: // n\n                    return 1 + pluginResult.getMessage().length();\n                case PluginResult.MESSAGE_TYPE_STRING: // s\n                    return 1 + pluginResult.getStrMessage().length();\n                case PluginResult.MESSAGE_TYPE_BINARYSTRING:\n                    return 1 + pluginResult.getMessage().length();\n                case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:\n                    return 1 + pluginResult.getMessage().length();\n                case PluginResult.MESSAGE_TYPE_MULTIPART:\n                    int ret = 1;\n                    for (int i = 0; i < pluginResult.getMultipartMessagesSize(); i++) {\n                        int length = calculateEncodedLengthHelper(pluginResult.getMultipartMessage(i));\n                        int argLength = String.valueOf(length).length();\n                        ret += argLength + 1 + length;\n                    }\n                    return ret;\n                case PluginResult.MESSAGE_TYPE_JSON:\n                default:\n                    return pluginResult.getMessage().length();\n            }\n        }\n\n        int calculateEncodedLength() {\n            if (pluginResult == null) {\n                return jsPayloadOrCallbackId.length() + 1;\n            }\n            int statusLen = String.valueOf(pluginResult.getStatus()).length();\n            int ret = 2 + statusLen + 1 + jsPayloadOrCallbackId.length() + 1;\n            return ret + calculateEncodedLengthHelper(pluginResult);\n            }\n\n        static void encodeAsMessageHelper(StringBuilder sb, PluginResult pluginResult) {\n            switch (pluginResult.getMessageType()) {\n                case PluginResult.MESSAGE_TYPE_BOOLEAN:\n                    sb.append(pluginResult.getMessage().charAt(0)); // t or f.\n                    break;\n                case PluginResult.MESSAGE_TYPE_NULL: // N\n                    sb.append('N');\n                    break;\n                case PluginResult.MESSAGE_TYPE_NUMBER: // n\n                    sb.append('n')\n                      .append(pluginResult.getMessage());\n                    break;\n                case PluginResult.MESSAGE_TYPE_STRING: // s\n                    sb.append('s');\n                    sb.append(pluginResult.getStrMessage());\n                    break;\n                case PluginResult.MESSAGE_TYPE_BINARYSTRING: // S\n                    sb.append('S');\n                    sb.append(pluginResult.getMessage());\n                    break;\n                case PluginResult.MESSAGE_TYPE_ARRAYBUFFER: // A\n                    sb.append('A');\n                    sb.append(pluginResult.getMessage());\n                    break;\n                case PluginResult.MESSAGE_TYPE_MULTIPART:\n                    sb.append('M');\n                    for (int i = 0; i < pluginResult.getMultipartMessagesSize(); i++) {\n                        PluginResult multipartMessage = pluginResult.getMultipartMessage(i);\n                        sb.append(String.valueOf(calculateEncodedLengthHelper(multipartMessage)));\n                        sb.append(' ');\n                        encodeAsMessageHelper(sb, multipartMessage);\n                    }\n                    break;\n                case PluginResult.MESSAGE_TYPE_JSON:\n                default:\n                    sb.append(pluginResult.getMessage()); // [ or {\n            }\n        }\n\n        void encodeAsMessage(StringBuilder sb) {\n            if (pluginResult == null) {\n                sb.append('J')\n                  .append(jsPayloadOrCallbackId);\n                return;\n            }\n            int status = pluginResult.getStatus();\n            boolean noResult = status == PluginResult.Status.NO_RESULT.ordinal();\n            boolean resultOk = status == PluginResult.Status.OK.ordinal();\n            boolean keepCallback = pluginResult.getKeepCallback();\n\n            sb.append((noResult || resultOk) ? 'S' : 'F')\n              .append(keepCallback ? '1' : '0')\n              .append(status)\n              .append(' ')\n              .append(jsPayloadOrCallbackId)\n              .append(' ');\n\n            encodeAsMessageHelper(sb, pluginResult);\n        }\n\n        void buildJsMessage(StringBuilder sb) {\n            switch (pluginResult.getMessageType()) {\n                case PluginResult.MESSAGE_TYPE_MULTIPART:\n                    int size = pluginResult.getMultipartMessagesSize();\n                    for (int i=0; i<size; i++) {\n                        PluginResult subresult = pluginResult.getMultipartMessage(i);\n                        JsMessage submessage = new JsMessage(subresult, jsPayloadOrCallbackId);\n                        submessage.buildJsMessage(sb);\n                        if (i < (size-1)) {\n                            sb.append(\",\");\n                        }\n                    }\n                    break;\n                case PluginResult.MESSAGE_TYPE_BINARYSTRING:\n                    sb.append(\"atob('\")\n                            .append(pluginResult.getMessage())\n                            .append(\"')\");\n                    break;\n                case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:\n                    sb.append(\"cordova.require('cordova/base64').toArrayBuffer('\")\n                            .append(pluginResult.getMessage())\n                            .append(\"')\");\n                    break;\n                default:\n                    sb.append(pluginResult.getMessage());\n            }\n        }\n\n        void encodeAsJsMessage(StringBuilder sb) {\n            if (pluginResult == null) {\n                sb.append(jsPayloadOrCallbackId);\n            } else {\n                int status = pluginResult.getStatus();\n                boolean success = (status == PluginResult.Status.OK.ordinal()) || (status == PluginResult.Status.NO_RESULT.ordinal());\n                sb.append(\"cordova.callbackFromNative('\")\n                        .append(jsPayloadOrCallbackId)\n                        .append(\"',\")\n                        .append(success)\n                        .append(\",\")\n                        .append(status)\n                        .append(\",[\");\n                buildJsMessage(sb);\n                sb.append(\"],\")\n                        .append(pluginResult.getKeepCallback())\n                        .append(\");\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/PluginEntry.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n */\npackage org.apache.cordova;\n\nimport org.apache.cordova.CordovaPlugin;\n\n/**\n * This class represents a service entry object.\n */\npublic final class PluginEntry {\n\n    /**\n     * The name of the service that this plugin implements\n     */\n    public final String service;\n\n    /**\n     * The plugin class name that implements the service.\n     */\n    public final String pluginClass;\n\n    /**\n     * The pre-instantiated plugin to use for this entry.\n     */\n    public final CordovaPlugin plugin;\n\n    /**\n     * Flag that indicates the plugin object should be created when PluginManager is initialized.\n     */\n    public final boolean onload;\n\n    /**\n     * Constructs with a CordovaPlugin already instantiated.\n     */\n    public PluginEntry(String service, CordovaPlugin plugin) {\n        this(service, plugin.getClass().getName(), true, plugin);\n    }\n\n    /**\n     * @param service               The name of the service\n     * @param pluginClass           The plugin class name\n     * @param onload                Create plugin object when HTML page is loaded\n     */\n    public PluginEntry(String service, String pluginClass, boolean onload) {\n        this(service, pluginClass, onload, null);\n    }\n\n    private PluginEntry(String service, String pluginClass, boolean onload, CordovaPlugin plugin) {\n        this.service = service;\n        this.pluginClass = pluginClass;\n        this.onload = onload;\n        this.plugin = plugin;\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/PluginManager.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n */\npackage org.apache.cordova;\n\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\n\nimport org.json.JSONException;\n\nimport android.content.Intent;\nimport android.content.res.Configuration;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Debug;\n\n/**\n * PluginManager is exposed to JavaScript in the Cordova WebView.\n *\n * Calling native plugin code can be done by calling PluginManager.exec(...)\n * from JavaScript.\n */\npublic class PluginManager {\n    private static String TAG = \"PluginManager\";\n    private static final int SLOW_EXEC_WARNING_THRESHOLD = Debug.isDebuggerConnected() ? 60 : 16;\n\n    // List of service entries\n    private final LinkedHashMap<String, CordovaPlugin> pluginMap = new LinkedHashMap<String, CordovaPlugin>();\n    private final LinkedHashMap<String, PluginEntry> entryMap = new LinkedHashMap<String, PluginEntry>();\n\n    private final CordovaInterface ctx;\n    private final CordovaWebView app;\n    private boolean isInitialized;\n\n    private CordovaPlugin permissionRequester;\n\n    public PluginManager(CordovaWebView cordovaWebView, CordovaInterface cordova, Collection<PluginEntry> pluginEntries) {\n        this.ctx = cordova;\n        this.app = cordovaWebView;\n        setPluginEntries(pluginEntries);\n    }\n\n    public Collection<PluginEntry> getPluginEntries() {\n        return entryMap.values();\n    }\n\n    public void setPluginEntries(Collection<PluginEntry> pluginEntries) {\n        if (isInitialized) {\n            this.onPause(false);\n            this.onDestroy();\n            pluginMap.clear();\n            entryMap.clear();\n        }\n        for (PluginEntry entry : pluginEntries) {\n            addService(entry);\n        }\n        if (isInitialized) {\n            startupPlugins();\n        }\n    }\n\n    /**\n     * Init when loading a new HTML page into webview.\n     */\n    public void init() {\n        LOG.d(TAG, \"init()\");\n        isInitialized = true;\n        this.onPause(false);\n        this.onDestroy();\n        pluginMap.clear();\n        this.startupPlugins();\n    }\n\n    /**\n     * Create plugins objects that have onload set.\n     */\n    private void startupPlugins() {\n        for (PluginEntry entry : entryMap.values()) {\n            // Add a null entry to for each non-startup plugin to avoid ConcurrentModificationException\n            // When iterating plugins.\n            if (entry.onload) {\n                getPlugin(entry.service);\n            } else {\n                pluginMap.put(entry.service, null);\n            }\n        }\n    }\n\n    /**\n     * Receives a request for execution and fulfills it by finding the appropriate\n     * Java class and calling it's execute method.\n     *\n     * PluginManager.exec can be used either synchronously or async. In either case, a JSON encoded\n     * string is returned that will indicate if any errors have occurred when trying to find\n     * or execute the class denoted by the clazz argument.\n     *\n     * @param service       String containing the service to run\n     * @param action        String containing the action that the class is supposed to perform. This is\n     *                      passed to the plugin execute method and it is up to the plugin developer\n     *                      how to deal with it.\n     * @param callbackId    String containing the id of the callback that is execute in JavaScript if\n     *                      this is an async plugin call.\n     * @param rawArgs       An Array literal string containing any arguments needed in the\n     *                      plugin execute method.\n     */\n    public void exec(final String service, final String action, final String callbackId, final String rawArgs) {\n        CordovaPlugin plugin = getPlugin(service);\n        if (plugin == null) {\n            LOG.d(TAG, \"exec() call to unknown plugin: \" + service);\n            PluginResult cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION);\n            app.sendPluginResult(cr, callbackId);\n            return;\n        }\n        CallbackContext callbackContext = new CallbackContext(callbackId, app);\n        try {\n            long pluginStartTime = System.currentTimeMillis();\n            boolean wasValidAction = plugin.execute(action, rawArgs, callbackContext);\n            long duration = System.currentTimeMillis() - pluginStartTime;\n\n            if (duration > SLOW_EXEC_WARNING_THRESHOLD) {\n                LOG.w(TAG, \"THREAD WARNING: exec() call to \" + service + \".\" + action + \" blocked the main thread for \" + duration + \"ms. Plugin should use CordovaInterface.getThreadPool().\");\n            }\n            if (!wasValidAction) {\n                PluginResult cr = new PluginResult(PluginResult.Status.INVALID_ACTION);\n                callbackContext.sendPluginResult(cr);\n            }\n        } catch (JSONException e) {\n            PluginResult cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION);\n            callbackContext.sendPluginResult(cr);\n        } catch (Exception e) {\n            LOG.e(TAG, \"Uncaught exception from plugin\", e);\n            callbackContext.error(e.getMessage());\n        }\n    }\n\n    /**\n     * Get the plugin object that implements the service.\n     * If the plugin object does not already exist, then create it.\n     * If the service doesn't exist, then return null.\n     *\n     * @param service       The name of the service.\n     * @return              CordovaPlugin or null\n     */\n    public CordovaPlugin getPlugin(String service) {\n        CordovaPlugin ret = pluginMap.get(service);\n        if (ret == null) {\n            PluginEntry pe = entryMap.get(service);\n            if (pe == null) {\n                return null;\n            }\n            if (pe.plugin != null) {\n                ret = pe.plugin;\n            } else {\n                ret = instantiatePlugin(pe.pluginClass);\n            }\n            ret.privateInitialize(service, ctx, app, app.getPreferences());\n            pluginMap.put(service, ret);\n        }\n        return ret;\n    }\n\n    /**\n     * Add a plugin class that implements a service to the service entry table.\n     * This does not create the plugin object instance.\n     *\n     * @param service           The service name\n     * @param className         The plugin class name\n     */\n    public void addService(String service, String className) {\n        PluginEntry entry = new PluginEntry(service, className, false);\n        this.addService(entry);\n    }\n\n    /**\n     * Add a plugin class that implements a service to the service entry table.\n     * This does not create the plugin object instance.\n     *\n     * @param entry             The plugin entry\n     */\n    public void addService(PluginEntry entry) {\n        this.entryMap.put(entry.service, entry);\n        if (entry.plugin != null) {\n            entry.plugin.privateInitialize(entry.service, ctx, app, app.getPreferences());\n            pluginMap.put(entry.service, entry.plugin);\n        }\n    }\n\n    /**\n     * Called when the system is about to start resuming a previous activity.\n     *\n     * @param multitasking      Flag indicating if multitasking is turned on for app\n     */\n    public void onPause(boolean multitasking) {\n        for (CordovaPlugin plugin : this.pluginMap.values()) {\n            if (plugin != null) {\n                plugin.onPause(multitasking);\n            }\n        }\n    }\n\n    /**\n     * Called when the system received an HTTP authentication request. Plugins can use\n     * the supplied HttpAuthHandler to process this auth challenge.\n     *\n     * @param view              The WebView that is initiating the callback\n     * @param handler           The HttpAuthHandler used to set the WebView's response\n     * @param host              The host requiring authentication\n     * @param realm             The realm for which authentication is required\n     *\n     * @return                  Returns True if there is a plugin which will resolve this auth challenge, otherwise False\n     *\n     */\n    public boolean onReceivedHttpAuthRequest(CordovaWebView view, ICordovaHttpAuthHandler handler, String host, String realm) {\n        for (CordovaPlugin plugin : this.pluginMap.values()) {\n            if (plugin != null && plugin.onReceivedHttpAuthRequest(app, handler, host, realm)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Called when he system received an SSL client certificate request.  Plugin can use\n     * the supplied ClientCertRequest to process this certificate challenge.\n     *\n     * @param view              The WebView that is initiating the callback\n     * @param request           The client certificate request\n     *\n     * @return                  Returns True if plugin will resolve this auth challenge, otherwise False\n     *\n     */\n    public boolean onReceivedClientCertRequest(CordovaWebView view, ICordovaClientCertRequest request) {\n        for (CordovaPlugin plugin : this.pluginMap.values()) {\n            if (plugin != null && plugin.onReceivedClientCertRequest(app, request)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Called when the activity will start interacting with the user.\n     *\n     * @param multitasking      Flag indicating if multitasking is turned on for app\n     */\n    public void onResume(boolean multitasking) {\n        for (CordovaPlugin plugin : this.pluginMap.values()) {\n            if (plugin != null) {\n                plugin.onResume(multitasking);\n            }\n        }\n    }\n\n    /**\n     * Called when the activity is becoming visible to the user.\n     */\n    public void onStart() {\n        for (CordovaPlugin plugin : this.pluginMap.values()) {\n            if (plugin != null) {\n                plugin.onStart();\n            }\n        }\n    }\n\n    /**\n     * Called when the activity is no longer visible to the user.\n     */\n    public void onStop() {\n        for (CordovaPlugin plugin : this.pluginMap.values()) {\n            if (plugin != null) {\n                plugin.onStop();\n            }\n        }\n    }\n\n    /**\n     * The final call you receive before your activity is destroyed.\n     */\n    public void onDestroy() {\n        for (CordovaPlugin plugin : this.pluginMap.values()) {\n            if (plugin != null) {\n                plugin.onDestroy();\n            }\n        }\n    }\n\n    /**\n     * Send a message to all plugins.\n     *\n     * @param id                The message id\n     * @param data              The message data\n     * @return                  Object to stop propagation or null\n     */\n    public Object postMessage(String id, Object data) {\n        for (CordovaPlugin plugin : this.pluginMap.values()) {\n            if (plugin != null) {\n                Object obj = plugin.onMessage(id, data);\n                if (obj != null) {\n                    return obj;\n                }\n            }\n        }\n        return ctx.onMessage(id, data);\n    }\n\n    /**\n     * Called when the activity receives a new intent.\n     */\n    public void onNewIntent(Intent intent) {\n        for (CordovaPlugin plugin : this.pluginMap.values()) {\n            if (plugin != null) {\n                plugin.onNewIntent(intent);\n            }\n        }\n    }\n\n    /**\n     * Called when the webview is going to request an external resource.\n     *\n     * This delegates to the installed plugins, and returns true/false for the\n     * first plugin to provide a non-null result.  If no plugins respond, then\n     * the default policy is applied.\n     *\n     * @param url       The URL that is being requested.\n     * @return          Returns true to allow the resource to load,\n     *                  false to block the resource.\n     */\n    public boolean shouldAllowRequest(String url) {\n        for (PluginEntry entry : this.entryMap.values()) {\n            CordovaPlugin plugin = pluginMap.get(entry.service);\n            if (plugin != null) {\n                Boolean result = plugin.shouldAllowRequest(url);\n                if (result != null) {\n                    return result;\n                }\n            }\n        }\n\n        // Default policy:\n        if (url.startsWith(\"blob:\") || url.startsWith(\"data:\") || url.startsWith(\"about:blank\")) {\n            return true;\n        }\n        // TalkBack requires this, so allow it by default.\n        if (url.startsWith(\"https://ssl.gstatic.com/accessibility/javascript/android/\")) {\n            return true;\n        }\n        if (url.startsWith(\"file://\")) {\n            //This directory on WebKit/Blink based webviews contains SQLite databases!\n            //DON'T CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING!\n            return !url.contains(\"/app_webview/\");\n        }\n        return false;\n    }\n\n    /**\n     * Called when the webview is going to change the URL of the loaded content.\n     *\n     * This delegates to the installed plugins, and returns true/false for the\n     * first plugin to provide a non-null result.  If no plugins respond, then\n     * the default policy is applied.\n     *\n     * @param url       The URL that is being requested.\n     * @return          Returns true to allow the navigation,\n     *                  false to block the navigation.\n     */\n    public boolean shouldAllowNavigation(String url) {\n        for (PluginEntry entry : this.entryMap.values()) {\n            CordovaPlugin plugin = pluginMap.get(entry.service);\n            if (plugin != null) {\n                Boolean result = plugin.shouldAllowNavigation(url);\n                if (result != null) {\n                    return result;\n                }\n            }\n        }\n\n        // Default policy:\n        return url.startsWith(\"file://\") || url.startsWith(\"about:blank\");\n    }\n\n\n    /**\n     * Called when the webview is requesting the exec() bridge be enabled.\n     */\n    public boolean shouldAllowBridgeAccess(String url) {\n        for (PluginEntry entry : this.entryMap.values()) {\n            CordovaPlugin plugin = pluginMap.get(entry.service);\n            if (plugin != null) {\n                Boolean result = plugin.shouldAllowBridgeAccess(url);\n                if (result != null) {\n                    return result;\n                }\n            }\n        }\n\n        // Default policy:\n        return url.startsWith(\"file://\");\n    }\n\n    /**\n     * Called when the webview is going not going to navigate, but may launch\n     * an Intent for an URL.\n     *\n     * This delegates to the installed plugins, and returns true/false for the\n     * first plugin to provide a non-null result.  If no plugins respond, then\n     * the default policy is applied.\n     *\n     * @param url       The URL that is being requested.\n     * @return          Returns true to allow the URL to launch an intent,\n     *                  false to block the intent.\n     */\n    public Boolean shouldOpenExternalUrl(String url) {\n        for (PluginEntry entry : this.entryMap.values()) {\n            CordovaPlugin plugin = pluginMap.get(entry.service);\n            if (plugin != null) {\n                Boolean result = plugin.shouldOpenExternalUrl(url);\n                if (result != null) {\n                    return result;\n                }\n            }\n        }\n        // Default policy:\n        // External URLs are not allowed\n        return false;\n    }\n\n    /**\n     * Called when the URL of the webview changes.\n     *\n     * @param url               The URL that is being changed to.\n     * @return                  Return false to allow the URL to load, return true to prevent the URL from loading.\n     */\n    public boolean onOverrideUrlLoading(String url) {\n        for (PluginEntry entry : this.entryMap.values()) {\n            CordovaPlugin plugin = pluginMap.get(entry.service);\n            if (plugin != null && plugin.onOverrideUrlLoading(url)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Called when the app navigates or refreshes.\n     */\n    public void onReset() {\n        for (CordovaPlugin plugin : this.pluginMap.values()) {\n            if (plugin != null) {\n                plugin.onReset();\n            }\n        }\n    }\n\n    Uri remapUri(Uri uri) {\n        for (CordovaPlugin plugin : this.pluginMap.values()) {\n            if (plugin != null) {\n                Uri ret = plugin.remapUri(uri);\n                if (ret != null) {\n                    return ret;\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Create a plugin based on class name.\n     */\n    private CordovaPlugin instantiatePlugin(String className) {\n        CordovaPlugin ret = null;\n        try {\n            Class<?> c = null;\n            if ((className != null) && !(\"\".equals(className))) {\n                c = Class.forName(className);\n            }\n            if (c != null & CordovaPlugin.class.isAssignableFrom(c)) {\n                ret = (CordovaPlugin) c.newInstance();\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"Error adding plugin \" + className + \".\");\n        }\n        return ret;\n    }\n\n    /**\n     * Called by the system when the device configuration changes while your activity is running.\n     *\n     * @param newConfig\t\tThe new device configuration\n     */\n    public void onConfigurationChanged(Configuration newConfig) {\n        for (CordovaPlugin plugin : this.pluginMap.values()) {\n            if (plugin != null) {\n                plugin.onConfigurationChanged(newConfig);\n            }\n        }\n    }\n\n    public Bundle onSaveInstanceState() {\n        Bundle state = new Bundle();\n        for (CordovaPlugin plugin : this.pluginMap.values()) {\n            if (plugin != null) {\n                Bundle pluginState = plugin.onSaveInstanceState();\n                if(pluginState != null) {\n                    state.putBundle(plugin.getServiceName(), pluginState);\n                }\n            }\n        }\n        return state;\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/PluginResult.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport java.util.List;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport android.util.Base64;\n\npublic class PluginResult {\n    private final int status;\n    private final int messageType;\n    private boolean keepCallback = false;\n    private String strMessage;\n    private String encodedMessage;\n    private List<PluginResult> multipartMessages;\n\n    public PluginResult(Status status) {\n        this(status, PluginResult.StatusMessages[status.ordinal()]);\n    }\n\n    public PluginResult(Status status, String message) {\n        this.status = status.ordinal();\n        this.messageType = message == null ? MESSAGE_TYPE_NULL : MESSAGE_TYPE_STRING;\n        this.strMessage = message;\n    }\n\n    public PluginResult(Status status, JSONArray message) {\n        this.status = status.ordinal();\n        this.messageType = MESSAGE_TYPE_JSON;\n        encodedMessage = message.toString();\n    }\n\n    public PluginResult(Status status, JSONObject message) {\n        this.status = status.ordinal();\n        this.messageType = MESSAGE_TYPE_JSON;\n        encodedMessage = message.toString();\n    }\n\n    public PluginResult(Status status, int i) {\n        this.status = status.ordinal();\n        this.messageType = MESSAGE_TYPE_NUMBER;\n        this.encodedMessage = \"\"+i;\n    }\n\n    public PluginResult(Status status, float f) {\n        this.status = status.ordinal();\n        this.messageType = MESSAGE_TYPE_NUMBER;\n        this.encodedMessage = \"\"+f;\n    }\n\n    public PluginResult(Status status, boolean b) {\n        this.status = status.ordinal();\n        this.messageType = MESSAGE_TYPE_BOOLEAN;\n        this.encodedMessage = Boolean.toString(b);\n    }\n\n    public PluginResult(Status status, byte[] data) {\n        this(status, data, false);\n    }\n\n    public PluginResult(Status status, byte[] data, boolean binaryString) {\n        this.status = status.ordinal();\n        this.messageType = binaryString ? MESSAGE_TYPE_BINARYSTRING : MESSAGE_TYPE_ARRAYBUFFER;\n        this.encodedMessage = Base64.encodeToString(data, Base64.NO_WRAP);\n    }\n    \n    // The keepCallback and status of multipartMessages are ignored.\n    public PluginResult(Status status, List<PluginResult> multipartMessages) {\n        this.status = status.ordinal();\n        this.messageType = MESSAGE_TYPE_MULTIPART;\n        this.multipartMessages = multipartMessages;\n    }\n\n    public void setKeepCallback(boolean b) {\n        this.keepCallback = b;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public int getMessageType() {\n        return messageType;\n    }\n\n    public String getMessage() {\n        if (encodedMessage == null) {\n            encodedMessage = JSONObject.quote(strMessage);\n        }\n        return encodedMessage;\n    }\n\n    public int getMultipartMessagesSize() {\n        return multipartMessages.size();\n    }\n\n    public PluginResult getMultipartMessage(int index) {\n        return multipartMessages.get(index);\n    }\n\n    /**\n     * If messageType == MESSAGE_TYPE_STRING, then returns the message string.\n     * Otherwise, returns null.\n     */\n    public String getStrMessage() {\n        return strMessage;\n    }\n\n    public boolean getKeepCallback() {\n        return this.keepCallback;\n    }\n\n    @Deprecated // Use sendPluginResult instead of sendJavascript.\n    public String getJSONString() {\n        return \"{\\\"status\\\":\" + this.status + \",\\\"message\\\":\" + this.getMessage() + \",\\\"keepCallback\\\":\" + this.keepCallback + \"}\";\n    }\n\n    @Deprecated // Use sendPluginResult instead of sendJavascript.\n    public String toCallbackString(String callbackId) {\n        // If no result to be sent and keeping callback, then no need to sent back to JavaScript\n        if ((status == PluginResult.Status.NO_RESULT.ordinal()) && keepCallback) {\n        \treturn null;\n        }\n\n        // Check the success (OK, NO_RESULT & !KEEP_CALLBACK)\n        if ((status == PluginResult.Status.OK.ordinal()) || (status == PluginResult.Status.NO_RESULT.ordinal())) {\n            return toSuccessCallbackString(callbackId);\n        }\n\n        return toErrorCallbackString(callbackId);\n    }\n\n    @Deprecated // Use sendPluginResult instead of sendJavascript.\n    public String toSuccessCallbackString(String callbackId) {\n        return \"cordova.callbackSuccess('\"+callbackId+\"',\"+this.getJSONString()+\");\";\n    }\n\n    @Deprecated // Use sendPluginResult instead of sendJavascript.\n    public String toErrorCallbackString(String callbackId) {\n        return \"cordova.callbackError('\"+callbackId+\"', \" + this.getJSONString()+ \");\";\n    }\n\n    public static final int MESSAGE_TYPE_STRING = 1;\n    public static final int MESSAGE_TYPE_JSON = 2;\n    public static final int MESSAGE_TYPE_NUMBER = 3;\n    public static final int MESSAGE_TYPE_BOOLEAN = 4;\n    public static final int MESSAGE_TYPE_NULL = 5;\n    public static final int MESSAGE_TYPE_ARRAYBUFFER = 6;\n    // Use BINARYSTRING when your string may contain null characters.\n    // This is required to work around a bug in the platform :(.\n    public static final int MESSAGE_TYPE_BINARYSTRING = 7;\n    public static final int MESSAGE_TYPE_MULTIPART = 8;\n\n    public static String[] StatusMessages = new String[] {\n        \"No result\",\n        \"OK\",\n        \"Class not found\",\n        \"Illegal access\",\n        \"Instantiation error\",\n        \"Malformed url\",\n        \"IO error\",\n        \"Invalid action\",\n        \"JSON error\",\n        \"Error\"\n    };\n\n    public enum Status {\n        NO_RESULT,\n        OK,\n        CLASS_NOT_FOUND_EXCEPTION,\n        ILLEGAL_ACCESS_EXCEPTION,\n        INSTANTIATION_EXCEPTION,\n        MALFORMED_URL_EXCEPTION,\n        IO_EXCEPTION,\n        INVALID_ACTION,\n        JSON_EXCEPTION,\n        ERROR\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/ResumeCallback.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ResumeCallback extends CallbackContext {\n    private final String TAG = \"CordovaResumeCallback\";\n    private String serviceName;\n    private PluginManager pluginManager;\n\n    public ResumeCallback(String serviceName, PluginManager pluginManager) {\n        super(\"resumecallback\", null);\n        this.serviceName = serviceName;\n        this.pluginManager = pluginManager;\n    }\n\n    @Override\n    public void sendPluginResult(PluginResult pluginResult) {\n        synchronized (this) {\n            if (finished) {\n                LOG.w(TAG, serviceName + \" attempted to send a second callback to ResumeCallback\\nResult was: \" + pluginResult.getMessage());\n                return;\n            } else {\n                finished = true;\n            }\n        }\n\n        JSONObject event = new JSONObject();\n        JSONObject pluginResultObject = new JSONObject();\n\n        try {\n            pluginResultObject.put(\"pluginServiceName\", this.serviceName);\n            pluginResultObject.put(\"pluginStatus\", PluginResult.StatusMessages[pluginResult.getStatus()]);\n\n            event.put(\"action\", \"resume\");\n            event.put(\"pendingResult\", pluginResultObject);\n        } catch (JSONException e) {\n            LOG.e(TAG, \"Unable to create resume object for Activity Result\");\n        }\n\n        PluginResult eventResult = new PluginResult(PluginResult.Status.OK, event);\n\n        // We send a list of results to the js so that we don't have to decode\n        // the PluginResult passed to this CallbackContext into JSON twice.\n        // The results are combined into an event payload before the event is\n        // fired on the js side of things (see platform.js)\n        List<PluginResult> result = new ArrayList<PluginResult>();\n        result.add(eventResult);\n        result.add(pluginResult);\n\n        CoreAndroid appPlugin = (CoreAndroid) pluginManager.getPlugin(CoreAndroid.PLUGIN_NAME);\n        appPlugin.sendResumeEvent(new PluginResult(PluginResult.Status.OK, result));\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/Whitelist.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport java.net.MalformedURLException;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.cordova.LOG;\n\nimport android.net.Uri;\n\npublic class Whitelist {\n    private static class URLPattern {\n        public Pattern scheme;\n        public Pattern host;\n        public Integer port;\n        public Pattern path;\n\n        private String regexFromPattern(String pattern, boolean allowWildcards) {\n            final String toReplace = \"\\\\.[]{}()^$?+|\";\n            StringBuilder regex = new StringBuilder();\n            for (int i=0; i < pattern.length(); i++) {\n                char c = pattern.charAt(i);\n                if (c == '*' && allowWildcards) {\n                    regex.append(\".\");\n                } else if (toReplace.indexOf(c) > -1) {\n                    regex.append('\\\\');\n                }\n                regex.append(c);\n            }\n            return regex.toString();\n        }\n\n        public URLPattern(String scheme, String host, String port, String path) throws MalformedURLException {\n            try {\n                if (scheme == null || \"*\".equals(scheme)) {\n                    this.scheme = null;\n                } else {\n                    this.scheme = Pattern.compile(regexFromPattern(scheme, false), Pattern.CASE_INSENSITIVE);\n                }\n                if (\"*\".equals(host)) {\n                    this.host = null;\n                } else if (host.startsWith(\"*.\")) {\n                    this.host = Pattern.compile(\"([a-z0-9.-]*\\\\.)?\" + regexFromPattern(host.substring(2), false), Pattern.CASE_INSENSITIVE);\n                } else {\n                    this.host = Pattern.compile(regexFromPattern(host, false), Pattern.CASE_INSENSITIVE);\n                }\n                if (port == null || \"*\".equals(port)) {\n                    this.port = null;\n                } else {\n                    this.port = Integer.parseInt(port,10);\n                }\n                if (path == null || \"/*\".equals(path)) {\n                    this.path = null;\n                } else {\n                    this.path = Pattern.compile(regexFromPattern(path, true));\n                }\n            } catch (NumberFormatException e) {\n                throw new MalformedURLException(\"Port must be a number\");\n            }\n        }\n\n        public boolean matches(Uri uri) {\n            try {\n                return ((scheme == null || scheme.matcher(uri.getScheme()).matches()) &&\n                        (host == null || host.matcher(uri.getHost()).matches()) &&\n                        (port == null || port.equals(uri.getPort())) &&\n                        (path == null || path.matcher(uri.getPath()).matches()));\n            } catch (Exception e) {\n                LOG.d(TAG, e.toString());\n                return false;\n            }\n        }\n    }\n\n    private ArrayList<URLPattern> whiteList;\n\n    public static final String TAG = \"Whitelist\";\n\n    public Whitelist() {\n        this.whiteList = new ArrayList<URLPattern>();\n    }\n\n    /* Match patterns (from http://developer.chrome.com/extensions/match_patterns.html)\n     *\n     * <url-pattern> := <scheme>://<host><path>\n     * <scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome-extension'\n     * <host> := '*' | '*.' <any char except '/' and '*'>+\n     * <path> := '/' <any chars>\n     *\n     * We extend this to explicitly allow a port attached to the host, and we allow\n     * the scheme to be omitted for backwards compatibility. (Also host is not required\n     * to begin with a \"*\" or \"*.\".)\n     */\n    public void addWhiteListEntry(String origin, boolean subdomains) {\n        if (whiteList != null) {\n            try {\n                // Unlimited access to network resources\n                if (origin.compareTo(\"*\") == 0) {\n                    LOG.d(TAG, \"Unlimited access to network resources\");\n                    whiteList = null;\n                }\n                else { // specific access\n                    Pattern parts = Pattern.compile(\"^((\\\\*|[A-Za-z-]+):(//)?)?(\\\\*|((\\\\*\\\\.)?[^*/:]+))?(:(\\\\d+))?(/.*)?\");\n                    Matcher m = parts.matcher(origin);\n                    if (m.matches()) {\n                        String scheme = m.group(2);\n                        String host = m.group(4);\n                        // Special case for two urls which are allowed to have empty hosts\n                        if ((\"file\".equals(scheme) || \"content\".equals(scheme)) && host == null) host = \"*\";\n                        String port = m.group(8);\n                        String path = m.group(9);\n                        if (scheme == null) {\n                            // XXX making it stupid friendly for people who forget to include protocol/SSL\n                            whiteList.add(new URLPattern(\"http\", host, port, path));\n                            whiteList.add(new URLPattern(\"https\", host, port, path));\n                        } else {\n                            whiteList.add(new URLPattern(scheme, host, port, path));\n                        }\n                    }\n                }\n            } catch (Exception e) {\n                LOG.d(TAG, \"Failed to add origin %s\", origin);\n            }\n        }\n    }\n\n\n    /**\n     * Determine if URL is in approved list of URLs to load.\n     *\n     * @param uri\n     * @return true if wide open or whitelisted\n     */\n    public boolean isUrlWhiteListed(String uri) {\n        // If there is no whitelist, then it's wide open\n        if (whiteList == null) return true;\n\n        Uri parsedUri = Uri.parse(uri);\n        // Look for match in white list\n        Iterator<URLPattern> pit = whiteList.iterator();\n        while (pit.hasNext()) {\n            URLPattern p = pit.next();\n            if (p.matches(parsedUri)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemCookieManager.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova.engine;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\nimport android.webkit.CookieManager;\nimport android.webkit.WebView;\n\nimport org.apache.cordova.ICordovaCookieManager;\n\nclass SystemCookieManager implements ICordovaCookieManager {\n\n    protected final WebView webView;\n    private final CookieManager cookieManager;\n\n    //Added because lint can't see the conditional RIGHT ABOVE this\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public SystemCookieManager(WebView webview) {\n        webView = webview;\n        cookieManager = CookieManager.getInstance();\n\n        //REALLY? Nobody has seen this UNTIL NOW?\n        cookieManager.setAcceptFileSchemeCookies(true);\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            cookieManager.setAcceptThirdPartyCookies(webView, true);\n        }\n    }\n\n    public void setCookiesEnabled(boolean accept) {\n        cookieManager.setAcceptCookie(accept);\n    }\n\n    public void setCookie(final String url, final String value) {\n        cookieManager.setCookie(url, value);\n    }\n\n    public String getCookie(final String url) {\n        return cookieManager.getCookie(url);\n    }\n\n    public void clearCookies() {\n        cookieManager.removeAllCookie();\n    }\n\n    public void flush() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            cookieManager.flush();\n        }\n    }\n};\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemExposedJsApi.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova.engine;\n\nimport android.webkit.JavascriptInterface;\n\nimport org.apache.cordova.CordovaBridge;\nimport org.apache.cordova.ExposedJsApi;\nimport org.json.JSONException;\n\n/**\n * Contains APIs that the JS can call. All functions in here should also have\n * an equivalent entry in CordovaChromeClient.java, and be added to\n * cordova-js/lib/android/plugin/android/promptbasednativeapi.js\n */\nclass SystemExposedJsApi implements ExposedJsApi {\n    private final CordovaBridge bridge;\n\n    SystemExposedJsApi(CordovaBridge bridge) {\n        this.bridge = bridge;\n    }\n\n    @JavascriptInterface\n    public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {\n        return bridge.jsExec(bridgeSecret, service, action, callbackId, arguments);\n    }\n\n    @JavascriptInterface\n    public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {\n        bridge.jsSetNativeToJsBridgeMode(bridgeSecret, value);\n    }\n\n    @JavascriptInterface\n    public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {\n        return bridge.jsRetrieveJsMessages(bridgeSecret, fromOnlineEvent);\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebChromeClient.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova.engine;\n\nimport java.util.Arrays;\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.ActivityNotFoundException;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewGroup.LayoutParams;\nimport android.webkit.ConsoleMessage;\nimport android.webkit.GeolocationPermissions.Callback;\nimport android.webkit.JsPromptResult;\nimport android.webkit.JsResult;\nimport android.webkit.ValueCallback;\nimport android.webkit.WebChromeClient;\nimport android.webkit.WebStorage;\nimport android.webkit.WebView;\nimport android.webkit.PermissionRequest;\nimport android.widget.LinearLayout;\nimport android.widget.ProgressBar;\nimport android.widget.RelativeLayout;\n\nimport org.apache.cordova.CordovaDialogsHelper;\nimport org.apache.cordova.CordovaPlugin;\nimport org.apache.cordova.LOG;\n\n/**\n * This class is the WebChromeClient that implements callbacks for our web view.\n * The kind of callbacks that happen here are on the chrome outside the document,\n * such as onCreateWindow(), onConsoleMessage(), onProgressChanged(), etc. Related\n * to but different than CordovaWebViewClient.\n */\npublic class SystemWebChromeClient extends WebChromeClient {\n\n    private static final int FILECHOOSER_RESULTCODE = 5173;\n    private static final String LOG_TAG = \"SystemWebChromeClient\";\n    private long MAX_QUOTA = 100 * 1024 * 1024;\n    protected final SystemWebViewEngine parentEngine;\n\n    // the video progress view\n    private View mVideoProgressView;\n\n    private CordovaDialogsHelper dialogsHelper;\n    private Context appContext;\n\n    private WebChromeClient.CustomViewCallback mCustomViewCallback;\n    private View mCustomView;\n\n    public SystemWebChromeClient(SystemWebViewEngine parentEngine) {\n        this.parentEngine = parentEngine;\n        appContext = parentEngine.webView.getContext();\n        dialogsHelper = new CordovaDialogsHelper(appContext);\n    }\n\n    /**\n     * Tell the client to display a javascript alert dialog.\n     */\n    @Override\n    public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {\n        dialogsHelper.showAlert(message, new CordovaDialogsHelper.Result() {\n            @Override public void gotResult(boolean success, String value) {\n                if (success) {\n                    result.confirm();\n                } else {\n                    result.cancel();\n                }\n            }\n        });\n        return true;\n    }\n\n    /**\n     * Tell the client to display a confirm dialog to the user.\n     */\n    @Override\n    public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {\n        dialogsHelper.showConfirm(message, new CordovaDialogsHelper.Result() {\n            @Override\n            public void gotResult(boolean success, String value) {\n                if (success) {\n                    result.confirm();\n                } else {\n                    result.cancel();\n                }\n            }\n        });\n        return true;\n    }\n\n    /**\n     * Tell the client to display a prompt dialog to the user.\n     * If the client returns true, WebView will assume that the client will\n     * handle the prompt dialog and call the appropriate JsPromptResult method.\n     *\n     * Since we are hacking prompts for our own purposes, we should not be using them for\n     * this purpose, perhaps we should hack console.log to do this instead!\n     */\n    @Override\n    public boolean onJsPrompt(WebView view, String origin, String message, String defaultValue, final JsPromptResult result) {\n        // Unlike the @JavascriptInterface bridge, this method is always called on the UI thread.\n        String handledRet = parentEngine.bridge.promptOnJsPrompt(origin, message, defaultValue);\n        if (handledRet != null) {\n            result.confirm(handledRet);\n        } else {\n            dialogsHelper.showPrompt(message, defaultValue, new CordovaDialogsHelper.Result() {\n                @Override\n                public void gotResult(boolean success, String value) {\n                    if (success) {\n                        result.confirm(value);\n                    } else {\n                        result.cancel();\n                    }\n                }\n            });\n        }\n        return true;\n    }\n\n    /**\n     * Handle database quota exceeded notification.\n     */\n    @Override\n    public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,\n            long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)\n    {\n        LOG.d(LOG_TAG, \"onExceededDatabaseQuota estimatedSize: %d  currentQuota: %d  totalUsedQuota: %d\", estimatedSize, currentQuota, totalUsedQuota);\n        quotaUpdater.updateQuota(MAX_QUOTA);\n    }\n\n    // console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html\n    // Expect this to not compile in a future Android release!\n    @SuppressWarnings(\"deprecation\")\n    @Override\n    public void onConsoleMessage(String message, int lineNumber, String sourceID)\n    {\n        //This is only for Android 2.1\n        if(android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.ECLAIR_MR1)\n        {\n            LOG.d(LOG_TAG, \"%s: Line %d : %s\", sourceID, lineNumber, message);\n            super.onConsoleMessage(message, lineNumber, sourceID);\n        }\n    }\n\n    @TargetApi(8)\n    @Override\n    public boolean onConsoleMessage(ConsoleMessage consoleMessage)\n    {\n        if (consoleMessage.message() != null)\n            LOG.d(LOG_TAG, \"%s: Line %d : %s\" , consoleMessage.sourceId() , consoleMessage.lineNumber(), consoleMessage.message());\n         return super.onConsoleMessage(consoleMessage);\n    }\n\n    @Override\n    /**\n     * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.\n     *\n     * This also checks for the Geolocation Plugin and requests permission from the application  to use Geolocation.\n     *\n     * @param origin\n     * @param callback\n     */\n    public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {\n        super.onGeolocationPermissionsShowPrompt(origin, callback);\n        callback.invoke(origin, true, false);\n        //Get the plugin, it should be loaded\n        CordovaPlugin geolocation = parentEngine.pluginManager.getPlugin(\"Geolocation\");\n        if(geolocation != null && !geolocation.hasPermisssion())\n        {\n            geolocation.requestPermissions(0);\n        }\n\n    }\n\n    // API level 7 is required for this, see if we could lower this using something else\n    @Override\n    public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) {\n        parentEngine.getCordovaWebView().showCustomView(view, callback);\n    }\n\n    @Override\n    public void onHideCustomView() {\n        parentEngine.getCordovaWebView().hideCustomView();\n    }\n\n    @Override\n    /**\n     * Ask the host application for a custom progress view to show while\n     * a <video> is loading.\n     * @return View The progress view.\n     */\n    public View getVideoLoadingProgressView() {\n\n        if (mVideoProgressView == null) {\n            // Create a new Loading view programmatically.\n\n            // create the linear layout\n            LinearLayout layout = new LinearLayout(parentEngine.getView().getContext());\n            layout.setOrientation(LinearLayout.VERTICAL);\n            RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);\n            layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);\n            layout.setLayoutParams(layoutParams);\n            // the proress bar\n            ProgressBar bar = new ProgressBar(parentEngine.getView().getContext());\n            LinearLayout.LayoutParams barLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);\n            barLayoutParams.gravity = Gravity.CENTER;\n            bar.setLayoutParams(barLayoutParams);\n            layout.addView(bar);\n\n            mVideoProgressView = layout;\n        }\n    return mVideoProgressView;\n    }\n\n    // <input type=file> support:\n    // openFileChooser() is for pre KitKat and in KitKat mr1 (it's known broken in KitKat).\n    // For Lollipop, we use onShowFileChooser().\n    public void openFileChooser(ValueCallback<Uri> uploadMsg) {\n        this.openFileChooser(uploadMsg, \"*/*\");\n    }\n\n    public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType ) {\n        this.openFileChooser(uploadMsg, acceptType, null);\n    }\n\n    public void openFileChooser(final ValueCallback<Uri> uploadMsg, String acceptType, String capture)\n    {\n        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);\n        intent.addCategory(Intent.CATEGORY_OPENABLE);\n        intent.setType(\"*/*\");\n        parentEngine.cordova.startActivityForResult(new CordovaPlugin() {\n            @Override\n            public void onActivityResult(int requestCode, int resultCode, Intent intent) {\n                Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();\n                LOG.d(LOG_TAG, \"Receive file chooser URL: \" + result);\n                uploadMsg.onReceiveValue(result);\n            }\n        }, intent, FILECHOOSER_RESULTCODE);\n    }\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    @Override\n    public boolean onShowFileChooser(WebView webView, final ValueCallback<Uri[]> filePathsCallback, final WebChromeClient.FileChooserParams fileChooserParams) {\n        Intent intent = fileChooserParams.createIntent();\n        try {\n            parentEngine.cordova.startActivityForResult(new CordovaPlugin() {\n                @Override\n                public void onActivityResult(int requestCode, int resultCode, Intent intent) {\n                    Uri[] result = WebChromeClient.FileChooserParams.parseResult(resultCode, intent);\n                    LOG.d(LOG_TAG, \"Receive file chooser URL: \" + result);\n                    filePathsCallback.onReceiveValue(result);\n                }\n            }, intent, FILECHOOSER_RESULTCODE);\n        } catch (ActivityNotFoundException e) {\n            LOG.w(\"No activity found to handle file chooser intent.\", e);\n            filePathsCallback.onReceiveValue(null);\n        }\n        return true;\n    }\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    @Override\n    public void onPermissionRequest(final PermissionRequest request) {\n        LOG.d(LOG_TAG, \"onPermissionRequest: \" + Arrays.toString(request.getResources()));\n        request.grant(request.getResources());\n    }\n\n    public void destroyLastDialog(){\n        dialogsHelper.destroyLastDialog();\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebView.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova.engine;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.KeyEvent;\nimport android.webkit.WebChromeClient;\nimport android.webkit.WebView;\nimport android.webkit.WebViewClient;\n\nimport org.apache.cordova.CordovaInterface;\nimport org.apache.cordova.CordovaWebView;\nimport org.apache.cordova.CordovaWebViewEngine;\n\n/**\n * Custom WebView subclass that enables us to capture events needed for Cordova.\n */\npublic class SystemWebView extends WebView implements CordovaWebViewEngine.EngineView {\n    private SystemWebViewClient viewClient;\n    SystemWebChromeClient chromeClient;\n    private SystemWebViewEngine parentEngine;\n    private CordovaInterface cordova;\n\n    public SystemWebView(Context context) {\n        this(context, null);\n    }\n\n    public SystemWebView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    // Package visibility to enforce that only SystemWebViewEngine should call this method.\n    void init(SystemWebViewEngine parentEngine, CordovaInterface cordova) {\n        this.cordova = cordova;\n        this.parentEngine = parentEngine;\n        if (this.viewClient == null) {\n            setWebViewClient(new SystemWebViewClient(parentEngine));\n        }\n\n        if (this.chromeClient == null) {\n            setWebChromeClient(new SystemWebChromeClient(parentEngine));\n        }\n    }\n\n    @Override\n    public CordovaWebView getCordovaWebView() {\n        return parentEngine != null ? parentEngine.getCordovaWebView() : null;\n    }\n\n    @Override\n    public void setWebViewClient(WebViewClient client) {\n        viewClient = (SystemWebViewClient)client;\n        super.setWebViewClient(client);\n    }\n\n    @Override\n    public void setWebChromeClient(WebChromeClient client) {\n        chromeClient = (SystemWebChromeClient)client;\n        super.setWebChromeClient(client);\n    }\n\n    @Override\n    public boolean dispatchKeyEvent(KeyEvent event) {\n        Boolean ret = parentEngine.client.onDispatchKeyEvent(event);\n        if (ret != null) {\n            return ret.booleanValue();\n        }\n        return super.dispatchKeyEvent(event);\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewClient.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova.engine;\n\nimport android.annotation.TargetApi;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PackageManager.NameNotFoundException;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.net.http.SslError;\nimport android.os.Build;\nimport android.webkit.ClientCertRequest;\nimport android.webkit.HttpAuthHandler;\nimport android.webkit.SslErrorHandler;\nimport android.webkit.WebResourceResponse;\nimport android.webkit.WebView;\nimport android.webkit.WebViewClient;\n\nimport org.apache.cordova.AuthenticationToken;\nimport org.apache.cordova.CordovaClientCertRequest;\nimport org.apache.cordova.CordovaHttpAuthHandler;\nimport org.apache.cordova.CordovaResourceApi;\nimport org.apache.cordova.LOG;\nimport org.apache.cordova.PluginManager;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.Hashtable;\n\n\n/**\n * This class is the WebViewClient that implements callbacks for our web view.\n * The kind of callbacks that happen here are regarding the rendering of the\n * document instead of the chrome surrounding it, such as onPageStarted(), \n * shouldOverrideUrlLoading(), etc. Related to but different than\n * CordovaChromeClient.\n */\npublic class SystemWebViewClient extends WebViewClient {\n\n    private static final String TAG = \"SystemWebViewClient\";\n    protected final SystemWebViewEngine parentEngine;\n    private boolean doClearHistory = false;\n    boolean isCurrentlyLoading;\n\n    /** The authorization tokens. */\n    private Hashtable<String, AuthenticationToken> authenticationTokens = new Hashtable<String, AuthenticationToken>();\n\n    public SystemWebViewClient(SystemWebViewEngine parentEngine) {\n        this.parentEngine = parentEngine;\n    }\n\n    /**\n     * Give the host application a chance to take over the control when a new url\n     * is about to be loaded in the current WebView.\n     *\n     * @param view          The WebView that is initiating the callback.\n     * @param url           The url to be loaded.\n     * @return              true to override, false for default behavior\n     */\n\t@Override\n    public boolean shouldOverrideUrlLoading(WebView view, String url) {\n        return parentEngine.client.onNavigationAttempt(url);\n    }\n\n    /**\n     * On received http auth request.\n     * The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination\n     */\n    @Override\n    public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {\n\n        // Get the authentication token (if specified)\n        AuthenticationToken token = this.getAuthenticationToken(host, realm);\n        if (token != null) {\n            handler.proceed(token.getUserName(), token.getPassword());\n            return;\n        }\n\n        // Check if there is some plugin which can resolve this auth challenge\n        PluginManager pluginManager = this.parentEngine.pluginManager;\n        if (pluginManager != null && pluginManager.onReceivedHttpAuthRequest(null, new CordovaHttpAuthHandler(handler), host, realm)) {\n            parentEngine.client.clearLoadTimeoutTimer();\n            return;\n        }\n\n        // By default handle 401 like we'd normally do!\n        super.onReceivedHttpAuthRequest(view, handler, host, realm);\n    }\n    \n    /**\n     * On received client cert request.\n     * The method forwards the request to any running plugins before using the default implementation.\n     *\n     * @param view\n     * @param request\n     */\n    @Override\n    @TargetApi(21)\n    public void onReceivedClientCertRequest (WebView view, ClientCertRequest request)\n    {\n\n        // Check if there is some plugin which can resolve this certificate request\n        PluginManager pluginManager = this.parentEngine.pluginManager;\n        if (pluginManager != null && pluginManager.onReceivedClientCertRequest(null, new CordovaClientCertRequest(request))) {\n            parentEngine.client.clearLoadTimeoutTimer();\n            return;\n        }\n\n        // By default pass to WebViewClient\n        super.onReceivedClientCertRequest(view, request);\n    }\n\n    /**\n     * Notify the host application that a page has started loading.\n     * This method is called once for each main frame load so a page with iframes or framesets will call onPageStarted\n     * one time for the main frame. This also means that onPageStarted will not be called when the contents of an\n     * embedded frame changes, i.e. clicking a link whose target is an iframe.\n     *\n     * @param view          The webview initiating the callback.\n     * @param url           The url of the page.\n     */\n    @Override\n    public void onPageStarted(WebView view, String url, Bitmap favicon) {\n        super.onPageStarted(view, url, favicon);\n        isCurrentlyLoading = true;\n        // Flush stale messages & reset plugins.\n        parentEngine.bridge.reset();\n        parentEngine.client.onPageStarted(url);\n    }\n\n    /**\n     * Notify the host application that a page has finished loading.\n     * This method is called only for main frame. When onPageFinished() is called, the rendering picture may not be updated yet.\n     *\n     *\n     * @param view          The webview initiating the callback.\n     * @param url           The url of the page.\n     */\n    @Override\n    public void onPageFinished(WebView view, String url) {\n        super.onPageFinished(view, url);\n        // Ignore excessive calls, if url is not about:blank (CB-8317).\n        if (!isCurrentlyLoading && !url.startsWith(\"about:\")) {\n            return;\n        }\n        isCurrentlyLoading = false;\n\n        /**\n         * Because of a timing issue we need to clear this history in onPageFinished as well as\n         * onPageStarted. However we only want to do this if the doClearHistory boolean is set to\n         * true. You see when you load a url with a # in it which is common in jQuery applications\n         * onPageStared is not called. Clearing the history at that point would break jQuery apps.\n         */\n        if (this.doClearHistory) {\n            view.clearHistory();\n            this.doClearHistory = false;\n        }\n        parentEngine.client.onPageFinishedLoading(url);\n\n    }\n\n    /**\n     * Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable).\n     * The errorCode parameter corresponds to one of the ERROR_* constants.\n     *\n     * @param view          The WebView that is initiating the callback.\n     * @param errorCode     The error code corresponding to an ERROR_* value.\n     * @param description   A String describing the error.\n     * @param failingUrl    The url that failed to load.\n     */\n    @Override\n    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {\n        // Ignore error due to stopLoading().\n        if (!isCurrentlyLoading) {\n            return;\n        }\n        LOG.d(TAG, \"CordovaWebViewClient.onReceivedError: Error code=%s Description=%s URL=%s\", errorCode, description, failingUrl);\n\n        // If this is a \"Protocol Not Supported\" error, then revert to the previous\n        // page. If there was no previous page, then punt. The application's config\n        // is likely incorrect (start page set to sms: or something like that)\n        if (errorCode == WebViewClient.ERROR_UNSUPPORTED_SCHEME) {\n            parentEngine.client.clearLoadTimeoutTimer();\n\n            if (view.canGoBack()) {\n                view.goBack();\n                return;\n            } else {\n                super.onReceivedError(view, errorCode, description, failingUrl);\n            }\n        }\n        parentEngine.client.onReceivedError(errorCode, description, failingUrl);\n    }\n\n    /**\n     * Notify the host application that an SSL error occurred while loading a resource.\n     * The host application must call either handler.cancel() or handler.proceed().\n     * Note that the decision may be retained for use in response to future SSL errors.\n     * The default behavior is to cancel the load.\n     *\n     * @param view          The WebView that is initiating the callback.\n     * @param handler       An SslErrorHandler object that will handle the user's response.\n     * @param error         The SSL error object.\n     */\n    @TargetApi(8)\n    @Override\n    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {\n\n        final String packageName = parentEngine.cordova.getActivity().getPackageName();\n        final PackageManager pm = parentEngine.cordova.getActivity().getPackageManager();\n\n        ApplicationInfo appInfo;\n        try {\n            appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);\n            if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {\n                // debug = true\n                handler.proceed();\n                return;\n            } else {\n                // debug = false\n                super.onReceivedSslError(view, handler, error);\n            }\n        } catch (NameNotFoundException e) {\n            // When it doubt, lock it out!\n            super.onReceivedSslError(view, handler, error);\n        }\n    }\n\n\n    /**\n     * Sets the authentication token.\n     *\n     * @param authenticationToken\n     * @param host\n     * @param realm\n     */\n    public void setAuthenticationToken(AuthenticationToken authenticationToken, String host, String realm) {\n        if (host == null) {\n            host = \"\";\n        }\n        if (realm == null) {\n            realm = \"\";\n        }\n        this.authenticationTokens.put(host.concat(realm), authenticationToken);\n    }\n\n    /**\n     * Removes the authentication token.\n     *\n     * @param host\n     * @param realm\n     *\n     * @return the authentication token or null if did not exist\n     */\n    public AuthenticationToken removeAuthenticationToken(String host, String realm) {\n        return this.authenticationTokens.remove(host.concat(realm));\n    }\n\n    /**\n     * Gets the authentication token.\n     *\n     * In order it tries:\n     * 1- host + realm\n     * 2- host\n     * 3- realm\n     * 4- no host, no realm\n     *\n     * @param host\n     * @param realm\n     *\n     * @return the authentication token\n     */\n    public AuthenticationToken getAuthenticationToken(String host, String realm) {\n        AuthenticationToken token = null;\n        token = this.authenticationTokens.get(host.concat(realm));\n\n        if (token == null) {\n            // try with just the host\n            token = this.authenticationTokens.get(host);\n\n            // Try the realm\n            if (token == null) {\n                token = this.authenticationTokens.get(realm);\n            }\n\n            // if no host found, just query for default\n            if (token == null) {\n                token = this.authenticationTokens.get(\"\");\n            }\n        }\n\n        return token;\n    }\n\n    /**\n     * Clear all authentication tokens.\n     */\n    public void clearAuthenticationTokens() {\n        this.authenticationTokens.clear();\n    }\n\n    @TargetApi(Build.VERSION_CODES.HONEYCOMB)\n    @Override\n    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {\n        try {\n            // Check the against the whitelist and lock out access to the WebView directory\n            // Changing this will cause problems for your application\n            if (!parentEngine.pluginManager.shouldAllowRequest(url)) {\n                LOG.w(TAG, \"URL blocked by whitelist: \" + url);\n                // Results in a 404.\n                return new WebResourceResponse(\"text/plain\", \"UTF-8\", null);\n            }\n\n            CordovaResourceApi resourceApi = parentEngine.resourceApi;\n            Uri origUri = Uri.parse(url);\n            // Allow plugins to intercept WebView requests.\n            Uri remappedUri = resourceApi.remapUri(origUri);\n\n            if (!origUri.equals(remappedUri) || needsSpecialsInAssetUrlFix(origUri) || needsKitKatContentUrlFix(origUri)) {\n                CordovaResourceApi.OpenForReadResult result = resourceApi.openForRead(remappedUri, true);\n                return new WebResourceResponse(result.mimeType, \"UTF-8\", result.inputStream);\n            }\n            // If we don't need to special-case the request, let the browser load it.\n            return null;\n        } catch (IOException e) {\n            if (!(e instanceof FileNotFoundException)) {\n                LOG.e(TAG, \"Error occurred while loading a file (returning a 404).\", e);\n            }\n            // Results in a 404.\n            return new WebResourceResponse(\"text/plain\", \"UTF-8\", null);\n        }\n    }\n\n    private static boolean needsKitKatContentUrlFix(Uri uri) {\n        return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && \"content\".equals(uri.getScheme());\n    }\n\n    private static boolean needsSpecialsInAssetUrlFix(Uri uri) {\n        if (CordovaResourceApi.getUriType(uri) != CordovaResourceApi.URI_TYPE_ASSET) {\n            return false;\n        }\n        if (uri.getQuery() != null || uri.getFragment() != null) {\n            return true;\n        }\n\n        if (!uri.toString().contains(\"%\")) {\n            return false;\n        }\n\n        switch(android.os.Build.VERSION.SDK_INT){\n            case android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH:\n            case android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1:\n                return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewEngine.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova.engine;\n\nimport android.annotation.SuppressLint;\nimport android.annotation.TargetApi;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.pm.ApplicationInfo;\nimport android.os.Build;\nimport android.view.View;\nimport android.webkit.ValueCallback;\nimport android.webkit.WebSettings;\nimport android.webkit.WebSettings.LayoutAlgorithm;\nimport android.webkit.WebView;\n\nimport org.apache.cordova.CordovaBridge;\nimport org.apache.cordova.CordovaInterface;\nimport org.apache.cordova.CordovaPreferences;\nimport org.apache.cordova.CordovaResourceApi;\nimport org.apache.cordova.CordovaWebView;\nimport org.apache.cordova.CordovaWebViewEngine;\nimport org.apache.cordova.ICordovaCookieManager;\nimport org.apache.cordova.LOG;\nimport org.apache.cordova.NativeToJsMessageQueue;\nimport org.apache.cordova.PluginManager;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\n\n/**\n * Glue class between CordovaWebView (main Cordova logic) and SystemWebView (the actual View).\n * We make the Engine separate from the actual View so that:\n *  A) We don't need to worry about WebView methods clashing with CordovaWebViewEngine methods\n *     (e.g.: goBack() is void for WebView, and boolean for CordovaWebViewEngine)\n *  B) Separating the actual View from the Engine makes API surfaces smaller.\n * Class uses two-phase initialization. However, CordovaWebView is responsible for calling .init().\n */\npublic class SystemWebViewEngine implements CordovaWebViewEngine {\n    public static final String TAG = \"SystemWebViewEngine\";\n\n    protected final SystemWebView webView;\n    protected final SystemCookieManager cookieManager;\n    protected CordovaPreferences preferences;\n    protected CordovaBridge bridge;\n    protected CordovaWebViewEngine.Client client;\n    protected CordovaWebView parentWebView;\n    protected CordovaInterface cordova;\n    protected PluginManager pluginManager;\n    protected CordovaResourceApi resourceApi;\n    protected NativeToJsMessageQueue nativeToJsMessageQueue;\n    private BroadcastReceiver receiver;\n\n    /** Used when created via reflection. */\n    public SystemWebViewEngine(Context context, CordovaPreferences preferences) {\n        this(new SystemWebView(context), preferences);\n    }\n\n    public SystemWebViewEngine(SystemWebView webView) {\n        this(webView, null);\n    }\n\n    public SystemWebViewEngine(SystemWebView webView, CordovaPreferences preferences) {\n        this.preferences = preferences;\n        this.webView = webView;\n        cookieManager = new SystemCookieManager(webView);\n    }\n\n    @Override\n    public void init(CordovaWebView parentWebView, CordovaInterface cordova, CordovaWebViewEngine.Client client,\n              CordovaResourceApi resourceApi, PluginManager pluginManager,\n              NativeToJsMessageQueue nativeToJsMessageQueue) {\n        if (this.cordova != null) {\n            throw new IllegalStateException();\n        }\n        // Needed when prefs are not passed by the constructor\n        if (preferences == null) {\n            preferences = parentWebView.getPreferences();\n        }\n        this.parentWebView = parentWebView;\n        this.cordova = cordova;\n        this.client = client;\n        this.resourceApi = resourceApi;\n        this.pluginManager = pluginManager;\n        this.nativeToJsMessageQueue = nativeToJsMessageQueue;\n        webView.init(this, cordova);\n\n        initWebViewSettings();\n\n        nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode.OnlineEventsBridgeModeDelegate() {\n            @Override\n            public void setNetworkAvailable(boolean value) {\n                webView.setNetworkAvailable(value);\n            }\n            @Override\n            public void runOnUiThread(Runnable r) {\n                SystemWebViewEngine.this.cordova.getActivity().runOnUiThread(r);\n            }\n        }));\n        if(Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2)\n            nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.EvalBridgeMode(this, cordova));\n\tbridge = new CordovaBridge(pluginManager, nativeToJsMessageQueue);\n        exposeJsInterface(webView, bridge);\n    }\n\n    @Override\n    public CordovaWebView getCordovaWebView() {\n        return parentWebView;\n    }\n\n    @Override\n    public ICordovaCookieManager getCookieManager() {\n        return cookieManager;\n    }\n\n    @Override\n    public View getView() {\n        return webView;\n    }\n\n    @SuppressLint({\"NewApi\", \"SetJavaScriptEnabled\"})\n    @SuppressWarnings(\"deprecation\")\n    private void initWebViewSettings() {\n        webView.setInitialScale(0);\n        webView.setVerticalScrollBarEnabled(false);\n        // Enable JavaScript\n        final WebSettings settings = webView.getSettings();\n        settings.setJavaScriptEnabled(true);\n        settings.setJavaScriptCanOpenWindowsAutomatically(true);\n        settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL);\n\n        // Set the nav dump for HTC 2.x devices (disabling for ICS, deprecated entirely for Jellybean 4.2)\n        try {\n            Method gingerbread_getMethod =  WebSettings.class.getMethod(\"setNavDump\", new Class[] { boolean.class });\n\n            String manufacturer = android.os.Build.MANUFACTURER;\n            LOG.d(TAG, \"CordovaWebView is running on device made by: \" + manufacturer);\n            if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB &&\n                    android.os.Build.MANUFACTURER.contains(\"HTC\"))\n            {\n                gingerbread_getMethod.invoke(settings, true);\n            }\n        } catch (NoSuchMethodException e) {\n            LOG.d(TAG, \"We are on a modern version of Android, we will deprecate HTC 2.3 devices in 2.8\");\n        } catch (IllegalArgumentException e) {\n            LOG.d(TAG, \"Doing the NavDump failed with bad arguments\");\n        } catch (IllegalAccessException e) {\n            LOG.d(TAG, \"This should never happen: IllegalAccessException means this isn't Android anymore\");\n        } catch (InvocationTargetException e) {\n            LOG.d(TAG, \"This should never happen: InvocationTargetException means this isn't Android anymore.\");\n        }\n\n        //We don't save any form data in the application\n        settings.setSaveFormData(false);\n        settings.setSavePassword(false);\n\n        // Jellybean rightfully tried to lock this down. Too bad they didn't give us a whitelist\n        // while we do this\n        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {\n            settings.setAllowUniversalAccessFromFileURLs(true);\n        }\n        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {\n            settings.setMediaPlaybackRequiresUserGesture(false);\n        }\n        // Enable database\n        // We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16\n        String databasePath = webView.getContext().getApplicationContext().getDir(\"database\", Context.MODE_PRIVATE).getPath();\n        settings.setDatabaseEnabled(true);\n        settings.setDatabasePath(databasePath);\n\n\n        //Determine whether we're in debug or release mode, and turn on Debugging!\n        ApplicationInfo appInfo = webView.getContext().getApplicationContext().getApplicationInfo();\n        if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0 &&\n            android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {\n            enableRemoteDebugging();\n        }\n\n        settings.setGeolocationDatabasePath(databasePath);\n\n        // Enable DOM storage\n        settings.setDomStorageEnabled(true);\n\n        // Enable built-in geolocation\n        settings.setGeolocationEnabled(true);\n\n        // Enable AppCache\n        // Fix for CB-2282\n        settings.setAppCacheMaxSize(5 * 1048576);\n        settings.setAppCachePath(databasePath);\n        settings.setAppCacheEnabled(true);\n\n        // Fix for CB-1405\n        // Google issue 4641\n        String defaultUserAgent = settings.getUserAgentString();\n\n        // Fix for CB-3360\n        String overrideUserAgent = preferences.getString(\"OverrideUserAgent\", null);\n        if (overrideUserAgent != null) {\n            settings.setUserAgentString(overrideUserAgent);\n        } else {\n            String appendUserAgent = preferences.getString(\"AppendUserAgent\", null);\n            if (appendUserAgent != null) {\n                settings.setUserAgentString(defaultUserAgent + \" \" + appendUserAgent);\n            }\n        }\n        // End CB-3360\n\n        IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);\n        if (this.receiver == null) {\n            this.receiver = new BroadcastReceiver() {\n                @Override\n                public void onReceive(Context context, Intent intent) {\n                    settings.getUserAgentString();\n                }\n            };\n            webView.getContext().registerReceiver(this.receiver, intentFilter);\n        }\n        // end CB-1405\n    }\n\n    @TargetApi(Build.VERSION_CODES.KITKAT)\n    private void enableRemoteDebugging() {\n        try {\n            WebView.setWebContentsDebuggingEnabled(true);\n        } catch (IllegalArgumentException e) {\n            LOG.d(TAG, \"You have one job! To turn on Remote Web Debugging! YOU HAVE FAILED! \");\n            e.printStackTrace();\n        }\n    }\n\n    private static void exposeJsInterface(WebView webView, CordovaBridge bridge) {\n        if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)) {\n            LOG.i(TAG, \"Disabled addJavascriptInterface() bridge since Android version is old.\");\n            // Bug being that Java Strings do not get converted to JS strings automatically.\n            // This isn't hard to work-around on the JS side, but it's easier to just\n            // use the prompt bridge instead.\n            return;\n        }\n        SystemExposedJsApi exposedJsApi = new SystemExposedJsApi(bridge);\n        webView.addJavascriptInterface(exposedJsApi, \"_cordovaNative\");\n    }\n\n\n    /**\n     * Load the url into the webview.\n     */\n    @Override\n    public void loadUrl(final String url, boolean clearNavigationStack) {\n        webView.loadUrl(url);\n    }\n\n    @Override\n    public String getUrl() {\n        return webView.getUrl();\n    }\n\n    @Override\n    public void stopLoading() {\n        webView.stopLoading();\n    }\n\n    @Override\n    public void clearCache() {\n        webView.clearCache(true);\n    }\n\n    @Override\n    public void clearHistory() {\n        webView.clearHistory();\n    }\n\n    @Override\n    public boolean canGoBack() {\n        return webView.canGoBack();\n    }\n\n    /**\n     * Go to previous page in history.  (We manage our own history)\n     *\n     * @return true if we went back, false if we are already at top\n     */\n    @Override\n    public boolean goBack() {\n        // Check webview first to see if there is a history\n        // This is needed to support curPage#diffLink, since they are added to parentEngine's history, but not our history url array (JQMobile behavior)\n        if (webView.canGoBack()) {\n            webView.goBack();\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public void setPaused(boolean value) {\n        if (value) {\n            webView.onPause();\n            webView.pauseTimers();\n        } else {\n            webView.onResume();\n            webView.resumeTimers();\n        }\n    }\n\n    @Override\n    public void destroy() {\n        webView.chromeClient.destroyLastDialog();\n        webView.destroy();\n        // unregister the receiver\n        if (receiver != null) {\n            try {\n                webView.getContext().unregisterReceiver(receiver);\n            } catch (Exception e) {\n                LOG.e(TAG, \"Error unregistering configuration receiver: \" + e.getMessage(), e);\n            }\n        }\n    }\n\n    @Override\n    public void evaluateJavascript(String js, ValueCallback<String> callback) {\n        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            webView.evaluateJavascript(js, callback);\n        }\n        else\n        {\n            LOG.d(TAG, \"This webview is using the old bridge\");\n        }\n    }\n}\n"
  },
  {
    "path": "platforms/android/android.json",
    "content": "{\n    \"prepare_queue\": {\n        \"installed\": [],\n        \"uninstalled\": []\n    },\n    \"config_munge\": {\n        \"files\": {\n            \"res/xml/config.xml\": {\n                \"parents\": {\n                    \"/*\": [\n                        {\n                            \"xml\": \"<feature name=\\\"SplashScreen\\\"><param name=\\\"android-package\\\" value=\\\"org.apache.cordova.splashscreen.SplashScreen\\\" /><param name=\\\"onload\\\" value=\\\"true\\\" /></feature>\",\n                            \"count\": 1\n                        },\n                        {\n                            \"xml\": \"<feature name=\\\"Whitelist\\\"><param name=\\\"android-package\\\" value=\\\"org.apache.cordova.whitelist.WhitelistPlugin\\\" /><param name=\\\"onload\\\" value=\\\"true\\\" /></feature>\",\n                            \"count\": 1\n                        },\n                        {\n                            \"xml\": \"<feature name=\\\"BarcodeScanner\\\"><param name=\\\"android-package\\\" value=\\\"com.phonegap.plugins.barcodescanner.BarcodeScanner\\\" /></feature>\",\n                            \"count\": 1\n                        }\n                    ]\n                }\n            },\n            \"AndroidManifest.xml\": {\n                \"parents\": {\n                    \"/manifest/application\": [\n                        {\n                            \"xml\": \"<activity android:clearTaskOnLaunch=\\\"true\\\" android:configChanges=\\\"orientation|keyboardHidden|screenSize\\\" android:exported=\\\"false\\\" android:name=\\\"com.google.zxing.client.android.CaptureActivity\\\" android:theme=\\\"@android:style/Theme.NoTitleBar.Fullscreen\\\" android:windowSoftInputMode=\\\"stateAlwaysHidden\\\" />\",\n                            \"count\": 1\n                        },\n                        {\n                            \"xml\": \"<activity android:label=\\\"Share\\\" android:name=\\\"com.google.zxing.client.android.encode.EncodeActivity\\\" />\",\n                            \"count\": 1\n                        }\n                    ],\n                    \"/manifest\": [\n                        {\n                            \"xml\": \"<uses-permission android:name=\\\"android.permission.CAMERA\\\" />\",\n                            \"count\": 1\n                        },\n                        {\n                            \"xml\": \"<uses-permission android:name=\\\"android.permission.FLASHLIGHT\\\" />\",\n                            \"count\": 1\n                        },\n                        {\n                            \"xml\": \"<uses-feature android:name=\\\"android.hardware.camera\\\" android:required=\\\"true\\\" />\",\n                            \"count\": 1\n                        }\n                    ]\n                }\n            }\n        }\n    },\n    \"installed_plugins\": {\n        \"cordova-plugin-compat\": {\n            \"PACKAGE_NAME\": \"friimaind.piholedroid\"\n        },\n        \"cordova-plugin-splashscreen\": {\n            \"PACKAGE_NAME\": \"friimaind.piholedroid\"\n        },\n        \"cordova-plugin-whitelist\": {\n            \"PACKAGE_NAME\": \"friimaind.piholedroid\"\n        },\n        \"phonegap-plugin-barcodescanner\": {\n            \"PACKAGE_NAME\": \"friimaind.piholedroid\"\n        }\n    },\n    \"dependent_plugins\": {},\n    \"modules\": [\n        {\n            \"id\": \"cordova-plugin-splashscreen.SplashScreen\",\n            \"file\": \"plugins/cordova-plugin-splashscreen/www/splashscreen.js\",\n            \"pluginId\": \"cordova-plugin-splashscreen\",\n            \"clobbers\": [\n                \"navigator.splashscreen\"\n            ]\n        },\n        {\n            \"id\": \"phonegap-plugin-barcodescanner.BarcodeScanner\",\n            \"file\": \"plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js\",\n            \"pluginId\": \"phonegap-plugin-barcodescanner\",\n            \"clobbers\": [\n                \"cordova.plugins.barcodeScanner\"\n            ]\n        }\n    ],\n    \"plugin_metadata\": {\n        \"cordova-plugin-compat\": \"1.1.0\",\n        \"cordova-plugin-splashscreen\": \"4.0.1\",\n        \"cordova-plugin-whitelist\": \"1.3.1\",\n        \"phonegap-plugin-barcodescanner\": \"6.0.6\"\n    }\n}"
  },
  {
    "path": "platforms/android/assets/www/cordova-js-src/android/nativeapiprovider.js",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n*/\n\n/**\n * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi.\n */\n\nvar nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi');\nvar currentApi = nativeApi;\n\nmodule.exports = {\n    get: function() { return currentApi; },\n    setPreferPrompt: function(value) {\n        currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi;\n    },\n    // Used only by tests.\n    set: function(value) {\n        currentApi = value;\n    }\n};\n"
  },
  {
    "path": "platforms/android/assets/www/cordova-js-src/android/promptbasednativeapi.js",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n*/\n\n/**\n * Implements the API of ExposedJsApi.java, but uses prompt() to communicate.\n * This is used pre-JellyBean, where addJavascriptInterface() is disabled.\n */\n\nmodule.exports = {\n    exec: function(bridgeSecret, service, action, callbackId, argsJson) {\n        return prompt(argsJson, 'gap:'+JSON.stringify([bridgeSecret, service, action, callbackId]));\n    },\n    setNativeToJsBridgeMode: function(bridgeSecret, value) {\n        prompt(value, 'gap_bridge_mode:' + bridgeSecret);\n    },\n    retrieveJsMessages: function(bridgeSecret, fromOnlineEvent) {\n        return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret);\n    }\n};\n"
  },
  {
    "path": "platforms/android/assets/www/cordova-js-src/exec.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n/**\n * Execute a cordova command.  It is up to the native side whether this action\n * is synchronous or asynchronous.  The native side can return:\n *      Synchronous: PluginResult object as a JSON string\n *      Asynchronous: Empty string \"\"\n * If async, the native side will cordova.callbackSuccess or cordova.callbackError,\n * depending upon the result of the action.\n *\n * @param {Function} success    The success callback\n * @param {Function} fail       The fail callback\n * @param {String} service      The name of the service to use\n * @param {String} action       Action to be run in cordova\n * @param {String[]} [args]     Zero or more arguments to pass to the method\n */\nvar cordova = require('cordova'),\n    nativeApiProvider = require('cordova/android/nativeapiprovider'),\n    utils = require('cordova/utils'),\n    base64 = require('cordova/base64'),\n    channel = require('cordova/channel'),\n    jsToNativeModes = {\n        PROMPT: 0,\n        JS_OBJECT: 1\n    },\n    nativeToJsModes = {\n        // Polls for messages using the JS->Native bridge.\n        POLLING: 0,\n        // For LOAD_URL to be viable, it would need to have a work-around for\n        // the bug where the soft-keyboard gets dismissed when a message is sent.\n        LOAD_URL: 1,\n        // For the ONLINE_EVENT to be viable, it would need to intercept all event\n        // listeners (both through addEventListener and window.ononline) as well\n        // as set the navigator property itself.\n        ONLINE_EVENT: 2,\n        EVAL_BRIDGE: 3\n    },\n    jsToNativeBridgeMode,  // Set lazily.\n    nativeToJsBridgeMode = nativeToJsModes.EVAL_BRIDGE,\n    pollEnabled = false,\n    bridgeSecret = -1;\n\nvar messagesFromNative = [];\nvar isProcessing = false;\nvar resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve();\nvar nextTick = resolvedPromise ? function(fn) { resolvedPromise.then(fn); } : function(fn) { setTimeout(fn); };\n\nfunction androidExec(success, fail, service, action, args) {\n    if (bridgeSecret < 0) {\n        // If we ever catch this firing, we'll need to queue up exec()s\n        // and fire them once we get a secret. For now, I don't think\n        // it's possible for exec() to be called since plugins are parsed but\n        // not run until until after onNativeReady.\n        throw new Error('exec() called without bridgeSecret');\n    }\n    // Set default bridge modes if they have not already been set.\n    // By default, we use the failsafe, since addJavascriptInterface breaks too often\n    if (jsToNativeBridgeMode === undefined) {\n        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);\n    }\n\n    // If args is not provided, default to an empty array\n    args = args || [];\n\n    // Process any ArrayBuffers in the args into a string.\n    for (var i = 0; i < args.length; i++) {\n        if (utils.typeName(args[i]) == 'ArrayBuffer') {\n            args[i] = base64.fromArrayBuffer(args[i]);\n        }\n    }\n\n    var callbackId = service + cordova.callbackId++,\n        argsJson = JSON.stringify(args);\n    if (success || fail) {\n        cordova.callbacks[callbackId] = {success:success, fail:fail};\n    }\n\n    var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);\n    // If argsJson was received by Java as null, try again with the PROMPT bridge mode.\n    // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.\n    if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && msgs === \"@Null arguments.\") {\n        androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);\n        androidExec(success, fail, service, action, args);\n        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);\n    } else if (msgs) {\n        messagesFromNative.push(msgs);\n        // Always process async to avoid exceptions messing up stack.\n        nextTick(processMessages);\n    }\n}\n\nandroidExec.init = function() {\n    //CB-11828\n    //This failsafe checks the version of Android and if it's Jellybean, it switches it to\n    //using the Online Event bridge for communicating from Native to JS\n    //\n    //It's ugly, but it's necessary.\n    var check = navigator.userAgent.toLowerCase().match(/android\\s[0-9].[0-9]/);\n    var version_code = check && check[0].match(/4.[0-3].*/);\n    if (version_code != null && nativeToJsBridgeMode == nativeToJsModes.EVAL_BRIDGE) {\n      nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT;\n    }\n\n    bridgeSecret = +prompt('', 'gap_init:' + nativeToJsBridgeMode);\n    channel.onNativeReady.fire();\n};\n\nfunction pollOnceFromOnlineEvent() {\n    pollOnce(true);\n}\n\nfunction pollOnce(opt_fromOnlineEvent) {\n    if (bridgeSecret < 0) {\n        // This can happen when the NativeToJsMessageQueue resets the online state on page transitions.\n        // We know there's nothing to retrieve, so no need to poll.\n        return;\n    }\n    var msgs = nativeApiProvider.get().retrieveJsMessages(bridgeSecret, !!opt_fromOnlineEvent);\n    if (msgs) {\n        messagesFromNative.push(msgs);\n        // Process sync since we know we're already top-of-stack.\n        processMessages();\n    }\n}\n\nfunction pollingTimerFunc() {\n    if (pollEnabled) {\n        pollOnce();\n        setTimeout(pollingTimerFunc, 50);\n    }\n}\n\nfunction hookOnlineApis() {\n    function proxyEvent(e) {\n        cordova.fireWindowEvent(e.type);\n    }\n    // The network module takes care of firing online and offline events.\n    // It currently fires them only on document though, so we bridge them\n    // to window here (while first listening for exec()-releated online/offline\n    // events).\n    window.addEventListener('online', pollOnceFromOnlineEvent, false);\n    window.addEventListener('offline', pollOnceFromOnlineEvent, false);\n    cordova.addWindowEventHandler('online');\n    cordova.addWindowEventHandler('offline');\n    document.addEventListener('online', proxyEvent, false);\n    document.addEventListener('offline', proxyEvent, false);\n}\n\nhookOnlineApis();\n\nandroidExec.jsToNativeModes = jsToNativeModes;\nandroidExec.nativeToJsModes = nativeToJsModes;\n\nandroidExec.setJsToNativeBridgeMode = function(mode) {\n    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {\n        mode = jsToNativeModes.PROMPT;\n    }\n    nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);\n    jsToNativeBridgeMode = mode;\n};\n\nandroidExec.setNativeToJsBridgeMode = function(mode) {\n    if (mode == nativeToJsBridgeMode) {\n        return;\n    }\n    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {\n        pollEnabled = false;\n    }\n\n    nativeToJsBridgeMode = mode;\n    // Tell the native side to switch modes.\n    // Otherwise, it will be set by androidExec.init()\n    if (bridgeSecret >= 0) {\n        nativeApiProvider.get().setNativeToJsBridgeMode(bridgeSecret, mode);\n    }\n\n    if (mode == nativeToJsModes.POLLING) {\n        pollEnabled = true;\n        setTimeout(pollingTimerFunc, 1);\n    }\n};\n\nfunction buildPayload(payload, message) {\n    var payloadKind = message.charAt(0);\n    if (payloadKind == 's') {\n        payload.push(message.slice(1));\n    } else if (payloadKind == 't') {\n        payload.push(true);\n    } else if (payloadKind == 'f') {\n        payload.push(false);\n    } else if (payloadKind == 'N') {\n        payload.push(null);\n    } else if (payloadKind == 'n') {\n        payload.push(+message.slice(1));\n    } else if (payloadKind == 'A') {\n        var data = message.slice(1);\n        payload.push(base64.toArrayBuffer(data));\n    } else if (payloadKind == 'S') {\n        payload.push(window.atob(message.slice(1)));\n    } else if (payloadKind == 'M') {\n        var multipartMessages = message.slice(1);\n        while (multipartMessages !== \"\") {\n            var spaceIdx = multipartMessages.indexOf(' ');\n            var msgLen = +multipartMessages.slice(0, spaceIdx);\n            var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen);\n            multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1);\n            buildPayload(payload, multipartMessage);\n        }\n    } else {\n        payload.push(JSON.parse(message));\n    }\n}\n\n// Processes a single message, as encoded by NativeToJsMessageQueue.java.\nfunction processMessage(message) {\n    var firstChar = message.charAt(0);\n    if (firstChar == 'J') {\n        // This is deprecated on the .java side. It doesn't work with CSP enabled.\n        eval(message.slice(1));\n    } else if (firstChar == 'S' || firstChar == 'F') {\n        var success = firstChar == 'S';\n        var keepCallback = message.charAt(1) == '1';\n        var spaceIdx = message.indexOf(' ', 2);\n        var status = +message.slice(2, spaceIdx);\n        var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);\n        var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);\n        var payloadMessage = message.slice(nextSpaceIdx + 1);\n        var payload = [];\n        buildPayload(payload, payloadMessage);\n        cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);\n    } else {\n        console.log(\"processMessage failed: invalid message: \" + JSON.stringify(message));\n    }\n}\n\nfunction processMessages() {\n    // Check for the reentrant case.\n    if (isProcessing) {\n        return;\n    }\n    if (messagesFromNative.length === 0) {\n        return;\n    }\n    isProcessing = true;\n    try {\n        var msg = popMessageFromQueue();\n        // The Java side can send a * message to indicate that it\n        // still has messages waiting to be retrieved.\n        if (msg == '*' && messagesFromNative.length === 0) {\n            nextTick(pollOnce);\n            return;\n        }\n        processMessage(msg);\n    } finally {\n        isProcessing = false;\n        if (messagesFromNative.length > 0) {\n            nextTick(processMessages);\n        }\n    }\n}\n\nfunction popMessageFromQueue() {\n    var messageBatch = messagesFromNative.shift();\n    if (messageBatch == '*') {\n        return '*';\n    }\n\n    var spaceIdx = messageBatch.indexOf(' ');\n    var msgLen = +messageBatch.slice(0, spaceIdx);\n    var message = messageBatch.substr(spaceIdx + 1, msgLen);\n    messageBatch = messageBatch.slice(spaceIdx + msgLen + 1);\n    if (messageBatch) {\n        messagesFromNative.unshift(messageBatch);\n    }\n    return message;\n}\n\nmodule.exports = androidExec;\n"
  },
  {
    "path": "platforms/android/assets/www/cordova-js-src/platform.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n// The last resume event that was received that had the result of a plugin call.\nvar lastResumeEvent = null;\n\nmodule.exports = {\n    id: 'android',\n    bootstrap: function() {\n        var channel = require('cordova/channel'),\n            cordova = require('cordova'),\n            exec = require('cordova/exec'),\n            modulemapper = require('cordova/modulemapper');\n\n        // Get the shared secret needed to use the bridge.\n        exec.init();\n\n        // TODO: Extract this as a proper plugin.\n        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');\n\n        var APP_PLUGIN_NAME = Number(cordova.platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';\n\n        // Inject a listener for the backbutton on the document.\n        var backButtonChannel = cordova.addDocumentEventHandler('backbutton');\n        backButtonChannel.onHasSubscribersChange = function() {\n            // If we just attached the first handler or detached the last handler,\n            // let native know we need to override the back button.\n            exec(null, null, APP_PLUGIN_NAME, \"overrideBackbutton\", [this.numHandlers == 1]);\n        };\n\n        // Add hardware MENU and SEARCH button handlers\n        cordova.addDocumentEventHandler('menubutton');\n        cordova.addDocumentEventHandler('searchbutton');\n\n        function bindButtonChannel(buttonName) {\n            // generic button bind used for volumeup/volumedown buttons\n            var volumeButtonChannel = cordova.addDocumentEventHandler(buttonName + 'button');\n            volumeButtonChannel.onHasSubscribersChange = function() {\n                exec(null, null, APP_PLUGIN_NAME, \"overrideButton\", [buttonName, this.numHandlers == 1]);\n            };\n        }\n        // Inject a listener for the volume buttons on the document.\n        bindButtonChannel('volumeup');\n        bindButtonChannel('volumedown');\n\n        // The resume event is not \"sticky\", but it is possible that the event\n        // will contain the result of a plugin call. We need to ensure that the\n        // plugin result is delivered even after the event is fired (CB-10498)\n        var cordovaAddEventListener = document.addEventListener;\n\n        document.addEventListener = function(evt, handler, capture) {\n            cordovaAddEventListener(evt, handler, capture);\n\n            if (evt === 'resume' && lastResumeEvent) {\n                handler(lastResumeEvent);\n            }\n        };\n\n        // Let native code know we are all done on the JS side.\n        // Native code will then un-hide the WebView.\n        channel.onCordovaReady.subscribe(function() {\n            exec(onMessageFromNative, null, APP_PLUGIN_NAME, 'messageChannel', []);\n            exec(null, null, APP_PLUGIN_NAME, \"show\", []);\n        });\n    }\n};\n\nfunction onMessageFromNative(msg) {\n    var cordova = require('cordova');\n    var action = msg.action;\n\n    switch (action)\n    {\n        // Button events\n        case 'backbutton':\n        case 'menubutton':\n        case 'searchbutton':\n        // App life cycle events\n        case 'pause':\n        // Volume events\n        case 'volumedownbutton':\n        case 'volumeupbutton':\n            cordova.fireDocumentEvent(action);\n            break;\n        case 'resume':\n            if(arguments.length > 1 && msg.pendingResult) {\n                if(arguments.length === 2) {\n                    msg.pendingResult.result = arguments[1];\n                } else {\n                    // The plugin returned a multipart message\n                    var res = [];\n                    for(var i = 1; i < arguments.length; i++) {\n                        res.push(arguments[i]);\n                    }\n                    msg.pendingResult.result = res;\n                }\n\n                // Save the plugin result so that it can be delivered to the js\n                // even if they miss the initial firing of the event\n                lastResumeEvent = msg;\n            }\n            cordova.fireDocumentEvent(action, msg);\n            break;\n        default:\n            throw new Error('Unknown event action ' + action);\n    }\n}\n"
  },
  {
    "path": "platforms/android/assets/www/cordova-js-src/plugin/android/app.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nvar exec = require('cordova/exec');\nvar APP_PLUGIN_NAME = Number(require('cordova').platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';\n\nmodule.exports = {\n    /**\n    * Clear the resource cache.\n    */\n    clearCache:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"clearCache\", []);\n    },\n\n    /**\n    * Load the url into the webview or into new browser instance.\n    *\n    * @param url           The URL to load\n    * @param props         Properties that can be passed in to the activity:\n    *      wait: int                           => wait msec before loading URL\n    *      loadingDialog: \"Title,Message\"      => display a native loading dialog\n    *      loadUrlTimeoutValue: int            => time in msec to wait before triggering a timeout error\n    *      clearHistory: boolean              => clear webview history (default=false)\n    *      openExternal: boolean              => open in a new browser (default=false)\n    *\n    * Example:\n    *      navigator.app.loadUrl(\"http://server/myapp/index.html\", {wait:2000, loadingDialog:\"Wait,Loading App\", loadUrlTimeoutValue: 60000});\n    */\n    loadUrl:function(url, props) {\n        exec(null, null, APP_PLUGIN_NAME, \"loadUrl\", [url, props]);\n    },\n\n    /**\n    * Cancel loadUrl that is waiting to be loaded.\n    */\n    cancelLoadUrl:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"cancelLoadUrl\", []);\n    },\n\n    /**\n    * Clear web history in this web view.\n    * Instead of BACK button loading the previous web page, it will exit the app.\n    */\n    clearHistory:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"clearHistory\", []);\n    },\n\n    /**\n    * Go to previous page displayed.\n    * This is the same as pressing the backbutton on Android device.\n    */\n    backHistory:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"backHistory\", []);\n    },\n\n    /**\n    * Override the default behavior of the Android back button.\n    * If overridden, when the back button is pressed, the \"backKeyDown\" JavaScript event will be fired.\n    *\n    * Note: The user should not have to call this method.  Instead, when the user\n    *       registers for the \"backbutton\" event, this is automatically done.\n    *\n    * @param override        T=override, F=cancel override\n    */\n    overrideBackbutton:function(override) {\n        exec(null, null, APP_PLUGIN_NAME, \"overrideBackbutton\", [override]);\n    },\n\n    /**\n    * Override the default behavior of the Android volume button.\n    * If overridden, when the volume button is pressed, the \"volume[up|down]button\"\n    * JavaScript event will be fired.\n    *\n    * Note: The user should not have to call this method.  Instead, when the user\n    *       registers for the \"volume[up|down]button\" event, this is automatically done.\n    *\n    * @param button          volumeup, volumedown\n    * @param override        T=override, F=cancel override\n    */\n    overrideButton:function(button, override) {\n        exec(null, null, APP_PLUGIN_NAME, \"overrideButton\", [button, override]);\n    },\n\n    /**\n    * Exit and terminate the application.\n    */\n    exitApp:function() {\n        return exec(null, null, APP_PLUGIN_NAME, \"exitApp\", []);\n    }\n};\n"
  },
  {
    "path": "platforms/android/assets/www/cordova.js",
    "content": "// Platform: android\n// 7c5fcc5a5adfbf3fb8ceaf36fbdd4bd970bd9c20\n/*\n Licensed to the Apache Software Foundation (ASF) under one\n or more contributor license agreements.  See the NOTICE file\n distributed with this work for additional information\n regarding copyright ownership.  The ASF licenses this file\n to you under the Apache License, Version 2.0 (the\n \"License\"); you may not use this file except in compliance\n with the License.  You may obtain a copy of the License at\n \n     http://www.apache.org/licenses/LICENSE-2.0\n \n Unless required by applicable law or agreed to in writing,\n software distributed under the License is distributed on an\n \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n KIND, either express or implied.  See the License for the\n specific language governing permissions and limitations\n under the License.\n*/\n;(function() {\nvar PLATFORM_VERSION_BUILD_LABEL = '6.2.1';\n// file: src/scripts/require.js\n\n/*jshint -W079 */\n/*jshint -W020 */\n\nvar require,\n    define;\n\n(function () {\n    var modules = {},\n    // Stack of moduleIds currently being built.\n        requireStack = [],\n    // Map of module ID -> index into requireStack of modules currently being built.\n        inProgressModules = {},\n        SEPARATOR = \".\";\n\n\n\n    function build(module) {\n        var factory = module.factory,\n            localRequire = function (id) {\n                var resultantId = id;\n                //Its a relative path, so lop off the last portion and add the id (minus \"./\")\n                if (id.charAt(0) === \".\") {\n                    resultantId = module.id.slice(0, module.id.lastIndexOf(SEPARATOR)) + SEPARATOR + id.slice(2);\n                }\n                return require(resultantId);\n            };\n        module.exports = {};\n        delete module.factory;\n        factory(localRequire, module.exports, module);\n        return module.exports;\n    }\n\n    require = function (id) {\n        if (!modules[id]) {\n            throw \"module \" + id + \" not found\";\n        } else if (id in inProgressModules) {\n            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;\n            throw \"Cycle in require graph: \" + cycle;\n        }\n        if (modules[id].factory) {\n            try {\n                inProgressModules[id] = requireStack.length;\n                requireStack.push(id);\n                return build(modules[id]);\n            } finally {\n                delete inProgressModules[id];\n                requireStack.pop();\n            }\n        }\n        return modules[id].exports;\n    };\n\n    define = function (id, factory) {\n        if (modules[id]) {\n            throw \"module \" + id + \" already defined\";\n        }\n\n        modules[id] = {\n            id: id,\n            factory: factory\n        };\n    };\n\n    define.remove = function (id) {\n        delete modules[id];\n    };\n\n    define.moduleMap = modules;\n})();\n\n//Export for use in node\nif (typeof module === \"object\" && typeof require === \"function\") {\n    module.exports.require = require;\n    module.exports.define = define;\n}\n\n// file: src/cordova.js\ndefine(\"cordova\", function(require, exports, module) {\n\n// Workaround for Windows 10 in hosted environment case\n// http://www.w3.org/html/wg/drafts/html/master/browsers.html#named-access-on-the-window-object\nif (window.cordova && !(window.cordova instanceof HTMLElement)) {\n    throw new Error(\"cordova already defined\");\n}\n\n\nvar channel = require('cordova/channel');\nvar platform = require('cordova/platform');\n\n\n/**\n * Intercept calls to addEventListener + removeEventListener and handle deviceready,\n * resume, and pause events.\n */\nvar m_document_addEventListener = document.addEventListener;\nvar m_document_removeEventListener = document.removeEventListener;\nvar m_window_addEventListener = window.addEventListener;\nvar m_window_removeEventListener = window.removeEventListener;\n\n/**\n * Houses custom event handlers to intercept on document + window event listeners.\n */\nvar documentEventHandlers = {},\n    windowEventHandlers = {};\n\ndocument.addEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    if (typeof documentEventHandlers[e] != 'undefined') {\n        documentEventHandlers[e].subscribe(handler);\n    } else {\n        m_document_addEventListener.call(document, evt, handler, capture);\n    }\n};\n\nwindow.addEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    if (typeof windowEventHandlers[e] != 'undefined') {\n        windowEventHandlers[e].subscribe(handler);\n    } else {\n        m_window_addEventListener.call(window, evt, handler, capture);\n    }\n};\n\ndocument.removeEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    // If unsubscribing from an event that is handled by a plugin\n    if (typeof documentEventHandlers[e] != \"undefined\") {\n        documentEventHandlers[e].unsubscribe(handler);\n    } else {\n        m_document_removeEventListener.call(document, evt, handler, capture);\n    }\n};\n\nwindow.removeEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    // If unsubscribing from an event that is handled by a plugin\n    if (typeof windowEventHandlers[e] != \"undefined\") {\n        windowEventHandlers[e].unsubscribe(handler);\n    } else {\n        m_window_removeEventListener.call(window, evt, handler, capture);\n    }\n};\n\nfunction createEvent(type, data) {\n    var event = document.createEvent('Events');\n    event.initEvent(type, false, false);\n    if (data) {\n        for (var i in data) {\n            if (data.hasOwnProperty(i)) {\n                event[i] = data[i];\n            }\n        }\n    }\n    return event;\n}\n\n\nvar cordova = {\n    define:define,\n    require:require,\n    version:PLATFORM_VERSION_BUILD_LABEL,\n    platformVersion:PLATFORM_VERSION_BUILD_LABEL,\n    platformId:platform.id,\n    /**\n     * Methods to add/remove your own addEventListener hijacking on document + window.\n     */\n    addWindowEventHandler:function(event) {\n        return (windowEventHandlers[event] = channel.create(event));\n    },\n    addStickyDocumentEventHandler:function(event) {\n        return (documentEventHandlers[event] = channel.createSticky(event));\n    },\n    addDocumentEventHandler:function(event) {\n        return (documentEventHandlers[event] = channel.create(event));\n    },\n    removeWindowEventHandler:function(event) {\n        delete windowEventHandlers[event];\n    },\n    removeDocumentEventHandler:function(event) {\n        delete documentEventHandlers[event];\n    },\n    /**\n     * Retrieve original event handlers that were replaced by Cordova\n     *\n     * @return object\n     */\n    getOriginalHandlers: function() {\n        return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},\n        'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};\n    },\n    /**\n     * Method to fire event from native code\n     * bNoDetach is required for events which cause an exception which needs to be caught in native code\n     */\n    fireDocumentEvent: function(type, data, bNoDetach) {\n        var evt = createEvent(type, data);\n        if (typeof documentEventHandlers[type] != 'undefined') {\n            if( bNoDetach ) {\n                documentEventHandlers[type].fire(evt);\n            }\n            else {\n                setTimeout(function() {\n                    // Fire deviceready on listeners that were registered before cordova.js was loaded.\n                    if (type == 'deviceready') {\n                        document.dispatchEvent(evt);\n                    }\n                    documentEventHandlers[type].fire(evt);\n                }, 0);\n            }\n        } else {\n            document.dispatchEvent(evt);\n        }\n    },\n    fireWindowEvent: function(type, data) {\n        var evt = createEvent(type,data);\n        if (typeof windowEventHandlers[type] != 'undefined') {\n            setTimeout(function() {\n                windowEventHandlers[type].fire(evt);\n            }, 0);\n        } else {\n            window.dispatchEvent(evt);\n        }\n    },\n\n    /**\n     * Plugin callback mechanism.\n     */\n    // Randomize the starting callbackId to avoid collisions after refreshing or navigating.\n    // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.\n    callbackId: Math.floor(Math.random() * 2000000000),\n    callbacks:  {},\n    callbackStatus: {\n        NO_RESULT: 0,\n        OK: 1,\n        CLASS_NOT_FOUND_EXCEPTION: 2,\n        ILLEGAL_ACCESS_EXCEPTION: 3,\n        INSTANTIATION_EXCEPTION: 4,\n        MALFORMED_URL_EXCEPTION: 5,\n        IO_EXCEPTION: 6,\n        INVALID_ACTION: 7,\n        JSON_EXCEPTION: 8,\n        ERROR: 9\n    },\n\n    /**\n     * Called by native code when returning successful result from an action.\n     */\n    callbackSuccess: function(callbackId, args) {\n        cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);\n    },\n\n    /**\n     * Called by native code when returning error result from an action.\n     */\n    callbackError: function(callbackId, args) {\n        // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.\n        // Derive success from status.\n        cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);\n    },\n\n    /**\n     * Called by native code when returning the result from an action.\n     */\n    callbackFromNative: function(callbackId, isSuccess, status, args, keepCallback) {\n        try {\n            var callback = cordova.callbacks[callbackId];\n            if (callback) {\n                if (isSuccess && status == cordova.callbackStatus.OK) {\n                    callback.success && callback.success.apply(null, args);\n                } else if (!isSuccess) {\n                    callback.fail && callback.fail.apply(null, args);\n                }\n                /*\n                else\n                    Note, this case is intentionally not caught.\n                    this can happen if isSuccess is true, but callbackStatus is NO_RESULT\n                    which is used to remove a callback from the list without calling the callbacks\n                    typically keepCallback is false in this case\n                */\n                // Clear callback if not expecting any more results\n                if (!keepCallback) {\n                    delete cordova.callbacks[callbackId];\n                }\n            }\n        }\n        catch (err) {\n            var msg = \"Error in \" + (isSuccess ? \"Success\" : \"Error\") + \" callbackId: \" + callbackId + \" : \" + err;\n            console && console.log && console.log(msg);\n            cordova.fireWindowEvent(\"cordovacallbackerror\", { 'message': msg });\n            throw err;\n        }\n    },\n    addConstructor: function(func) {\n        channel.onCordovaReady.subscribe(function() {\n            try {\n                func();\n            } catch(e) {\n                console.log(\"Failed to run constructor: \" + e);\n            }\n        });\n    }\n};\n\n\nmodule.exports = cordova;\n\n});\n\n// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/android/nativeapiprovider.js\ndefine(\"cordova/android/nativeapiprovider\", function(require, exports, module) {\n\n/**\n * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi.\n */\n\nvar nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi');\nvar currentApi = nativeApi;\n\nmodule.exports = {\n    get: function() { return currentApi; },\n    setPreferPrompt: function(value) {\n        currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi;\n    },\n    // Used only by tests.\n    set: function(value) {\n        currentApi = value;\n    }\n};\n\n});\n\n// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/android/promptbasednativeapi.js\ndefine(\"cordova/android/promptbasednativeapi\", function(require, exports, module) {\n\n/**\n * Implements the API of ExposedJsApi.java, but uses prompt() to communicate.\n * This is used pre-JellyBean, where addJavascriptInterface() is disabled.\n */\n\nmodule.exports = {\n    exec: function(bridgeSecret, service, action, callbackId, argsJson) {\n        return prompt(argsJson, 'gap:'+JSON.stringify([bridgeSecret, service, action, callbackId]));\n    },\n    setNativeToJsBridgeMode: function(bridgeSecret, value) {\n        prompt(value, 'gap_bridge_mode:' + bridgeSecret);\n    },\n    retrieveJsMessages: function(bridgeSecret, fromOnlineEvent) {\n        return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret);\n    }\n};\n\n});\n\n// file: src/common/argscheck.js\ndefine(\"cordova/argscheck\", function(require, exports, module) {\n\nvar utils = require('cordova/utils');\n\nvar moduleExports = module.exports;\n\nvar typeMap = {\n    'A': 'Array',\n    'D': 'Date',\n    'N': 'Number',\n    'S': 'String',\n    'F': 'Function',\n    'O': 'Object'\n};\n\nfunction extractParamName(callee, argIndex) {\n    return (/.*?\\((.*?)\\)/).exec(callee)[1].split(', ')[argIndex];\n}\n\nfunction checkArgs(spec, functionName, args, opt_callee) {\n    if (!moduleExports.enableChecks) {\n        return;\n    }\n    var errMsg = null;\n    var typeName;\n    for (var i = 0; i < spec.length; ++i) {\n        var c = spec.charAt(i),\n            cUpper = c.toUpperCase(),\n            arg = args[i];\n        // Asterix means allow anything.\n        if (c == '*') {\n            continue;\n        }\n        typeName = utils.typeName(arg);\n        if ((arg === null || arg === undefined) && c == cUpper) {\n            continue;\n        }\n        if (typeName != typeMap[cUpper]) {\n            errMsg = 'Expected ' + typeMap[cUpper];\n            break;\n        }\n    }\n    if (errMsg) {\n        errMsg += ', but got ' + typeName + '.';\n        errMsg = 'Wrong type for parameter \"' + extractParamName(opt_callee || args.callee, i) + '\" of ' + functionName + ': ' + errMsg;\n        // Don't log when running unit tests.\n        if (typeof jasmine == 'undefined') {\n            console.error(errMsg);\n        }\n        throw TypeError(errMsg);\n    }\n}\n\nfunction getValue(value, defaultValue) {\n    return value === undefined ? defaultValue : value;\n}\n\nmoduleExports.checkArgs = checkArgs;\nmoduleExports.getValue = getValue;\nmoduleExports.enableChecks = true;\n\n\n});\n\n// file: src/common/base64.js\ndefine(\"cordova/base64\", function(require, exports, module) {\n\nvar base64 = exports;\n\nbase64.fromArrayBuffer = function(arrayBuffer) {\n    var array = new Uint8Array(arrayBuffer);\n    return uint8ToBase64(array);\n};\n\nbase64.toArrayBuffer = function(str) {\n    var decodedStr = typeof atob != 'undefined' ? atob(str) : new Buffer(str,'base64').toString('binary');\n    var arrayBuffer = new ArrayBuffer(decodedStr.length);\n    var array = new Uint8Array(arrayBuffer);\n    for (var i=0, len=decodedStr.length; i < len; i++) {\n        array[i] = decodedStr.charCodeAt(i);\n    }\n    return arrayBuffer;\n};\n\n//------------------------------------------------------------------------------\n\n/* This code is based on the performance tests at http://jsperf.com/b64tests\n * This 12-bit-at-a-time algorithm was the best performing version on all\n * platforms tested.\n */\n\nvar b64_6bit = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nvar b64_12bit;\n\nvar b64_12bitTable = function() {\n    b64_12bit = [];\n    for (var i=0; i<64; i++) {\n        for (var j=0; j<64; j++) {\n            b64_12bit[i*64+j] = b64_6bit[i] + b64_6bit[j];\n        }\n    }\n    b64_12bitTable = function() { return b64_12bit; };\n    return b64_12bit;\n};\n\nfunction uint8ToBase64(rawData) {\n    var numBytes = rawData.byteLength;\n    var output=\"\";\n    var segment;\n    var table = b64_12bitTable();\n    for (var i=0;i<numBytes-2;i+=3) {\n        segment = (rawData[i] << 16) + (rawData[i+1] << 8) + rawData[i+2];\n        output += table[segment >> 12];\n        output += table[segment & 0xfff];\n    }\n    if (numBytes - i == 2) {\n        segment = (rawData[i] << 16) + (rawData[i+1] << 8);\n        output += table[segment >> 12];\n        output += b64_6bit[(segment & 0xfff) >> 6];\n        output += '=';\n    } else if (numBytes - i == 1) {\n        segment = (rawData[i] << 16);\n        output += table[segment >> 12];\n        output += '==';\n    }\n    return output;\n}\n\n});\n\n// file: src/common/builder.js\ndefine(\"cordova/builder\", function(require, exports, module) {\n\nvar utils = require('cordova/utils');\n\nfunction each(objects, func, context) {\n    for (var prop in objects) {\n        if (objects.hasOwnProperty(prop)) {\n            func.apply(context, [objects[prop], prop]);\n        }\n    }\n}\n\nfunction clobber(obj, key, value) {\n    exports.replaceHookForTesting(obj, key);\n    var needsProperty = false;\n    try {\n        obj[key] = value;\n    } catch (e) {\n        needsProperty = true;\n    }\n    // Getters can only be overridden by getters.\n    if (needsProperty || obj[key] !== value) {\n        utils.defineGetter(obj, key, function() {\n            return value;\n        });\n    }\n}\n\nfunction assignOrWrapInDeprecateGetter(obj, key, value, message) {\n    if (message) {\n        utils.defineGetter(obj, key, function() {\n            console.log(message);\n            delete obj[key];\n            clobber(obj, key, value);\n            return value;\n        });\n    } else {\n        clobber(obj, key, value);\n    }\n}\n\nfunction include(parent, objects, clobber, merge) {\n    each(objects, function (obj, key) {\n        try {\n            var result = obj.path ? require(obj.path) : {};\n\n            if (clobber) {\n                // Clobber if it doesn't exist.\n                if (typeof parent[key] === 'undefined') {\n                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);\n                } else if (typeof obj.path !== 'undefined') {\n                    // If merging, merge properties onto parent, otherwise, clobber.\n                    if (merge) {\n                        recursiveMerge(parent[key], result);\n                    } else {\n                        assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);\n                    }\n                }\n                result = parent[key];\n            } else {\n                // Overwrite if not currently defined.\n                if (typeof parent[key] == 'undefined') {\n                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);\n                } else {\n                    // Set result to what already exists, so we can build children into it if they exist.\n                    result = parent[key];\n                }\n            }\n\n            if (obj.children) {\n                include(result, obj.children, clobber, merge);\n            }\n        } catch(e) {\n            utils.alert('Exception building Cordova JS globals: ' + e + ' for key \"' + key + '\"');\n        }\n    });\n}\n\n/**\n * Merge properties from one object onto another recursively.  Properties from\n * the src object will overwrite existing target property.\n *\n * @param target Object to merge properties into.\n * @param src Object to merge properties from.\n */\nfunction recursiveMerge(target, src) {\n    for (var prop in src) {\n        if (src.hasOwnProperty(prop)) {\n            if (target.prototype && target.prototype.constructor === target) {\n                // If the target object is a constructor override off prototype.\n                clobber(target.prototype, prop, src[prop]);\n            } else {\n                if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {\n                    recursiveMerge(target[prop], src[prop]);\n                } else {\n                    clobber(target, prop, src[prop]);\n                }\n            }\n        }\n    }\n}\n\nexports.buildIntoButDoNotClobber = function(objects, target) {\n    include(target, objects, false, false);\n};\nexports.buildIntoAndClobber = function(objects, target) {\n    include(target, objects, true, false);\n};\nexports.buildIntoAndMerge = function(objects, target) {\n    include(target, objects, true, true);\n};\nexports.recursiveMerge = recursiveMerge;\nexports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;\nexports.replaceHookForTesting = function() {};\n\n});\n\n// file: src/common/channel.js\ndefine(\"cordova/channel\", function(require, exports, module) {\n\nvar utils = require('cordova/utils'),\n    nextGuid = 1;\n\n/**\n * Custom pub-sub \"channel\" that can have functions subscribed to it\n * This object is used to define and control firing of events for\n * cordova initialization, as well as for custom events thereafter.\n *\n * The order of events during page load and Cordova startup is as follows:\n *\n * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.\n * onNativeReady*              Internal event that indicates the Cordova native side is ready.\n * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.\n * onDeviceReady*              User event fired to indicate that Cordova is ready\n * onResume                    User event fired to indicate a start/resume lifecycle event\n * onPause                     User event fired to indicate a pause lifecycle event\n *\n * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.\n * All listeners that subscribe after the event is fired will be executed right away.\n *\n * The only Cordova events that user code should register for are:\n *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript\n *      pause                 App has moved to background\n *      resume                App has returned to foreground\n *\n * Listeners can be registered as:\n *      document.addEventListener(\"deviceready\", myDeviceReadyListener, false);\n *      document.addEventListener(\"resume\", myResumeListener, false);\n *      document.addEventListener(\"pause\", myPauseListener, false);\n *\n * The DOM lifecycle events should be used for saving and restoring state\n *      window.onload\n *      window.onunload\n *\n */\n\n/**\n * Channel\n * @constructor\n * @param type  String the channel name\n */\nvar Channel = function(type, sticky) {\n    this.type = type;\n    // Map of guid -> function.\n    this.handlers = {};\n    // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.\n    this.state = sticky ? 1 : 0;\n    // Used in sticky mode to remember args passed to fire().\n    this.fireArgs = null;\n    // Used by onHasSubscribersChange to know if there are any listeners.\n    this.numHandlers = 0;\n    // Function that is called when the first listener is subscribed, or when\n    // the last listener is unsubscribed.\n    this.onHasSubscribersChange = null;\n},\n    channel = {\n        /**\n         * Calls the provided function only after all of the channels specified\n         * have been fired. All channels must be sticky channels.\n         */\n        join: function(h, c) {\n            var len = c.length,\n                i = len,\n                f = function() {\n                    if (!(--i)) h();\n                };\n            for (var j=0; j<len; j++) {\n                if (c[j].state === 0) {\n                    throw Error('Can only use join with sticky channels.');\n                }\n                c[j].subscribe(f);\n            }\n            if (!len) h();\n        },\n        create: function(type) {\n            return channel[type] = new Channel(type, false);\n        },\n        createSticky: function(type) {\n            return channel[type] = new Channel(type, true);\n        },\n\n        /**\n         * cordova Channels that must fire before \"deviceready\" is fired.\n         */\n        deviceReadyChannelsArray: [],\n        deviceReadyChannelsMap: {},\n\n        /**\n         * Indicate that a feature needs to be initialized before it is ready to be used.\n         * This holds up Cordova's \"deviceready\" event until the feature has been initialized\n         * and Cordova.initComplete(feature) is called.\n         *\n         * @param feature {String}     The unique feature name\n         */\n        waitForInitialization: function(feature) {\n            if (feature) {\n                var c = channel[feature] || this.createSticky(feature);\n                this.deviceReadyChannelsMap[feature] = c;\n                this.deviceReadyChannelsArray.push(c);\n            }\n        },\n\n        /**\n         * Indicate that initialization code has completed and the feature is ready to be used.\n         *\n         * @param feature {String}     The unique feature name\n         */\n        initializationComplete: function(feature) {\n            var c = this.deviceReadyChannelsMap[feature];\n            if (c) {\n                c.fire();\n            }\n        }\n    };\n\nfunction checkSubscriptionArgument(argument) {\n    if (typeof argument !== \"function\" && typeof argument.handleEvent !== \"function\") {\n        throw new Error(\n                \"Must provide a function or an EventListener object \" +\n                \"implementing the handleEvent interface.\"\n        );\n    }\n}\n\n/**\n * Subscribes the given function to the channel. Any time that\n * Channel.fire is called so too will the function.\n * Optionally specify an execution context for the function\n * and a guid that can be used to stop subscribing to the channel.\n * Returns the guid.\n */\nChannel.prototype.subscribe = function(eventListenerOrFunction, eventListener) {\n    checkSubscriptionArgument(eventListenerOrFunction);\n    var handleEvent, guid;\n\n    if (eventListenerOrFunction && typeof eventListenerOrFunction === \"object\") {\n        // Received an EventListener object implementing the handleEvent interface\n        handleEvent = eventListenerOrFunction.handleEvent;\n        eventListener = eventListenerOrFunction;\n    } else {\n        // Received a function to handle event\n        handleEvent = eventListenerOrFunction;\n    }\n\n    if (this.state == 2) {\n        handleEvent.apply(eventListener || this, this.fireArgs);\n        return;\n    }\n\n    guid = eventListenerOrFunction.observer_guid;\n    if (typeof eventListener === \"object\") {\n        handleEvent = utils.close(eventListener, handleEvent);\n    }\n\n    if (!guid) {\n        // First time any channel has seen this subscriber\n        guid = '' + nextGuid++;\n    }\n    handleEvent.observer_guid = guid;\n    eventListenerOrFunction.observer_guid = guid;\n\n    // Don't add the same handler more than once.\n    if (!this.handlers[guid]) {\n        this.handlers[guid] = handleEvent;\n        this.numHandlers++;\n        if (this.numHandlers == 1) {\n            this.onHasSubscribersChange && this.onHasSubscribersChange();\n        }\n    }\n};\n\n/**\n * Unsubscribes the function with the given guid from the channel.\n */\nChannel.prototype.unsubscribe = function(eventListenerOrFunction) {\n    checkSubscriptionArgument(eventListenerOrFunction);\n    var handleEvent, guid, handler;\n\n    if (eventListenerOrFunction && typeof eventListenerOrFunction === \"object\") {\n        // Received an EventListener object implementing the handleEvent interface\n        handleEvent = eventListenerOrFunction.handleEvent;\n    } else {\n        // Received a function to handle event\n        handleEvent = eventListenerOrFunction;\n    }\n\n    guid = handleEvent.observer_guid;\n    handler = this.handlers[guid];\n    if (handler) {\n        delete this.handlers[guid];\n        this.numHandlers--;\n        if (this.numHandlers === 0) {\n            this.onHasSubscribersChange && this.onHasSubscribersChange();\n        }\n    }\n};\n\n/**\n * Calls all functions subscribed to this channel.\n */\nChannel.prototype.fire = function(e) {\n    var fail = false,\n        fireArgs = Array.prototype.slice.call(arguments);\n    // Apply stickiness.\n    if (this.state == 1) {\n        this.state = 2;\n        this.fireArgs = fireArgs;\n    }\n    if (this.numHandlers) {\n        // Copy the values first so that it is safe to modify it from within\n        // callbacks.\n        var toCall = [];\n        for (var item in this.handlers) {\n            toCall.push(this.handlers[item]);\n        }\n        for (var i = 0; i < toCall.length; ++i) {\n            toCall[i].apply(this, fireArgs);\n        }\n        if (this.state == 2 && this.numHandlers) {\n            this.numHandlers = 0;\n            this.handlers = {};\n            this.onHasSubscribersChange && this.onHasSubscribersChange();\n        }\n    }\n};\n\n\n// defining them here so they are ready super fast!\n// DOM event that is received when the web page is loaded and parsed.\nchannel.createSticky('onDOMContentLoaded');\n\n// Event to indicate the Cordova native side is ready.\nchannel.createSticky('onNativeReady');\n\n// Event to indicate that all Cordova JavaScript objects have been created\n// and it's time to run plugin constructors.\nchannel.createSticky('onCordovaReady');\n\n// Event to indicate that all automatically loaded JS plugins are loaded and ready.\n// FIXME remove this\nchannel.createSticky('onPluginsReady');\n\n// Event to indicate that Cordova is ready\nchannel.createSticky('onDeviceReady');\n\n// Event to indicate a resume lifecycle event\nchannel.create('onResume');\n\n// Event to indicate a pause lifecycle event\nchannel.create('onPause');\n\n// Channels that must fire before \"deviceready\" is fired.\nchannel.waitForInitialization('onCordovaReady');\nchannel.waitForInitialization('onDOMContentLoaded');\n\nmodule.exports = channel;\n\n});\n\n// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/exec.js\ndefine(\"cordova/exec\", function(require, exports, module) {\n\n/**\n * Execute a cordova command.  It is up to the native side whether this action\n * is synchronous or asynchronous.  The native side can return:\n *      Synchronous: PluginResult object as a JSON string\n *      Asynchronous: Empty string \"\"\n * If async, the native side will cordova.callbackSuccess or cordova.callbackError,\n * depending upon the result of the action.\n *\n * @param {Function} success    The success callback\n * @param {Function} fail       The fail callback\n * @param {String} service      The name of the service to use\n * @param {String} action       Action to be run in cordova\n * @param {String[]} [args]     Zero or more arguments to pass to the method\n */\nvar cordova = require('cordova'),\n    nativeApiProvider = require('cordova/android/nativeapiprovider'),\n    utils = require('cordova/utils'),\n    base64 = require('cordova/base64'),\n    channel = require('cordova/channel'),\n    jsToNativeModes = {\n        PROMPT: 0,\n        JS_OBJECT: 1\n    },\n    nativeToJsModes = {\n        // Polls for messages using the JS->Native bridge.\n        POLLING: 0,\n        // For LOAD_URL to be viable, it would need to have a work-around for\n        // the bug where the soft-keyboard gets dismissed when a message is sent.\n        LOAD_URL: 1,\n        // For the ONLINE_EVENT to be viable, it would need to intercept all event\n        // listeners (both through addEventListener and window.ononline) as well\n        // as set the navigator property itself.\n        ONLINE_EVENT: 2,\n        EVAL_BRIDGE: 3\n    },\n    jsToNativeBridgeMode,  // Set lazily.\n    nativeToJsBridgeMode = nativeToJsModes.EVAL_BRIDGE,\n    pollEnabled = false,\n    bridgeSecret = -1;\n\nvar messagesFromNative = [];\nvar isProcessing = false;\nvar resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve();\nvar nextTick = resolvedPromise ? function(fn) { resolvedPromise.then(fn); } : function(fn) { setTimeout(fn); };\n\nfunction androidExec(success, fail, service, action, args) {\n    if (bridgeSecret < 0) {\n        // If we ever catch this firing, we'll need to queue up exec()s\n        // and fire them once we get a secret. For now, I don't think\n        // it's possible for exec() to be called since plugins are parsed but\n        // not run until until after onNativeReady.\n        throw new Error('exec() called without bridgeSecret');\n    }\n    // Set default bridge modes if they have not already been set.\n    // By default, we use the failsafe, since addJavascriptInterface breaks too often\n    if (jsToNativeBridgeMode === undefined) {\n        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);\n    }\n\n    // If args is not provided, default to an empty array\n    args = args || [];\n\n    // Process any ArrayBuffers in the args into a string.\n    for (var i = 0; i < args.length; i++) {\n        if (utils.typeName(args[i]) == 'ArrayBuffer') {\n            args[i] = base64.fromArrayBuffer(args[i]);\n        }\n    }\n\n    var callbackId = service + cordova.callbackId++,\n        argsJson = JSON.stringify(args);\n    if (success || fail) {\n        cordova.callbacks[callbackId] = {success:success, fail:fail};\n    }\n\n    var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);\n    // If argsJson was received by Java as null, try again with the PROMPT bridge mode.\n    // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.\n    if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && msgs === \"@Null arguments.\") {\n        androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);\n        androidExec(success, fail, service, action, args);\n        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);\n    } else if (msgs) {\n        messagesFromNative.push(msgs);\n        // Always process async to avoid exceptions messing up stack.\n        nextTick(processMessages);\n    }\n}\n\nandroidExec.init = function() {\n    //CB-11828\n    //This failsafe checks the version of Android and if it's Jellybean, it switches it to\n    //using the Online Event bridge for communicating from Native to JS\n    //\n    //It's ugly, but it's necessary.\n    var check = navigator.userAgent.toLowerCase().match(/android\\s[0-9].[0-9]/);\n    var version_code = check && check[0].match(/4.[0-3].*/);\n    if (version_code != null && nativeToJsBridgeMode == nativeToJsModes.EVAL_BRIDGE) {\n      nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT;\n    }\n\n    bridgeSecret = +prompt('', 'gap_init:' + nativeToJsBridgeMode);\n    channel.onNativeReady.fire();\n};\n\nfunction pollOnceFromOnlineEvent() {\n    pollOnce(true);\n}\n\nfunction pollOnce(opt_fromOnlineEvent) {\n    if (bridgeSecret < 0) {\n        // This can happen when the NativeToJsMessageQueue resets the online state on page transitions.\n        // We know there's nothing to retrieve, so no need to poll.\n        return;\n    }\n    var msgs = nativeApiProvider.get().retrieveJsMessages(bridgeSecret, !!opt_fromOnlineEvent);\n    if (msgs) {\n        messagesFromNative.push(msgs);\n        // Process sync since we know we're already top-of-stack.\n        processMessages();\n    }\n}\n\nfunction pollingTimerFunc() {\n    if (pollEnabled) {\n        pollOnce();\n        setTimeout(pollingTimerFunc, 50);\n    }\n}\n\nfunction hookOnlineApis() {\n    function proxyEvent(e) {\n        cordova.fireWindowEvent(e.type);\n    }\n    // The network module takes care of firing online and offline events.\n    // It currently fires them only on document though, so we bridge them\n    // to window here (while first listening for exec()-releated online/offline\n    // events).\n    window.addEventListener('online', pollOnceFromOnlineEvent, false);\n    window.addEventListener('offline', pollOnceFromOnlineEvent, false);\n    cordova.addWindowEventHandler('online');\n    cordova.addWindowEventHandler('offline');\n    document.addEventListener('online', proxyEvent, false);\n    document.addEventListener('offline', proxyEvent, false);\n}\n\nhookOnlineApis();\n\nandroidExec.jsToNativeModes = jsToNativeModes;\nandroidExec.nativeToJsModes = nativeToJsModes;\n\nandroidExec.setJsToNativeBridgeMode = function(mode) {\n    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {\n        mode = jsToNativeModes.PROMPT;\n    }\n    nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);\n    jsToNativeBridgeMode = mode;\n};\n\nandroidExec.setNativeToJsBridgeMode = function(mode) {\n    if (mode == nativeToJsBridgeMode) {\n        return;\n    }\n    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {\n        pollEnabled = false;\n    }\n\n    nativeToJsBridgeMode = mode;\n    // Tell the native side to switch modes.\n    // Otherwise, it will be set by androidExec.init()\n    if (bridgeSecret >= 0) {\n        nativeApiProvider.get().setNativeToJsBridgeMode(bridgeSecret, mode);\n    }\n\n    if (mode == nativeToJsModes.POLLING) {\n        pollEnabled = true;\n        setTimeout(pollingTimerFunc, 1);\n    }\n};\n\nfunction buildPayload(payload, message) {\n    var payloadKind = message.charAt(0);\n    if (payloadKind == 's') {\n        payload.push(message.slice(1));\n    } else if (payloadKind == 't') {\n        payload.push(true);\n    } else if (payloadKind == 'f') {\n        payload.push(false);\n    } else if (payloadKind == 'N') {\n        payload.push(null);\n    } else if (payloadKind == 'n') {\n        payload.push(+message.slice(1));\n    } else if (payloadKind == 'A') {\n        var data = message.slice(1);\n        payload.push(base64.toArrayBuffer(data));\n    } else if (payloadKind == 'S') {\n        payload.push(window.atob(message.slice(1)));\n    } else if (payloadKind == 'M') {\n        var multipartMessages = message.slice(1);\n        while (multipartMessages !== \"\") {\n            var spaceIdx = multipartMessages.indexOf(' ');\n            var msgLen = +multipartMessages.slice(0, spaceIdx);\n            var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen);\n            multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1);\n            buildPayload(payload, multipartMessage);\n        }\n    } else {\n        payload.push(JSON.parse(message));\n    }\n}\n\n// Processes a single message, as encoded by NativeToJsMessageQueue.java.\nfunction processMessage(message) {\n    var firstChar = message.charAt(0);\n    if (firstChar == 'J') {\n        // This is deprecated on the .java side. It doesn't work with CSP enabled.\n        eval(message.slice(1));\n    } else if (firstChar == 'S' || firstChar == 'F') {\n        var success = firstChar == 'S';\n        var keepCallback = message.charAt(1) == '1';\n        var spaceIdx = message.indexOf(' ', 2);\n        var status = +message.slice(2, spaceIdx);\n        var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);\n        var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);\n        var payloadMessage = message.slice(nextSpaceIdx + 1);\n        var payload = [];\n        buildPayload(payload, payloadMessage);\n        cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);\n    } else {\n        console.log(\"processMessage failed: invalid message: \" + JSON.stringify(message));\n    }\n}\n\nfunction processMessages() {\n    // Check for the reentrant case.\n    if (isProcessing) {\n        return;\n    }\n    if (messagesFromNative.length === 0) {\n        return;\n    }\n    isProcessing = true;\n    try {\n        var msg = popMessageFromQueue();\n        // The Java side can send a * message to indicate that it\n        // still has messages waiting to be retrieved.\n        if (msg == '*' && messagesFromNative.length === 0) {\n            nextTick(pollOnce);\n            return;\n        }\n        processMessage(msg);\n    } finally {\n        isProcessing = false;\n        if (messagesFromNative.length > 0) {\n            nextTick(processMessages);\n        }\n    }\n}\n\nfunction popMessageFromQueue() {\n    var messageBatch = messagesFromNative.shift();\n    if (messageBatch == '*') {\n        return '*';\n    }\n\n    var spaceIdx = messageBatch.indexOf(' ');\n    var msgLen = +messageBatch.slice(0, spaceIdx);\n    var message = messageBatch.substr(spaceIdx + 1, msgLen);\n    messageBatch = messageBatch.slice(spaceIdx + msgLen + 1);\n    if (messageBatch) {\n        messagesFromNative.unshift(messageBatch);\n    }\n    return message;\n}\n\nmodule.exports = androidExec;\n\n});\n\n// file: src/common/exec/proxy.js\ndefine(\"cordova/exec/proxy\", function(require, exports, module) {\n\n\n// internal map of proxy function\nvar CommandProxyMap = {};\n\nmodule.exports = {\n\n    // example: cordova.commandProxy.add(\"Accelerometer\",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);\n    add:function(id,proxyObj) {\n        console.log(\"adding proxy for \" + id);\n        CommandProxyMap[id] = proxyObj;\n        return proxyObj;\n    },\n\n    // cordova.commandProxy.remove(\"Accelerometer\");\n    remove:function(id) {\n        var proxy = CommandProxyMap[id];\n        delete CommandProxyMap[id];\n        CommandProxyMap[id] = null;\n        return proxy;\n    },\n\n    get:function(service,action) {\n        return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );\n    }\n};\n});\n\n// file: src/common/init.js\ndefine(\"cordova/init\", function(require, exports, module) {\n\nvar channel = require('cordova/channel');\nvar cordova = require('cordova');\nvar modulemapper = require('cordova/modulemapper');\nvar platform = require('cordova/platform');\nvar pluginloader = require('cordova/pluginloader');\nvar utils = require('cordova/utils');\n\nvar platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];\n\nfunction logUnfiredChannels(arr) {\n    for (var i = 0; i < arr.length; ++i) {\n        if (arr[i].state != 2) {\n            console.log('Channel not fired: ' + arr[i].type);\n        }\n    }\n}\n\nwindow.setTimeout(function() {\n    if (channel.onDeviceReady.state != 2) {\n        console.log('deviceready has not fired after 5 seconds.');\n        logUnfiredChannels(platformInitChannelsArray);\n        logUnfiredChannels(channel.deviceReadyChannelsArray);\n    }\n}, 5000);\n\n// Replace navigator before any modules are required(), to ensure it happens as soon as possible.\n// We replace it so that properties that can't be clobbered can instead be overridden.\nfunction replaceNavigator(origNavigator) {\n    var CordovaNavigator = function() {};\n    CordovaNavigator.prototype = origNavigator;\n    var newNavigator = new CordovaNavigator();\n    // This work-around really only applies to new APIs that are newer than Function.bind.\n    // Without it, APIs such as getGamepads() break.\n    if (CordovaNavigator.bind) {\n        for (var key in origNavigator) {\n            if (typeof origNavigator[key] == 'function') {\n                newNavigator[key] = origNavigator[key].bind(origNavigator);\n            }\n            else {\n                (function(k) {\n                    utils.defineGetterSetter(newNavigator,key,function() {\n                        return origNavigator[k];\n                    });\n                })(key);\n            }\n        }\n    }\n    return newNavigator;\n}\n\nif (window.navigator) {\n    window.navigator = replaceNavigator(window.navigator);\n}\n\nif (!window.console) {\n    window.console = {\n        log: function(){}\n    };\n}\nif (!window.console.warn) {\n    window.console.warn = function(msg) {\n        this.log(\"warn: \" + msg);\n    };\n}\n\n// Register pause, resume and deviceready channels as events on document.\nchannel.onPause = cordova.addDocumentEventHandler('pause');\nchannel.onResume = cordova.addDocumentEventHandler('resume');\nchannel.onActivated = cordova.addDocumentEventHandler('activated');\nchannel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');\n\n// Listen for DOMContentLoaded and notify our channel subscribers.\nif (document.readyState == 'complete' || document.readyState == 'interactive') {\n    channel.onDOMContentLoaded.fire();\n} else {\n    document.addEventListener('DOMContentLoaded', function() {\n        channel.onDOMContentLoaded.fire();\n    }, false);\n}\n\n// _nativeReady is global variable that the native side can set\n// to signify that the native code is ready. It is a global since\n// it may be called before any cordova JS is ready.\nif (window._nativeReady) {\n    channel.onNativeReady.fire();\n}\n\nmodulemapper.clobbers('cordova', 'cordova');\nmodulemapper.clobbers('cordova/exec', 'cordova.exec');\nmodulemapper.clobbers('cordova/exec', 'Cordova.exec');\n\n// Call the platform-specific initialization.\nplatform.bootstrap && platform.bootstrap();\n\n// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js.\n// The delay allows the attached modules to be defined before the plugin loader looks for them.\nsetTimeout(function() {\n    pluginloader.load(function() {\n        channel.onPluginsReady.fire();\n    });\n}, 0);\n\n/**\n * Create all cordova objects once native side is ready.\n */\nchannel.join(function() {\n    modulemapper.mapModules(window);\n\n    platform.initialize && platform.initialize();\n\n    // Fire event to notify that all objects are created\n    channel.onCordovaReady.fire();\n\n    // Fire onDeviceReady event once page has fully loaded, all\n    // constructors have run and cordova info has been received from native\n    // side.\n    channel.join(function() {\n        require('cordova').fireDocumentEvent('deviceready');\n    }, channel.deviceReadyChannelsArray);\n\n}, platformInitChannelsArray);\n\n\n});\n\n// file: src/common/init_b.js\ndefine(\"cordova/init_b\", function(require, exports, module) {\n\nvar channel = require('cordova/channel');\nvar cordova = require('cordova');\nvar modulemapper = require('cordova/modulemapper');\nvar platform = require('cordova/platform');\nvar pluginloader = require('cordova/pluginloader');\nvar utils = require('cordova/utils');\n\nvar platformInitChannelsArray = [channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady];\n\n// setting exec\ncordova.exec = require('cordova/exec');\n\nfunction logUnfiredChannels(arr) {\n    for (var i = 0; i < arr.length; ++i) {\n        if (arr[i].state != 2) {\n            console.log('Channel not fired: ' + arr[i].type);\n        }\n    }\n}\n\nwindow.setTimeout(function() {\n    if (channel.onDeviceReady.state != 2) {\n        console.log('deviceready has not fired after 5 seconds.');\n        logUnfiredChannels(platformInitChannelsArray);\n        logUnfiredChannels(channel.deviceReadyChannelsArray);\n    }\n}, 5000);\n\n// Replace navigator before any modules are required(), to ensure it happens as soon as possible.\n// We replace it so that properties that can't be clobbered can instead be overridden.\nfunction replaceNavigator(origNavigator) {\n    var CordovaNavigator = function() {};\n    CordovaNavigator.prototype = origNavigator;\n    var newNavigator = new CordovaNavigator();\n    // This work-around really only applies to new APIs that are newer than Function.bind.\n    // Without it, APIs such as getGamepads() break.\n    if (CordovaNavigator.bind) {\n        for (var key in origNavigator) {\n            if (typeof origNavigator[key] == 'function') {\n                newNavigator[key] = origNavigator[key].bind(origNavigator);\n            }\n            else {\n                (function(k) {\n                    utils.defineGetterSetter(newNavigator,key,function() {\n                        return origNavigator[k];\n                    });\n                })(key);\n            }\n        }\n    }\n    return newNavigator;\n}\nif (window.navigator) {\n    window.navigator = replaceNavigator(window.navigator);\n}\n\nif (!window.console) {\n    window.console = {\n        log: function(){}\n    };\n}\nif (!window.console.warn) {\n    window.console.warn = function(msg) {\n        this.log(\"warn: \" + msg);\n    };\n}\n\n// Register pause, resume and deviceready channels as events on document.\nchannel.onPause = cordova.addDocumentEventHandler('pause');\nchannel.onResume = cordova.addDocumentEventHandler('resume');\nchannel.onActivated = cordova.addDocumentEventHandler('activated');\nchannel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');\n\n// Listen for DOMContentLoaded and notify our channel subscribers.\nif (document.readyState == 'complete' || document.readyState == 'interactive') {\n    channel.onDOMContentLoaded.fire();\n} else {\n    document.addEventListener('DOMContentLoaded', function() {\n        channel.onDOMContentLoaded.fire();\n    }, false);\n}\n\n// _nativeReady is global variable that the native side can set\n// to signify that the native code is ready. It is a global since\n// it may be called before any cordova JS is ready.\nif (window._nativeReady) {\n    channel.onNativeReady.fire();\n}\n\n// Call the platform-specific initialization.\nplatform.bootstrap && platform.bootstrap();\n\n// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js.\n// The delay allows the attached modules to be defined before the plugin loader looks for them.\nsetTimeout(function() {\n    pluginloader.load(function() {\n        channel.onPluginsReady.fire();\n    });\n}, 0);\n\n/**\n * Create all cordova objects once native side is ready.\n */\nchannel.join(function() {\n    modulemapper.mapModules(window);\n\n    platform.initialize && platform.initialize();\n\n    // Fire event to notify that all objects are created\n    channel.onCordovaReady.fire();\n\n    // Fire onDeviceReady event once page has fully loaded, all\n    // constructors have run and cordova info has been received from native\n    // side.\n    channel.join(function() {\n        require('cordova').fireDocumentEvent('deviceready');\n    }, channel.deviceReadyChannelsArray);\n\n}, platformInitChannelsArray);\n\n});\n\n// file: src/common/modulemapper.js\ndefine(\"cordova/modulemapper\", function(require, exports, module) {\n\nvar builder = require('cordova/builder'),\n    moduleMap = define.moduleMap,\n    symbolList,\n    deprecationMap;\n\nexports.reset = function() {\n    symbolList = [];\n    deprecationMap = {};\n};\n\nfunction addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {\n    if (!(moduleName in moduleMap)) {\n        throw new Error('Module ' + moduleName + ' does not exist.');\n    }\n    symbolList.push(strategy, moduleName, symbolPath);\n    if (opt_deprecationMessage) {\n        deprecationMap[symbolPath] = opt_deprecationMessage;\n    }\n}\n\n// Note: Android 2.3 does have Function.bind().\nexports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.runs = function(moduleName) {\n    addEntry('r', moduleName, null);\n};\n\nfunction prepareNamespace(symbolPath, context) {\n    if (!symbolPath) {\n        return context;\n    }\n    var parts = symbolPath.split('.');\n    var cur = context;\n    for (var i = 0, part; part = parts[i]; ++i) {\n        cur = cur[part] = cur[part] || {};\n    }\n    return cur;\n}\n\nexports.mapModules = function(context) {\n    var origSymbols = {};\n    context.CDV_origSymbols = origSymbols;\n    for (var i = 0, len = symbolList.length; i < len; i += 3) {\n        var strategy = symbolList[i];\n        var moduleName = symbolList[i + 1];\n        var module = require(moduleName);\n        // <runs/>\n        if (strategy == 'r') {\n            continue;\n        }\n        var symbolPath = symbolList[i + 2];\n        var lastDot = symbolPath.lastIndexOf('.');\n        var namespace = symbolPath.substr(0, lastDot);\n        var lastName = symbolPath.substr(lastDot + 1);\n\n        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;\n        var parentObj = prepareNamespace(namespace, context);\n        var target = parentObj[lastName];\n\n        if (strategy == 'm' && target) {\n            builder.recursiveMerge(target, module);\n        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {\n            if (!(symbolPath in origSymbols)) {\n                origSymbols[symbolPath] = target;\n            }\n            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);\n        }\n    }\n};\n\nexports.getOriginalSymbol = function(context, symbolPath) {\n    var origSymbols = context.CDV_origSymbols;\n    if (origSymbols && (symbolPath in origSymbols)) {\n        return origSymbols[symbolPath];\n    }\n    var parts = symbolPath.split('.');\n    var obj = context;\n    for (var i = 0; i < parts.length; ++i) {\n        obj = obj && obj[parts[i]];\n    }\n    return obj;\n};\n\nexports.reset();\n\n\n});\n\n// file: src/common/modulemapper_b.js\ndefine(\"cordova/modulemapper_b\", function(require, exports, module) {\n\nvar builder = require('cordova/builder'),\n    symbolList = [],\n    deprecationMap;\n\nexports.reset = function() {\n    symbolList = [];\n    deprecationMap = {};\n};\n\nfunction addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {\n    symbolList.push(strategy, moduleName, symbolPath);\n    if (opt_deprecationMessage) {\n        deprecationMap[symbolPath] = opt_deprecationMessage;\n    }\n}\n\n// Note: Android 2.3 does have Function.bind().\nexports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.runs = function(moduleName) {\n    addEntry('r', moduleName, null);\n};\n\nfunction prepareNamespace(symbolPath, context) {\n    if (!symbolPath) {\n        return context;\n    }\n    var parts = symbolPath.split('.');\n    var cur = context;\n    for (var i = 0, part; part = parts[i]; ++i) {\n        cur = cur[part] = cur[part] || {};\n    }\n    return cur;\n}\n\nexports.mapModules = function(context) {\n    var origSymbols = {};\n    context.CDV_origSymbols = origSymbols;\n    for (var i = 0, len = symbolList.length; i < len; i += 3) {\n        var strategy = symbolList[i];\n        var moduleName = symbolList[i + 1];\n        var module = require(moduleName);\n        // <runs/>\n        if (strategy == 'r') {\n            continue;\n        }\n        var symbolPath = symbolList[i + 2];\n        var lastDot = symbolPath.lastIndexOf('.');\n        var namespace = symbolPath.substr(0, lastDot);\n        var lastName = symbolPath.substr(lastDot + 1);\n\n        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;\n        var parentObj = prepareNamespace(namespace, context);\n        var target = parentObj[lastName];\n\n        if (strategy == 'm' && target) {\n            builder.recursiveMerge(target, module);\n        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {\n            if (!(symbolPath in origSymbols)) {\n                origSymbols[symbolPath] = target;\n            }\n            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);\n        }\n    }\n};\n\nexports.getOriginalSymbol = function(context, symbolPath) {\n    var origSymbols = context.CDV_origSymbols;\n    if (origSymbols && (symbolPath in origSymbols)) {\n        return origSymbols[symbolPath];\n    }\n    var parts = symbolPath.split('.');\n    var obj = context;\n    for (var i = 0; i < parts.length; ++i) {\n        obj = obj && obj[parts[i]];\n    }\n    return obj;\n};\n\nexports.reset();\n\n\n});\n\n// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/platform.js\ndefine(\"cordova/platform\", function(require, exports, module) {\n\n// The last resume event that was received that had the result of a plugin call.\nvar lastResumeEvent = null;\n\nmodule.exports = {\n    id: 'android',\n    bootstrap: function() {\n        var channel = require('cordova/channel'),\n            cordova = require('cordova'),\n            exec = require('cordova/exec'),\n            modulemapper = require('cordova/modulemapper');\n\n        // Get the shared secret needed to use the bridge.\n        exec.init();\n\n        // TODO: Extract this as a proper plugin.\n        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');\n\n        var APP_PLUGIN_NAME = Number(cordova.platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';\n\n        // Inject a listener for the backbutton on the document.\n        var backButtonChannel = cordova.addDocumentEventHandler('backbutton');\n        backButtonChannel.onHasSubscribersChange = function() {\n            // If we just attached the first handler or detached the last handler,\n            // let native know we need to override the back button.\n            exec(null, null, APP_PLUGIN_NAME, \"overrideBackbutton\", [this.numHandlers == 1]);\n        };\n\n        // Add hardware MENU and SEARCH button handlers\n        cordova.addDocumentEventHandler('menubutton');\n        cordova.addDocumentEventHandler('searchbutton');\n\n        function bindButtonChannel(buttonName) {\n            // generic button bind used for volumeup/volumedown buttons\n            var volumeButtonChannel = cordova.addDocumentEventHandler(buttonName + 'button');\n            volumeButtonChannel.onHasSubscribersChange = function() {\n                exec(null, null, APP_PLUGIN_NAME, \"overrideButton\", [buttonName, this.numHandlers == 1]);\n            };\n        }\n        // Inject a listener for the volume buttons on the document.\n        bindButtonChannel('volumeup');\n        bindButtonChannel('volumedown');\n\n        // The resume event is not \"sticky\", but it is possible that the event\n        // will contain the result of a plugin call. We need to ensure that the\n        // plugin result is delivered even after the event is fired (CB-10498)\n        var cordovaAddEventListener = document.addEventListener;\n\n        document.addEventListener = function(evt, handler, capture) {\n            cordovaAddEventListener(evt, handler, capture);\n\n            if (evt === 'resume' && lastResumeEvent) {\n                handler(lastResumeEvent);\n            }\n        };\n\n        // Let native code know we are all done on the JS side.\n        // Native code will then un-hide the WebView.\n        channel.onCordovaReady.subscribe(function() {\n            exec(onMessageFromNative, null, APP_PLUGIN_NAME, 'messageChannel', []);\n            exec(null, null, APP_PLUGIN_NAME, \"show\", []);\n        });\n    }\n};\n\nfunction onMessageFromNative(msg) {\n    var cordova = require('cordova');\n    var action = msg.action;\n\n    switch (action)\n    {\n        // Button events\n        case 'backbutton':\n        case 'menubutton':\n        case 'searchbutton':\n        // App life cycle events\n        case 'pause':\n        // Volume events\n        case 'volumedownbutton':\n        case 'volumeupbutton':\n            cordova.fireDocumentEvent(action);\n            break;\n        case 'resume':\n            if(arguments.length > 1 && msg.pendingResult) {\n                if(arguments.length === 2) {\n                    msg.pendingResult.result = arguments[1];\n                } else {\n                    // The plugin returned a multipart message\n                    var res = [];\n                    for(var i = 1; i < arguments.length; i++) {\n                        res.push(arguments[i]);\n                    }\n                    msg.pendingResult.result = res;\n                }\n\n                // Save the plugin result so that it can be delivered to the js\n                // even if they miss the initial firing of the event\n                lastResumeEvent = msg;\n            }\n            cordova.fireDocumentEvent(action, msg);\n            break;\n        default:\n            throw new Error('Unknown event action ' + action);\n    }\n}\n\n});\n\n// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/plugin/android/app.js\ndefine(\"cordova/plugin/android/app\", function(require, exports, module) {\n\nvar exec = require('cordova/exec');\nvar APP_PLUGIN_NAME = Number(require('cordova').platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';\n\nmodule.exports = {\n    /**\n    * Clear the resource cache.\n    */\n    clearCache:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"clearCache\", []);\n    },\n\n    /**\n    * Load the url into the webview or into new browser instance.\n    *\n    * @param url           The URL to load\n    * @param props         Properties that can be passed in to the activity:\n    *      wait: int                           => wait msec before loading URL\n    *      loadingDialog: \"Title,Message\"      => display a native loading dialog\n    *      loadUrlTimeoutValue: int            => time in msec to wait before triggering a timeout error\n    *      clearHistory: boolean              => clear webview history (default=false)\n    *      openExternal: boolean              => open in a new browser (default=false)\n    *\n    * Example:\n    *      navigator.app.loadUrl(\"http://server/myapp/index.html\", {wait:2000, loadingDialog:\"Wait,Loading App\", loadUrlTimeoutValue: 60000});\n    */\n    loadUrl:function(url, props) {\n        exec(null, null, APP_PLUGIN_NAME, \"loadUrl\", [url, props]);\n    },\n\n    /**\n    * Cancel loadUrl that is waiting to be loaded.\n    */\n    cancelLoadUrl:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"cancelLoadUrl\", []);\n    },\n\n    /**\n    * Clear web history in this web view.\n    * Instead of BACK button loading the previous web page, it will exit the app.\n    */\n    clearHistory:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"clearHistory\", []);\n    },\n\n    /**\n    * Go to previous page displayed.\n    * This is the same as pressing the backbutton on Android device.\n    */\n    backHistory:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"backHistory\", []);\n    },\n\n    /**\n    * Override the default behavior of the Android back button.\n    * If overridden, when the back button is pressed, the \"backKeyDown\" JavaScript event will be fired.\n    *\n    * Note: The user should not have to call this method.  Instead, when the user\n    *       registers for the \"backbutton\" event, this is automatically done.\n    *\n    * @param override        T=override, F=cancel override\n    */\n    overrideBackbutton:function(override) {\n        exec(null, null, APP_PLUGIN_NAME, \"overrideBackbutton\", [override]);\n    },\n\n    /**\n    * Override the default behavior of the Android volume button.\n    * If overridden, when the volume button is pressed, the \"volume[up|down]button\"\n    * JavaScript event will be fired.\n    *\n    * Note: The user should not have to call this method.  Instead, when the user\n    *       registers for the \"volume[up|down]button\" event, this is automatically done.\n    *\n    * @param button          volumeup, volumedown\n    * @param override        T=override, F=cancel override\n    */\n    overrideButton:function(button, override) {\n        exec(null, null, APP_PLUGIN_NAME, \"overrideButton\", [button, override]);\n    },\n\n    /**\n    * Exit and terminate the application.\n    */\n    exitApp:function() {\n        return exec(null, null, APP_PLUGIN_NAME, \"exitApp\", []);\n    }\n};\n\n});\n\n// file: src/common/pluginloader.js\ndefine(\"cordova/pluginloader\", function(require, exports, module) {\n\nvar modulemapper = require('cordova/modulemapper');\nvar urlutil = require('cordova/urlutil');\n\n// Helper function to inject a <script> tag.\n// Exported for testing.\nexports.injectScript = function(url, onload, onerror) {\n    var script = document.createElement(\"script\");\n    // onload fires even when script fails loads with an error.\n    script.onload = onload;\n    // onerror fires for malformed URLs.\n    script.onerror = onerror;\n    script.src = url;\n    document.head.appendChild(script);\n};\n\nfunction injectIfNecessary(id, url, onload, onerror) {\n    onerror = onerror || onload;\n    if (id in define.moduleMap) {\n        onload();\n    } else {\n        exports.injectScript(url, function() {\n            if (id in define.moduleMap) {\n                onload();\n            } else {\n                onerror();\n            }\n        }, onerror);\n    }\n}\n\nfunction onScriptLoadingComplete(moduleList, finishPluginLoading) {\n    // Loop through all the plugins and then through their clobbers and merges.\n    for (var i = 0, module; module = moduleList[i]; i++) {\n        if (module.clobbers && module.clobbers.length) {\n            for (var j = 0; j < module.clobbers.length; j++) {\n                modulemapper.clobbers(module.id, module.clobbers[j]);\n            }\n        }\n\n        if (module.merges && module.merges.length) {\n            for (var k = 0; k < module.merges.length; k++) {\n                modulemapper.merges(module.id, module.merges[k]);\n            }\n        }\n\n        // Finally, if runs is truthy we want to simply require() the module.\n        if (module.runs) {\n            modulemapper.runs(module.id);\n        }\n    }\n\n    finishPluginLoading();\n}\n\n// Handler for the cordova_plugins.js content.\n// See plugman's plugin_loader.js for the details of this object.\n// This function is only called if the really is a plugins array that isn't empty.\n// Otherwise the onerror response handler will just call finishPluginLoading().\nfunction handlePluginsObject(path, moduleList, finishPluginLoading) {\n    // Now inject the scripts.\n    var scriptCounter = moduleList.length;\n\n    if (!scriptCounter) {\n        finishPluginLoading();\n        return;\n    }\n    function scriptLoadedCallback() {\n        if (!--scriptCounter) {\n            onScriptLoadingComplete(moduleList, finishPluginLoading);\n        }\n    }\n\n    for (var i = 0; i < moduleList.length; i++) {\n        injectIfNecessary(moduleList[i].id, path + moduleList[i].file, scriptLoadedCallback);\n    }\n}\n\nfunction findCordovaPath() {\n    var path = null;\n    var scripts = document.getElementsByTagName('script');\n    var term = '/cordova.js';\n    for (var n = scripts.length-1; n>-1; n--) {\n        var src = scripts[n].src.replace(/\\?.*$/, ''); // Strip any query param (CB-6007).\n        if (src.indexOf(term) == (src.length - term.length)) {\n            path = src.substring(0, src.length - term.length) + '/';\n            break;\n        }\n    }\n    return path;\n}\n\n// Tries to load all plugins' js-modules.\n// This is an async process, but onDeviceReady is blocked on onPluginsReady.\n// onPluginsReady is fired when there are no plugins to load, or they are all done.\nexports.load = function(callback) {\n    var pathPrefix = findCordovaPath();\n    if (pathPrefix === null) {\n        console.log('Could not find cordova.js script tag. Plugin loading may fail.');\n        pathPrefix = '';\n    }\n    injectIfNecessary('cordova/plugin_list', pathPrefix + 'cordova_plugins.js', function() {\n        var moduleList = require(\"cordova/plugin_list\");\n        handlePluginsObject(pathPrefix, moduleList, callback);\n    }, callback);\n};\n\n\n});\n\n// file: src/common/pluginloader_b.js\ndefine(\"cordova/pluginloader_b\", function(require, exports, module) {\n\nvar modulemapper = require('cordova/modulemapper');\n\n// Handler for the cordova_plugins.js content.\n// See plugman's plugin_loader.js for the details of this object.\nfunction handlePluginsObject(moduleList) {\n    // if moduleList is not defined or empty, we've nothing to do\n    if (!moduleList || !moduleList.length) {\n        return;\n    }\n\n    // Loop through all the modules and then through their clobbers and merges.\n    for (var i = 0, module; module = moduleList[i]; i++) {\n        if (module.clobbers && module.clobbers.length) {\n            for (var j = 0; j < module.clobbers.length; j++) {\n                modulemapper.clobbers(module.id, module.clobbers[j]);\n            }\n        }\n\n        if (module.merges && module.merges.length) {\n            for (var k = 0; k < module.merges.length; k++) {\n                modulemapper.merges(module.id, module.merges[k]);\n            }\n        }\n\n        // Finally, if runs is truthy we want to simply require() the module.\n        if (module.runs) {\n            modulemapper.runs(module.id);\n        }\n    }\n}\n\n// Loads all plugins' js-modules. Plugin loading is syncronous in browserified bundle\n// but the method accepts callback to be compatible with non-browserify flow.\n// onDeviceReady is blocked on onPluginsReady. onPluginsReady is fired when there are\n// no plugins to load, or they are all done.\nexports.load = function(callback) {\n    var moduleList = require(\"cordova/plugin_list\");\n    handlePluginsObject(moduleList);\n\n    callback();\n};\n\n\n});\n\n// file: src/common/urlutil.js\ndefine(\"cordova/urlutil\", function(require, exports, module) {\n\n\n/**\n * For already absolute URLs, returns what is passed in.\n * For relative URLs, converts them to absolute ones.\n */\nexports.makeAbsolute = function makeAbsolute(url) {\n    var anchorEl = document.createElement('a');\n    anchorEl.href = url;\n    return anchorEl.href;\n};\n\n\n});\n\n// file: src/common/utils.js\ndefine(\"cordova/utils\", function(require, exports, module) {\n\nvar utils = exports;\n\n/**\n * Defines a property getter / setter for obj[key].\n */\nutils.defineGetterSetter = function(obj, key, getFunc, opt_setFunc) {\n    if (Object.defineProperty) {\n        var desc = {\n            get: getFunc,\n            configurable: true\n        };\n        if (opt_setFunc) {\n            desc.set = opt_setFunc;\n        }\n        Object.defineProperty(obj, key, desc);\n    } else {\n        obj.__defineGetter__(key, getFunc);\n        if (opt_setFunc) {\n            obj.__defineSetter__(key, opt_setFunc);\n        }\n    }\n};\n\n/**\n * Defines a property getter for obj[key].\n */\nutils.defineGetter = utils.defineGetterSetter;\n\nutils.arrayIndexOf = function(a, item) {\n    if (a.indexOf) {\n        return a.indexOf(item);\n    }\n    var len = a.length;\n    for (var i = 0; i < len; ++i) {\n        if (a[i] == item) {\n            return i;\n        }\n    }\n    return -1;\n};\n\n/**\n * Returns whether the item was found in the array.\n */\nutils.arrayRemove = function(a, item) {\n    var index = utils.arrayIndexOf(a, item);\n    if (index != -1) {\n        a.splice(index, 1);\n    }\n    return index != -1;\n};\n\nutils.typeName = function(val) {\n    return Object.prototype.toString.call(val).slice(8, -1);\n};\n\n/**\n * Returns an indication of whether the argument is an array or not\n */\nutils.isArray = Array.isArray ||\n                function(a) {return utils.typeName(a) == 'Array';};\n\n/**\n * Returns an indication of whether the argument is a Date or not\n */\nutils.isDate = function(d) {\n    return (d instanceof Date);\n};\n\n/**\n * Does a deep clone of the object.\n */\nutils.clone = function(obj) {\n    if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') {\n        return obj;\n    }\n\n    var retVal, i;\n\n    if(utils.isArray(obj)){\n        retVal = [];\n        for(i = 0; i < obj.length; ++i){\n            retVal.push(utils.clone(obj[i]));\n        }\n        return retVal;\n    }\n\n    retVal = {};\n    for(i in obj){\n        // https://issues.apache.org/jira/browse/CB-11522 'unknown' type may be returned in\n        // custom protocol activation case on Windows Phone 8.1 causing \"No such interface supported\" exception\n        // on cloning.\n        if((!(i in retVal) || retVal[i] != obj[i]) && typeof obj[i] != 'undefined' && typeof obj[i] != 'unknown') {\n            retVal[i] = utils.clone(obj[i]);\n        }\n    }\n    return retVal;\n};\n\n/**\n * Returns a wrapped version of the function\n */\nutils.close = function(context, func, params) {\n    return function() {\n        var args = params || arguments;\n        return func.apply(context, args);\n    };\n};\n\n//------------------------------------------------------------------------------\nfunction UUIDcreatePart(length) {\n    var uuidpart = \"\";\n    for (var i=0; i<length; i++) {\n        var uuidchar = parseInt((Math.random() * 256), 10).toString(16);\n        if (uuidchar.length == 1) {\n            uuidchar = \"0\" + uuidchar;\n        }\n        uuidpart += uuidchar;\n    }\n    return uuidpart;\n}\n\n/**\n * Create a UUID\n */\nutils.createUUID = function() {\n    return UUIDcreatePart(4) + '-' +\n        UUIDcreatePart(2) + '-' +\n        UUIDcreatePart(2) + '-' +\n        UUIDcreatePart(2) + '-' +\n        UUIDcreatePart(6);\n};\n\n\n/**\n * Extends a child object from a parent object using classical inheritance\n * pattern.\n */\nutils.extend = (function() {\n    // proxy used to establish prototype chain\n    var F = function() {};\n    // extend Child from Parent\n    return function(Child, Parent) {\n\n        F.prototype = Parent.prototype;\n        Child.prototype = new F();\n        Child.__super__ = Parent.prototype;\n        Child.prototype.constructor = Child;\n    };\n}());\n\n/**\n * Alerts a message in any available way: alert or console.log.\n */\nutils.alert = function(msg) {\n    if (window.alert) {\n        window.alert(msg);\n    } else if (console && console.log) {\n        console.log(msg);\n    }\n};\n\n\n\n\n\n});\n\nwindow.cordova = require('cordova');\n// file: src/scripts/bootstrap.js\n\nrequire('cordova/init');\n\n})();"
  },
  {
    "path": "platforms/android/assets/www/cordova_plugins.js",
    "content": "cordova.define('cordova/plugin_list', function(require, exports, module) {\nmodule.exports = [\n    {\n        \"id\": \"cordova-plugin-splashscreen.SplashScreen\",\n        \"file\": \"plugins/cordova-plugin-splashscreen/www/splashscreen.js\",\n        \"pluginId\": \"cordova-plugin-splashscreen\",\n        \"clobbers\": [\n            \"navigator.splashscreen\"\n        ]\n    },\n    {\n        \"id\": \"phonegap-plugin-barcodescanner.BarcodeScanner\",\n        \"file\": \"plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js\",\n        \"pluginId\": \"phonegap-plugin-barcodescanner\",\n        \"clobbers\": [\n            \"cordova.plugins.barcodeScanner\"\n        ]\n    }\n];\nmodule.exports.metadata = \n// TOP OF METADATA\n{\n    \"cordova-plugin-compat\": \"1.1.0\",\n    \"cordova-plugin-splashscreen\": \"4.0.1\",\n    \"cordova-plugin-whitelist\": \"1.3.1\",\n    \"phonegap-plugin-barcodescanner\": \"6.0.6\"\n};\n// BOTTOM OF METADATA\n});"
  },
  {
    "path": "platforms/android/assets/www/css/responsive.css",
    "content": "/* TABLES */\n@media all and (max-width:500px) {\n    .force-landscape {\n        display: none;\n    }\n}\n@media all and (min-width:500px){\n    .please-rotate {\n        display: none;\n    }\n}\n/* /TABLES */\n\n/* MDL CARD */\n@media all and (min-width:590px) {\n    .pihole-card.pihole-card-floating > .mdl-card__actions > .material-icons{\n        padding-right: 0;\n    }\n\n    .pihole-card.pihole-card-floating > .mdl-card__actions {\n        font-size: 15px;\n    }\n\n    .pihole-card.pihole-card-floating.mdl-card{\n        display: inline-block;\n        width: 46%;\n        margin: 15px 2% 0 0;\n    }\n\n    .pihole-card.pihole-card-floating.mdl-card:nth-child(1),\n    .pihole-card.pihole-card-floating.mdl-card:nth-child(2){\n        margin-top: 0;\n    }\n\n    .pihole-card.pihole-card-floating.mdl-card:nth-of-type(even){\n        margin-right: 0;\n    }\n}\n/* /MDL CARD */"
  },
  {
    "path": "platforms/android/assets/www/css/styles.css",
    "content": "/* GENERAL */\nhtml, body {\n    font-family: 'Roboto', 'Helvetica', sans-serif;\n}\n\n.centered-element {\n    align-items: center;\n    justify-content: center;\n    text-align: center;\n}\n\n#main_content {\n    padding: 25px 0;\n}\n\n.fullwidth {\n    width: 100%;\n}\n\n.mdl-data-table tbody tr:hover {\n    background-color: transparent; \n}\n/* /GENERAL */\n\n/* DRAWER */\n.pihole-drawer {\n    border: none;\n}\n\n.pihole-drawer .mdl-menu .mdl-menu__item {\n    display: -webkit-flex;\n    display: -ms-flexbox;\n    display: flex;\n    -webkit-align-items: center;\n    -ms-flex-align: center;\n    align-items: center;\n}\n\n.pihole-drawer-header {\n    box-sizing: border-box;\n    display: -webkit-flex;\n    display: -ms-flexbox;\n    display: flex;\n    -webkit-flex-direction: column;\n    -ms-flex-direction: column;\n    flex-direction: column;\n    -webkit-justify-content: flex-end;\n    -ms-flex-pack: end;\n    justify-content: flex-end;\n    padding: 16px;\n}\n\n.pihole-avatar-dropdown {\n    display: -webkit-flex;\n    display: -ms-flexbox;\n    display: flex;\n    position: relative;\n    -webkit-flex-direction: row;\n    -ms-flex-direction: row;\n    flex-direction: row;\n    -webkit-align-items: center;\n    -ms-flex-align: center;\n    align-items: center;\n    width: 100%;\n}\n\n.pihole-navigation {\n    -webkit-flex-grow: 1;\n    -ms-flex-positive: 1;\n    flex-grow: 1;\n}\n\n.pihole-layout .pihole-navigation .mdl-navigation__link {\n    display: -webkit-flex !important;\n    display: -ms-flexbox !important;\n    display: flex !important;\n    -webkit-flex-direction: row;\n    -ms-flex-direction: row;\n    flex-direction: row;\n    -webkit-align-items: center;\n    -ms-flex-align: center;\n    align-items: center;\n    font-weight: 500;\n}\n\n.pihole-navigation .mdl-navigation__link .material-icons {\n    margin-right: 32px;\n}\n\n.pihole-drawer .pihole_logo {\n    width: 48px;\n    height: 48px;\n    padding-right: 10px;\n}\n/* /DRAWER */\n\n/* HEADER */\n\n.pihole-header #container-pihole-toggle {\n    padding-right: 10px;\n}\n\n.pihole-header .mdl-switch__thumb {\n    background:#dd4b39;\n}\n\n.pihole-header .mdl-switch.is-checked .mdl-switch__thumb {\n    background: #00a65a;\n}\n\n.pihole-header .mdl-switch.is-checked .mdl-switch__track {\n    background: rgba(0,0,0,.26);\n}\n\n/* /HEADER */\n\n/* CHARTS */\n.pihole-card .ct-chart {\n    margin: 0 auto;\n    width: 100%;\n    text-align: center;\n}\n\n.ct-chart .ct-slice-pie {\n    stroke: white;\n    stroke-width: 2px;\n}\n\n.ct-label {\n    font-size: 15px;\n    fill:#333;\n}\n\n.ct-fill-red {\n    fill:#f56954;\n}\n\n.ct-fill-blue{\n    fill:#3c8dbc;\n}\n\n.ct-fill-light-blue{\n    fill:#00c0ef;\n}\n\n.ct-fill-green{\n    fill:#00a65a;\n}\n\n.ct-fill-orange{\n    fill:#f39c12;\n}\n\n/* /CHARTS */\n\n/* MDL CARD */\n.pihole-card h2 {\n    margin:0;\n}\n\n.material-icons.loading {\n    -webkit-animation:fa-spin 2s infinite linear;\n    animation:fa-spin 2s infinite linear;\n}\n\n@-webkit-keyframes fa-spin {\n    0% {\n        -webkit-transform: rotate(0deg);\n        transform: rotate(0deg);\n    }\n    100% {\n        -webkit-transform: rotate(359deg);\n        transform: rotate(359deg);\n    }\n}\n@keyframes fa-spin {\n    0% {\n        -webkit-transform: rotate(0deg);\n        transform: rotate(0deg);\n    }\n    100% {\n        -webkit-transform: rotate(359deg);\n        transform: rotate(359deg);\n    }\n}\n\n.pihole-card.bg-aqua {     \n    background: #00c0ef;   \n}\n\n.pihole-card.bg-green {     \n    background: #00a65a;   \n}\n\n.pihole-card.bg-yellow {     \n    background: #f39c12;   \n}\n\n.pihole-card.bg-red {     \n    background: #dd4b39;   \n}\n\n.pihole-card.bg-white {\n    background: #fff;        \n}    \n\n.pihole-card.mdl-card {\n    width: 95%;\n    height: auto;\n    margin: 15px auto;\n    min-height: initial;\n}\n\n.pihole-card.mdl-card:first-child{\n    margin-top:0;\n}\n\n.pihole-card > .mdl-card__actions {\n    border-color: rgba(255, 255, 255, 0.2);\n}\n\n.pihole-card > .mdl-card__title {\n    align-items: flex-start;\n}\n\n.pihole-card > .mdl-card__title > h4 {\n    margin-top: 0;\n}\n\n.pihole-card > .mdl-card__actions {\n    display: flex;\n    box-sizing:border-box;\n    align-items: center;\n}\n\n.pihole-card > .mdl-card__actions > .material-icons {\n    padding-right: 10px;\n}\n\n.pihole-card:not(.bg-white) > .mdl-card__title,\n.pihole-card:not(.bg-white) > .mdl-card__actions,\n.pihole-card:not(.bg-white) > .mdl-card__actions > .mdl-button {\n    color: #fff;\n}\n/* /MDL CARD */\n\n/* DATATABLES */\n.dataTables_length,\n.dataTables_filter {\n    margin: 0 15px 15px 15px;\n}\n\ntable.dataTable thead th,\ntable.dataTable thead td,\ntable.dataTable.no-footer{\n    border-bottom: inherit;\n}\n\n@media screen and (max-width: 640px) {\n    .dataTables_wrapper .dataTables_filter {\n        margin-top:0;\n    }\n\n    .dataTables_wrapper .dataTables_length{\n        float:left;\n    }\n\n    .dataTables_wrapper .dataTables_filter {\n        float:right;\n    }\n}\n/* /DATATABLES */\n\n/* SETTINGS */\n.mdl-cell.mdl-card:first-child{\n    margin-top:0;\n}\n\n#form_settings{\n    margin:30px 0 15px 0;\n}\n\n#form_settings .mdl-button {\n    margin: 15px 0 0 0;\n}\n\n.mdl-textfield {\n    width: 100%;\n}\n\n#pihole_token {\n    width:85%;\n    display:inline-block;\n}\n\n#qrcode_scan {\n    float:right;\n    padding-top:5px;\n    opacity:.6;\n}\n/* /SETTINGS */\n\n/* ABOUT&HELP */\nh5 i.material-icons {\n    vertical-align: -4px;\n}\n/* /ABOUT&HELP */\n\n/* QUERYLOG */\n.mdl-chip.mdl-please-wait .material-icons {\n    vertical-align: -6px;\n}\n/* /QUERYLOG */"
  },
  {
    "path": "platforms/android/assets/www/index.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        <title>Pi-hole App</title>\n        <meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">\n        <meta name=\"format-detection\" content=\"telephone=no\">\n        <meta name=\"msapplication-tap-highlight\" content=\"no\">\n        <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width\">\n\n        <!-- styles -->\n        <link rel=\"stylesheet\" href=\"lib/mdl/css/fonts.min.css\">\n        <link rel=\"stylesheet\" href=\"lib/mdl/css/material.icons.min.css\">\n        <link rel=\"stylesheet\" href=\"lib/mdl/css/material.indigo-red.min.css\">\n        <link rel=\"stylesheet\" href=\"lib/chartist/chartist.min.css\">        \n        <link rel=\"stylesheet\" href=\"lib/DataTables/datatables.min.css\"/>\n        <link rel=\"stylesheet\" href=\"css/styles.css\">\n        <link rel=\"stylesheet\" href=\"css/responsive.css\">\n        <!-- /styles -->\n    </head>\n    <body>\n        <div class=\"pihole-layout mdl-layout mdl-js-layout mdl-layout--fixed-drawer mdl-layout--fixed-header\">\n            <header class=\"pihole-header mdl-layout__header\">\n                <div class=\"mdl-layout__header-row\">\n                    <span class=\"mdl-layout-title\"></span>\n                    <div class=\"mdl-layout-spacer\"></div>\n\n                    <!-- Pi-hole toggle -->\n                    <div id=\"container-pihole-toggle\" style=\"display:none\">\n                        <label id=\"label-pihole-toggle\" class=\"mdl-switch mdl-js-switch mdl-js-ripple-effect\" for=\"switch-pihole-toggle\">\n                            <input type=\"checkbox\" id=\"switch-pihole-toggle\" class=\"mdl-switch__input\" checked>\n                            <span class=\"mdl-switch__label\"></span>\n                        </label>\n                    </div>\n                </div>\n            </header>\n\n            <!-- drawer -->\n            <div class=\"pihole-drawer mdl-layout__drawer\">\n                <header id=\"header_loggedin\" style=\"display:none\" class=\"pihole-drawer-header mdl-color--primary-dark mdl-color-text--blue-grey-50\">\n                    <div class=\"pihole-avatar-dropdown\">\n                        <img class=\"pihole_logo\" src=\"img/logo.svg\">\n                        <span>You are logged in</span>\n                        <div class=\"mdl-layout-spacer\"></div>\n                        <button id=\"accbtn\" class=\"mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon\">\n                            <i class=\"material-icons\" role=\"presentation\">arrow_drop_down</i>\n                            <span class=\"visuallyhidden\">Accounts</span>\n                        </button>\n                        <ul class=\"mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect\" for=\"accbtn\">\n                            <li class=\"mdl-menu__item\" id=\"logout\"><i class=\"material-icons\">exit_to_app</i>Logout</li>\n                        </ul>\n                    </div>\n                </header>\n                <header id=\"header_guest\" class=\"pihole-drawer-header mdl-color--primary-dark mdl-color-text--blue-grey-50\">\n                    <div class=\"pihole-avatar-dropdown\">\n                        <img class=\"pihole_logo\" src=\"img/logo.svg\">\n                        <span>You are not logged in</span>\n                        <div class=\"mdl-layout-spacer\"></div>                        \n                    </div>\n                </header>\n                <nav id=\"drawer\" class=\"pihole-navigation mdl-navigation mdl-color--white\">\n                    <a class=\"mdl-navigation__link\" href=\"dashboard\"><i class=\"material-icons\" role=\"presentation\">dashboard</i>Dashboard</a>\n                    <a class=\"mdl-navigation__link\" href=\"query_log\"><i class=\"material-icons\" role=\"presentation\">filter_list</i>Query log</a>\n                    <a class=\"mdl-navigation__link\" href=\"app_settings\"><i class=\"material-icons\" role=\"presentation\">settings</i>App settings</a>\n                    <a class=\"mdl-navigation__link\" href=\"about_help\"><i class=\"material-icons\" role=\"presentation\">help_outline</i>About & Help</a>\n                </nav>\n            </div>\n            <!-- /drawer -->\n\n            <main id=\"main_content\" class=\"mdl-layout__content mdl-color--grey-100\">\n                <!-- the ajax area -->\n            </main>\n        </div>\n\n        <!-- scripts -->\n        <script type=\"text/javascript\" src=\"cordova.js\"></script>   \n        <script type=\"text/javascript\" src=\"lib/jQuery/jquery-3.1.1.min.js\"></script>\n        <script type=\"text/javascript\" src=\"lib/mdl/js/material.min.js\"></script>        \n        <script type=\"text/javascript\" src=\"lib/chartist/chartist.min.js\"></script>\n        <script type=\"text/javascript\" src=\"lib/DataTables/datatables.min.js\"></script>\n        <script type=\"text/javascript\" src=\"lib/hammerjs/hammer.min.js\"></script>\n        <script type=\"text/javascript\" src=\"lib/hammerjs/hammer-time.min.js\"></script>\n        <script type=\"text/javascript\" src=\"js/utilities.js\"></script>\n        <script type=\"text/javascript\" src=\"js/main.js\"></script>        \n        <!-- /scripts -->\n    </body>\n</html>\n"
  },
  {
    "path": "platforms/android/assets/www/js/main.js",
    "content": "/*\n * Check if is a cordova app or browser\n */\n\nvar isCordovaApp = (typeof window.cordova !== \"undefined\");\n\nif (isCordovaApp) {\n    document.addEventListener(\"deviceready\", init, false);\n} else {\n    init();\n}\n\n/*\n * Init app\n */\n\nfunction init() {\n\n    // Bind menu voices\n    $('.pihole-navigation a').click(function (event) {\n        event.preventDefault();\n        mdl_toggleDrawer();\n\n        if ($(this).attr('href') == 'dashboard') {\n            if (getPiholeSuccess()) {\n                pageDashboard();\n                _updateToggleButton();\n            } else {\n                pageAppSettings();\n            }\n        } else if ($(this).attr('href') == 'app_settings') {\n            pageAppSettings();\n        } else if ($(this).attr('href') == 'query_log') {\n            if (getPiholeSuccess()) {\n                pageQueryLog();\n                _updateToggleButton();\n            } else {\n                pageAppSettings();\n            }\n        } else if ($(this).attr('href') == 'about_help') {\n            pageAboutHelp();\n            _updateToggleButton();\n        }\n    });\n\n    // Update current status of toggle button\n    _updateToggleButton();\n\n    // Bind logo click enable/disable\n    $('#label-pihole-toggle input').change(function (evt) {\n        if ($(this).is(':checked')) {\n            if (confirm(\"Do you want to ENABLE Pi-hole's ad blocking?\")) {\n                $.getJSON(getPiholeHost() + \"/admin/api.php?enable&auth=\" + getPiholeToken(), function (response_data) {\n\n                });\n            } else {\n                $('#label-pihole-toggle')[0].MaterialSwitch.off();\n                evt.preventDefault();\n            }\n        } else {\n            if (confirm(\"Do you want to DISABLE Pi-hole's ad blocking?\")) {\n                $.getJSON(getPiholeHost() + \"/admin/api.php?disable&auth=\" + getPiholeToken(), function (response_data) {\n\n                });\n            } else {\n                $('#label-pihole-toggle')[0].MaterialSwitch.on();\n                evt.preventDefault();\n            }\n        }\n    });\n\n    // Bind swipe drawer actions\n    var hammertime_content = new Hammer(document.getElementById('main_content'));\n    hammertime_content.on('swiperight', function () {\n        mdl_toggleDrawer();\n    });\n\n    var hammertime_drawer = new Hammer(document.getElementById('drawer'));\n    hammertime_drawer.on('swipeleft', function () {\n        mdl_toggleDrawer();\n    });\n\n    // Start\n    if (getPiholeHost() && getPiholeToken()) {\n        _manageVisibilityToggle('show');\n        userIsLoggedIn();\n        pageDashboard();\n    } else {\n        pageAppSettings();\n    }\n\n}\n\n/*************************************************************\n * Settings page\n *************************************************************/\n\nfunction pageAppSettings() {\n    $.get(\"partial/app-settings.html\", function (data) {\n        updateAppTitle('<strong>Pi</strong>-hole app settings');\n        $(\"#main_content\").html(data);\n        mdl_upgradeDom();\n\n        // bind go_to_help click\n        $('#go_to_help').click(function () {\n            pageAboutHelp();\n        });\n\n        if (getPiholeHost()) {\n            $('#pihole_host').val(getPiholeHost());\n        }\n\n        if (getPiholeToken()) {\n            $('#pihole_token').val(getPiholeToken());\n        }\n\n        updateFloatLabel();\n\n        document.addEventListener(\"deviceready\", function () {\n            function scanQRCode() {\n                cordova.plugins.barcodeScanner.scan(\n                        function (result) {\n                            if (result.text) {\n                                $('#pihole_token').val(result.text);\n                                updateFloatLabel();\n                            }\n                        },\n                        function (error) {\n                            alert(\"Scanning failed: \" + error);\n                        },\n                        {\n                            preferFrontCamera: false,\n                            showFlipCameraButton: true,\n                            showTorchButton: true,\n                            torchOn: false,\n                            prompt: \"Place Pi-hole QR Code inside the scan area\",\n                            resultDisplayDuration: 0,\n                            formats: \"QR_CODE,PDF_417\",\n                            orientation: \"portrait\"\n                        }\n                );\n            }\n\n            $('#qrcode_scan').click(scanQRCode);\n        });\n\n        $('#form_settings').submit(function (event) {\n            event.preventDefault();\n\n            $(\"#form_settings > button[type='submit']\").html('PLEASE WAIT <i class=\"material-icons loading\">refresh</i>').prop(\"disabled\", true);\n            $(\"#form_settings > button[type='submit'] > .loading\").show();\n\n            var pihole_host = $('#pihole_host').val();\n            var pihole_token = $('#pihole_token').val();\n\n            // check if pihole_host contains http or https, otherwise add http as default\n            // TODO: complete the check\n            if (pihole_host.indexOf(\"http://\") == 0 || pihole_host.indexOf(\"https://\") == 0) {\n\n            }\n\n            _localStorage('save', 'pihole_host', pihole_host);\n            _localStorage('save', 'pihole_token', pihole_token);\n            _localStorage('remove', 'pihole_success');\n\n            $.ajax({\n                type: \"GET\",\n                url: pihole_host + \"/admin/api.php?getQuerySources&auth=\" + pihole_token,\n                success: function (data) {\n                    $.getJSON(pihole_host + \"/admin/api.php?getQuerySources&auth=\" + pihole_token, function (response) {\n                        if (jQuery.isEmptyObject(response)) {\n                            showErrorSettings();\n                        } else {\n                            _localStorage('save', 'pihole_success', 1);\n                            userIsLoggedIn();\n                            _updateToggleButton();\n                            pageDashboard();\n                        }\n                    });\n                },\n                error: function () {\n                    showErrorSettings();\n                }\n            });\n\n        });\n\n    });\n}\n\n/*\n * Show error dialog when settings are wrong\n */\n\nfunction showErrorSettings() {\n    var dialog = document.querySelector('dialog');\n    if (!dialog.showModal) {\n        dialogPolyfill.registerDialog(dialog);\n    }\n    dialog.showModal();\n    dialog.querySelector('.close').addEventListener('click', function () {\n        dialog.close();\n        $(\"#form_settings > button[type='submit']\").html('SAVE').prop(\"disabled\", false);\n    });\n}\n/*************************************************************/\n\n\n/*************************************************************\n * Dashboard page\n *************************************************************/\n\nfunction pageDashboard() {\n    $.get(\"partial/dashboard.html\", function (dataHtml) {\n        updateAppTitle('<strong>Pi</strong>-hole dashboard');\n        $(\"#main_content\").html(dataHtml);\n        mdl_upgradeDom();\n\n        /* summary */\n        var pihole_host = getPiholeHost();\n        var pihole_token = getPiholeToken();\n\n        $.getJSON(pihole_host + \"/admin/api.php?summary&auth=\" + pihole_token, function (response_data) {\n            $('#ads_blocked_today > .mdl-card__title > h2').html(response_data.ads_blocked_today);\n            $('#dns_queries_today > .mdl-card__title > h2').html(response_data.dns_queries_today);\n            $('#ads_percentage_today > .mdl-card__title > h2').html(response_data.ads_percentage_today + '%');\n            $('#domains_being_blocked > .mdl-card__title > h2').html(response_data.domains_being_blocked);\n        });\n\n        /* query types */\n        $.getJSON(pihole_host + \"/admin/api.php?getQueryTypes&auth=\" + pihole_token, function (response_data) {\n\n            var data = {\n                labels: ['A (IPv4)', 'AAAA (IPv6)'],\n                series: [{\n                        value: response_data.querytypes['A (IPv4)'],\n                        className: \"ct-fill-red\"\n                    }, {\n                        value: response_data.querytypes['AAAA (IPv6)'],\n                        className: \"ct-fill-blue\"\n                    }]\n            };\n\n            var options = {\n                height: 300,\n                chartPadding: 50,\n                labelOffset: 85\n            };\n\n            $('.ct-chart-query-types .loading').fadeOut('normal', function () {\n                new Chartist.Pie('.ct-chart-query-types', data, options);\n            });\n        });\n\n\n        /* forward destinations */\n        $.getJSON(pihole_host + \"/admin/api.php?getForwardDestinations&auth=\" + pihole_token, function (response_data) {\n            var labels_array = [];\n            var series_array = [];\n            var colors_array = [\"ct-fill-red\", \"ct-fill-blue\", \"ct-fill-light-blue\", \"ct-fill-orange\", \"ct-fill-green\"];\n\n            $.each(response_data.forward_destinations, function (key, val) {\n\n                // split key for labels\n                var label_array = key.split('|');\n                if (label_array[1]) {\n                    labels_array.push(label_array[1]);\n                } else {\n                    labels_array.push(label_array[0]);\n                }\n\n                serie_value = {value: val, className: colors_array[Math.floor(Math.random() * colors_array.length)]};\n                series_array.push(serie_value);\n            });\n\n            var data = {\n                labels: labels_array,\n                series: series_array\n            };\n\n            var options = {\n                height: 300,\n                chartPadding: 50,\n                labelOffset: 80\n            };\n\n            $('.ct-chart-forward-destinations .loading').fadeOut('normal', function () {\n                new Chartist.Pie('.ct-chart-forward-destinations', data, options);\n            });\n        });\n\n\n        /* top domains + top advertisers */\n        $.getJSON(pihole_host + \"/admin/api.php?topItems&auth=\" + pihole_token, function (response_data) {\n            $.each(response_data, function (key, val) {\n                if (key == 'top_queries') {\n                    if (jQuery.isEmptyObject(val) == false) {\n\n                        // remove loading row and replace it with results\n                        $('#tbody-table-top-queries > tr:first-child').fadeOut(400, function () {\n                            $.each(val, function (domain, domain_hits) {\n                                $('#tbody-table-top-queries:last-child').append('<tr><td class=\"mdl-data-table__cell--non-numeric\">' + domain + '</td><td>' + domain_hits + '</td></tr>');\n                            });\n                        });\n\n                    } else {\n                        // privacy mode enabled, hide the table\n                        $('#tbody-table-top-queries').parents('div.pihole-card').hide();\n                    }\n                } else if (key == 'top_ads') {\n\n                    // remove loading row and replace it with results\n                    $('#tbody-table-top-ads > tr:first-child').fadeOut(400, function () {\n                        $.each(val, function (domain, domain_hits) {\n                            $('#tbody-table-top-ads:last-child').append('<tr><td class=\"mdl-data-table__cell--non-numeric\">' + domain + '</td><td>' + domain_hits + '</td></tr>');\n                        });\n                    });\n\n                }\n            });\n        });\n\n\n        /* top clients */\n        $.getJSON(pihole_host + \"/admin/api.php?getQuerySources&auth=\" + pihole_token, function (response_data) {\n            $.each(response_data, function (key, val) {\n                if (key == 'top_sources') {\n\n                    // remove loading row and replace it with results\n                    $('#tbody-table-top-clients > tr:first-child').fadeOut(400, function () {\n                        $.each(val, function (client, client_hits) {\n                            $('#tbody-table-top-clients:last-child').append('<tr><td class=\"mdl-data-table__cell--non-numeric\">' + client + '</td><td class=\"mdl-data-table__cell--non-numeric\">' + client_hits + '</td></tr>');\n                        });\n                    });\n                }\n            });\n        });\n\n\n        /* recent items */\n        // TODO: forced PHP api version, can't find an alternative on FTL's API\n        $.getJSON(pihole_host + \"/admin/api.php?recentItems=10&PHP&auth=\" + pihole_token, function (response_data) {\n            $.each(response_data, function (key, val) {\n                if (key == 'recent_queries') {\n\n                    // remove loading row and replace it with results\n                    $('#tbody-table-recent-items > tr:first-child').fadeOut(400, function () {\n                        $.each(val, function (key_query, val_query) {\n                            $('#tbody-table-recent-items:last-child').append('<tr><td class=\"mdl-data-table__cell--non-numeric\">' + val_query.time + '</td><td>' + val_query.domain + '</td><td>' + val_query.ip + '</td></tr>');\n                        });\n                    });\n\n                }\n            });\n        });\n    });\n}\n\n/*************************************************************/\n\n\n/*************************************************************\n * Query log page\n *************************************************************/\n\nfunction pageQueryLog() {\n    $.get(\"partial/query-log.html\", function (dataHtml) {\n        updateAppTitle('<strong>Pi</strong>-hole query log');\n        $(\"#main_content\").html(dataHtml);\n        mdl_upgradeDom();\n\n        var pihole_host = getPiholeHost();\n        var pihole_token = getPiholeToken();\n\n        // TODO: add loading to tbody\n        var dataSet = [];\n        $.getJSON(pihole_host + \"/admin/api.php?getAllQueries&auth=\" + pihole_token, function (data) {\n            $.each(data, function (key, val) {\n                $.each(val, function (query) {\n\n                    // replace unnecessary long strings\n                    var client = val[query][3];\n                    var client_short = client.replace('(127.0.0.1)', '');\n\n                    var datetime = val[query][0];\n                    var datetime_short = datetime.replace('T', '<br />');\n\n                    dataSet.push([datetime_short, val[query][1], val[query][2], client_short, val[query][4]]);\n                });\n            });\n\n            $('.mdl-chip.mdl-please-wait').hide();\n\n            $('#query-log-table').DataTable({\n                data: dataSet,\n                order: [[0, \"desc\"]],\n                columns: [\n                    {title: \"Time\", class: \"mdl-data-table__cell--non-numeric fullwidth\"},\n                    {title: \"Type\"},\n                    {title: \"Domain\"},\n                    {title: \"Client\"},\n                    {title: \"Status\"}\n                ]\n            });\n        });\n    });\n}\n\n/*************************************************************/\n\n\n/*************************************************************\n * About&Help page\n *************************************************************/\n\nfunction pageAboutHelp() {\n    $.get(\"partial/about-help.html\", function (data) {\n        updateAppTitle('<strong>Pi</strong>-hole about & help');\n        $(\"#main_content\").html(data);\n        mdl_upgradeDom();\n    });\n}\n\n/*************************************************************/\n\n\n/*************************************************************\n * Helpers\n *************************************************************/\n\n// Get Pi-hole current status\nfunction _updateToggleButton() {\n    var pihole_host = getPiholeHost();\n    var pihole_token = getPiholeToken();\n\n    if (pihole_host && pihole_token) {\n        $.getJSON(pihole_host + \"/admin/api.php?status&auth=\" + pihole_token, function (response_data) {\n            var current_status = response_data.status;\n\n            if (current_status) {\n                _manageVisibilityToggle('show');\n\n                if (current_status == 'disabled') {\n                    $('#label-pihole-toggle')[0].MaterialSwitch.off();\n                } else if (current_status == 'enabled') {\n                    $('#label-pihole-toggle')[0].MaterialSwitch.on();\n                }\n            }\n        });\n    }\n}\n\n/*************************************************************/"
  },
  {
    "path": "platforms/android/assets/www/js/utilities.js",
    "content": "/*\n * Refresh the DOM for MDL dynamic content\n */\n\nfunction mdl_upgradeDom() {\n    componentHandler.upgradeDom();\n}\n\n/*\n * Toggle open/close of Drawer\n */\n\nfunction mdl_toggleDrawer() {\n    var layout = document.querySelector('.mdl-layout');\n    layout.MaterialLayout.toggleDrawer();\n}\n\n/*\n * Handler localStorage\n */\n\nfunction _localStorage(action, key, value) {\n    var storage = window.localStorage;\n\n    if (action == 'get') {\n        return storage.getItem(key);\n    } else if (action == 'save') {\n        if (storage.setItem(key, value)) {\n            return true;\n        }\n    } else if (action == 'remove') {\n        if (storage.removeItem(key)) {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n/*\n * Action to perform when the user is logged in\n */\n\nfunction userIsLoggedIn() {\n    _localStorage('save', 'pihole_success', 1);\n    $('#header_guest').hide();\n    $('#header_loggedin').show();\n\n    $('#logout').click(function (event) {\n        event.preventDefault();\n        _localStorage('remove', 'pihole_success');\n        _localStorage('remove', 'pihole_host');\n        _localStorage('remove', 'pihole_token');\n        userIsGuest();\n        pageAppSettings();\n    });\n}\n\n/*\n * Action to perform when the user is not logged in (guest)\n */\n\nfunction userIsGuest() {\n    $('#header_guest').show();\n    $('#header_loggedin').hide();\n    mdl_toggleDrawer();\n}\n\n/*\n * Get Pihole Hostname\n */\n\nfunction getPiholeHost() {\n    return _localStorage('get', 'pihole_host');\n}\n\n/*\n * Get Pihole Token\n */\n\nfunction getPiholeToken() {\n    return _localStorage('get', 'pihole_token');\n}\n\n/*\n * Get Pihole Success connect flag\n */\n\nfunction getPiholeSuccess() {\n    return _localStorage('get', 'pihole_success');\n}\n\n/*\n * Update MDL float label when there is a value on the input\n */\n\nfunction updateFloatLabel() {\n    var nodeList = document.querySelectorAll('.mdl-textfield');\n\n    Array.prototype.forEach.call(nodeList, function (elem) {\n        elem.MaterialTextfield.checkDirty();\n    });\n}\n\n/*\n * Update the App title according to active page\n */\n\nfunction updateAppTitle(title) {\n    $('.mdl-layout-title').html(title);\n}\n\n/*\n * Manage visibility of toggle button\n */\n\nfunction _manageVisibilityToggle(action) {\n    if(action == 'show') {\n        $('#container-pihole-toggle').show();\n    } else if(action == 'hide') {\n        $('#container-pihole-toggle').hide();\n    }\n}"
  },
  {
    "path": "platforms/android/assets/www/lib/DataTables/DataTables-1.10.13/css/dataTables.bootstrap.css",
    "content": "table.dataTable {\n  clear: both;\n  margin-top: 6px !important;\n  margin-bottom: 6px !important;\n  max-width: none !important;\n  border-collapse: separate !important;\n}\ntable.dataTable td,\ntable.dataTable th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable td.dataTables_empty,\ntable.dataTable th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.nowrap th,\ntable.dataTable.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper div.dataTables_length label {\n  font-weight: normal;\n  text-align: left;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_length select {\n  width: 75px;\n  display: inline-block;\n}\ndiv.dataTables_wrapper div.dataTables_filter {\n  text-align: right;\n}\ndiv.dataTables_wrapper div.dataTables_filter label {\n  font-weight: normal;\n  white-space: nowrap;\n  text-align: left;\n}\ndiv.dataTables_wrapper div.dataTables_filter input {\n  margin-left: 0.5em;\n  display: inline-block;\n  width: auto;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 8px;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_paginate {\n  margin: 0;\n  white-space: nowrap;\n  text-align: right;\n}\ndiv.dataTables_wrapper div.dataTables_paginate ul.pagination {\n  margin: 2px 0;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  margin-top: -26px;\n  text-align: center;\n  padding: 1em 0;\n}\n\ntable.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting,\ntable.dataTable thead > tr > td.sorting_asc,\ntable.dataTable thead > tr > td.sorting_desc,\ntable.dataTable thead > tr > td.sorting {\n  padding-right: 30px;\n}\ntable.dataTable thead > tr > th:active,\ntable.dataTable thead > tr > td:active {\n  outline: none;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  cursor: pointer;\n  position: relative;\n}\ntable.dataTable thead .sorting:after,\ntable.dataTable thead .sorting_asc:after,\ntable.dataTable thead .sorting_desc:after,\ntable.dataTable thead .sorting_asc_disabled:after,\ntable.dataTable thead .sorting_desc_disabled:after {\n  position: absolute;\n  bottom: 8px;\n  right: 8px;\n  display: block;\n  font-family: 'Glyphicons Halflings';\n  opacity: 0.5;\n}\ntable.dataTable thead .sorting:after {\n  opacity: 0.2;\n  content: \"\\e150\";\n  /* sort */\n}\ntable.dataTable thead .sorting_asc:after {\n  content: \"\\e155\";\n  /* sort-by-attributes */\n}\ntable.dataTable thead .sorting_desc:after {\n  content: \"\\e156\";\n  /* sort-by-attributes-alt */\n}\ntable.dataTable thead .sorting_asc_disabled:after,\ntable.dataTable thead .sorting_desc_disabled:after {\n  color: #eee;\n}\n\ndiv.dataTables_scrollHead table.dataTable {\n  margin-bottom: 0 !important;\n}\n\ndiv.dataTables_scrollBody table {\n  border-top: none;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\ndiv.dataTables_scrollBody table thead .sorting:after,\ndiv.dataTables_scrollBody table thead .sorting_asc:after,\ndiv.dataTables_scrollBody table thead .sorting_desc:after {\n  display: none;\n}\ndiv.dataTables_scrollBody table tbody tr:first-child th,\ndiv.dataTables_scrollBody table tbody tr:first-child td {\n  border-top: none;\n}\n\ndiv.dataTables_scrollFoot table {\n  margin-top: 0 !important;\n  border-top: none;\n}\n\n@media screen and (max-width: 767px) {\n  div.dataTables_wrapper div.dataTables_length,\n  div.dataTables_wrapper div.dataTables_filter,\n  div.dataTables_wrapper div.dataTables_info,\n  div.dataTables_wrapper div.dataTables_paginate {\n    text-align: center;\n  }\n}\ntable.dataTable.table-condensed > thead > tr > th {\n  padding-right: 20px;\n}\ntable.dataTable.table-condensed .sorting:after,\ntable.dataTable.table-condensed .sorting_asc:after,\ntable.dataTable.table-condensed .sorting_desc:after {\n  top: 6px;\n  right: 6px;\n}\n\ntable.table-bordered.dataTable th,\ntable.table-bordered.dataTable td {\n  border-left-width: 0;\n}\ntable.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child,\ntable.table-bordered.dataTable td:last-child,\ntable.table-bordered.dataTable td:last-child {\n  border-right-width: 0;\n}\ntable.table-bordered.dataTable tbody th,\ntable.table-bordered.dataTable tbody td {\n  border-bottom-width: 0;\n}\n\ndiv.dataTables_scrollHead table.table-bordered {\n  border-bottom-width: 0;\n}\n\ndiv.table-responsive > div.dataTables_wrapper > div.row {\n  margin: 0;\n}\ndiv.table-responsive > div.dataTables_wrapper > div.row > div[class^=\"col-\"]:first-child {\n  padding-left: 0;\n}\ndiv.table-responsive > div.dataTables_wrapper > div.row > div[class^=\"col-\"]:last-child {\n  padding-right: 0;\n}\n"
  },
  {
    "path": "platforms/android/assets/www/lib/DataTables/DataTables-1.10.13/css/dataTables.foundation.css",
    "content": "table.dataTable {\n  clear: both;\n  margin: 0.5em 0 !important;\n  max-width: none !important;\n  width: 100%;\n}\ntable.dataTable td,\ntable.dataTable th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable td.dataTables_empty,\ntable.dataTable th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper {\n  position: relative;\n}\ndiv.dataTables_wrapper div.dataTables_length label {\n  float: left;\n  text-align: left;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_length select {\n  width: 75px;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter label {\n  float: right;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter input {\n  display: inline-block !important;\n  width: auto !important;\n  margin-bottom: 0;\n  margin-left: 0.5em;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 2px;\n}\ndiv.dataTables_wrapper div.dataTables_paginate {\n  float: right;\n  margin: 0;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  margin-top: -26px;\n  text-align: center;\n  padding: 1rem 0;\n}\n\ntable.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting,\ntable.dataTable thead > tr > td.sorting_asc,\ntable.dataTable thead > tr > td.sorting_desc,\ntable.dataTable thead > tr > td.sorting {\n  padding-right: 1.5rem;\n}\ntable.dataTable thead > tr > th:active,\ntable.dataTable thead > tr > td:active {\n  outline: none;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc {\n  cursor: pointer;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"../images/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"../images/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"../images/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"../images/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"../images/sort_desc_disabled.png\");\n}\n\ndiv.dataTables_scrollHead table {\n  margin-bottom: 0 !important;\n}\n\ndiv.dataTables_scrollBody table {\n  border-top: none;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\ndiv.dataTables_scrollBody table tbody tr:first-child th,\ndiv.dataTables_scrollBody table tbody tr:first-child td {\n  border-top: none;\n}\n\ndiv.dataTables_scrollFoot table {\n  margin-top: 0 !important;\n  border-top: none;\n}\n"
  },
  {
    "path": "platforms/android/assets/www/lib/DataTables/DataTables-1.10.13/css/dataTables.jqueryui.css",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: #f6f6f6;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #fafafa;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #fafafa;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fcfcfc;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fefefe;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ececec;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #efefef;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em 1em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #979797;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  color: white !important;\n  border: 1px solid #111;\n  background-color: #585858;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #585858 0%, #111 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #585858 0%, #111 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #585858 0%, #111 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #585858 0%, #111 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  background-color: #2b2b2b;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);\n  /* W3C */\n  box-shadow: inset 0 0 3px #111;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td {\n  vertical-align: middle;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}\ntable.dataTable thead th div.DataTables_sort_wrapper {\n  position: relative;\n}\ntable.dataTable thead th div.DataTables_sort_wrapper span {\n  position: absolute;\n  top: 50%;\n  margin-top: -8px;\n  right: -18px;\n}\ntable.dataTable thead th.ui-state-default,\ntable.dataTable tfoot th.ui-state-default {\n  border-left-width: 0;\n}\ntable.dataTable thead th.ui-state-default:first-child,\ntable.dataTable tfoot th.ui-state-default:first-child {\n  border-left-width: 1px;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper .dataTables_paginate .fg-button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  border: 1px solid transparent;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:active {\n  outline: none;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:first-child {\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:last-child {\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.dataTables_wrapper .ui-widget-header {\n  font-weight: normal;\n}\n.dataTables_wrapper .ui-toolbar {\n  padding: 8px;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: none;\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: inherit;\n}\n"
  },
  {
    "path": "platforms/android/assets/www/lib/DataTables/DataTables-1.10.13/css/dataTables.semanticui.css",
    "content": "/*\n * Styling for DataTables with Semantic UI\n */\ntable.dataTable.table {\n  margin: 0;\n}\ntable.dataTable.table thead th,\ntable.dataTable.table thead td {\n  position: relative;\n}\ntable.dataTable.table thead th.sorting, table.dataTable.table thead th.sorting_asc, table.dataTable.table thead th.sorting_desc,\ntable.dataTable.table thead td.sorting,\ntable.dataTable.table thead td.sorting_asc,\ntable.dataTable.table thead td.sorting_desc {\n  padding-right: 20px;\n}\ntable.dataTable.table thead th.sorting:after, table.dataTable.table thead th.sorting_asc:after, table.dataTable.table thead th.sorting_desc:after,\ntable.dataTable.table thead td.sorting:after,\ntable.dataTable.table thead td.sorting_asc:after,\ntable.dataTable.table thead td.sorting_desc:after {\n  position: absolute;\n  top: 12px;\n  right: 8px;\n  display: block;\n  font-family: Icons;\n}\ntable.dataTable.table thead th.sorting:after,\ntable.dataTable.table thead td.sorting:after {\n  content: \"\\f0dc\";\n  color: #ddd;\n  font-size: 0.8em;\n}\ntable.dataTable.table thead th.sorting_asc:after,\ntable.dataTable.table thead td.sorting_asc:after {\n  content: \"\\f0de\";\n}\ntable.dataTable.table thead th.sorting_desc:after,\ntable.dataTable.table thead td.sorting_desc:after {\n  content: \"\\f0dd\";\n}\ntable.dataTable.table td,\ntable.dataTable.table th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable.table td.dataTables_empty,\ntable.dataTable.table th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.table.nowrap th,\ntable.dataTable.table.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper div.dataTables_length select {\n  vertical-align: middle;\n  min-height: 2.7142em;\n}\ndiv.dataTables_wrapper div.dataTables_length .ui.selection.dropdown {\n  min-width: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter input {\n  margin-left: 0.5em;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 13px;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  text-align: center;\n}\ndiv.dataTables_wrapper div.row.dt-table {\n  padding: 0;\n}\ndiv.dataTables_wrapper div.dataTables_scrollHead table.dataTable {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n  border-bottom: none;\n}\ndiv.dataTables_wrapper div.dataTables_scrollBody thead .sorting:after,\ndiv.dataTables_wrapper div.dataTables_scrollBody thead .sorting_asc:after,\ndiv.dataTables_wrapper div.dataTables_scrollBody thead .sorting_desc:after {\n  display: none;\n}\ndiv.dataTables_wrapper div.dataTables_scrollBody table.dataTable {\n  border-radius: 0;\n  border-top: none;\n  border-bottom-width: 0;\n}\ndiv.dataTables_wrapper div.dataTables_scrollBody table.dataTable.no-footer {\n  border-bottom-width: 1px;\n}\ndiv.dataTables_wrapper div.dataTables_scrollFoot table.dataTable {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n  border-top: none;\n}\n"
  },
  {
    "path": "platforms/android/assets/www/lib/DataTables/DataTables-1.10.13/css/jquery.dataTables.css",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px;\n  border-bottom: 1px solid #111;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n  border-top: 1px solid #111;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc {\n  cursor: pointer;\n  *cursor: hand;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"../images/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"../images/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"../images/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"../images/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"../images/sort_desc_disabled.png\");\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: #f6f6f6;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #fafafa;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #fafafa;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fcfcfc;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fefefe;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ececec;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #efefef;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em 1em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #979797;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  color: white !important;\n  border: 1px solid #111;\n  background-color: #585858;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #585858 0%, #111 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #585858 0%, #111 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #585858 0%, #111 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #585858 0%, #111 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  background-color: #2b2b2b;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);\n  /* W3C */\n  box-shadow: inset 0 0 3px #111;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td {\n  vertical-align: middle;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}\n"
  },
  {
    "path": "platforms/android/assets/www/lib/DataTables/DataTables-1.10.13/css/jquery.dataTables_themeroller.css",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable thead td,\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 4px 10px;\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting {\n  cursor: pointer;\n  *cursor: hand;\n}\ntable.dataTable thead th div.DataTables_sort_wrapper {\n  position: relative;\n  padding-right: 10px;\n}\ntable.dataTable thead th div.DataTables_sort_wrapper span {\n  position: absolute;\n  top: 50%;\n  margin-top: -8px;\n  right: -5px;\n}\ntable.dataTable thead th.ui-state-default {\n  border-right-width: 0;\n}\ntable.dataTable thead th.ui-state-default:last-child {\n  border-right-width: 1px;\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable th.center,\ntable.dataTable td.center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.right,\ntable.dataTable td.right {\n  text-align: right;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #abb9d3;\n}\ntable.dataTable.hover tbody tr:hover,\ntable.dataTable.hover tbody tr.odd:hover,\ntable.dataTable.hover tbody tr.even:hover, table.dataTable.display tbody tr:hover,\ntable.dataTable.display tbody tr.odd:hover,\ntable.dataTable.display tbody tr.even:hover {\n  background-color: whitesmoke;\n}\ntable.dataTable.hover tbody tr:hover.selected,\ntable.dataTable.hover tbody tr.odd:hover.selected,\ntable.dataTable.hover tbody tr.even:hover.selected, table.dataTable.display tbody tr:hover.selected,\ntable.dataTable.display tbody tr.odd:hover.selected,\ntable.dataTable.display tbody tr.even:hover.selected {\n  background-color: #a9b7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #f9f9f9;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad4;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b3cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a7b5ce;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b6d0;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #f9f9f9;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fbfbfb;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fdfdfd;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad4;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #adbbd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1,\ntable.dataTable.display tbody tr.odd:hover > .sorting_1,\ntable.dataTable.display tbody tr.even:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1,\ntable.dataTable.order-column.hover tbody tr.odd:hover > .sorting_1,\ntable.dataTable.order-column.hover tbody tr.even:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2,\ntable.dataTable.display tbody tr.odd:hover > .sorting_2,\ntable.dataTable.display tbody tr.even:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2,\ntable.dataTable.order-column.hover tbody tr.odd:hover > .sorting_2,\ntable.dataTable.order-column.hover tbody tr.even:hover > .sorting_2 {\n  background-color: #ebebeb;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3,\ntable.dataTable.display tbody tr.odd:hover > .sorting_3,\ntable.dataTable.display tbody tr.even:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3,\ntable.dataTable.order-column.hover tbody tr.odd:hover > .sorting_3,\ntable.dataTable.order-column.hover tbody tr.even:hover > .sorting_3 {\n  background-color: #eeeeee;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1,\ntable.dataTable.display tbody tr.odd:hover.selected > .sorting_1,\ntable.dataTable.display tbody tr.even:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1,\ntable.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_1,\ntable.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_1 {\n  background-color: #a1aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2,\ntable.dataTable.display tbody tr.odd:hover.selected > .sorting_2,\ntable.dataTable.display tbody tr.even:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2,\ntable.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_2,\ntable.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_2 {\n  background-color: #a2afc8;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3,\ntable.dataTable.display tbody tr.odd:hover.selected > .sorting_3,\ntable.dataTable.display tbody tr.even:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3,\ntable.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_3,\ntable.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_3 {\n  background-color: #a4b2cb;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 5px 9px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 5px 9px 3px 9px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px 5px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.55em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:active {\n  outline: none;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:first-child {\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:last-child {\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .ui-widget-header {\n  font-weight: normal;\n}\n.dataTables_wrapper .ui-toolbar {\n  padding: 8px;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter,\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter,\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n"
  },
  {
    "path": "platforms/android/assets/www/lib/DataTables/DataTables-1.10.13/js/dataTables.bootstrap.js",
    "content": "/*! DataTables Bootstrap 3 integration\n * ©2011-2015 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Bootstrap 3. This requires Bootstrap 3 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t// Require DataTables, which attaches to jQuery, including\n\t\t\t\t// jQuery if needed and have a $ property so we can access the\n\t\t\t\t// jQuery object that is used\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'row'<'col-sm-6'l><'col-sm-6'f>>\" +\n\t\t\"<'row'<'col-sm-12'tr>>\" +\n\t\t\"<'row'<'col-sm-5'i><'col-sm-7'p>>\",\n\trenderer: 'bootstrap'\n} );\n\n\n/* Default class modification */\n$.extend( DataTable.ext.classes, {\n\tsWrapper:      \"dataTables_wrapper form-inline dt-bootstrap\",\n\tsFilterInput:  \"form-control input-sm\",\n\tsLengthSelect: \"form-control input-sm\",\n\tsProcessing:   \"dataTables_processing panel panel-default\"\n} );\n\n\n/* Bootstrap paging button renderer */\nDataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api     = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang    = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass, counter=0;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'disabled';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'active' : '';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<li>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append( $('<a>', {\n\t\t\t\t\t\t\t\t'href': '#',\n\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\n\t\t\t\t\tcounter++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t// inside an iframe or frame. \n\tvar activeEl;\n\n\ttry {\n\t\t// Because this approach is destroying and recreating the paging\n\t\t// elements, focus is lost on the select button which is bad for\n\t\t// accessibility. So we want to restore focus once the draw has\n\t\t// completed\n\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t}\n\tcatch (e) {}\n\n\tattach(\n\t\t$(host).empty().html('<ul class=\"pagination\"/>').children('ul'),\n\t\tbuttons\n\t);\n\n\tif ( activeEl !== undefined ) {\n\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t}\n};\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "platforms/android/assets/www/lib/DataTables/DataTables-1.10.13/js/dataTables.foundation.js",
    "content": "/*! DataTables Foundation integration\n * ©2011-2015 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Foundation. This requires Foundation 5 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Foundation. See http://datatables.net/manual/styling/foundation\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n// Detect Foundation 5 / 6 as they have different element and class requirements\nvar meta = $('<meta class=\"foundation-mq\"/>').appendTo('head');\nDataTable.ext.foundationVersion = meta.css('font-family').match(/small|medium|large/) ? 6 : 5;\nmeta.remove();\n\n\n$.extend( DataTable.ext.classes, {\n\tsWrapper:    \"dataTables_wrapper dt-foundation\",\n\tsProcessing: \"dataTables_processing panel callout\"\n} );\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'row'<'small-6 columns'l><'small-6 columns'f>r>\"+\n\t\t\"t\"+\n\t\t\"<'row'<'small-6 columns'i><'small-6 columns'p>>\",\n\trenderer: 'foundation'\n} );\n\n\n/* Page button renderer */\nDataTable.ext.renderer.pageButton.foundation = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass;\n\tvar tag;\n\tvar v5 = DataTable.ext.foundationVersion === 5;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('unavailable') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\t\t\t\ttag = null;\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'unavailable disabled';\n\t\t\t\t\t\ttag = null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page > 0 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page > 0 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page < pages-1 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page < pages-1 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'current' : '';\n\t\t\t\t\t\ttag = page === button ?\n\t\t\t\t\t\t\tnull : 'a';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( v5 ) {\n\t\t\t\t\ttag = 'a';\n\t\t\t\t}\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<li>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append( tag ?\n\t\t\t\t\t\t\t$('<'+tag+'/>', {'href': '#'} ).html( btnDisplay ) :\n\t\t\t\t\t\t\tbtnDisplay\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tattach(\n\t\t$(host).empty().html('<ul class=\"pagination\"/>').children('ul'),\n\t\tbuttons\n\t);\n};\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "platforms/android/assets/www/lib/DataTables/DataTables-1.10.13/js/dataTables.jqueryui.js",
    "content": "/*! DataTables jQuery UI integration\n * ©2011-2014 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for jQuery UI. This requires jQuery UI and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using jQuery UI. See http://datatables.net/manual/styling/jqueryui\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar sort_prefix = 'css_right ui-icon ui-icon-';\nvar toolbar_prefix = 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix ui-corner-';\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t'<\"'+toolbar_prefix+'tl ui-corner-tr\"lfr>'+\n\t\t't'+\n\t\t'<\"'+toolbar_prefix+'bl ui-corner-br\"ip>',\n\trenderer: 'jqueryui'\n} );\n\n\n$.extend( DataTable.ext.classes, {\n\t\"sWrapper\":            \"dataTables_wrapper dt-jqueryui\",\n\n\t/* Full numbers paging buttons */\n\t\"sPageButton\":         \"fg-button ui-button ui-state-default\",\n\t\"sPageButtonActive\":   \"ui-state-disabled\",\n\t\"sPageButtonDisabled\": \"ui-state-disabled\",\n\n\t/* Features */\n\t\"sPaging\": \"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi \"+\n\t\t\"ui-buttonset-multi paging_\", /* Note that the type is postfixed */\n\n\t/* Sorting */\n\t\"sSortAsc\":            \"ui-state-default sorting_asc\",\n\t\"sSortDesc\":           \"ui-state-default sorting_desc\",\n\t\"sSortable\":           \"ui-state-default sorting\",\n\t\"sSortableAsc\":        \"ui-state-default sorting_asc_disabled\",\n\t\"sSortableDesc\":       \"ui-state-default sorting_desc_disabled\",\n\t\"sSortableNone\":       \"ui-state-default sorting_disabled\",\n\t\"sSortIcon\":           \"DataTables_sort_icon\",\n\n\t/* Scrolling */\n\t\"sScrollHead\": \"dataTables_scrollHead \"+\"ui-state-default\",\n\t\"sScrollFoot\": \"dataTables_scrollFoot \"+\"ui-state-default\",\n\n\t/* Misc */\n\t\"sHeaderTH\":  \"ui-state-default\",\n\t\"sFooterTH\":  \"ui-state-default\"\n} );\n\n\nDataTable.ext.renderer.header.jqueryui = function ( settings, cell, column, classes ) {\n\t// Calculate what the unsorted class should be\n\tvar noSortAppliedClass = sort_prefix+'carat-2-n-s';\n\tvar asc = $.inArray('asc', column.asSorting) !== -1;\n\tvar desc = $.inArray('desc', column.asSorting) !== -1;\n\n\tif ( !column.bSortable || (!asc && !desc) ) {\n\t\tnoSortAppliedClass = '';\n\t}\n\telse if ( asc && !desc ) {\n\t\tnoSortAppliedClass = sort_prefix+'carat-1-n';\n\t}\n\telse if ( !asc && desc ) {\n\t\tnoSortAppliedClass = sort_prefix+'carat-1-s';\n\t}\n\n\t// Setup the DOM structure\n\t$('<div/>')\n\t\t.addClass( 'DataTables_sort_wrapper' )\n\t\t.append( cell.contents() )\n\t\t.append( $('<span/>')\n\t\t\t.addClass( classes.sSortIcon+' '+noSortAppliedClass )\n\t\t)\n\t\t.appendTo( cell );\n\n\t// Attach a sort listener to update on sort\n\t$(settings.nTable).on( 'order.dt', function ( e, ctx, sorting, columns ) {\n\t\tif ( settings !== ctx ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar colIdx = column.idx;\n\n\t\tcell\n\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\tcolumn.sSortingClass\n\t\t\t);\n\n\t\tcell\n\t\t\t.find( 'span.'+classes.sSortIcon )\n\t\t\t.removeClass(\n\t\t\t\tsort_prefix+'triangle-1-n' +\" \"+\n\t\t\t\tsort_prefix+'triangle-1-s' +\" \"+\n\t\t\t\tsort_prefix+'carat-2-n-s' +\" \"+\n\t\t\t\tsort_prefix+'carat-1-n' +\" \"+\n\t\t\t\tsort_prefix+'carat-1-s'\n\t\t\t)\n\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\tsort_prefix+'triangle-1-n' : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\tsort_prefix+'triangle-1-s' :\n\t\t\t\t\tnoSortAppliedClass\n\t\t\t);\n\t} );\n};\n\n\n/*\n * TableTools jQuery UI compatibility\n * Required TableTools 2.1+\n */\nif ( DataTable.TableTools ) {\n\t$.extend( true, DataTable.TableTools.classes, {\n\t\t\"container\": \"DTTT_container ui-buttonset ui-buttonset-multi\",\n\t\t\"buttons\": {\n\t\t\t\"normal\": \"DTTT_button ui-button ui-state-default\"\n\t\t},\n\t\t\"collection\": {\n\t\t\t\"container\": \"DTTT_collection ui-buttonset ui-buttonset-multi\"\n\t\t}\n\t} );\n}\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "platforms/android/assets/www/lib/DataTables/DataTables-1.10.13/js/dataTables.semanticui.js",
    "content": "/*! DataTables Bootstrap 3 integration\n * ©2011-2015 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Bootstrap 3. This requires Bootstrap 3 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t// Require DataTables, which attaches to jQuery, including\n\t\t\t\t// jQuery if needed and have a $ property so we can access the\n\t\t\t\t// jQuery object that is used\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'ui grid'\"+\n\t\t\t\"<'row'\"+\n\t\t\t\t\"<'eight wide column'l>\"+\n\t\t\t\t\"<'right aligned eight wide column'f>\"+\n\t\t\t\">\"+\n\t\t\t\"<'row dt-table'\"+\n\t\t\t\t\"<'sixteen wide column'tr>\"+\n\t\t\t\">\"+\n\t\t\t\"<'row'\"+\n\t\t\t\t\"<'seven wide column'i>\"+\n\t\t\t\t\"<'right aligned nine wide column'p>\"+\n\t\t\t\">\"+\n\t\t\">\",\n\trenderer: 'semanticUI'\n} );\n\n\n/* Default class modification */\n$.extend( DataTable.ext.classes, {\n\tsWrapper:      \"dataTables_wrapper dt-semanticUI\",\n\tsFilter:       \"dataTables_filter ui input\",\n\tsProcessing:   \"dataTables_processing ui segment\",\n\tsPageButton:   \"paginate_button item\"\n} );\n\n\n/* Bootstrap paging button renderer */\nDataTable.ext.renderer.pageButton.semanticUI = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api     = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang    = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass, counter=0;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'disabled';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'active' : '';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tvar tag = btnClass.indexOf( 'disabled' ) === -1 ?\n\t\t\t\t\t'a' :\n\t\t\t\t\t'div';\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<'+tag+'>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t'href': '#',\n\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t'tabindex': settings.iTabIndex\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\n\t\t\t\t\tcounter++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t// inside an iframe or frame. \n\tvar activeEl;\n\n\ttry {\n\t\t// Because this approach is destroying and recreating the paging\n\t\t// elements, focus is lost on the select button which is bad for\n\t\t// accessibility. So we want to restore focus once the draw has\n\t\t// completed\n\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t}\n\tcatch (e) {}\n\n\tattach(\n\t\t$(host).empty().html('<div class=\"ui pagination menu\"/>').children(),\n\t\tbuttons\n\t);\n\n\tif ( activeEl !== undefined ) {\n\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t}\n};\n\n\n// Javascript enhancements on table initialisation\n$(document).on( 'init.dt', function (e, ctx) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\t// Length menu drop down\n\tif ( $.fn.dropdown ) {\n\t\tvar api = new $.fn.dataTable.Api( ctx );\n\n\t\t$( 'div.dataTables_length select', api.table().container() ).dropdown();\n\t}\n} );\n\n\nreturn DataTable;\n}));"
  },
  {
    "path": "platforms/android/assets/www/lib/DataTables/DataTables-1.10.13/js/jquery.dataTables.js",
    "content": "/*! DataTables 1.10.13\n * ©2008-2016 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     DataTables\n * @description Paginate, search and order HTML tables\n * @version     1.10.13\n * @file        jquery.dataTables.js\n * @author      SpryMedia Ltd\n * @contact     www.datatables.net\n * @copyright   Copyright 2008-2016 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n/*jslint evil: true, undef: true, browser: true */\n/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/\n\n(function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\t// CommonJS environments without a window global must pass a\n\t\t\t\t// root. This will give an error otherwise\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ ) {\n\t\t\t\t$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window\n\t\t\t\t\trequire('jquery') :\n\t\t\t\t\trequire('jquery')( root );\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}\n(function( $, window, document, undefined ) {\n\t\"use strict\";\n\n\t/**\n\t * DataTables is a plug-in for the jQuery Javascript library. It is a highly\n\t * flexible tool, based upon the foundations of progressive enhancement,\n\t * which will add advanced interaction controls to any HTML table. For a\n\t * full list of features please refer to\n\t * [DataTables.net](href=\"http://datatables.net).\n\t *\n\t * Note that the `DataTable` object is not a global variable but is aliased\n\t * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may\n\t * be  accessed.\n\t *\n\t *  @class\n\t *  @param {object} [init={}] Configuration object for DataTables. Options\n\t *    are defined by {@link DataTable.defaults}\n\t *  @requires jQuery 1.7+\n\t *\n\t *  @example\n\t *    // Basic initialisation\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable();\n\t *    } );\n\t *\n\t *  @example\n\t *    // Initialisation with configuration options - in this case, disable\n\t *    // pagination and sorting.\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable( {\n\t *        \"paginate\": false,\n\t *        \"sort\": false\n\t *      } );\n\t *    } );\n\t */\n\tvar DataTable = function ( options )\n\t{\n\t\t/**\n\t\t * Perform a jQuery selector action on the table's TR elements (from the tbody) and\n\t\t * return the resulting jQuery object.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter\n\t\t *    criterion (\"applied\") or all TR elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {object} jQuery object, filtered by the given selector.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Highlight every second row\n\t\t *      oTable.$('tr:odd').css('backgroundColor', 'blue');\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to rows with 'Webkit' in them, add a background colour and then\n\t\t *      // remove the filter, thus highlighting the 'Webkit' rows only.\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      oTable.$('tr', {\"search\": \"applied\"}).css('backgroundColor', 'blue');\n\t\t *      oTable.fnFilter('');\n\t\t *    } );\n\t\t */\n\t\tthis.$ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).$( sSelector, oOpts );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Almost identical to $ in operation, but in this case returns the data for the matched\n\t\t * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes\n\t\t * rather than any descendants, so the data can be obtained for the row/cell. If matching\n\t\t * rows are found, the data returned is the original data array/object that was used to\n\t\t * create the row (or a generated array if from a DOM source).\n\t\t *\n\t\t * This method is often useful in-combination with $ where both functions are given the\n\t\t * same parameters and the array indexes will match identically.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select elements that meet the current filter\n\t\t *    criterion (\"applied\") or all elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the data in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {array} Data for the matched elements. If any elements, as a result of the\n\t\t *    selector, were not TR, TD or TH elements in the DataTable, they will have a null\n\t\t *    entry in the array.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the data from the first row in the table\n\t\t *      var data = oTable._('tr:first');\n\t\t *\n\t\t *      // Do something useful with the data\n\t\t *      alert( \"First cell is: \"+data[0] );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to 'Webkit' and get all data for\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      var data = oTable._('tr', {\"search\": \"applied\"});\n\t\t *\n\t\t *      // Do something with the data\n\t\t *      alert( data.length+\" rows matched the search\" );\n\t\t *    } );\n\t\t */\n\t\tthis._ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).rows( sSelector, oOpts ).data();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Create a DataTables Api instance, with the currently selected tables for\n\t\t * the Api's context.\n\t\t * @param {boolean} [traditional=false] Set the API instance's context to be\n\t\t *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was\n\t\t *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),\n\t\t *   or if all tables captured in the jQuery object should be used.\n\t\t * @return {DataTables.Api}\n\t\t */\n\t\tthis.api = function ( traditional )\n\t\t{\n\t\t\treturn traditional ?\n\t\t\t\tnew _Api(\n\t\t\t\t\t_fnSettingsFromNode( this[ _ext.iApiIndex ] )\n\t\t\t\t) :\n\t\t\t\tnew _Api( this );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Add a single new row or multiple rows of data to the table. Please note\n\t\t * that this is suitable for client-side processing only - if you are using\n\t\t * server-side processing (i.e. \"bServerSide\": true), then to add data, you\n\t\t * must add it to the data source, i.e. the server-side, through an Ajax call.\n\t\t *  @param {array|object} data The data to be added to the table. This can be:\n\t\t *    <ul>\n\t\t *      <li>1D array of data - add a single row with the data provided</li>\n\t\t *      <li>2D array of arrays - add multiple rows in a single call</li>\n\t\t *      <li>object - data object when using <i>mData</i></li>\n\t\t *      <li>array of objects - multiple data objects when using <i>mData</i></li>\n\t\t *    </ul>\n\t\t *  @param {bool} [redraw=true] redraw the table or not\n\t\t *  @returns {array} An array of integers, representing the list of indexes in\n\t\t *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to\n\t\t *    the table.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Global var for counter\n\t\t *    var giCount = 2;\n\t\t *\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example').dataTable();\n\t\t *    } );\n\t\t *\n\t\t *    function fnClickAddRow() {\n\t\t *      $('#example').dataTable().fnAddData( [\n\t\t *        giCount+\".1\",\n\t\t *        giCount+\".2\",\n\t\t *        giCount+\".3\",\n\t\t *        giCount+\".4\" ]\n\t\t *      );\n\t\t *\n\t\t *      giCount++;\n\t\t *    }\n\t\t */\n\t\tthis.fnAddData = function( data, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\t/* Check if we want to add multiple rows or not */\n\t\t\tvar rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?\n\t\t\t\tapi.rows.add( data ) :\n\t\t\t\tapi.row.add( data );\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn rows.flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will make DataTables recalculate the column sizes, based on the data\n\t\t * contained in the table and the sizes applied to the columns (in the DOM, CSS or\n\t\t * through the sWidth parameter). This can be useful when the width of the table's\n\t\t * parent element changes (for example a window resize).\n\t\t *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable( {\n\t\t *        \"sScrollY\": \"200px\",\n\t\t *        \"bPaginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      $(window).on('resize', function () {\n\t\t *        oTable.fnAdjustColumnSizing();\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnAdjustColumnSizing = function ( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).columns.adjust();\n\t\t\tvar settings = api.settings()[0];\n\t\t\tvar scroll = settings.oScroll;\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw( false );\n\t\t\t}\n\t\t\telse if ( scroll.sX !== \"\" || scroll.sY !== \"\" ) {\n\t\t\t\t/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */\n\t\t\t\t_fnScrollDraw( settings );\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Quickly and simply clear a table\n\t\t *  @param {bool} [bRedraw=true] redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)\n\t\t *      oTable.fnClearTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClearTable = function( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).clear();\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * The exact opposite of 'opening' a row, this function will close any rows which\n\t\t * are currently 'open'.\n\t\t *  @param {node} nTr the table row to 'close'\n\t\t *  @returns {int} 0 on success, or 1 if failed (can't find the row)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClose = function( nTr )\n\t\t{\n\t\t\tthis.api( true ).row( nTr ).child.hide();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Remove a row for the table\n\t\t *  @param {mixed} target The index of the row from aoData to be deleted, or\n\t\t *    the TR element you want to delete\n\t\t *  @param {function|null} [callBack] Callback function\n\t\t *  @param {bool} [redraw=true] Redraw the table or not\n\t\t *  @returns {array} The row that was deleted\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately remove the first row\n\t\t *      oTable.fnDeleteRow( 0 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnDeleteRow = function( target, callback, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar rows = api.rows( target );\n\t\t\tvar settings = rows.settings()[0];\n\t\t\tvar data = settings.aoData[ rows[0][0] ];\n\t\t\n\t\t\trows.remove();\n\t\t\n\t\t\tif ( callback ) {\n\t\t\t\tcallback.call( this, settings, data );\n\t\t\t}\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn data;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Restore the table to it's original state in the DOM by removing all of DataTables\n\t\t * enhancements, alterations to the DOM structure of the table and event listeners.\n\t\t *  @param {boolean} [remove=false] Completely remove the table from the DOM\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      // This example is fairly pointless in reality, but shows how fnDestroy can be used\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnDestroy();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDestroy = function ( remove )\n\t\t{\n\t\t\tthis.api( true ).destroy( remove );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Redraw the table\n\t\t *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)\n\t\t *      oTable.fnDraw();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDraw = function( complete )\n\t\t{\n\t\t\t// Note that this isn't an exact match to the old call to _fnDraw - it takes\n\t\t\t// into account the new data, but can hold position.\n\t\t\tthis.api( true ).draw( complete );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Filter the input based on data\n\t\t *  @param {string} sInput String to filter the table on\n\t\t *  @param {int|null} [iColumn] Column to limit filtering to\n\t\t *  @param {bool} [bRegex=false] Treat as regular expression or not\n\t\t *  @param {bool} [bSmart=true] Perform smart filtering or not\n\t\t *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)\n\t\t *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sometime later - filter...\n\t\t *      oTable.fnFilter( 'test string' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === null || iColumn === undefined ) {\n\t\t\t\tapi.search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\n\t\t\tapi.draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the data for the whole table, an individual row or an individual cell based on the\n\t\t * provided parameters.\n\t\t *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as\n\t\t *    a TR node then the data source for the whole row will be returned. If given as a\n\t\t *    TD/TH cell node then iCol will be automatically calculated and the data for the\n\t\t *    cell returned. If given as an integer, then this is treated as the aoData internal\n\t\t *    data index for the row (see fnGetPosition) and the data for that row used.\n\t\t *  @param {int} [col] Optional column index that you want the data of.\n\t\t *  @returns {array|object|string} If mRow is undefined, then the data for all rows is\n\t\t *    returned. If mRow is defined, just data for that row, and is iCol is\n\t\t *    defined, only data for the designated cell is returned.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Row data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('tr').click( function () {\n\t\t *        var data = oTable.fnGetData( this );\n\t\t *        // ... do something with the array / object of data for the row\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Individual cell data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('td').click( function () {\n\t\t *        var sData = oTable.fnGetData( this );\n\t\t *        alert( 'The cell clicked on had the value of '+sData );\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetData = function( src, col )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( src !== undefined ) {\n\t\t\t\tvar type = src.nodeName ? src.nodeName.toLowerCase() : '';\n\t\t\n\t\t\t\treturn col !== undefined || type == 'td' || type == 'th' ?\n\t\t\t\t\tapi.cell( src, col ).data() :\n\t\t\t\t\tapi.row( src ).data() || null;\n\t\t\t}\n\t\t\n\t\t\treturn api.data().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get an array of the TR nodes that are used in the table's body. Note that you will\n\t\t * typically want to use the '$' API method in preference to this as it is more\n\t\t * flexible.\n\t\t *  @param {int} [iRow] Optional row index for the TR element you want\n\t\t *  @returns {array|node} If iRow is undefined, returns an array of all TR elements\n\t\t *    in the table's body, or iRow is defined, just the TR element requested.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the nodes from the table\n\t\t *      var nNodes = oTable.fnGetNodes( );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetNodes = function( iRow )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\treturn iRow !== undefined ?\n\t\t\t\tapi.row( iRow ).node() :\n\t\t\t\tapi.rows().nodes().flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the array indexes of a particular cell from it's DOM element\n\t\t * and column index including hidden columns\n\t\t *  @param {node} node this can either be a TR, TD or TH in the table's body\n\t\t *  @returns {int} If nNode is given as a TR, then a single index is returned, or\n\t\t *    if given as a cell, an array of [row index, column index (visible),\n\t\t *    column index (all)] is given.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example tbody td').click( function () {\n\t\t *        // Get the position of the current data from the node\n\t\t *        var aPos = oTable.fnGetPosition( this );\n\t\t *\n\t\t *        // Get the data array for this row\n\t\t *        var aData = oTable.fnGetData( aPos[0] );\n\t\t *\n\t\t *        // Update the data array and return the value\n\t\t *        aData[ aPos[1] ] = 'clicked';\n\t\t *        this.innerHTML = 'clicked';\n\t\t *      } );\n\t\t *\n\t\t *      // Init DataTables\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetPosition = function( node )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar nodeName = node.nodeName.toUpperCase();\n\t\t\n\t\t\tif ( nodeName == 'TR' ) {\n\t\t\t\treturn api.row( node ).index();\n\t\t\t}\n\t\t\telse if ( nodeName == 'TD' || nodeName == 'TH' ) {\n\t\t\t\tvar cell = api.cell( node ).index();\n\t\t\n\t\t\t\treturn [\n\t\t\t\t\tcell.row,\n\t\t\t\t\tcell.columnVisible,\n\t\t\t\t\tcell.column\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Check to see if a row is 'open' or not.\n\t\t *  @param {node} nTr the table row to check\n\t\t *  @returns {boolean} true if the row is currently open, false otherwise\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnIsOpen = function( nTr )\n\t\t{\n\t\t\treturn this.api( true ).row( nTr ).child.isShown();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will place a new row directly after a row which is currently\n\t\t * on display on the page, with the HTML contents that is passed into the\n\t\t * function. This can be used, for example, to ask for confirmation that a\n\t\t * particular record should be deleted.\n\t\t *  @param {node} nTr The table row to 'open'\n\t\t *  @param {string|node|jQuery} mHtml The HTML to put into the row\n\t\t *  @param {string} sClass Class to give the new TD cell\n\t\t *  @returns {node} The row opened. Note that if the table row passed in as the\n\t\t *    first parameter, is not found in the table, this method will silently\n\t\t *    return.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnOpen = function( nTr, mHtml, sClass )\n\t\t{\n\t\t\treturn this.api( true )\n\t\t\t\t.row( nTr )\n\t\t\t\t.child( mHtml, sClass )\n\t\t\t\t.show()\n\t\t\t\t.child()[0];\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Change the pagination - provides the internal logic for pagination in a simple API\n\t\t * function. With this function you can have a DataTables table go to the next,\n\t\t * previous, first or last pages.\n\t\t *  @param {string|int} mAction Paging action to take: \"first\", \"previous\", \"next\" or \"last\"\n\t\t *    or page number to jump to (integer), note that page 0 is the first page.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnPageChange( 'next' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnPageChange = function ( mAction, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).page( mAction );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw(false);\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Show a particular column\n\t\t *  @param {int} iCol The column whose display should be changed\n\t\t *  @param {bool} bShow Show (true) or hide (false) the column\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Hide the second column after initialisation\n\t\t *      oTable.fnSetColumnVis( 1, false );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSetColumnVis = function ( iCol, bShow, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).column( iCol ).visible( bShow );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.columns.adjust().draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the settings for a particular table for external manipulation\n\t\t *  @returns {object} DataTables settings object. See\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      var oSettings = oTable.fnSettings();\n\t\t *\n\t\t *      // Show an example parameter from the settings\n\t\t *      alert( oSettings._iDisplayStart );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSettings = function()\n\t\t{\n\t\t\treturn _fnSettingsFromNode( this[_ext.iApiIndex] );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Sort the table by a particular column\n\t\t *  @param {int} iCol the data index to sort on. Note that this will not match the\n\t\t *    'display index' if you have hidden data entries\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort immediately with columns 0 and 1\n\t\t *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSort = function( aaSort )\n\t\t{\n\t\t\tthis.api( true ).order( aaSort ).draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Attach a sort listener to an element for a given column\n\t\t *  @param {node} nNode the element to attach the sort listener to\n\t\t *  @param {int} iColumn the column that a click on this node will sort on\n\t\t *  @param {function} [fnCallback] callback function when sort is run\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort on column 1, when 'sorter' is clicked on\n\t\t *      oTable.fnSortListener( document.getElementById('sorter'), 1 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSortListener = function( nNode, iColumn, fnCallback )\n\t\t{\n\t\t\tthis.api( true ).order.listener( nNode, iColumn, fnCallback );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Update a table cell or row - this method will accept either a single value to\n\t\t * update the cell with, an array of values with one element for each column or\n\t\t * an object in the same format as the original data source. The function is\n\t\t * self-referencing in order to make the multi column updates easier.\n\t\t *  @param {object|array|string} mData Data to update the cell/row with\n\t\t *  @param {node|int} mRow TR element you want to update or the aoData index\n\t\t *  @param {int} [iColumn] The column to update, give as null or undefined to\n\t\t *    update a whole row.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @param {bool} [bAction=true] Perform pre-draw actions or not\n\t\t *  @returns {int} 0 on success, 1 on error\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell\n\t\t *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row\n\t\t *    } );\n\t\t */\n\t\tthis.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === undefined || iColumn === null ) {\n\t\t\t\tapi.row( mRow ).data( mData );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.cell( mRow, iColumn ).data( mData );\n\t\t\t}\n\t\t\n\t\t\tif ( bAction === undefined || bAction ) {\n\t\t\t\tapi.columns.adjust();\n\t\t\t}\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Provide a common method for plug-ins to check the version of DataTables being used, in order\n\t\t * to ensure compatibility.\n\t\t *  @param {string} sVersion Version string to check for, in the format \"X.Y.Z\". Note that the\n\t\t *    formats \"X\" and \"X.Y\" are also acceptable.\n\t\t *  @returns {boolean} true if this version of DataTables is greater or equal to the required\n\t\t *    version, or false if this version of DataTales is not suitable\n\t\t *  @method\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      alert( oTable.fnVersionCheck( '1.9.0' ) );\n\t\t *    } );\n\t\t */\n\t\tthis.fnVersionCheck = _ext.fnVersionCheck;\n\t\t\n\n\t\tvar _that = this;\n\t\tvar emptyInit = options === undefined;\n\t\tvar len = this.length;\n\n\t\tif ( emptyInit ) {\n\t\t\toptions = {};\n\t\t}\n\n\t\tthis.oApi = this.internal = _ext.internal;\n\n\t\t// Extend with old style plug-in API methods\n\t\tfor ( var fn in DataTable.ext.internal ) {\n\t\t\tif ( fn ) {\n\t\t\t\tthis[fn] = _fnExternApiFunc(fn);\n\t\t\t}\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\t// For each initialisation we want to give it a clean initialisation\n\t\t\t// object that can be bashed around\n\t\t\tvar o = {};\n\t\t\tvar oInit = len > 1 ? // optimisation for single table case\n\t\t\t\t_fnExtend( o, options, true ) :\n\t\t\t\toptions;\n\n\t\t\t/*global oInit,_that,emptyInit*/\n\t\t\tvar i=0, iLen, j, jLen, k, kLen;\n\t\t\tvar sId = this.getAttribute( 'id' );\n\t\t\tvar bInitHandedOff = false;\n\t\t\tvar defaults = DataTable.defaults;\n\t\t\tvar $this = $(this);\n\t\t\t\n\t\t\t\n\t\t\t/* Sanity check */\n\t\t\tif ( this.nodeName.toLowerCase() != 'table' )\n\t\t\t{\n\t\t\t\t_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/* Backwards compatibility for the defaults */\n\t\t\t_fnCompatOpts( defaults );\n\t\t\t_fnCompatCols( defaults.column );\n\t\t\t\n\t\t\t/* Convert the camel-case defaults to Hungarian */\n\t\t\t_fnCamelToHungarian( defaults, defaults, true );\n\t\t\t_fnCamelToHungarian( defaults.column, defaults.column, true );\n\t\t\t\n\t\t\t/* Setting up the initialisation object */\n\t\t\t_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/* Check to see if we are re-initialising a table */\n\t\t\tvar allSettings = DataTable.settings;\n\t\t\tfor ( i=0, iLen=allSettings.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tvar s = allSettings[i];\n\t\t\t\n\t\t\t\t/* Base check on table node */\n\t\t\t\tif ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )\n\t\t\t\t{\n\t\t\t\t\tvar bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;\n\t\t\t\t\tvar bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;\n\t\t\t\n\t\t\t\t\tif ( emptyInit || bRetrieve )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn s.oInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( bDestroy )\n\t\t\t\t\t{\n\t\t\t\t\t\ts.oInstance.fnDestroy();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* If the element we are initialising has the same ID as a table which was previously\n\t\t\t\t * initialised, but the table nodes don't match (from before) then we destroy the old\n\t\t\t\t * instance by simply deleting it. This is under the assumption that the table has been\n\t\t\t\t * destroyed by other methods. Anyone using non-id selectors will need to do this manually\n\t\t\t\t */\n\t\t\t\tif ( s.sTableId == this.id )\n\t\t\t\t{\n\t\t\t\t\tallSettings.splice( i, 1 );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Ensure the table has an ID - required for accessibility */\n\t\t\tif ( sId === null || sId === \"\" )\n\t\t\t{\n\t\t\t\tsId = \"DataTables_Table_\"+(DataTable.ext._unique++);\n\t\t\t\tthis.id = sId;\n\t\t\t}\n\t\t\t\n\t\t\t/* Create the settings object for this table and set some of the default parameters */\n\t\t\tvar oSettings = $.extend( true, {}, DataTable.models.oSettings, {\n\t\t\t\t\"sDestroyWidth\": $this[0].style.width,\n\t\t\t\t\"sInstance\":     sId,\n\t\t\t\t\"sTableId\":      sId\n\t\t\t} );\n\t\t\toSettings.nTable = this;\n\t\t\toSettings.oApi   = _that.internal;\n\t\t\toSettings.oInit  = oInit;\n\t\t\t\n\t\t\tallSettings.push( oSettings );\n\t\t\t\n\t\t\t// Need to add the instance after the instance after the settings object has been added\n\t\t\t// to the settings array, so we can self reference the table instance if more than one\n\t\t\toSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();\n\t\t\t\n\t\t\t// Backwards compatibility, before we apply all the defaults\n\t\t\t_fnCompatOpts( oInit );\n\t\t\t\n\t\t\tif ( oInit.oLanguage )\n\t\t\t{\n\t\t\t\t_fnLanguageCompat( oInit.oLanguage );\n\t\t\t}\n\t\t\t\n\t\t\t// If the length menu is given, but the init display length is not, use the length menu\n\t\t\tif ( oInit.aLengthMenu && ! oInit.iDisplayLength )\n\t\t\t{\n\t\t\t\toInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?\n\t\t\t\t\toInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];\n\t\t\t}\n\t\t\t\n\t\t\t// Apply the defaults and init options to make a single init object will all\n\t\t\t// options defined from defaults and instance options.\n\t\t\toInit = _fnExtend( $.extend( true, {}, defaults ), oInit );\n\t\t\t\n\t\t\t\n\t\t\t// Map the initialisation options onto the settings object\n\t\t\t_fnMap( oSettings.oFeatures, oInit, [\n\t\t\t\t\"bPaginate\",\n\t\t\t\t\"bLengthChange\",\n\t\t\t\t\"bFilter\",\n\t\t\t\t\"bSort\",\n\t\t\t\t\"bSortMulti\",\n\t\t\t\t\"bInfo\",\n\t\t\t\t\"bProcessing\",\n\t\t\t\t\"bAutoWidth\",\n\t\t\t\t\"bSortClasses\",\n\t\t\t\t\"bServerSide\",\n\t\t\t\t\"bDeferRender\"\n\t\t\t] );\n\t\t\t_fnMap( oSettings, oInit, [\n\t\t\t\t\"asStripeClasses\",\n\t\t\t\t\"ajax\",\n\t\t\t\t\"fnServerData\",\n\t\t\t\t\"fnFormatNumber\",\n\t\t\t\t\"sServerMethod\",\n\t\t\t\t\"aaSorting\",\n\t\t\t\t\"aaSortingFixed\",\n\t\t\t\t\"aLengthMenu\",\n\t\t\t\t\"sPaginationType\",\n\t\t\t\t\"sAjaxSource\",\n\t\t\t\t\"sAjaxDataProp\",\n\t\t\t\t\"iStateDuration\",\n\t\t\t\t\"sDom\",\n\t\t\t\t\"bSortCellsTop\",\n\t\t\t\t\"iTabIndex\",\n\t\t\t\t\"fnStateLoadCallback\",\n\t\t\t\t\"fnStateSaveCallback\",\n\t\t\t\t\"renderer\",\n\t\t\t\t\"searchDelay\",\n\t\t\t\t\"rowId\",\n\t\t\t\t[ \"iCookieDuration\", \"iStateDuration\" ], // backwards compat\n\t\t\t\t[ \"oSearch\", \"oPreviousSearch\" ],\n\t\t\t\t[ \"aoSearchCols\", \"aoPreSearchCols\" ],\n\t\t\t\t[ \"iDisplayLength\", \"_iDisplayLength\" ],\n\t\t\t\t[ \"bJQueryUI\", \"bJUI\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oScroll, oInit, [\n\t\t\t\t[ \"sScrollX\", \"sX\" ],\n\t\t\t\t[ \"sScrollXInner\", \"sXInner\" ],\n\t\t\t\t[ \"sScrollY\", \"sY\" ],\n\t\t\t\t[ \"bScrollCollapse\", \"bCollapse\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oLanguage, oInit, \"fnInfoCallback\" );\n\t\t\t\n\t\t\t/* Callback functions which are array driven */\n\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );\n\t\t\t\n\t\t\toSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );\n\t\t\t\n\t\t\t/* Browser support detection */\n\t\t\t_fnBrowserDetect( oSettings );\n\t\t\t\n\t\t\tvar oClasses = oSettings.oClasses;\n\t\t\t\n\t\t\t// @todo Remove in 1.11\n\t\t\tif ( oInit.bJQueryUI )\n\t\t\t{\n\t\t\t\t/* Use the JUI classes object for display. You could clone the oStdClasses object if\n\t\t\t\t * you want to have multiple tables with multiple independent classes\n\t\t\t\t */\n\t\t\t\t$.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );\n\t\t\t\n\t\t\t\tif ( oInit.sDom === defaults.sDom && defaults.sDom === \"lfrtip\" )\n\t\t\t\t{\n\t\t\t\t\t/* Set the DOM to use a layout suitable for jQuery UI's theming */\n\t\t\t\t\toSettings.sDom = '<\"H\"lfr>t<\"F\"ip>';\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( ! oSettings.renderer ) {\n\t\t\t\t\toSettings.renderer = 'jqueryui';\n\t\t\t\t}\n\t\t\t\telse if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {\n\t\t\t\t\toSettings.renderer.header = 'jqueryui';\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );\n\t\t\t}\n\t\t\t$this.addClass( oClasses.sTable );\n\t\t\t\n\t\t\t\n\t\t\tif ( oSettings.iInitDisplayStart === undefined )\n\t\t\t{\n\t\t\t\t/* Display start point, taking into account the save saving */\n\t\t\t\toSettings.iInitDisplayStart = oInit.iDisplayStart;\n\t\t\t\toSettings._iDisplayStart = oInit.iDisplayStart;\n\t\t\t}\n\t\t\t\n\t\t\tif ( oInit.iDeferLoading !== null )\n\t\t\t{\n\t\t\t\toSettings.bDeferLoading = true;\n\t\t\t\tvar tmp = $.isArray( oInit.iDeferLoading );\n\t\t\t\toSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;\n\t\t\t\toSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;\n\t\t\t}\n\t\t\t\n\t\t\t/* Language definitions */\n\t\t\tvar oLanguage = oSettings.oLanguage;\n\t\t\t$.extend( true, oLanguage, oInit.oLanguage );\n\t\t\t\n\t\t\tif ( oLanguage.sUrl )\n\t\t\t{\n\t\t\t\t/* Get the language definitions from a file - because this Ajax call makes the language\n\t\t\t\t * get async to the remainder of this function we use bInitHandedOff to indicate that\n\t\t\t\t * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor\n\t\t\t\t */\n\t\t\t\t$.ajax( {\n\t\t\t\t\tdataType: 'json',\n\t\t\t\t\turl: oLanguage.sUrl,\n\t\t\t\t\tsuccess: function ( json ) {\n\t\t\t\t\t\t_fnLanguageCompat( json );\n\t\t\t\t\t\t_fnCamelToHungarian( defaults.oLanguage, json );\n\t\t\t\t\t\t$.extend( true, oLanguage, json );\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t},\n\t\t\t\t\terror: function () {\n\t\t\t\t\t\t// Error occurred loading language file, continue on as best we can\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tbInitHandedOff = true;\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Stripes\n\t\t\t */\n\t\t\tif ( oInit.asStripeClasses === null )\n\t\t\t{\n\t\t\t\toSettings.asStripeClasses =[\n\t\t\t\t\toClasses.sStripeOdd,\n\t\t\t\t\toClasses.sStripeEven\n\t\t\t\t];\n\t\t\t}\n\t\t\t\n\t\t\t/* Remove row stripe classes if they are already on the table row */\n\t\t\tvar stripeClasses = oSettings.asStripeClasses;\n\t\t\tvar rowOne = $this.children('tbody').find('tr').eq(0);\n\t\t\tif ( $.inArray( true, $.map( stripeClasses, function(el, i) {\n\t\t\t\treturn rowOne.hasClass(el);\n\t\t\t} ) ) !== -1 ) {\n\t\t\t\t$('tbody tr', this).removeClass( stripeClasses.join(' ') );\n\t\t\t\toSettings.asDestroyStripes = stripeClasses.slice();\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Columns\n\t\t\t * See if we should load columns automatically or use defined ones\n\t\t\t */\n\t\t\tvar anThs = [];\n\t\t\tvar aoColumnsInit;\n\t\t\tvar nThead = this.getElementsByTagName('thead');\n\t\t\tif ( nThead.length !== 0 )\n\t\t\t{\n\t\t\t\t_fnDetectHeader( oSettings.aoHeader, nThead[0] );\n\t\t\t\tanThs = _fnGetUniqueThs( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* If not given a column array, generate one with nulls */\n\t\t\tif ( oInit.aoColumns === null )\n\t\t\t{\n\t\t\t\taoColumnsInit = [];\n\t\t\t\tfor ( i=0, iLen=anThs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\taoColumnsInit.push( null );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoColumnsInit = oInit.aoColumns;\n\t\t\t}\n\t\t\t\n\t\t\t/* Add the columns */\n\t\t\tfor ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t_fnAddColumn( oSettings, anThs ? anThs[i] : null );\n\t\t\t}\n\t\t\t\n\t\t\t/* Apply the column definitions */\n\t\t\t_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {\n\t\t\t\t_fnColumnOptions( oSettings, iCol, oDef );\n\t\t\t} );\n\t\t\t\n\t\t\t/* HTML5 attribute detection - build an mData object automatically if the\n\t\t\t * attributes are found\n\t\t\t */\n\t\t\tif ( rowOne.length ) {\n\t\t\t\tvar a = function ( cell, name ) {\n\t\t\t\t\treturn cell.getAttribute( 'data-'+name ) !== null ? name : null;\n\t\t\t\t};\n\t\t\t\n\t\t\t\t$( rowOne[0] ).children('th, td').each( function (i, cell) {\n\t\t\t\t\tvar col = oSettings.aoColumns[i];\n\t\t\t\n\t\t\t\t\tif ( col.mData === i ) {\n\t\t\t\t\t\tvar sort = a( cell, 'sort' ) || a( cell, 'order' );\n\t\t\t\t\t\tvar filter = a( cell, 'filter' ) || a( cell, 'search' );\n\t\t\t\n\t\t\t\t\t\tif ( sort !== null || filter !== null ) {\n\t\t\t\t\t\t\tcol.mData = {\n\t\t\t\t\t\t\t\t_:      i+'.display',\n\t\t\t\t\t\t\t\tsort:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\ttype:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\tfilter: filter !== null ? i+'.@data-'+filter : undefined\n\t\t\t\t\t\t\t};\n\t\t\t\n\t\t\t\t\t\t\t_fnColumnOptions( oSettings, i );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\t\n\t\t\tvar features = oSettings.oFeatures;\n\t\t\tvar loadedInit = function () {\n\t\t\t\t/*\n\t\t\t\t * Sorting\n\t\t\t\t * @todo For modularisation (1.11) this needs to do into a sort start up handler\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// If aaSorting is not defined, then we use the first indicator in asSorting\n\t\t\t\t// in case that has been altered, so the default sort reflects that option\n\t\t\t\tif ( oInit.aaSorting === undefined ) {\n\t\t\t\t\tvar sorting = oSettings.aaSorting;\n\t\t\t\t\tfor ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {\n\t\t\t\t\t\tsorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Do a first pass on the sorting classes (allows any size changes to be taken into\n\t\t\t\t * account, and also will apply sorting disabled classes if disabled\n\t\t\t\t */\n\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\n\t\t\t\tif ( features.bSort ) {\n\t\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\t\tif ( oSettings.bSorted ) {\n\t\t\t\t\t\t\tvar aSort = _fnSortFlatten( oSettings );\n\t\t\t\t\t\t\tvar sortedColumns = {};\n\t\t\t\n\t\t\t\t\t\t\t$.each( aSort, function (i, val) {\n\t\t\t\t\t\t\t\tsortedColumns[ val.src ] = val.dir;\n\t\t\t\t\t\t\t} );\n\t\t\t\n\t\t\t\t\t\t\t_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );\n\t\t\t\t\t\t\t_fnSortAria( oSettings );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\tif ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {\n\t\t\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\t\t}\n\t\t\t\t}, 'sc' );\n\t\t\t\n\t\t\t\n\t\t\t\t/*\n\t\t\t\t * Final init\n\t\t\t\t * Cache the header, body and footer as required, creating them if needed\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// Work around for Webkit bug 83867 - store the caption-side before removing from doc\n\t\t\t\tvar captions = $this.children('caption').each( function () {\n\t\t\t\t\tthis._captionSide = $(this).css('caption-side');\n\t\t\t\t} );\n\t\t\t\n\t\t\t\tvar thead = $this.children('thead');\n\t\t\t\tif ( thead.length === 0 ) {\n\t\t\t\t\tthead = $('<thead/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTHead = thead[0];\n\t\t\t\n\t\t\t\tvar tbody = $this.children('tbody');\n\t\t\t\tif ( tbody.length === 0 ) {\n\t\t\t\t\ttbody = $('<tbody/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTBody = tbody[0];\n\t\t\t\n\t\t\t\tvar tfoot = $this.children('tfoot');\n\t\t\t\tif ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\") ) {\n\t\t\t\t\t// If we are a scrolling table, and no footer has been given, then we need to create\n\t\t\t\t\t// a tfoot element for the caption element to be appended to\n\t\t\t\t\ttfoot = $('<tfoot/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( tfoot.length === 0 || tfoot.children().length === 0 ) {\n\t\t\t\t\t$this.addClass( oClasses.sNoFooter );\n\t\t\t\t}\n\t\t\t\telse if ( tfoot.length > 0 ) {\n\t\t\t\t\toSettings.nTFoot = tfoot[0];\n\t\t\t\t\t_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Check if there is data passing into the constructor */\n\t\t\t\tif ( oInit.aaData ) {\n\t\t\t\t\tfor ( i=0 ; i<oInit.aaData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( oSettings, oInit.aaData[ i ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {\n\t\t\t\t\t/* Grab the data from the page - only do this when deferred loading or no Ajax\n\t\t\t\t\t * source since there is no point in reading the DOM data if we are then going\n\t\t\t\t\t * to replace it with Ajax data\n\t\t\t\t\t */\n\t\t\t\t\t_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Copy the data index array */\n\t\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\n\t\t\t\t/* Initialisation complete - table can be drawn */\n\t\t\t\toSettings.bInitialised = true;\n\t\t\t\n\t\t\t\t/* Check if we need to initialise the table (it might not have been handed off to the\n\t\t\t\t * language processor)\n\t\t\t\t */\n\t\t\t\tif ( bInitHandedOff === false ) {\n\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\t/* Must be done after everything which can be overridden by the state saving! */\n\t\t\tif ( oInit.bStateSave )\n\t\t\t{\n\t\t\t\tfeatures.bStateSave = true;\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );\n\t\t\t\t_fnLoadState( oSettings, oInit, loadedInit );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadedInit();\n\t\t\t}\n\t\t\t\n\t\t} );\n\t\t_that = null;\n\t\treturn this;\n\t};\n\n\t\n\t/*\n\t * It is useful to have variables which are scoped locally so only the\n\t * DataTables functions can access them and they don't leak into global space.\n\t * At the same time these functions are often useful over multiple files in the\n\t * core and API, so we list, or at least document, all variables which are used\n\t * by DataTables as private variables here. This also ensures that there is no\n\t * clashing of variable names and that they can easily referenced for reuse.\n\t */\n\t\n\t\n\t// Defined else where\n\t//  _selector_run\n\t//  _selector_opts\n\t//  _selector_first\n\t//  _selector_row_indexes\n\t\n\tvar _ext; // DataTable.ext\n\tvar _Api; // DataTable.Api\n\tvar _api_register; // DataTable.Api.register\n\tvar _api_registerPlural; // DataTable.Api.registerPlural\n\t\n\tvar _re_dic = {};\n\tvar _re_new_lines = /[\\r\\n]/g;\n\tvar _re_html = /<.*?>/g;\n\t\n\t// This is not strict ISO8601 - Date.parse() is quite lax, although\n\t// implementations differ between browsers.\n\tvar _re_date = /^\\d{2,4}[\\.\\/\\-]\\d{1,2}[\\.\\/\\-]\\d{1,2}([T ]{1}\\d{1,2}[:\\.]\\d{2}([\\.:]\\d{2})?)?$/;\n\t\n\t// Escape regular expression special characters\n\tvar _re_escape_regex = new RegExp( '(\\\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\\\', '$', '^', '-' ].join('|\\\\') + ')', 'g' );\n\t\n\t// http://en.wikipedia.org/wiki/Foreign_exchange_market\n\t// - \\u20BD - Russian ruble.\n\t// - \\u20a9 - South Korean Won\n\t// - \\u20BA - Turkish Lira\n\t// - \\u20B9 - Indian Rupee\n\t// - R - Brazil (R$) and South Africa\n\t// - fr - Swiss Franc\n\t// - kr - Swedish krona, Norwegian krone and Danish krone\n\t// - \\u2009 is thin space and \\u202F is narrow no-break space, both used in many\n\t//   standards as thousands separators.\n\tvar _re_formatted_numeric = /[',$£€¥%\\u2009\\u202F\\u20BD\\u20a9\\u20BArfk]/gi;\n\t\n\t\n\tvar _empty = function ( d ) {\n\t\treturn !d || d === true || d === '-' ? true : false;\n\t};\n\t\n\t\n\tvar _intVal = function ( s ) {\n\t\tvar integer = parseInt( s, 10 );\n\t\treturn !isNaN(integer) && isFinite(s) ? integer : null;\n\t};\n\t\n\t// Convert from a formatted number with characters other than `.` as the\n\t// decimal place, to a Javascript number\n\tvar _numToDecimal = function ( num, decimalPoint ) {\n\t\t// Cache created regular expressions for speed as this function is called often\n\t\tif ( ! _re_dic[ decimalPoint ] ) {\n\t\t\t_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );\n\t\t}\n\t\treturn typeof num === 'string' && decimalPoint !== '.' ?\n\t\t\tnum.replace( /\\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :\n\t\t\tnum;\n\t};\n\t\n\t\n\tvar _isNumber = function ( d, decimalPoint, formatted ) {\n\t\tvar strType = typeof d === 'string';\n\t\n\t\t// If empty return immediately so there must be a number if it is a\n\t\t// formatted string (this stops the string \"k\", or \"kr\", etc being detected\n\t\t// as a formatted number for currency\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tif ( decimalPoint && strType ) {\n\t\t\td = _numToDecimal( d, decimalPoint );\n\t\t}\n\t\n\t\tif ( formatted && strType ) {\n\t\t\td = d.replace( _re_formatted_numeric, '' );\n\t\t}\n\t\n\t\treturn !isNaN( parseFloat(d) ) && isFinite( d );\n\t};\n\t\n\t\n\t// A string without HTML in it can be considered to be HTML still\n\tvar _isHtml = function ( d ) {\n\t\treturn _empty( d ) || typeof d === 'string';\n\t};\n\t\n\t\n\tvar _htmlNumeric = function ( d, decimalPoint, formatted ) {\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tvar html = _isHtml( d );\n\t\treturn ! html ?\n\t\t\tnull :\n\t\t\t_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?\n\t\t\t\ttrue :\n\t\t\t\tnull;\n\t};\n\t\n\t\n\tvar _pluck = function ( a, prop, prop2 ) {\n\t\tvar out = [];\n\t\tvar i=0, ien=a.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] && a[i][ prop ] ) {\n\t\t\t\t\tout.push( a[i][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] ) {\n\t\t\t\t\tout.push( a[i][ prop ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t// Basically the same as _pluck, but rather than looping over `a` we use `order`\n\t// as the indexes to pick from `a`\n\tvar _pluck_order = function ( a, order, prop, prop2 )\n\t{\n\t\tvar out = [];\n\t\tvar i=0, ien=order.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[ order[i] ][ prop ] ) {\n\t\t\t\t\tout.push( a[ order[i] ][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tout.push( a[ order[i] ][ prop ] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _range = function ( len, start )\n\t{\n\t\tvar out = [];\n\t\tvar end;\n\t\n\t\tif ( start === undefined ) {\n\t\t\tstart = 0;\n\t\t\tend = len;\n\t\t}\n\t\telse {\n\t\t\tend = start;\n\t\t\tstart = len;\n\t\t}\n\t\n\t\tfor ( var i=start ; i<end ; i++ ) {\n\t\t\tout.push( i );\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _removeEmpty = function ( a )\n\t{\n\t\tvar out = [];\n\t\n\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\tif ( a[i] ) { // careful - will remove all falsy values!\n\t\t\t\tout.push( a[i] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _stripHtml = function ( d ) {\n\t\treturn d.replace( _re_html, '' );\n\t};\n\t\n\t\n\t/**\n\t * Find the unique elements in a source array.\n\t *\n\t * @param  {array} src Source array\n\t * @return {array} Array of unique items\n\t * @ignore\n\t */\n\tvar _unique = function ( src )\n\t{\n\t\t// A faster unique method is to use object keys to identify used values,\n\t\t// but this doesn't work with arrays or objects, which we must also\n\t\t// consider. See jsperf.com/compare-array-unique-versions/4 for more\n\t\t// information.\n\t\tvar\n\t\t\tout = [],\n\t\t\tval,\n\t\t\ti, ien=src.length,\n\t\t\tj, k=0;\n\t\n\t\tagain: for ( i=0 ; i<ien ; i++ ) {\n\t\t\tval = src[i];\n\t\n\t\t\tfor ( j=0 ; j<k ; j++ ) {\n\t\t\t\tif ( out[j] === val ) {\n\t\t\t\t\tcontinue again;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tout.push( val );\n\t\t\tk++;\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t/**\n\t * DataTables utility methods\n\t * \n\t * This namespace provides helper methods that DataTables uses internally to\n\t * create a DataTable, but which are not exclusively used only for DataTables.\n\t * These methods can be used by extension authors to save the duplication of\n\t * code.\n\t *\n\t *  @namespace\n\t */\n\tDataTable.util = {\n\t\t/**\n\t\t * Throttle the calls to a function. Arguments and context are maintained\n\t\t * for the throttled function.\n\t\t *\n\t\t * @param {function} fn Function to be called\n\t\t * @param {integer} freq Call frequency in mS\n\t\t * @return {function} Wrapped function\n\t\t */\n\t\tthrottle: function ( fn, freq ) {\n\t\t\tvar\n\t\t\t\tfrequency = freq !== undefined ? freq : 200,\n\t\t\t\tlast,\n\t\t\t\ttimer;\n\t\n\t\t\treturn function () {\n\t\t\t\tvar\n\t\t\t\t\tthat = this,\n\t\t\t\t\tnow  = +new Date(),\n\t\t\t\t\targs = arguments;\n\t\n\t\t\t\tif ( last && now < last + frequency ) {\n\t\t\t\t\tclearTimeout( timer );\n\t\n\t\t\t\t\ttimer = setTimeout( function () {\n\t\t\t\t\t\tlast = undefined;\n\t\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t\t}, frequency );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlast = now;\n\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Escape a string such that it can be used in a regular expression\n\t\t *\n\t\t *  @param {string} val string to escape\n\t\t *  @returns {string} escaped string\n\t\t */\n\t\tescapeRegex: function ( val ) {\n\t\t\treturn val.replace( _re_escape_regex, '\\\\$1' );\n\t\t}\n\t};\n\t\n\t\n\t\n\t/**\n\t * Create a mapping object that allows camel case parameters to be looked up\n\t * for their Hungarian counterparts. The mapping is stored in a private\n\t * parameter called `_hungarianMap` which can be accessed on the source object.\n\t *  @param {object} o\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnHungarianMap ( o )\n\t{\n\t\tvar\n\t\t\thungarian = 'a aa ai ao as b fn i m o s ',\n\t\t\tmatch,\n\t\t\tnewKey,\n\t\t\tmap = {};\n\t\n\t\t$.each( o, function (key, val) {\n\t\t\tmatch = key.match(/^([^A-Z]+?)([A-Z])/);\n\t\n\t\t\tif ( match && hungarian.indexOf(match[1]+' ') !== -1 )\n\t\t\t{\n\t\t\t\tnewKey = key.replace( match[0], match[2].toLowerCase() );\n\t\t\t\tmap[ newKey ] = key;\n\t\n\t\t\t\tif ( match[1] === 'o' )\n\t\t\t\t{\n\t\t\t\t\t_fnHungarianMap( o[key] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\n\t\to._hungarianMap = map;\n\t}\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian, based on a Hungarian map\n\t * created by _fnHungarianMap.\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCamelToHungarian ( src, user, force )\n\t{\n\t\tif ( ! src._hungarianMap ) {\n\t\t\t_fnHungarianMap( src );\n\t\t}\n\t\n\t\tvar hungarianKey;\n\t\n\t\t$.each( user, function (key, val) {\n\t\t\thungarianKey = src._hungarianMap[ key ];\n\t\n\t\t\tif ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )\n\t\t\t{\n\t\t\t\t// For objects, we need to buzz down into the object to copy parameters\n\t\t\t\tif ( hungarianKey.charAt(0) === 'o' )\n\t\t\t\t{\n\t\t\t\t\t// Copy the camelCase options over to the hungarian\n\t\t\t\t\tif ( ! user[ hungarianKey ] ) {\n\t\t\t\t\t\tuser[ hungarianKey ] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, user[hungarianKey], user[key] );\n\t\n\t\t\t\t\t_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tuser[hungarianKey] = user[ key ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Language compatibility - when certain options are given, and others aren't, we\n\t * need to duplicate the values over, in order to provide backwards compatibility\n\t * with older language files.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLanguageCompat( lang )\n\t{\n\t\tvar defaults = DataTable.defaults.oLanguage;\n\t\tvar zeroRecords = lang.sZeroRecords;\n\t\n\t\t/* Backwards compatibility - if there is no sEmptyTable given, then use the same as\n\t\t * sZeroRecords - assuming that is given.\n\t\t */\n\t\tif ( ! lang.sEmptyTable && zeroRecords &&\n\t\t\tdefaults.sEmptyTable === \"No data available in table\" )\n\t\t{\n\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );\n\t\t}\n\t\n\t\t/* Likewise with loading records */\n\t\tif ( ! lang.sLoadingRecords && zeroRecords &&\n\t\t\tdefaults.sLoadingRecords === \"Loading...\" )\n\t\t{\n\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );\n\t\t}\n\t\n\t\t// Old parameter name of the thousands separator mapped onto the new\n\t\tif ( lang.sInfoThousands ) {\n\t\t\tlang.sThousands = lang.sInfoThousands;\n\t\t}\n\t\n\t\tvar decimal = lang.sDecimal;\n\t\tif ( decimal ) {\n\t\t\t_addNumericSort( decimal );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Map one parameter onto another\n\t *  @param {object} o Object to map\n\t *  @param {*} knew The new parameter name\n\t *  @param {*} old The old parameter name\n\t */\n\tvar _fnCompatMap = function ( o, knew, old ) {\n\t\tif ( o[ knew ] !== undefined ) {\n\t\t\to[ old ] = o[ knew ];\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for the main DT options. Note that the new\n\t * options are mapped onto the old parameters, so this is an external interface\n\t * change only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatOpts ( init )\n\t{\n\t\t_fnCompatMap( init, 'ordering',      'bSort' );\n\t\t_fnCompatMap( init, 'orderMulti',    'bSortMulti' );\n\t\t_fnCompatMap( init, 'orderClasses',  'bSortClasses' );\n\t\t_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );\n\t\t_fnCompatMap( init, 'order',         'aaSorting' );\n\t\t_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );\n\t\t_fnCompatMap( init, 'paging',        'bPaginate' );\n\t\t_fnCompatMap( init, 'pagingType',    'sPaginationType' );\n\t\t_fnCompatMap( init, 'pageLength',    'iDisplayLength' );\n\t\t_fnCompatMap( init, 'searching',     'bFilter' );\n\t\n\t\t// Boolean initialisation of x-scrolling\n\t\tif ( typeof init.sScrollX === 'boolean' ) {\n\t\t\tinit.sScrollX = init.sScrollX ? '100%' : '';\n\t\t}\n\t\tif ( typeof init.scrollX === 'boolean' ) {\n\t\t\tinit.scrollX = init.scrollX ? '100%' : '';\n\t\t}\n\t\n\t\t// Column search objects are in an array, so it needs to be converted\n\t\t// element by element\n\t\tvar searchCols = init.aoSearchCols;\n\t\n\t\tif ( searchCols ) {\n\t\t\tfor ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {\n\t\t\t\tif ( searchCols[i] ) {\n\t\t\t\t\t_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for column options. Note that the new options\n\t * are mapped onto the old parameters, so this is an external interface change\n\t * only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatCols ( init )\n\t{\n\t\t_fnCompatMap( init, 'orderable',     'bSortable' );\n\t\t_fnCompatMap( init, 'orderData',     'aDataSort' );\n\t\t_fnCompatMap( init, 'orderSequence', 'asSorting' );\n\t\t_fnCompatMap( init, 'orderDataType', 'sortDataType' );\n\t\n\t\t// orderData can be given as an integer\n\t\tvar dataSort = init.aDataSort;\n\t\tif ( dataSort && ! $.isArray( dataSort ) ) {\n\t\t\tinit.aDataSort = [ dataSort ];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Browser feature detection for capabilities, quirks\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBrowserDetect( settings )\n\t{\n\t\t// We don't need to do this every time DataTables is constructed, the values\n\t\t// calculated are specific to the browser and OS configuration which we\n\t\t// don't expect to change between initialisations\n\t\tif ( ! DataTable.__browser ) {\n\t\t\tvar browser = {};\n\t\t\tDataTable.__browser = browser;\n\t\n\t\t\t// Scrolling feature / quirks detection\n\t\t\tvar n = $('<div/>')\n\t\t\t\t.css( {\n\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: $(window).scrollLeft()*-1, // allow for scrolling\n\t\t\t\t\theight: 1,\n\t\t\t\t\twidth: 1,\n\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t} )\n\t\t\t\t.append(\n\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\ttop: 1,\n\t\t\t\t\t\t\tleft: 1,\n\t\t\t\t\t\t\twidth: 100,\n\t\t\t\t\t\t\toverflow: 'scroll'\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t\t\t\theight: 10\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t.appendTo( 'body' );\n\t\n\t\t\tvar outer = n.children();\n\t\t\tvar inner = outer.children();\n\t\n\t\t\t// Numbers below, in order, are:\n\t\t\t// inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth\n\t\t\t//\n\t\t\t// IE6 XP:                           100 100 100  83\n\t\t\t// IE7 Vista:                        100 100 100  83\n\t\t\t// IE 8+ Windows:                     83  83 100  83\n\t\t\t// Evergreen Windows:                 83  83 100  83\n\t\t\t// Evergreen Mac with scrollbars:     85  85 100  85\n\t\t\t// Evergreen Mac without scrollbars: 100 100 100 100\n\t\n\t\t\t// Get scrollbar width\n\t\t\tbrowser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;\n\t\n\t\t\t// IE6/7 will oversize a width 100% element inside a scrolling element, to\n\t\t\t// include the width of the scrollbar, while other browsers ensure the inner\n\t\t\t// element is contained without forcing scrolling\n\t\t\tbrowser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;\n\t\n\t\t\t// In rtl text layout, some browsers (most, but not all) will place the\n\t\t\t// scrollbar on the left, rather than the right.\n\t\t\tbrowser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;\n\t\n\t\t\t// IE8- don't provide height and width for getBoundingClientRect\n\t\t\tbrowser.bBounding = n[0].getBoundingClientRect().width ? true : false;\n\t\n\t\t\tn.remove();\n\t\t}\n\t\n\t\t$.extend( settings.oBrowser, DataTable.__browser );\n\t\tsettings.oScroll.iBarWidth = DataTable.__browser.barWidth;\n\t}\n\t\n\t\n\t/**\n\t * Array.prototype reduce[Right] method, used for browsers which don't support\n\t * JS 1.6. Done this way to reduce code size, since we iterate either way\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReduce ( that, fn, init, start, end, inc )\n\t{\n\t\tvar\n\t\t\ti = start,\n\t\t\tvalue,\n\t\t\tisSet = false;\n\t\n\t\tif ( init !== undefined ) {\n\t\t\tvalue = init;\n\t\t\tisSet = true;\n\t\t}\n\t\n\t\twhile ( i !== end ) {\n\t\t\tif ( ! that.hasOwnProperty(i) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\tvalue = isSet ?\n\t\t\t\tfn( value, that[i], i, that ) :\n\t\t\t\tthat[i];\n\t\n\t\t\tisSet = true;\n\t\t\ti += inc;\n\t\t}\n\t\n\t\treturn value;\n\t}\n\t\n\t/**\n\t * Add a column to the list used for the table with default values\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nTh The th element for this column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddColumn( oSettings, nTh )\n\t{\n\t\t// Add column to aoColumns array\n\t\tvar oDefaults = DataTable.defaults.column;\n\t\tvar iCol = oSettings.aoColumns.length;\n\t\tvar oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {\n\t\t\t\"nTh\": nTh ? nTh : document.createElement('th'),\n\t\t\t\"sTitle\":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',\n\t\t\t\"aDataSort\": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],\n\t\t\t\"mData\": oDefaults.mData ? oDefaults.mData : iCol,\n\t\t\tidx: iCol\n\t\t} );\n\t\toSettings.aoColumns.push( oCol );\n\t\n\t\t// Add search object for column specific search. Note that the `searchCols[ iCol ]`\n\t\t// passed into extend can be undefined. This allows the user to give a default\n\t\t// with only some of the parameters defined, and also not give a default\n\t\tvar searchCols = oSettings.aoPreSearchCols;\n\t\tsearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );\n\t\n\t\t// Use the default column options function to initialise classes etc\n\t\t_fnColumnOptions( oSettings, iCol, $(nTh).data() );\n\t}\n\t\n\t\n\t/**\n\t * Apply options for a column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iCol column index to consider\n\t *  @param {object} oOptions object with sType, bVisible and bSearchable etc\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnOptions( oSettings, iCol, oOptions )\n\t{\n\t\tvar oCol = oSettings.aoColumns[ iCol ];\n\t\tvar oClasses = oSettings.oClasses;\n\t\tvar th = $(oCol.nTh);\n\t\n\t\t// Try to get width information from the DOM. We can't get it from CSS\n\t\t// as we'd need to parse the CSS stylesheet. `width` option can override\n\t\tif ( ! oCol.sWidthOrig ) {\n\t\t\t// Width attribute\n\t\t\toCol.sWidthOrig = th.attr('width') || null;\n\t\n\t\t\t// Style attribute\n\t\t\tvar t = (th.attr('style') || '').match(/width:\\s*(\\d+[pxem%]+)/);\n\t\t\tif ( t ) {\n\t\t\t\toCol.sWidthOrig = t[1];\n\t\t\t}\n\t\t}\n\t\n\t\t/* User specified column options */\n\t\tif ( oOptions !== undefined && oOptions !== null )\n\t\t{\n\t\t\t// Backwards compatibility\n\t\t\t_fnCompatCols( oOptions );\n\t\n\t\t\t// Map camel case parameters to their Hungarian counterparts\n\t\t\t_fnCamelToHungarian( DataTable.defaults.column, oOptions );\n\t\n\t\t\t/* Backwards compatibility for mDataProp */\n\t\t\tif ( oOptions.mDataProp !== undefined && !oOptions.mData )\n\t\t\t{\n\t\t\t\toOptions.mData = oOptions.mDataProp;\n\t\t\t}\n\t\n\t\t\tif ( oOptions.sType )\n\t\t\t{\n\t\t\t\toCol._sManualType = oOptions.sType;\n\t\t\t}\n\t\n\t\t\t// `class` is a reserved word in Javascript, so we need to provide\n\t\t\t// the ability to use a valid name for the camel case input\n\t\t\tif ( oOptions.className && ! oOptions.sClass )\n\t\t\t{\n\t\t\t\toOptions.sClass = oOptions.className;\n\t\t\t}\n\t\n\t\t\t$.extend( oCol, oOptions );\n\t\t\t_fnMap( oCol, oOptions, \"sWidth\", \"sWidthOrig\" );\n\t\n\t\t\t/* iDataSort to be applied (backwards compatibility), but aDataSort will take\n\t\t\t * priority if defined\n\t\t\t */\n\t\t\tif ( oOptions.iDataSort !== undefined )\n\t\t\t{\n\t\t\t\toCol.aDataSort = [ oOptions.iDataSort ];\n\t\t\t}\n\t\t\t_fnMap( oCol, oOptions, \"aDataSort\" );\n\t\t}\n\t\n\t\t/* Cache the data get and set functions for speed */\n\t\tvar mDataSrc = oCol.mData;\n\t\tvar mData = _fnGetObjectDataFn( mDataSrc );\n\t\tvar mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;\n\t\n\t\tvar attrTest = function( src ) {\n\t\t\treturn typeof src === 'string' && src.indexOf('@') !== -1;\n\t\t};\n\t\toCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (\n\t\t\tattrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)\n\t\t);\n\t\toCol._setter = null;\n\t\n\t\toCol.fnGetData = function (rowData, type, meta) {\n\t\t\tvar innerData = mData( rowData, type, undefined, meta );\n\t\n\t\t\treturn mRender && type ?\n\t\t\t\tmRender( innerData, type, rowData, meta ) :\n\t\t\t\tinnerData;\n\t\t};\n\t\toCol.fnSetData = function ( rowData, val, meta ) {\n\t\t\treturn _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );\n\t\t};\n\t\n\t\t// Indicate if DataTables should read DOM data as an object or array\n\t\t// Used in _fnGetRowElements\n\t\tif ( typeof mDataSrc !== 'number' ) {\n\t\t\toSettings._rowReadObject = true;\n\t\t}\n\t\n\t\t/* Feature sorting overrides column specific when off */\n\t\tif ( !oSettings.oFeatures.bSort )\n\t\t{\n\t\t\toCol.bSortable = false;\n\t\t\tth.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called\n\t\t}\n\t\n\t\t/* Check that the class assignment is correct for sorting */\n\t\tvar bAsc = $.inArray('asc', oCol.asSorting) !== -1;\n\t\tvar bDesc = $.inArray('desc', oCol.asSorting) !== -1;\n\t\tif ( !oCol.bSortable || (!bAsc && !bDesc) )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableNone;\n\t\t\toCol.sSortingClassJUI = \"\";\n\t\t}\n\t\telse if ( bAsc && !bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableAsc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;\n\t\t}\n\t\telse if ( !bAsc && bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableDesc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;\n\t\t}\n\t\telse\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortable;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUI;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Adjust the table column widths for new data. Note: you would probably want to\n\t * do a redraw after calling this function!\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAdjustColumnSizing ( settings )\n\t{\n\t\t/* Not interested in doing column width calculation if auto-width is disabled */\n\t\tif ( settings.oFeatures.bAutoWidth !== false )\n\t\t{\n\t\t\tvar columns = settings.aoColumns;\n\t\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t\tfor ( var i=0 , iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tcolumns[i].nTh.style.width = columns[i].sWidth;\n\t\t\t}\n\t\t}\n\t\n\t\tvar scroll = settings.oScroll;\n\t\tif ( scroll.sY !== '' || scroll.sX !== '')\n\t\t{\n\t\t\t_fnScrollDraw( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'column-sizing', [settings] );\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of a visible column to the index in the data array (take account\n\t * of hidden columns)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iMatch Visible column index to lookup\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisibleToColumnIndex( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\n\t\treturn typeof aiVis[iMatch] === 'number' ?\n\t\t\taiVis[iMatch] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of an index in the data array and convert it to the visible\n\t *   column index (take account of hidden columns)\n\t *  @param {int} iMatch Column index to lookup\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnIndexToVisible( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\tvar iPos = $.inArray( iMatch, aiVis );\n\t\n\t\treturn iPos !== -1 ? iPos : null;\n\t}\n\t\n\t\n\t/**\n\t * Get the number of visible columns\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the number of visible columns\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisbleColumns( oSettings )\n\t{\n\t\tvar vis = 0;\n\t\n\t\t// No reduce in IE8, use a loop for now\n\t\t$.each( oSettings.aoColumns, function ( i, col ) {\n\t\t\tif ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {\n\t\t\t\tvis++;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn vis;\n\t}\n\t\n\t\n\t/**\n\t * Get an array of column indexes that match a given property\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sParam Parameter in aoColumns to look for - typically\n\t *    bVisible or bSearchable\n\t *  @returns {array} Array of indexes with matched properties\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetColumns( oSettings, sParam )\n\t{\n\t\tvar a = [];\n\t\n\t\t$.map( oSettings.aoColumns, function(val, i) {\n\t\t\tif ( val[sParam] ) {\n\t\t\t\ta.push( i );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn a;\n\t}\n\t\n\t\n\t/**\n\t * Calculate the 'type' of a column\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnTypes ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar data = settings.aoData;\n\t\tvar types = DataTable.ext.type.detect;\n\t\tvar i, ien, j, jen, k, ken;\n\t\tvar col, cell, detectedType, cache;\n\t\n\t\t// For each column, spin over the \n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcol = columns[i];\n\t\t\tcache = [];\n\t\n\t\t\tif ( ! col.sType && col._sManualType ) {\n\t\t\t\tcol.sType = col._sManualType;\n\t\t\t}\n\t\t\telse if ( ! col.sType ) {\n\t\t\t\tfor ( j=0, jen=types.length ; j<jen ; j++ ) {\n\t\t\t\t\tfor ( k=0, ken=data.length ; k<ken ; k++ ) {\n\t\t\t\t\t\t// Use a cache array so we only need to get the type data\n\t\t\t\t\t\t// from the formatter once (when using multiple detectors)\n\t\t\t\t\t\tif ( cache[k] === undefined ) {\n\t\t\t\t\t\t\tcache[k] = _fnGetCellData( settings, k, i, 'type' );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tdetectedType = types[j]( cache[k], settings );\n\t\n\t\t\t\t\t\t// If null, then this type can't apply to this column, so\n\t\t\t\t\t\t// rather than testing all cells, break out. There is an\n\t\t\t\t\t\t// exception for the last type which is `html`. We need to\n\t\t\t\t\t\t// scan all rows since it is possible to mix string and HTML\n\t\t\t\t\t\t// types\n\t\t\t\t\t\tif ( ! detectedType && j !== types.length-1 ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Only a single match is needed for html type since it is\n\t\t\t\t\t\t// bottom of the pile and very similar to string\n\t\t\t\t\t\tif ( detectedType === 'html' ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Type is valid for all data points in the column - use this\n\t\t\t\t\t// type\n\t\t\t\t\tif ( detectedType ) {\n\t\t\t\t\t\tcol.sType = detectedType;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Fall back - if no type was detected, always use string\n\t\t\t\tif ( ! col.sType ) {\n\t\t\t\t\tcol.sType = 'string';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Take the column definitions and static columns arrays and calculate how\n\t * they relate to column indexes. The callback function will then apply the\n\t * definition found for a column to a suitable configuration object.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aoColDefs The aoColumnDefs array that is to be applied\n\t *  @param {array} aoCols The aoColumns array that defines columns individually\n\t *  @param {function} fn Callback function - takes two parameters, the calculated\n\t *    column index and the definition for that column.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, def;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Column definitions with aTargets\n\t\tif ( aoColDefs )\n\t\t{\n\t\t\t/* Loop over the definitions array - loop in reverse so first instance has priority */\n\t\t\tfor ( i=aoColDefs.length-1 ; i>=0 ; i-- )\n\t\t\t{\n\t\t\t\tdef = aoColDefs[i];\n\t\n\t\t\t\t/* Each definition can target multiple columns, as it is an array */\n\t\t\t\tvar aTargets = def.targets !== undefined ?\n\t\t\t\t\tdef.targets :\n\t\t\t\t\tdef.aTargets;\n\t\n\t\t\t\tif ( ! $.isArray( aTargets ) )\n\t\t\t\t{\n\t\t\t\t\taTargets = [ aTargets ];\n\t\t\t\t}\n\t\n\t\t\t\tfor ( j=0, jLen=aTargets.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Add columns that we don't yet know about */\n\t\t\t\t\t\twhile( columns.length <= aTargets[j] )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_fnAddColumn( oSettings );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t/* Integer, basic index */\n\t\t\t\t\t\tfn( aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Negative integer, right to left column counting */\n\t\t\t\t\t\tfn( columns.length+aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'string' )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Class name matching on TH element */\n\t\t\t\t\t\tfor ( k=0, kLen=columns.length ; k<kLen ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( aTargets[j] == \"_all\" ||\n\t\t\t\t\t\t\t     $(columns[k].nTh).hasClass( aTargets[j] ) )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfn( k, def );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// Statically defined columns array\n\t\tif ( aoCols )\n\t\t{\n\t\t\tfor ( i=0, iLen=aoCols.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfn( i, aoCols[i] );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * Add a data array to the table, creating DOM node etc. This is the parallel to\n\t * _fnGatherData, but for adding rows from a Javascript source, rather than a\n\t * DOM source.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aData data array to be added\n\t *  @param {node} [nTr] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddData ( oSettings, aDataIn, nTr, anTds )\n\t{\n\t\t/* Create the object for storing information about this new row */\n\t\tvar iRow = oSettings.aoData.length;\n\t\tvar oData = $.extend( true, {}, DataTable.models.oRow, {\n\t\t\tsrc: nTr ? 'dom' : 'data',\n\t\t\tidx: iRow\n\t\t} );\n\t\n\t\toData._aData = aDataIn;\n\t\toSettings.aoData.push( oData );\n\t\n\t\t/* Create the cells */\n\t\tvar nTd, sThisType;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Invalidate the column types as the new data needs to be revalidated\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tcolumns[i].sType = null;\n\t\t}\n\t\n\t\t/* Add to the display array */\n\t\toSettings.aiDisplayMaster.push( iRow );\n\t\n\t\tvar id = oSettings.rowIdFn( aDataIn );\n\t\tif ( id !== undefined ) {\n\t\t\toSettings.aIds[ id ] = oData;\n\t\t}\n\t\n\t\t/* Create the DOM information, or register it if already present */\n\t\tif ( nTr || ! oSettings.oFeatures.bDeferRender )\n\t\t{\n\t\t\t_fnCreateTr( oSettings, iRow, nTr, anTds );\n\t\t}\n\t\n\t\treturn iRow;\n\t}\n\t\n\t\n\t/**\n\t * Add one or more TR elements to the table. Generally we'd expect to\n\t * use this for reading data from a DOM sourced table, but it could be\n\t * used for an TR element. Note that if a TR is given, it is used (i.e.\n\t * it is not cloned).\n\t *  @param {object} settings dataTables settings object\n\t *  @param {array|node|jQuery} trs The TR element(s) to add to the table\n\t *  @returns {array} Array of indexes for the added rows\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddTr( settings, trs )\n\t{\n\t\tvar row;\n\t\n\t\t// Allow an individual node to be passed in\n\t\tif ( ! (trs instanceof $) ) {\n\t\t\ttrs = $(trs);\n\t\t}\n\t\n\t\treturn trs.map( function (i, el) {\n\t\t\trow = _fnGetRowElements( settings, el );\n\t\t\treturn _fnAddData( settings, row.data, el, row.cells );\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Take a TR element and convert it to an index in aoData\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} n the TR element to find\n\t *  @returns {int} index if the node is found, null if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToDataIndex( oSettings, n )\n\t{\n\t\treturn (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;\n\t}\n\t\n\t\n\t/**\n\t * Take a TD element and convert it into a column data index (not the visible index)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow The row number the TD/TH can be found in\n\t *  @param {node} n The TD/TH element to find\n\t *  @returns {int} index if the node is found, -1 if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToColumnIndex( oSettings, iRow, n )\n\t{\n\t\treturn $.inArray( n, oSettings.aoData[ iRow ].anCells );\n\t}\n\t\n\t\n\t/**\n\t * Get the data for a given cell from the internal cache, taking into account data mapping\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {string} type data get type ('display', 'type' 'filter' 'sort')\n\t *  @returns {*} Cell data\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetCellData( settings, rowIdx, colIdx, type )\n\t{\n\t\tvar draw           = settings.iDraw;\n\t\tvar col            = settings.aoColumns[colIdx];\n\t\tvar rowData        = settings.aoData[rowIdx]._aData;\n\t\tvar defaultContent = col.sDefaultContent;\n\t\tvar cellData       = col.fnGetData( rowData, type, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t} );\n\t\n\t\tif ( cellData === undefined ) {\n\t\t\tif ( settings.iDrawError != draw && defaultContent === null ) {\n\t\t\t\t_fnLog( settings, 0, \"Requested unknown parameter \"+\n\t\t\t\t\t(typeof col.mData=='function' ? '{function}' : \"'\"+col.mData+\"'\")+\n\t\t\t\t\t\" for row \"+rowIdx+\", column \"+colIdx, 4 );\n\t\t\t\tsettings.iDrawError = draw;\n\t\t\t}\n\t\t\treturn defaultContent;\n\t\t}\n\t\n\t\t// When the data source is null and a specific data type is requested (i.e.\n\t\t// not the original data), we can use default column data\n\t\tif ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {\n\t\t\tcellData = defaultContent;\n\t\t}\n\t\telse if ( typeof cellData === 'function' ) {\n\t\t\t// If the data source is a function, then we run it and use the return,\n\t\t\t// executing in the scope of the data object (for instances)\n\t\t\treturn cellData.call( rowData );\n\t\t}\n\t\n\t\tif ( cellData === null && type == 'display' ) {\n\t\t\treturn '';\n\t\t}\n\t\treturn cellData;\n\t}\n\t\n\t\n\t/**\n\t * Set the value for a specific cell, into the internal data cache\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {*} val Value to set\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetCellData( settings, rowIdx, colIdx, val )\n\t{\n\t\tvar col     = settings.aoColumns[colIdx];\n\t\tvar rowData = settings.aoData[rowIdx]._aData;\n\t\n\t\tcol.fnSetData( rowData, val, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t}  );\n\t}\n\t\n\t\n\t// Private variable that is used to match action syntax in the data property object\n\tvar __reArray = /\\[.*?\\]$/;\n\tvar __reFn = /\\(\\)$/;\n\t\n\t/**\n\t * Split string on periods, taking into account escaped periods\n\t * @param  {string} str String to split\n\t * @return {array} Split string\n\t */\n\tfunction _fnSplitObjNotation( str )\n\t{\n\t\treturn $.map( str.match(/(\\\\.|[^\\.])+/g) || [''], function ( s ) {\n\t\t\treturn s.replace(/\\\\\\./g, '.');\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to get data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data get function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Build an object of get functions, and wrap them in a single call */\n\t\t\tvar o = {};\n\t\t\t$.each( mSource, function (key, val) {\n\t\t\t\tif ( val ) {\n\t\t\t\t\to[key] = _fnGetObjectDataFn( val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\tvar t = o[type] || o._;\n\t\t\t\treturn t !== undefined ?\n\t\t\t\t\tt(data, type, row, meta) :\n\t\t\t\t\tdata;\n\t\t\t};\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Give an empty string for rendering / sorting etc */\n\t\t\treturn function (data) { // type, row and meta also passed, but not used\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\treturn mSource( data, type, row, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* If there is a . in the source string then the data source is in a\n\t\t\t * nested object so we loop over the data for each level to get the next\n\t\t\t * level down. On each loop we test for undefined, and if found immediately\n\t\t\t * return. This allows entire objects to be missing and sDefaultContent to\n\t\t\t * be used if defined, rather than throwing an error\n\t\t\t */\n\t\t\tvar fetchData = function (data, type, src) {\n\t\t\t\tvar arrayNotation, funcNotation, out, innerSrc;\n\t\n\t\t\t\tif ( src !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tvar a = _fnSplitObjNotation( src );\n\t\n\t\t\t\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if we are dealing with special notation\n\t\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Array notation\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\n\t\t\t\t\t\t\t// Condition allows simply [] to be passed in\n\t\t\t\t\t\t\tif ( a[i] !== \"\" ) {\n\t\t\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tout = [];\n\t\n\t\t\t\t\t\t\t// Get the remainder of the nested object to get\n\t\t\t\t\t\t\ta.splice( 0, i+1 );\n\t\t\t\t\t\t\tinnerSrc = a.join('.');\n\t\n\t\t\t\t\t\t\t// Traverse each entry in the array getting the properties requested\n\t\t\t\t\t\t\tif ( $.isArray( data ) ) {\n\t\t\t\t\t\t\t\tfor ( var j=0, jLen=data.length ; j<jLen ; j++ ) {\n\t\t\t\t\t\t\t\t\tout.push( fetchData( data[j], type, innerSrc ) );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\t// If a string is given in between the array notation indicators, that\n\t\t\t\t\t\t\t// is used to join the strings together, otherwise an array is returned\n\t\t\t\t\t\t\tvar join = arrayNotation[0].substring(1, arrayNotation[0].length-1);\n\t\t\t\t\t\t\tdata = (join===\"\") ? out : out.join(join);\n\t\n\t\t\t\t\t\t\t// The inner call to fetchData has already traversed through the remainder\n\t\t\t\t\t\t\t// of the source requested, so we exit from the loop\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Function call\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\t\tdata = data[ a[i] ]();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( data === null || data[ a[i] ] === undefined )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn data;\n\t\t\t};\n\t\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn fetchData( data, type, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn data[mSource];\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to set data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data set function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Unlike get, only the underscore (global) option is used for for\n\t\t\t * setting data since we don't know the type here. This is why an object\n\t\t\t * option is not documented for `mData` (which is read/write), but it is\n\t\t\t * for `mRender` which is read only.\n\t\t\t */\n\t\t\treturn _fnSetObjectDataFn( mSource._ );\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Nothing to do when the data source is null */\n\t\t\treturn function () {};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, val, meta) {\n\t\t\t\tmSource( data, 'set', val, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* Like the get, we need to get data from a nested object */\n\t\t\tvar setData = function (data, val, src) {\n\t\t\t\tvar a = _fnSplitObjNotation( src ), b;\n\t\t\t\tvar aLast = a[a.length-1];\n\t\t\t\tvar arrayNotation, funcNotation, o, innerSrc;\n\t\n\t\t\t\tfor ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\t// Check if we are dealing with an array notation request\n\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\t\t\t\t\tdata[ a[i] ] = [];\n\t\n\t\t\t\t\t\t// Get the remainder of the nested object to set so we can recurse\n\t\t\t\t\t\tb = a.slice();\n\t\t\t\t\t\tb.splice( 0, i+1 );\n\t\t\t\t\t\tinnerSrc = b.join('.');\n\t\n\t\t\t\t\t\t// Traverse each entry in the array setting the properties requested\n\t\t\t\t\t\tif ( $.isArray( val ) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor ( var j=0, jLen=val.length ; j<jLen ; j++ )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\to = {};\n\t\t\t\t\t\t\t\tsetData( o, val[j], innerSrc );\n\t\t\t\t\t\t\t\tdata[ a[i] ].push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We've been asked to save data to an array, but it\n\t\t\t\t\t\t\t// isn't array data to be saved. Best that can be done\n\t\t\t\t\t\t\t// is to just save the value.\n\t\t\t\t\t\t\tdata[ a[i] ] = val;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// The inner call to setData has already traversed through the remainder\n\t\t\t\t\t\t// of the source and has set the data, thus we can exit here\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Function call\n\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\tdata = data[ a[i] ]( val );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If the nested object doesn't currently exist - since we are\n\t\t\t\t\t// trying to set the value - create it\n\t\t\t\t\tif ( data[ a[i] ] === null || data[ a[i] ] === undefined )\n\t\t\t\t\t{\n\t\t\t\t\t\tdata[ a[i] ] = {};\n\t\t\t\t\t}\n\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t}\n\t\n\t\t\t\t// Last item in the input - i.e, the actual set\n\t\t\t\tif ( aLast.match(__reFn ) )\n\t\t\t\t{\n\t\t\t\t\t// Function call\n\t\t\t\t\tdata = data[ aLast.replace(__reFn, '') ]( val );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// If array notation is used, we just want to strip it and use the property name\n\t\t\t\t\t// and assign the value. If it isn't used, then we get the result we want anyway\n\t\t\t\t\tdata[ aLast.replace(__reArray, '') ] = val;\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\treturn setData( data, val, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\tdata[mSource] = val;\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return an array with the full table data\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns array {array} aData Master data array\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetDataMaster ( settings )\n\t{\n\t\treturn _pluck( settings.aoData, '_aData' );\n\t}\n\t\n\t\n\t/**\n\t * Nuke the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnClearTable( settings )\n\t{\n\t\tsettings.aoData.length = 0;\n\t\tsettings.aiDisplayMaster.length = 0;\n\t\tsettings.aiDisplay.length = 0;\n\t\tsettings.aIds = {};\n\t}\n\t\n\t\n\t /**\n\t * Take an array of integers (index array) and remove a target integer (value - not\n\t * the key!)\n\t *  @param {array} a Index array to target\n\t *  @param {int} iTarget value to find\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDeleteIndex( a, iTarget, splice )\n\t{\n\t\tvar iTargetIndex = -1;\n\t\n\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( a[i] == iTarget )\n\t\t\t{\n\t\t\t\tiTargetIndex = i;\n\t\t\t}\n\t\t\telse if ( a[i] > iTarget )\n\t\t\t{\n\t\t\t\ta[i]--;\n\t\t\t}\n\t\t}\n\t\n\t\tif ( iTargetIndex != -1 && splice === undefined )\n\t\t{\n\t\t\ta.splice( iTargetIndex, 1 );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Mark cached data as invalid such that a re-read of the data will occur when\n\t * the cached data is next requested. Also update from the data source object.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {int}    rowIdx   Row index to invalidate\n\t * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'\n\t *     or 'data'\n\t * @param {int}    [colIdx] Column index to invalidate. If undefined the whole\n\t *     row will be invalidated\n\t * @memberof DataTable#oApi\n\t *\n\t * @todo For the modularisation of v1.11 this will need to become a callback, so\n\t *   the sort and filter methods can subscribe to it. That will required\n\t *   initialisation options for sorting, which is why it is not already baked in\n\t */\n\tfunction _fnInvalidate( settings, rowIdx, src, colIdx )\n\t{\n\t\tvar row = settings.aoData[ rowIdx ];\n\t\tvar i, ien;\n\t\tvar cellWrite = function ( cell, col ) {\n\t\t\t// This is very frustrating, but in IE if you just write directly\n\t\t\t// to innerHTML, and elements that are overwritten are GC'ed,\n\t\t\t// even if there is a reference to them elsewhere\n\t\t\twhile ( cell.childNodes.length ) {\n\t\t\t\tcell.removeChild( cell.firstChild );\n\t\t\t}\n\t\n\t\t\tcell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );\n\t\t};\n\t\n\t\t// Are we reading last data from DOM or the data object?\n\t\tif ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {\n\t\t\t// Read the data from the DOM\n\t\t\trow._aData = _fnGetRowElements(\n\t\t\t\t\tsettings, row, colIdx, colIdx === undefined ? undefined : row._aData\n\t\t\t\t)\n\t\t\t\t.data;\n\t\t}\n\t\telse {\n\t\t\t// Reading from data object, update the DOM\n\t\t\tvar cells = row.anCells;\n\t\n\t\t\tif ( cells ) {\n\t\t\t\tif ( colIdx !== undefined ) {\n\t\t\t\t\tcellWrite( cells[colIdx], colIdx );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tcellWrite( cells[i], i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// For both row and cell invalidation, the cached data for sorting and\n\t\t// filtering is nulled out\n\t\trow._aSortData = null;\n\t\trow._aFilterData = null;\n\t\n\t\t// Invalidate the type for a specific column (if given) or all columns since\n\t\t// the data might have changed\n\t\tvar cols = settings.aoColumns;\n\t\tif ( colIdx !== undefined ) {\n\t\t\tcols[ colIdx ].sType = null;\n\t\t}\n\t\telse {\n\t\t\tfor ( i=0, ien=cols.length ; i<ien ; i++ ) {\n\t\t\t\tcols[i].sType = null;\n\t\t\t}\n\t\n\t\t\t// Update DataTables special `DT_*` attributes for the row\n\t\t\t_fnRowAttributes( settings, row );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a data source object from an HTML row, reading the contents of the\n\t * cells that are in the row.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {node|object} TR element from which to read data or existing row\n\t *   object from which to re-read the data from the cells\n\t * @param {int} [colIdx] Optional column index\n\t * @param {array|object} [d] Data source object. If `colIdx` is given then this\n\t *   parameter should also be given and will be used to write the data into.\n\t *   Only the column in question will be written\n\t * @returns {object} Object with two parameters: `data` the data read, in\n\t *   document order, and `cells` and array of nodes (they can be useful to the\n\t *   caller, so rather than needing a second traversal to get them, just return\n\t *   them from here).\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetRowElements( settings, row, colIdx, d )\n\t{\n\t\tvar\n\t\t\ttds = [],\n\t\t\ttd = row.firstChild,\n\t\t\tname, col, o, i=0, contents,\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tobjectRead = settings._rowReadObject;\n\t\n\t\t// Allow the data object to be passed in, or construct\n\t\td = d !== undefined ?\n\t\t\td :\n\t\t\tobjectRead ?\n\t\t\t\t{} :\n\t\t\t\t[];\n\t\n\t\tvar attr = function ( str, td  ) {\n\t\t\tif ( typeof str === 'string' ) {\n\t\t\t\tvar idx = str.indexOf('@');\n\t\n\t\t\t\tif ( idx !== -1 ) {\n\t\t\t\t\tvar attr = str.substring( idx+1 );\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( str );\n\t\t\t\t\tsetter( d, td.getAttribute( attr ) );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\n\t\t// Read data from a cell and store into the data object\n\t\tvar cellProcess = function ( cell ) {\n\t\t\tif ( colIdx === undefined || colIdx === i ) {\n\t\t\t\tcol = columns[i];\n\t\t\t\tcontents = $.trim(cell.innerHTML);\n\t\n\t\t\t\tif ( col && col._bAttrSrc ) {\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( col.mData._ );\n\t\t\t\t\tsetter( d, contents );\n\t\n\t\t\t\t\tattr( col.mData.sort, cell );\n\t\t\t\t\tattr( col.mData.type, cell );\n\t\t\t\t\tattr( col.mData.filter, cell );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Depending on the `data` option for the columns the data can\n\t\t\t\t\t// be read to either an object or an array.\n\t\t\t\t\tif ( objectRead ) {\n\t\t\t\t\t\tif ( ! col._setter ) {\n\t\t\t\t\t\t\t// Cache the setter function\n\t\t\t\t\t\t\tcol._setter = _fnSetObjectDataFn( col.mData );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcol._setter( d, contents );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\td[i] = contents;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t};\n\t\n\t\tif ( td ) {\n\t\t\t// `tr` element was passed in\n\t\t\twhile ( td ) {\n\t\t\t\tname = td.nodeName.toUpperCase();\n\t\n\t\t\t\tif ( name == \"TD\" || name == \"TH\" ) {\n\t\t\t\t\tcellProcess( td );\n\t\t\t\t\ttds.push( td );\n\t\t\t\t}\n\t\n\t\t\t\ttd = td.nextSibling;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Existing row object passed in\n\t\t\ttds = row.anCells;\n\t\n\t\t\tfor ( var j=0, jen=tds.length ; j<jen ; j++ ) {\n\t\t\t\tcellProcess( tds[j] );\n\t\t\t}\n\t\t}\n\t\n\t\t// Read the ID from the DOM if present\n\t\tvar rowNode = row.firstChild ? row : row.nTr;\n\t\n\t\tif ( rowNode ) {\n\t\t\tvar id = rowNode.getAttribute( 'id' );\n\t\n\t\t\tif ( id ) {\n\t\t\t\t_fnSetObjectDataFn( settings.rowId )( d, id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn {\n\t\t\tdata: d,\n\t\t\tcells: tds\n\t\t};\n\t}\n\t/**\n\t * Create a new TR element (and it's TD children) for a row\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow Row to consider\n\t *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCreateTr ( oSettings, iRow, nTrIn, anTds )\n\t{\n\t\tvar\n\t\t\trow = oSettings.aoData[iRow],\n\t\t\trowData = row._aData,\n\t\t\tcells = [],\n\t\t\tnTr, nTd, oCol,\n\t\t\ti, iLen;\n\t\n\t\tif ( row.nTr === null )\n\t\t{\n\t\t\tnTr = nTrIn || document.createElement('tr');\n\t\n\t\t\trow.nTr = nTr;\n\t\t\trow.anCells = cells;\n\t\n\t\t\t/* Use a private property on the node to allow reserve mapping from the node\n\t\t\t * to the aoData array for fast look up\n\t\t\t */\n\t\t\tnTr._DT_RowIndex = iRow;\n\t\n\t\t\t/* Special parameters can be given by the data source to be used on the row */\n\t\t\t_fnRowAttributes( oSettings, row );\n\t\n\t\t\t/* Process each column */\n\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toCol = oSettings.aoColumns[i];\n\t\n\t\t\t\tnTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );\n\t\t\t\tnTd._DT_CellIndex = {\n\t\t\t\t\trow: iRow,\n\t\t\t\t\tcolumn: i\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tcells.push( nTd );\n\t\n\t\t\t\t// Need to create the HTML if new, or if a rendering function is defined\n\t\t\t\tif ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&\n\t\t\t\t\t (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')\n\t\t\t\t) {\n\t\t\t\t\tnTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );\n\t\t\t\t}\n\t\n\t\t\t\t/* Add user defined class */\n\t\t\t\tif ( oCol.sClass )\n\t\t\t\t{\n\t\t\t\t\tnTd.className += ' '+oCol.sClass;\n\t\t\t\t}\n\t\n\t\t\t\t// Visibility - add or remove as required\n\t\t\t\tif ( oCol.bVisible && ! nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTr.appendChild( nTd );\n\t\t\t\t}\n\t\t\t\telse if ( ! oCol.bVisible && nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTd.parentNode.removeChild( nTd );\n\t\t\t\t}\n\t\n\t\t\t\tif ( oCol.fnCreatedCell )\n\t\t\t\t{\n\t\t\t\t\toCol.fnCreatedCell.call( oSettings.oInstance,\n\t\t\t\t\t\tnTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );\n\t\t}\n\t\n\t\t// Remove once webkit bug 131819 and Chromium bug 365619 have been resolved\n\t\t// and deployed\n\t\trow.nTr.setAttribute( 'role', 'row' );\n\t}\n\t\n\t\n\t/**\n\t * Add attributes to a row based on the special `DT_*` parameters in a data\n\t * source object.\n\t *  @param {object} settings DataTables settings object\n\t *  @param {object} DataTables row object for the row to be modified\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnRowAttributes( settings, row )\n\t{\n\t\tvar tr = row.nTr;\n\t\tvar data = row._aData;\n\t\n\t\tif ( tr ) {\n\t\t\tvar id = settings.rowIdFn( data );\n\t\n\t\t\tif ( id ) {\n\t\t\t\ttr.id = id;\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowClass ) {\n\t\t\t\t// Remove any classes added by DT_RowClass before\n\t\t\t\tvar a = data.DT_RowClass.split(' ');\n\t\t\t\trow.__rowc = row.__rowc ?\n\t\t\t\t\t_unique( row.__rowc.concat( a ) ) :\n\t\t\t\t\ta;\n\t\n\t\t\t\t$(tr)\n\t\t\t\t\t.removeClass( row.__rowc.join(' ') )\n\t\t\t\t\t.addClass( data.DT_RowClass );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowAttr ) {\n\t\t\t\t$(tr).attr( data.DT_RowAttr );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowData ) {\n\t\t\t\t$(tr).data( data.DT_RowData );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Create the HTML header for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBuildHead( oSettings )\n\t{\n\t\tvar i, ien, cell, row, column;\n\t\tvar thead = oSettings.nTHead;\n\t\tvar tfoot = oSettings.nTFoot;\n\t\tvar createHeader = $('th, td', thead).length === 0;\n\t\tvar classes = oSettings.oClasses;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\tif ( createHeader ) {\n\t\t\trow = $('<tr/>').appendTo( thead );\n\t\t}\n\t\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcell = $( column.nTh ).addClass( column.sClass );\n\t\n\t\t\tif ( createHeader ) {\n\t\t\t\tcell.appendTo( row );\n\t\t\t}\n\t\n\t\t\t// 1.11 move into sorting\n\t\t\tif ( oSettings.oFeatures.bSort ) {\n\t\t\t\tcell.addClass( column.sSortingClass );\n\t\n\t\t\t\tif ( column.bSortable !== false ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.attr( 'tabindex', oSettings.iTabIndex )\n\t\t\t\t\t\t.attr( 'aria-controls', oSettings.sTableId );\n\t\n\t\t\t\t\t_fnSortAttachListener( oSettings, column.nTh, i );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( column.sTitle != cell[0].innerHTML ) {\n\t\t\t\tcell.html( column.sTitle );\n\t\t\t}\n\t\n\t\t\t_fnRenderer( oSettings, 'header' )(\n\t\t\t\toSettings, cell, column, classes\n\t\t\t);\n\t\t}\n\t\n\t\tif ( createHeader ) {\n\t\t\t_fnDetectHeader( oSettings.aoHeader, thead );\n\t\t}\n\t\t\n\t\t/* ARIA role for the rows */\n\t \t$(thead).find('>tr').attr('role', 'row');\n\t\n\t\t/* Deal with the footer - add classes if required */\n\t\t$(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );\n\t\t$(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );\n\t\n\t\t// Cache the footer cells. Note that we only take the cells from the first\n\t\t// row in the footer. If there is more than one row the user wants to\n\t\t// interact with, they need to use the table().foot() method. Note also this\n\t\t// allows cells to be used for multiple columns using colspan\n\t\tif ( tfoot !== null ) {\n\t\t\tvar cells = oSettings.aoFooter[0];\n\t\n\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tcolumn = columns[i];\n\t\t\t\tcolumn.nTf = cells[i].cell;\n\t\n\t\t\t\tif ( column.sClass ) {\n\t\t\t\t\t$(column.nTf).addClass( column.sClass );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the header (or footer) element based on the column visibility states. The\n\t * methodology here is to use the layout array from _fnDetectHeader, modified for\n\t * the instantaneous column visibility, to construct the new layout. The grid is\n\t * traversed over cell at a time in a rows x columns grid fashion, although each\n\t * cell insert can cover multiple elements in the grid - which is tracks using the\n\t * aApplied array. Cell inserts in the grid will only occur where there isn't\n\t * already a cell in that position.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param array {objects} aoSource Layout array from _fnDetectHeader\n\t *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDrawHead( oSettings, aoSource, bIncludeHidden )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, n, nLocalTr;\n\t\tvar aoLocal = [];\n\t\tvar aApplied = [];\n\t\tvar iColumns = oSettings.aoColumns.length;\n\t\tvar iRowspan, iColspan;\n\t\n\t\tif ( ! aoSource )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif (  bIncludeHidden === undefined )\n\t\t{\n\t\t\tbIncludeHidden = false;\n\t\t}\n\t\n\t\t/* Make a copy of the master layout array, but without the visible columns in it */\n\t\tfor ( i=0, iLen=aoSource.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taoLocal[i] = aoSource[i].slice();\n\t\t\taoLocal[i].nTr = aoSource[i].nTr;\n\t\n\t\t\t/* Remove any columns which are currently hidden */\n\t\t\tfor ( j=iColumns-1 ; j>=0 ; j-- )\n\t\t\t{\n\t\t\t\tif ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )\n\t\t\t\t{\n\t\t\t\t\taoLocal[i].splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Prep the applied array - it needs an element for each row */\n\t\t\taApplied.push( [] );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnLocalTr = aoLocal[i].nTr;\n\t\n\t\t\t/* All cells are going to be replaced, so empty out the row */\n\t\t\tif ( nLocalTr )\n\t\t\t{\n\t\t\t\twhile( (n = nLocalTr.firstChild) )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.removeChild( n );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tfor ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tiRowspan = 1;\n\t\t\t\tiColspan = 1;\n\t\n\t\t\t\t/* Check to see if there is already a cell (row/colspan) covering our target\n\t\t\t\t * insert point. If there is, then there is nothing to do.\n\t\t\t\t */\n\t\t\t\tif ( aApplied[i][j] === undefined )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.appendChild( aoLocal[i][j].cell );\n\t\t\t\t\taApplied[i][j] = 1;\n\t\n\t\t\t\t\t/* Expand the cell to cover as many rows as needed */\n\t\t\t\t\twhile ( aoLocal[i+iRowspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\taApplied[i+iRowspan][j] = 1;\n\t\t\t\t\t\tiRowspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Expand the cell to cover as many columns as needed */\n\t\t\t\t\twhile ( aoLocal[i][j+iColspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Must update the applied array over the rows for the columns */\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taApplied[i+k][j+iColspan] = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiColspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Do the actual expansion in the DOM */\n\t\t\t\t\t$(aoLocal[i][j].cell)\n\t\t\t\t\t\t.attr('rowspan', iRowspan)\n\t\t\t\t\t\t.attr('colspan', iColspan);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Insert the required TR nodes into the table for display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDraw( oSettings )\n\t{\n\t\t/* Provide a pre-callback function which can be used to cancel the draw is false is returned */\n\t\tvar aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );\n\t\tif ( $.inArray( false, aPreDraw ) !== -1 )\n\t\t{\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar i, iLen, n;\n\t\tvar anRows = [];\n\t\tvar iRowCount = 0;\n\t\tvar asStripeClasses = oSettings.asStripeClasses;\n\t\tvar iStripes = asStripeClasses.length;\n\t\tvar iOpenRows = oSettings.aoOpenRows.length;\n\t\tvar oLang = oSettings.oLanguage;\n\t\tvar iInitDisplayStart = oSettings.iInitDisplayStart;\n\t\tvar bServerSide = _fnDataSource( oSettings ) == 'ssp';\n\t\tvar aiDisplay = oSettings.aiDisplay;\n\t\n\t\toSettings.bDrawing = true;\n\t\n\t\t/* Check and see if we have an initial draw position from state saving */\n\t\tif ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )\n\t\t{\n\t\t\toSettings._iDisplayStart = bServerSide ?\n\t\t\t\tiInitDisplayStart :\n\t\t\t\tiInitDisplayStart >= oSettings.fnRecordsDisplay() ?\n\t\t\t\t\t0 :\n\t\t\t\t\tiInitDisplayStart;\n\t\n\t\t\toSettings.iInitDisplayStart = -1;\n\t\t}\n\t\n\t\tvar iDisplayStart = oSettings._iDisplayStart;\n\t\tvar iDisplayEnd = oSettings.fnDisplayEnd();\n\t\n\t\t/* Server-side processing draw intercept */\n\t\tif ( oSettings.bDeferLoading )\n\t\t{\n\t\t\toSettings.bDeferLoading = false;\n\t\t\toSettings.iDraw++;\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t}\n\t\telse if ( !bServerSide )\n\t\t{\n\t\t\toSettings.iDraw++;\n\t\t}\n\t\telse if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( aiDisplay.length !== 0 )\n\t\t{\n\t\t\tvar iStart = bServerSide ? 0 : iDisplayStart;\n\t\t\tvar iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;\n\t\n\t\t\tfor ( var j=iStart ; j<iEnd ; j++ )\n\t\t\t{\n\t\t\t\tvar iDataIndex = aiDisplay[j];\n\t\t\t\tvar aoData = oSettings.aoData[ iDataIndex ];\n\t\t\t\tif ( aoData.nTr === null )\n\t\t\t\t{\n\t\t\t\t\t_fnCreateTr( oSettings, iDataIndex );\n\t\t\t\t}\n\t\n\t\t\t\tvar nRow = aoData.nTr;\n\t\n\t\t\t\t/* Remove the old striping classes and then add the new one */\n\t\t\t\tif ( iStripes !== 0 )\n\t\t\t\t{\n\t\t\t\t\tvar sStripe = asStripeClasses[ iRowCount % iStripes ];\n\t\t\t\t\tif ( aoData._sRowStripe != sStripe )\n\t\t\t\t\t{\n\t\t\t\t\t\t$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );\n\t\t\t\t\t\taoData._sRowStripe = sStripe;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Row callback functions - might want to manipulate the row\n\t\t\t\t// iRowCount and j are not currently documented. Are they at all\n\t\t\t\t// useful?\n\t\t\t\t_fnCallbackFire( oSettings, 'aoRowCallback', null,\n\t\t\t\t\t[nRow, aoData._aData, iRowCount, j] );\n\t\n\t\t\t\tanRows.push( nRow );\n\t\t\t\tiRowCount++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Table is empty - create a row with an empty message in it */\n\t\t\tvar sZero = oLang.sZeroRecords;\n\t\t\tif ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )\n\t\t\t{\n\t\t\t\tsZero = oLang.sLoadingRecords;\n\t\t\t}\n\t\t\telse if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )\n\t\t\t{\n\t\t\t\tsZero = oLang.sEmptyTable;\n\t\t\t}\n\t\n\t\t\tanRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )\n\t\t\t\t.append( $('<td />', {\n\t\t\t\t\t'valign':  'top',\n\t\t\t\t\t'colSpan': _fnVisbleColumns( oSettings ),\n\t\t\t\t\t'class':   oSettings.oClasses.sRowEmpty\n\t\t\t\t} ).html( sZero ) )[0];\n\t\t}\n\t\n\t\t/* Header and footer callbacks */\n\t\t_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\t_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\tvar body = $(oSettings.nTBody);\n\t\n\t\tbody.children().detach();\n\t\tbody.append( $(anRows) );\n\t\n\t\t/* Call all required callback functions for the end of a draw */\n\t\t_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );\n\t\n\t\t/* Draw is complete, sorting and filtering must be as well */\n\t\toSettings.bSorted = false;\n\t\toSettings.bFiltered = false;\n\t\toSettings.bDrawing = false;\n\t}\n\t\n\t\n\t/**\n\t * Redraw the table - taking account of the various features which are enabled\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {boolean} [holdPosition] Keep the current paging position. By default\n\t *    the paging is reset to the first page\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReDraw( settings, holdPosition )\n\t{\n\t\tvar\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tsort     = features.bSort,\n\t\t\tfilter   = features.bFilter;\n\t\n\t\tif ( sort ) {\n\t\t\t_fnSort( settings );\n\t\t}\n\t\n\t\tif ( filter ) {\n\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch );\n\t\t}\n\t\telse {\n\t\t\t// No filtering, so we want to just use the display master\n\t\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\t}\n\t\n\t\tif ( holdPosition !== true ) {\n\t\t\tsettings._iDisplayStart = 0;\n\t\t}\n\t\n\t\t// Let any modules know about the draw hold position state (used by\n\t\t// scrolling internally)\n\t\tsettings._drawHold = holdPosition;\n\t\n\t\t_fnDraw( settings );\n\t\n\t\tsettings._drawHold = false;\n\t}\n\t\n\t\n\t/**\n\t * Add the options to the page HTML for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddOptionsHtml ( oSettings )\n\t{\n\t\tvar classes = oSettings.oClasses;\n\t\tvar table = $(oSettings.nTable);\n\t\tvar holding = $('<div/>').insertBefore( table ); // Holding element for speed\n\t\tvar features = oSettings.oFeatures;\n\t\n\t\t// All DataTables are wrapped in a div\n\t\tvar insert = $('<div/>', {\n\t\t\tid:      oSettings.sTableId+'_wrapper',\n\t\t\t'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)\n\t\t} );\n\t\n\t\toSettings.nHolding = holding[0];\n\t\toSettings.nTableWrapper = insert[0];\n\t\toSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;\n\t\n\t\t/* Loop over the user set positioning and place the elements as needed */\n\t\tvar aDom = oSettings.sDom.split('');\n\t\tvar featureNode, cOption, nNewNode, cNext, sAttr, j;\n\t\tfor ( var i=0 ; i<aDom.length ; i++ )\n\t\t{\n\t\t\tfeatureNode = null;\n\t\t\tcOption = aDom[i];\n\t\n\t\t\tif ( cOption == '<' )\n\t\t\t{\n\t\t\t\t/* New container div */\n\t\t\t\tnNewNode = $('<div/>')[0];\n\t\n\t\t\t\t/* Check to see if we should append an id and/or a class name to the container */\n\t\t\t\tcNext = aDom[i+1];\n\t\t\t\tif ( cNext == \"'\" || cNext == '\"' )\n\t\t\t\t{\n\t\t\t\t\tsAttr = \"\";\n\t\t\t\t\tj = 2;\n\t\t\t\t\twhile ( aDom[i+j] != cNext )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr += aDom[i+j];\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Replace jQuery UI constants @todo depreciated */\n\t\t\t\t\tif ( sAttr == \"H\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIHeader;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr == \"F\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIFooter;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* The attribute can be in the format of \"#id.class\", \"#id\" or \"class\" This logic\n\t\t\t\t\t * breaks the string into parts and applies them as needed\n\t\t\t\t\t */\n\t\t\t\t\tif ( sAttr.indexOf('.') != -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar aSplit = sAttr.split('.');\n\t\t\t\t\t\tnNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);\n\t\t\t\t\t\tnNewNode.className = aSplit[1];\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr.charAt(0) == \"#\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.id = sAttr.substr(1, sAttr.length-1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.className = sAttr;\n\t\t\t\t\t}\n\t\n\t\t\t\t\ti += j; /* Move along the position array */\n\t\t\t\t}\n\t\n\t\t\t\tinsert.append( nNewNode );\n\t\t\t\tinsert = $(nNewNode);\n\t\t\t}\n\t\t\telse if ( cOption == '>' )\n\t\t\t{\n\t\t\t\t/* End container div */\n\t\t\t\tinsert = insert.parent();\n\t\t\t}\n\t\t\t// @todo Move options into their own plugins?\n\t\t\telse if ( cOption == 'l' && features.bPaginate && features.bLengthChange )\n\t\t\t{\n\t\t\t\t/* Length */\n\t\t\t\tfeatureNode = _fnFeatureHtmlLength( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'f' && features.bFilter )\n\t\t\t{\n\t\t\t\t/* Filter */\n\t\t\t\tfeatureNode = _fnFeatureHtmlFilter( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'r' && features.bProcessing )\n\t\t\t{\n\t\t\t\t/* pRocessing */\n\t\t\t\tfeatureNode = _fnFeatureHtmlProcessing( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 't' )\n\t\t\t{\n\t\t\t\t/* Table */\n\t\t\t\tfeatureNode = _fnFeatureHtmlTable( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption ==  'i' && features.bInfo )\n\t\t\t{\n\t\t\t\t/* Info */\n\t\t\t\tfeatureNode = _fnFeatureHtmlInfo( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'p' && features.bPaginate )\n\t\t\t{\n\t\t\t\t/* Pagination */\n\t\t\t\tfeatureNode = _fnFeatureHtmlPaginate( oSettings );\n\t\t\t}\n\t\t\telse if ( DataTable.ext.feature.length !== 0 )\n\t\t\t{\n\t\t\t\t/* Plug-in features */\n\t\t\t\tvar aoFeatures = DataTable.ext.feature;\n\t\t\t\tfor ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )\n\t\t\t\t{\n\t\t\t\t\tif ( cOption == aoFeatures[k].cFeature )\n\t\t\t\t\t{\n\t\t\t\t\t\tfeatureNode = aoFeatures[k].fnInit( oSettings );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Add to the 2D features array */\n\t\t\tif ( featureNode )\n\t\t\t{\n\t\t\t\tvar aanFeatures = oSettings.aanFeatures;\n\t\n\t\t\t\tif ( ! aanFeatures[cOption] )\n\t\t\t\t{\n\t\t\t\t\taanFeatures[cOption] = [];\n\t\t\t\t}\n\t\n\t\t\t\taanFeatures[cOption].push( featureNode );\n\t\t\t\tinsert.append( featureNode );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Built our DOM structure - replace the holding div with what we want */\n\t\tholding.replaceWith( insert );\n\t\toSettings.nHolding = null;\n\t}\n\t\n\t\n\t/**\n\t * Use the DOM source to create up an array of header cells. The idea here is to\n\t * create a layout grid (array) of rows x columns, which contains a reference\n\t * to the cell that that point in the grid (regardless of col/rowspan), such that\n\t * any column / row could be removed and the new grid constructed\n\t *  @param array {object} aLayout Array to store the calculated layout in\n\t *  @param {node} nThead The header/footer element for the table\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDetectHeader ( aLayout, nThead )\n\t{\n\t\tvar nTrs = $(nThead).children('tr');\n\t\tvar nTr, nCell;\n\t\tvar i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;\n\t\tvar bUnique;\n\t\tvar fnShiftCol = function ( a, i, j ) {\n\t\t\tvar k = a[i];\n\t                while ( k[j] ) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\treturn j;\n\t\t};\n\t\n\t\taLayout.splice( 0, aLayout.length );\n\t\n\t\t/* We know how many rows there are in the layout - so prep it */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taLayout.push( [] );\n\t\t}\n\t\n\t\t/* Calculate a layout array */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnTr = nTrs[i];\n\t\t\tiColumn = 0;\n\t\n\t\t\t/* For every cell in the row... */\n\t\t\tnCell = nTr.firstChild;\n\t\t\twhile ( nCell ) {\n\t\t\t\tif ( nCell.nodeName.toUpperCase() == \"TD\" ||\n\t\t\t\t     nCell.nodeName.toUpperCase() == \"TH\" )\n\t\t\t\t{\n\t\t\t\t\t/* Get the col and rowspan attributes from the DOM and sanitise them */\n\t\t\t\t\tiColspan = nCell.getAttribute('colspan') * 1;\n\t\t\t\t\tiRowspan = nCell.getAttribute('rowspan') * 1;\n\t\t\t\t\tiColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;\n\t\t\t\t\tiRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;\n\t\n\t\t\t\t\t/* There might be colspan cells already in this row, so shift our target\n\t\t\t\t\t * accordingly\n\t\t\t\t\t */\n\t\t\t\t\tiColShifted = fnShiftCol( aLayout, i, iColumn );\n\t\n\t\t\t\t\t/* Cache calculation for unique columns */\n\t\t\t\t\tbUnique = iColspan === 1 ? true : false;\n\t\n\t\t\t\t\t/* If there is col / rowspan, copy the information into the layout grid */\n\t\t\t\t\tfor ( l=0 ; l<iColspan ; l++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taLayout[i+k][iColShifted+l] = {\n\t\t\t\t\t\t\t\t\"cell\": nCell,\n\t\t\t\t\t\t\t\t\"unique\": bUnique\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\taLayout[i+k].nTr = nTr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnCell = nCell.nextSibling;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Get an array of unique th elements, one for each column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nHeader automatically detect the layout from this node - optional\n\t *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional\n\t *  @returns array {node} aReturn list of unique th's\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetUniqueThs ( oSettings, nHeader, aLayout )\n\t{\n\t\tvar aReturn = [];\n\t\tif ( !aLayout )\n\t\t{\n\t\t\taLayout = oSettings.aoHeader;\n\t\t\tif ( nHeader )\n\t\t\t{\n\t\t\t\taLayout = [];\n\t\t\t\t_fnDetectHeader( aLayout, nHeader );\n\t\t\t}\n\t\t}\n\t\n\t\tfor ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfor ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( aLayout[i][j].unique &&\n\t\t\t\t\t (!aReturn[j] || !oSettings.bSortCellsTop) )\n\t\t\t\t{\n\t\t\t\t\taReturn[j] = aLayout[i][j].cell;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn aReturn;\n\t}\n\t\n\t/**\n\t * Create an Ajax call based on the table's settings, taking into account that\n\t * parameters can have multiple forms, and backwards compatibility.\n\t *\n\t * @param {object} oSettings dataTables settings object\n\t * @param {array} data Data to send to the server, required by\n\t *     DataTables - may be augmented by developer callbacks\n\t * @param {function} fn Callback function to run when data is obtained\n\t */\n\tfunction _fnBuildAjax( oSettings, data, fn )\n\t{\n\t\t// Compatibility with 1.9-, allow fnServerData and event to manipulate\n\t\t_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );\n\t\n\t\t// Convert to object based for 1.10+ if using the old array scheme which can\n\t\t// come from server-side processing or serverParams\n\t\tif ( data && $.isArray(data) ) {\n\t\t\tvar tmp = {};\n\t\t\tvar rbracket = /(.*?)\\[\\]$/;\n\t\n\t\t\t$.each( data, function (key, val) {\n\t\t\t\tvar match = val.name.match(rbracket);\n\t\n\t\t\t\tif ( match ) {\n\t\t\t\t\t// Support for arrays\n\t\t\t\t\tvar name = match[0];\n\t\n\t\t\t\t\tif ( ! tmp[ name ] ) {\n\t\t\t\t\t\ttmp[ name ] = [];\n\t\t\t\t\t}\n\t\t\t\t\ttmp[ name ].push( val.value );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttmp[val.name] = val.value;\n\t\t\t\t}\n\t\t\t} );\n\t\t\tdata = tmp;\n\t\t}\n\t\n\t\tvar ajaxData;\n\t\tvar ajax = oSettings.ajax;\n\t\tvar instance = oSettings.oInstance;\n\t\tvar callback = function ( json ) {\n\t\t\t_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );\n\t\t\tfn( json );\n\t\t};\n\t\n\t\tif ( $.isPlainObject( ajax ) && ajax.data )\n\t\t{\n\t\t\tajaxData = ajax.data;\n\t\n\t\t\tvar newData = $.isFunction( ajaxData ) ?\n\t\t\t\tajaxData( data, oSettings ) :  // fn can manipulate data or return\n\t\t\t\tajaxData;                      // an object object or array to merge\n\t\n\t\t\t// If the function returned something, use that alone\n\t\t\tdata = $.isFunction( ajaxData ) && newData ?\n\t\t\t\tnewData :\n\t\t\t\t$.extend( true, data, newData );\n\t\n\t\t\t// Remove the data property as we've resolved it already and don't want\n\t\t\t// jQuery to do it again (it is restored at the end of the function)\n\t\t\tdelete ajax.data;\n\t\t}\n\t\n\t\tvar baseAjax = {\n\t\t\t\"data\": data,\n\t\t\t\"success\": function (json) {\n\t\t\t\tvar error = json.error || json.sError;\n\t\t\t\tif ( error ) {\n\t\t\t\t\t_fnLog( oSettings, 0, error );\n\t\t\t\t}\n\t\n\t\t\t\toSettings.json = json;\n\t\t\t\tcallback( json );\n\t\t\t},\n\t\t\t\"dataType\": \"json\",\n\t\t\t\"cache\": false,\n\t\t\t\"type\": oSettings.sServerMethod,\n\t\t\t\"error\": function (xhr, error, thrown) {\n\t\t\t\tvar ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );\n\t\n\t\t\t\tif ( $.inArray( true, ret ) === -1 ) {\n\t\t\t\t\tif ( error == \"parsererror\" ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Invalid JSON response', 1 );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( xhr.readyState === 4 ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Ajax error', 7 );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\t}\n\t\t};\n\t\n\t\t// Store the data submitted for the API\n\t\toSettings.oAjaxData = data;\n\t\n\t\t// Allow plug-ins and external processes to modify the data\n\t\t_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );\n\t\n\t\tif ( oSettings.fnServerData )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.fnServerData.call( instance,\n\t\t\t\toSettings.sAjaxSource,\n\t\t\t\t$.map( data, function (val, key) { // Need to convert back to 1.9 trad format\n\t\t\t\t\treturn { name: key, value: val };\n\t\t\t\t} ),\n\t\t\t\tcallback,\n\t\t\t\toSettings\n\t\t\t);\n\t\t}\n\t\telse if ( oSettings.sAjaxSource || typeof ajax === 'string' )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, {\n\t\t\t\turl: ajax || oSettings.sAjaxSource\n\t\t\t} ) );\n\t\t}\n\t\telse if ( $.isFunction( ajax ) )\n\t\t{\n\t\t\t// Is a function - let the caller define what needs to be done\n\t\t\toSettings.jqXHR = ajax.call( instance, data, callback, oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Object to extend the base settings\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );\n\t\n\t\t\t// Restore for next time around\n\t\t\tajax.data = ajaxData;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Update the table using an Ajax call\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {boolean} Block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdate( settings )\n\t{\n\t\tif ( settings.bAjaxDataGet ) {\n\t\t\tsettings.iDraw++;\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t_fnBuildAjax(\n\t\t\t\tsettings,\n\t\t\t\t_fnAjaxParameters( settings ),\n\t\t\t\tfunction(json) {\n\t\t\t\t\t_fnAjaxUpdateDraw( settings, json );\n\t\t\t\t}\n\t\t\t);\n\t\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\t\n\t/**\n\t * Build up the parameters in an object needed for a server-side processing\n\t * request. Note that this is basically done twice, is different ways - a modern\n\t * method which is used by default in DataTables 1.10 which uses objects and\n\t * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if\n\t * the sAjaxSource option is used in the initialisation, or the legacyAjax\n\t * option is set.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {bool} block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxParameters( settings )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tcolumnCount = columns.length,\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tpreSearch = settings.oPreviousSearch,\n\t\t\tpreColSearch = settings.aoPreSearchCols,\n\t\t\ti, data = [], dataProp, column, columnSearch,\n\t\t\tsort = _fnSortFlatten( settings ),\n\t\t\tdisplayStart = settings._iDisplayStart,\n\t\t\tdisplayLength = features.bPaginate !== false ?\n\t\t\t\tsettings._iDisplayLength :\n\t\t\t\t-1;\n\t\n\t\tvar param = function ( name, value ) {\n\t\t\tdata.push( { 'name': name, 'value': value } );\n\t\t};\n\t\n\t\t// DataTables 1.9- compatible method\n\t\tparam( 'sEcho',          settings.iDraw );\n\t\tparam( 'iColumns',       columnCount );\n\t\tparam( 'sColumns',       _pluck( columns, 'sName' ).join(',') );\n\t\tparam( 'iDisplayStart',  displayStart );\n\t\tparam( 'iDisplayLength', displayLength );\n\t\n\t\t// DataTables 1.10+ method\n\t\tvar d = {\n\t\t\tdraw:    settings.iDraw,\n\t\t\tcolumns: [],\n\t\t\torder:   [],\n\t\t\tstart:   displayStart,\n\t\t\tlength:  displayLength,\n\t\t\tsearch:  {\n\t\t\t\tvalue: preSearch.sSearch,\n\t\t\t\tregex: preSearch.bRegex\n\t\t\t}\n\t\t};\n\t\n\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcolumnSearch = preColSearch[i];\n\t\t\tdataProp = typeof column.mData==\"function\" ? 'function' : column.mData ;\n\t\n\t\t\td.columns.push( {\n\t\t\t\tdata:       dataProp,\n\t\t\t\tname:       column.sName,\n\t\t\t\tsearchable: column.bSearchable,\n\t\t\t\torderable:  column.bSortable,\n\t\t\t\tsearch:     {\n\t\t\t\t\tvalue: columnSearch.sSearch,\n\t\t\t\t\tregex: columnSearch.bRegex\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\tparam( \"mDataProp_\"+i, dataProp );\n\t\n\t\t\tif ( features.bFilter ) {\n\t\t\t\tparam( 'sSearch_'+i,     columnSearch.sSearch );\n\t\t\t\tparam( 'bRegex_'+i,      columnSearch.bRegex );\n\t\t\t\tparam( 'bSearchable_'+i, column.bSearchable );\n\t\t\t}\n\t\n\t\t\tif ( features.bSort ) {\n\t\t\t\tparam( 'bSortable_'+i, column.bSortable );\n\t\t\t}\n\t\t}\n\t\n\t\tif ( features.bFilter ) {\n\t\t\tparam( 'sSearch', preSearch.sSearch );\n\t\t\tparam( 'bRegex', preSearch.bRegex );\n\t\t}\n\t\n\t\tif ( features.bSort ) {\n\t\t\t$.each( sort, function ( i, val ) {\n\t\t\t\td.order.push( { column: val.col, dir: val.dir } );\n\t\n\t\t\t\tparam( 'iSortCol_'+i, val.col );\n\t\t\t\tparam( 'sSortDir_'+i, val.dir );\n\t\t\t} );\n\t\n\t\t\tparam( 'iSortingCols', sort.length );\n\t\t}\n\t\n\t\t// If the legacy.ajax parameter is null, then we automatically decide which\n\t\t// form to use, based on sAjaxSource\n\t\tvar legacy = DataTable.ext.legacy.ajax;\n\t\tif ( legacy === null ) {\n\t\t\treturn settings.sAjaxSource ? data : d;\n\t\t}\n\t\n\t\t// Otherwise, if legacy has been specified then we use that to decide on the\n\t\t// form\n\t\treturn legacy ? data : d;\n\t}\n\t\n\t\n\t/**\n\t * Data the data from the server (nuking the old) and redraw the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} json json data return from the server.\n\t *  @param {string} json.sEcho Tracking flag for DataTables to match requests\n\t *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering\n\t *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering\n\t *  @param {array} json.aaData The data to display on this page\n\t *  @param {string} [json.sColumns] Column ordering (sName, comma separated)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdateDraw ( settings, json )\n\t{\n\t\t// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.\n\t\t// Support both\n\t\tvar compat = function ( old, modern ) {\n\t\t\treturn json[old] !== undefined ? json[old] : json[modern];\n\t\t};\n\t\n\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\tvar draw            = compat( 'sEcho',                'draw' );\n\t\tvar recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );\n\t\tvar recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );\n\t\n\t\tif ( draw ) {\n\t\t\t// Protect against out of sequence returns\n\t\t\tif ( draw*1 < settings.iDraw ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettings.iDraw = draw * 1;\n\t\t}\n\t\n\t\t_fnClearTable( settings );\n\t\tsettings._iRecordsTotal   = parseInt(recordsTotal, 10);\n\t\tsettings._iRecordsDisplay = parseInt(recordsFiltered, 10);\n\t\n\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t_fnAddData( settings, data[i] );\n\t\t}\n\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\n\t\tsettings.bAjaxDataGet = false;\n\t\t_fnDraw( settings );\n\t\n\t\tif ( ! settings._bInitComplete ) {\n\t\t\t_fnInitComplete( settings, json );\n\t\t}\n\t\n\t\tsettings.bAjaxDataGet = true;\n\t\t_fnProcessingDisplay( settings, false );\n\t}\n\t\n\t\n\t/**\n\t * Get the data from the JSON data source to use for drawing a table. Using\n\t * `_fnGetObjectDataFn` allows the data to be sourced from a property of the\n\t * source object, or from a processing function.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param  {object} json Data source object / array from the server\n\t *  @return {array} Array of data to use\n\t */\n\tfunction _fnAjaxDataSrc ( oSettings, json )\n\t{\n\t\tvar dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?\n\t\t\toSettings.ajax.dataSrc :\n\t\t\toSettings.sAjaxDataProp; // Compatibility with 1.9-.\n\t\n\t\t// Compatibility with 1.9-. In order to read from aaData, check if the\n\t\t// default has been changed, if not, check for aaData\n\t\tif ( dataSrc === 'data' ) {\n\t\t\treturn json.aaData || json[dataSrc];\n\t\t}\n\t\n\t\treturn dataSrc !== \"\" ?\n\t\t\t_fnGetObjectDataFn( dataSrc )( json ) :\n\t\t\tjson;\n\t}\n\t\n\t/**\n\t * Generate the node required for filtering text\n\t *  @returns {node} Filter control element\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlFilter ( settings )\n\t{\n\t\tvar classes = settings.oClasses;\n\t\tvar tableId = settings.sTableId;\n\t\tvar language = settings.oLanguage;\n\t\tvar previousSearch = settings.oPreviousSearch;\n\t\tvar features = settings.aanFeatures;\n\t\tvar input = '<input type=\"search\" class=\"'+classes.sFilterInput+'\"/>';\n\t\n\t\tvar str = language.sSearch;\n\t\tstr = str.match(/_INPUT_/) ?\n\t\t\tstr.replace('_INPUT_', input) :\n\t\t\tstr+input;\n\t\n\t\tvar filter = $('<div/>', {\n\t\t\t\t'id': ! features.f ? tableId+'_filter' : null,\n\t\t\t\t'class': classes.sFilter\n\t\t\t} )\n\t\t\t.append( $('<label/>' ).append( str ) );\n\t\n\t\tvar searchFn = function() {\n\t\t\t/* Update all other filter input elements for the new display */\n\t\t\tvar n = features.f;\n\t\t\tvar val = !this.value ? \"\" : this.value; // mental IE8 fix :-(\n\t\n\t\t\t/* Now do the filter */\n\t\t\tif ( val != previousSearch.sSearch ) {\n\t\t\t\t_fnFilterComplete( settings, {\n\t\t\t\t\t\"sSearch\": val,\n\t\t\t\t\t\"bRegex\": previousSearch.bRegex,\n\t\t\t\t\t\"bSmart\": previousSearch.bSmart ,\n\t\t\t\t\t\"bCaseInsensitive\": previousSearch.bCaseInsensitive\n\t\t\t\t} );\n\t\n\t\t\t\t// Need to redraw, without resorting\n\t\t\t\tsettings._iDisplayStart = 0;\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t};\n\t\n\t\tvar searchDelay = settings.searchDelay !== null ?\n\t\t\tsettings.searchDelay :\n\t\t\t_fnDataSource( settings ) === 'ssp' ?\n\t\t\t\t400 :\n\t\t\t\t0;\n\t\n\t\tvar jqFilter = $('input', filter)\n\t\t\t.val( previousSearch.sSearch )\n\t\t\t.attr( 'placeholder', language.sSearchPlaceholder )\n\t\t\t.on(\n\t\t\t\t'keyup.DT search.DT input.DT paste.DT cut.DT',\n\t\t\t\tsearchDelay ?\n\t\t\t\t\t_fnThrottle( searchFn, searchDelay ) :\n\t\t\t\t\tsearchFn\n\t\t\t)\n\t\t\t.on( 'keypress.DT', function(e) {\n\t\t\t\t/* Prevent form submission */\n\t\t\t\tif ( e.keyCode == 13 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.attr('aria-controls', tableId);\n\t\n\t\t// Update the input elements whenever the table is filtered\n\t\t$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame...\n\t\t\t\ttry {\n\t\t\t\t\tif ( jqFilter[0] !== document.activeElement ) {\n\t\t\t\t\t\tjqFilter.val( previousSearch.sSearch );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch ( e ) {}\n\t\t\t}\n\t\t} );\n\t\n\t\treturn filter[0];\n\t}\n\t\n\t\n\t/**\n\t * Filter the table using both the global filter and column based filtering\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oSearch search information\n\t *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterComplete ( oSettings, oInput, iForce )\n\t{\n\t\tvar oPrevSearch = oSettings.oPreviousSearch;\n\t\tvar aoPrevSearch = oSettings.aoPreSearchCols;\n\t\tvar fnSaveFilter = function ( oFilter ) {\n\t\t\t/* Save the filtering values */\n\t\t\toPrevSearch.sSearch = oFilter.sSearch;\n\t\t\toPrevSearch.bRegex = oFilter.bRegex;\n\t\t\toPrevSearch.bSmart = oFilter.bSmart;\n\t\t\toPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;\n\t\t};\n\t\tvar fnRegex = function ( o ) {\n\t\t\t// Backwards compatibility with the bEscapeRegex option\n\t\t\treturn o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;\n\t\t};\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo As per sort - can this be moved into an event handler?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\t/* In server-side processing all filtering is done by the server, so no point hanging around here */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' )\n\t\t{\n\t\t\t/* Global filter */\n\t\t\t_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );\n\t\t\tfnSaveFilter( oInput );\n\t\n\t\t\t/* Now do the individual column filter */\n\t\t\tfor ( var i=0 ; i<aoPrevSearch.length ; i++ )\n\t\t\t{\n\t\t\t\t_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),\n\t\t\t\t\taoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );\n\t\t\t}\n\t\n\t\t\t/* Custom filtering */\n\t\t\t_fnFilterCustom( oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfnSaveFilter( oInput );\n\t\t}\n\t\n\t\t/* Tell the draw function we have been filtering */\n\t\toSettings.bFiltered = true;\n\t\t_fnCallbackFire( oSettings, null, 'search', [oSettings] );\n\t}\n\t\n\t\n\t/**\n\t * Apply custom filtering functions\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCustom( settings )\n\t{\n\t\tvar filters = DataTable.ext.search;\n\t\tvar displayRows = settings.aiDisplay;\n\t\tvar row, rowIdx;\n\t\n\t\tfor ( var i=0, ien=filters.length ; i<ien ; i++ ) {\n\t\t\tvar rows = [];\n\t\n\t\t\t// Loop over each row and see if it should be included\n\t\t\tfor ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {\n\t\t\t\trowIdx = displayRows[ j ];\n\t\t\t\trow = settings.aoData[ rowIdx ];\n\t\n\t\t\t\tif ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {\n\t\t\t\t\trows.push( rowIdx );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// So the array reference doesn't break set the results into the\n\t\t\t// existing array\n\t\t\tdisplayRows.length = 0;\n\t\t\t$.merge( displayRows, rows );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Filter the table on a per-column basis\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sInput string to filter on\n\t *  @param {int} iColumn column to filter\n\t *  @param {bool} bRegex treat search string as a regular expression or not\n\t *  @param {bool} bSmart use smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )\n\t{\n\t\tif ( searchStr === '' ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar data;\n\t\tvar out = [];\n\t\tvar display = settings.aiDisplay;\n\t\tvar rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );\n\t\n\t\tfor ( var i=0 ; i<display.length ; i++ ) {\n\t\t\tdata = settings.aoData[ display[i] ]._aFilterData[ colIdx ];\n\t\n\t\t\tif ( rpSearch.test( data ) ) {\n\t\t\t\tout.push( display[i] );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aiDisplay = out;\n\t}\n\t\n\t\n\t/**\n\t * Filter the data table based on user input and draw the table\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} input string to filter on\n\t *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)\n\t *  @param {bool} regex treat as a regular expression or not\n\t *  @param {bool} smart perform smart filtering or not\n\t *  @param {bool} caseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilter( settings, input, force, regex, smart, caseInsensitive )\n\t{\n\t\tvar rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );\n\t\tvar prevSearch = settings.oPreviousSearch.sSearch;\n\t\tvar displayMaster = settings.aiDisplayMaster;\n\t\tvar display, invalidated, i;\n\t\tvar filtered = [];\n\t\n\t\t// Need to take account of custom filtering functions - always filter\n\t\tif ( DataTable.ext.search.length !== 0 ) {\n\t\t\tforce = true;\n\t\t}\n\t\n\t\t// Check if any of the rows were invalidated\n\t\tinvalidated = _fnFilterData( settings );\n\t\n\t\t// If the input is blank - we just want the full data set\n\t\tif ( input.length <= 0 ) {\n\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t}\n\t\telse {\n\t\t\t// New search - start from the master array\n\t\t\tif ( invalidated ||\n\t\t\t\t force ||\n\t\t\t\t prevSearch.length > input.length ||\n\t\t\t\t input.indexOf(prevSearch) !== 0 ||\n\t\t\t\t settings.bSorted // On resort, the display master needs to be\n\t\t\t\t                  // re-filtered since indexes will have changed\n\t\t\t) {\n\t\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t\t}\n\t\n\t\t\t// Search the display array\n\t\t\tdisplay = settings.aiDisplay;\n\t\n\t\t\tfor ( i=0 ; i<display.length ; i++ ) {\n\t\t\t\tif ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {\n\t\t\t\t\tfiltered.push( display[i] );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tsettings.aiDisplay = filtered;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a regular expression object suitable for searching a table\n\t *  @param {string} sSearch string to search for\n\t *  @param {bool} bRegex treat as a regular expression or not\n\t *  @param {bool} bSmart perform smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insensitive matching or not\n\t *  @returns {RegExp} constructed object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCreateSearch( search, regex, smart, caseInsensitive )\n\t{\n\t\tsearch = regex ?\n\t\t\tsearch :\n\t\t\t_fnEscapeRegex( search );\n\t\t\n\t\tif ( smart ) {\n\t\t\t/* For smart filtering we want to allow the search to work regardless of\n\t\t\t * word order. We also want double quoted text to be preserved, so word\n\t\t\t * order is important - a la google. So this is what we want to\n\t\t\t * generate:\n\t\t\t * \n\t\t\t * ^(?=.*?\\bone\\b)(?=.*?\\btwo three\\b)(?=.*?\\bfour\\b).*$\n\t\t\t */\n\t\t\tvar a = $.map( search.match( /\"[^\"]+\"|[^ ]+/g ) || [''], function ( word ) {\n\t\t\t\tif ( word.charAt(0) === '\"' ) {\n\t\t\t\t\tvar m = word.match( /^\"(.*)\"$/ );\n\t\t\t\t\tword = m ? m[1] : word;\n\t\t\t\t}\n\t\n\t\t\t\treturn word.replace('\"', '');\n\t\t\t} );\n\t\n\t\t\tsearch = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';\n\t\t}\n\t\n\t\treturn new RegExp( search, caseInsensitive ? 'i' : '' );\n\t}\n\t\n\t\n\t/**\n\t * Escape a string such that it can be used in a regular expression\n\t *  @param {string} sVal string to escape\n\t *  @returns {string} escaped string\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnEscapeRegex = DataTable.util.escapeRegex;\n\t\n\tvar __filter_div = $('<div>')[0];\n\tvar __filter_div_textContent = __filter_div.textContent !== undefined;\n\t\n\t// Update the filtering data for each row if needed (by invalidation or first run)\n\tfunction _fnFilterData ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar column;\n\t\tvar i, j, ien, jen, filterData, cellData, row;\n\t\tvar fomatters = DataTable.ext.type.search;\n\t\tvar wasInvalidated = false;\n\t\n\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aFilterData ) {\n\t\t\t\tfilterData = [];\n\t\n\t\t\t\tfor ( j=0, jen=columns.length ; j<jen ; j++ ) {\n\t\t\t\t\tcolumn = columns[j];\n\t\n\t\t\t\t\tif ( column.bSearchable ) {\n\t\t\t\t\t\tcellData = _fnGetCellData( settings, i, j, 'filter' );\n\t\n\t\t\t\t\t\tif ( fomatters[ column.sType ] ) {\n\t\t\t\t\t\t\tcellData = fomatters[ column.sType ]( cellData );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Search in DataTables 1.10 is string based. In 1.11 this\n\t\t\t\t\t\t// should be altered to also allow strict type checking.\n\t\t\t\t\t\tif ( cellData === null ) {\n\t\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( typeof cellData !== 'string' && cellData.toString ) {\n\t\t\t\t\t\t\tcellData = cellData.toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If it looks like there is an HTML entity in the string,\n\t\t\t\t\t// attempt to decode it so sorting works as expected. Note that\n\t\t\t\t\t// we could use a single line of jQuery to do this, but the DOM\n\t\t\t\t\t// method used here is much faster http://jsperf.com/html-decode\n\t\t\t\t\tif ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {\n\t\t\t\t\t\t__filter_div.innerHTML = cellData;\n\t\t\t\t\t\tcellData = __filter_div_textContent ?\n\t\t\t\t\t\t\t__filter_div.textContent :\n\t\t\t\t\t\t\t__filter_div.innerText;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tif ( cellData.replace ) {\n\t\t\t\t\t\tcellData = cellData.replace(/[\\r\\n]/g, '');\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfilterData.push( cellData );\n\t\t\t\t}\n\t\n\t\t\t\trow._aFilterData = filterData;\n\t\t\t\trow._sFilterRow = filterData.join('  ');\n\t\t\t\twasInvalidated = true;\n\t\t\t}\n\t\t}\n\t\n\t\treturn wasInvalidated;\n\t}\n\t\n\t\n\t/**\n\t * Convert from the internal Hungarian notation to camelCase for external\n\t * interaction\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToCamel ( obj )\n\t{\n\t\treturn {\n\t\t\tsearch:          obj.sSearch,\n\t\t\tsmart:           obj.bSmart,\n\t\t\tregex:           obj.bRegex,\n\t\t\tcaseInsensitive: obj.bCaseInsensitive\n\t\t};\n\t}\n\t\n\t\n\t\n\t/**\n\t * Convert from camelCase notation to the internal Hungarian. We could use the\n\t * Hungarian convert function here, but this is cleaner\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToHung ( obj )\n\t{\n\t\treturn {\n\t\t\tsSearch:          obj.search,\n\t\t\tbSmart:           obj.smart,\n\t\t\tbRegex:           obj.regex,\n\t\t\tbCaseInsensitive: obj.caseInsensitive\n\t\t};\n\t}\n\t\n\t/**\n\t * Generate the node required for the info display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Information element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlInfo ( settings )\n\t{\n\t\tvar\n\t\t\ttid = settings.sTableId,\n\t\t\tnodes = settings.aanFeatures.i,\n\t\t\tn = $('<div/>', {\n\t\t\t\t'class': settings.oClasses.sInfo,\n\t\t\t\t'id': ! nodes ? tid+'_info' : null\n\t\t\t} );\n\t\n\t\tif ( ! nodes ) {\n\t\t\t// Update display on each draw\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": _fnUpdateInfo,\n\t\t\t\t\"sName\": \"information\"\n\t\t\t} );\n\t\n\t\t\tn\n\t\t\t\t.attr( 'role', 'status' )\n\t\t\t\t.attr( 'aria-live', 'polite' );\n\t\n\t\t\t// Table is described by our info div\n\t\t\t$(settings.nTable).attr( 'aria-describedby', tid+'_info' );\n\t\t}\n\t\n\t\treturn n[0];\n\t}\n\t\n\t\n\t/**\n\t * Update the information elements in the display\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnUpdateInfo ( settings )\n\t{\n\t\t/* Show information about the table */\n\t\tvar nodes = settings.aanFeatures.i;\n\t\tif ( nodes.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\tlang  = settings.oLanguage,\n\t\t\tstart = settings._iDisplayStart+1,\n\t\t\tend   = settings.fnDisplayEnd(),\n\t\t\tmax   = settings.fnRecordsTotal(),\n\t\t\ttotal = settings.fnRecordsDisplay(),\n\t\t\tout   = total ?\n\t\t\t\tlang.sInfo :\n\t\t\t\tlang.sInfoEmpty;\n\t\n\t\tif ( total !== max ) {\n\t\t\t/* Record set after filtering */\n\t\t\tout += ' ' + lang.sInfoFiltered;\n\t\t}\n\t\n\t\t// Convert the macros\n\t\tout += lang.sInfoPostFix;\n\t\tout = _fnInfoMacros( settings, out );\n\t\n\t\tvar callback = lang.fnInfoCallback;\n\t\tif ( callback !== null ) {\n\t\t\tout = callback.call( settings.oInstance,\n\t\t\t\tsettings, start, end, max, total, out\n\t\t\t);\n\t\t}\n\t\n\t\t$(nodes).html( out );\n\t}\n\t\n\t\n\tfunction _fnInfoMacros ( settings, str )\n\t{\n\t\t// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only\n\t\t// internally\n\t\tvar\n\t\t\tformatter  = settings.fnFormatNumber,\n\t\t\tstart      = settings._iDisplayStart+1,\n\t\t\tlen        = settings._iDisplayLength,\n\t\t\tvis        = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn str.\n\t\t\treplace(/_START_/g, formatter.call( settings, start ) ).\n\t\t\treplace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).\n\t\t\treplace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).\n\t\t\treplace(/_TOTAL_/g, formatter.call( settings, vis ) ).\n\t\t\treplace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).\n\t\t\treplace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );\n\t}\n\t\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitialise ( settings )\n\t{\n\t\tvar i, iLen, iAjaxStart=settings.iInitDisplayStart;\n\t\tvar columns = settings.aoColumns, column;\n\t\tvar features = settings.oFeatures;\n\t\tvar deferLoading = settings.bDeferLoading; // value modified by the draw\n\t\n\t\t/* Ensure that the table data is fully initialised */\n\t\tif ( ! settings.bInitialised ) {\n\t\t\tsetTimeout( function(){ _fnInitialise( settings ); }, 200 );\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Show the display HTML options */\n\t\t_fnAddOptionsHtml( settings );\n\t\n\t\t/* Build and draw the header / footer for the table */\n\t\t_fnBuildHead( settings );\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t/* Okay to show that something is going on now */\n\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t/* Calculate sizes for columns */\n\t\tif ( features.bAutoWidth ) {\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\n\t\t\tif ( column.sWidth ) {\n\t\t\t\tcolumn.nTh.style.width = _fnStringToCss( column.sWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'preInit', [settings] );\n\t\n\t\t// If there is default sorting required - let's do it. The sort function\n\t\t// will do the drawing for us. Otherwise we draw the table regardless of the\n\t\t// Ajax source - this allows the table to look initialised for Ajax sourcing\n\t\t// data (show 'loading' message possibly)\n\t\t_fnReDraw( settings );\n\t\n\t\t// Server-side processing init complete is done by _fnAjaxUpdateDraw\n\t\tvar dataSrc = _fnDataSource( settings );\n\t\tif ( dataSrc != 'ssp' || deferLoading ) {\n\t\t\t// if there is an ajax source load the data\n\t\t\tif ( dataSrc == 'ajax' ) {\n\t\t\t\t_fnBuildAjax( settings, [], function(json) {\n\t\t\t\t\tvar aData = _fnAjaxDataSrc( settings, json );\n\t\n\t\t\t\t\t// Got the data - add it to the table\n\t\t\t\t\tfor ( i=0 ; i<aData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( settings, aData[i] );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Reset the init display for cookie saving. We've already done\n\t\t\t\t\t// a filter, and therefore cleared it before. So we need to make\n\t\t\t\t\t// it appear 'fresh'\n\t\t\t\t\tsettings.iInitDisplayStart = iAjaxStart;\n\t\n\t\t\t\t\t_fnReDraw( settings );\n\t\n\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t_fnInitComplete( settings, json );\n\t\t\t\t}, settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t_fnInitComplete( settings );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} [json] JSON from the server that completed the table, if using Ajax source\n\t *    with client-side processing (optional)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitComplete ( settings, json )\n\t{\n\t\tsettings._bInitComplete = true;\n\t\n\t\t// When data was added after the initialisation (data or Ajax) we need to\n\t\t// calculate the column sizing\n\t\tif ( json || settings.oInit.aaData ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'plugin-init', [settings, json] );\n\t\t_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );\n\t}\n\t\n\t\n\tfunction _fnLengthChange ( settings, val )\n\t{\n\t\tvar len = parseInt( val, 10 );\n\t\tsettings._iDisplayLength = len;\n\t\n\t\t_fnLengthOverflow( settings );\n\t\n\t\t// Fire length change event\n\t\t_fnCallbackFire( settings, null, 'length', [settings, len] );\n\t}\n\t\n\t\n\t/**\n\t * Generate the node required for user display length changing\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Display length feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlLength ( settings )\n\t{\n\t\tvar\n\t\t\tclasses  = settings.oClasses,\n\t\t\ttableId  = settings.sTableId,\n\t\t\tmenu     = settings.aLengthMenu,\n\t\t\td2       = $.isArray( menu[0] ),\n\t\t\tlengths  = d2 ? menu[0] : menu,\n\t\t\tlanguage = d2 ? menu[1] : menu;\n\t\n\t\tvar select = $('<select/>', {\n\t\t\t'name':          tableId+'_length',\n\t\t\t'aria-controls': tableId,\n\t\t\t'class':         classes.sLengthSelect\n\t\t} );\n\t\n\t\tfor ( var i=0, ien=lengths.length ; i<ien ; i++ ) {\n\t\t\tselect[0][ i ] = new Option( language[i], lengths[i] );\n\t\t}\n\t\n\t\tvar div = $('<div><label/></div>').addClass( classes.sLength );\n\t\tif ( ! settings.aanFeatures.l ) {\n\t\t\tdiv[0].id = tableId+'_length';\n\t\t}\n\t\n\t\tdiv.children().append(\n\t\t\tsettings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )\n\t\t);\n\t\n\t\t// Can't use `select` variable as user might provide their own and the\n\t\t// reference is broken by the use of outerHTML\n\t\t$('select', div)\n\t\t\t.val( settings._iDisplayLength )\n\t\t\t.on( 'change.DT', function(e) {\n\t\t\t\t_fnLengthChange( settings, $(this).val() );\n\t\t\t\t_fnDraw( settings );\n\t\t\t} );\n\t\n\t\t// Update node value whenever anything changes the table's length\n\t\t$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t$('select', div).val( len );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn div[0];\n\t}\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Note that most of the paging logic is done in\n\t * DataTable.ext.pager\n\t */\n\t\n\t/**\n\t * Generate the node required for default pagination\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Pagination feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlPaginate ( settings )\n\t{\n\t\tvar\n\t\t\ttype   = settings.sPaginationType,\n\t\t\tplugin = DataTable.ext.pager[ type ],\n\t\t\tmodern = typeof plugin === 'function',\n\t\t\tredraw = function( settings ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t},\n\t\t\tnode = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],\n\t\t\tfeatures = settings.aanFeatures;\n\t\n\t\tif ( ! modern ) {\n\t\t\tplugin.fnInit( settings, node, redraw );\n\t\t}\n\t\n\t\t/* Add a draw callback for the pagination on first instance, to update the paging display */\n\t\tif ( ! features.p )\n\t\t{\n\t\t\tnode.id = settings.sTableId+'_paginate';\n\t\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": function( settings ) {\n\t\t\t\t\tif ( modern ) {\n\t\t\t\t\t\tvar\n\t\t\t\t\t\t\tstart      = settings._iDisplayStart,\n\t\t\t\t\t\t\tlen        = settings._iDisplayLength,\n\t\t\t\t\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\t\t\t\t\tall        = len === -1,\n\t\t\t\t\t\t\tpage = all ? 0 : Math.ceil( start / len ),\n\t\t\t\t\t\t\tpages = all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\t\t\t\tbuttons = plugin(page, pages),\n\t\t\t\t\t\t\ti, ien;\n\t\n\t\t\t\t\t\tfor ( i=0, ien=features.p.length ; i<ien ; i++ ) {\n\t\t\t\t\t\t\t_fnRenderer( settings, 'pageButton' )(\n\t\t\t\t\t\t\t\tsettings, features.p[i], i, buttons, page, pages\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tplugin.fnUpdate( settings, redraw );\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"sName\": \"pagination\"\n\t\t\t} );\n\t\t}\n\t\n\t\treturn node;\n\t}\n\t\n\t\n\t/**\n\t * Alter the display settings to change the page\n\t *  @param {object} settings DataTables settings object\n\t *  @param {string|int} action Paging action to take: \"first\", \"previous\",\n\t *    \"next\" or \"last\" or page number to jump to (integer)\n\t *  @param [bool] redraw Automatically draw the update or not\n\t *  @returns {bool} true page has changed, false - no change\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnPageChange ( settings, action, redraw )\n\t{\n\t\tvar\n\t\t\tstart     = settings._iDisplayStart,\n\t\t\tlen       = settings._iDisplayLength,\n\t\t\trecords   = settings.fnRecordsDisplay();\n\t\n\t\tif ( records === 0 || len === -1 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( typeof action === \"number\" )\n\t\t{\n\t\t\tstart = action * len;\n\t\n\t\t\tif ( start > records )\n\t\t\t{\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"first\" )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( action == \"previous\" )\n\t\t{\n\t\t\tstart = len >= 0 ?\n\t\t\t\tstart - len :\n\t\t\t\t0;\n\t\n\t\t\tif ( start < 0 )\n\t\t\t{\n\t\t\t  start = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"next\" )\n\t\t{\n\t\t\tif ( start + len < records )\n\t\t\t{\n\t\t\t\tstart += len;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"last\" )\n\t\t{\n\t\t\tstart = Math.floor( (records-1) / len) * len;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_fnLog( settings, 0, \"Unknown paging action: \"+action, 5 );\n\t\t}\n\t\n\t\tvar changed = settings._iDisplayStart !== start;\n\t\tsettings._iDisplayStart = start;\n\t\n\t\tif ( changed ) {\n\t\t\t_fnCallbackFire( settings, null, 'page', [settings] );\n\t\n\t\t\tif ( redraw ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t}\n\t\n\t\treturn changed;\n\t}\n\t\n\t\n\t\n\t/**\n\t * Generate the node required for the processing node\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Processing element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlProcessing ( settings )\n\t{\n\t\treturn $('<div/>', {\n\t\t\t\t'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,\n\t\t\t\t'class': settings.oClasses.sProcessing\n\t\t\t} )\n\t\t\t.html( settings.oLanguage.sProcessing )\n\t\t\t.insertBefore( settings.nTable )[0];\n\t}\n\t\n\t\n\t/**\n\t * Display or hide the processing indicator\n\t *  @param {object} settings dataTables settings object\n\t *  @param {bool} show Show the processing indicator (true) or not (false)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnProcessingDisplay ( settings, show )\n\t{\n\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t$(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'processing', [settings, show] );\n\t}\n\t\n\t/**\n\t * Add any control elements for the table - specifically scrolling\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Node to add to the DOM\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlTable ( settings )\n\t{\n\t\tvar table = $(settings.nTable);\n\t\n\t\t// Add the ARIA grid role to the table\n\t\ttable.attr( 'role', 'grid' );\n\t\n\t\t// Scrolling from here on in\n\t\tvar scroll = settings.oScroll;\n\t\n\t\tif ( scroll.sX === '' && scroll.sY === '' ) {\n\t\t\treturn settings.nTable;\n\t\t}\n\t\n\t\tvar scrollX = scroll.sX;\n\t\tvar scrollY = scroll.sY;\n\t\tvar classes = settings.oClasses;\n\t\tvar caption = table.children('caption');\n\t\tvar captionSide = caption.length ? caption[0]._captionSide : null;\n\t\tvar headerClone = $( table[0].cloneNode(false) );\n\t\tvar footerClone = $( table[0].cloneNode(false) );\n\t\tvar footer = table.children('tfoot');\n\t\tvar _div = '<div/>';\n\t\tvar size = function ( s ) {\n\t\t\treturn !s ? null : _fnStringToCss( s );\n\t\t};\n\t\n\t\tif ( ! footer.length ) {\n\t\t\tfooter = null;\n\t\t}\n\t\n\t\t/*\n\t\t * The HTML structure that we want to generate in this function is:\n\t\t *  div - scroller\n\t\t *    div - scroll head\n\t\t *      div - scroll head inner\n\t\t *        table - scroll head table\n\t\t *          thead - thead\n\t\t *    div - scroll body\n\t\t *      table - table (master table)\n\t\t *        thead - thead clone for sizing\n\t\t *        tbody - tbody\n\t\t *    div - scroll foot\n\t\t *      div - scroll foot inner\n\t\t *        table - scroll foot table\n\t\t *          tfoot - tfoot\n\t\t */\n\t\tvar scroller = $( _div, { 'class': classes.sScrollWrapper } )\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollHead } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollHeadInner } )\n\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t'box-sizing': 'content-box',\n\t\t\t\t\t\t\t\twidth: scroll.sXInner || '100%'\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\theaderClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'top' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('thead')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t)\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollBody } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\toverflow: 'auto',\n\t\t\t\t\t\twidth: size( scrollX )\n\t\t\t\t\t} )\n\t\t\t\t\t.append( table )\n\t\t\t);\n\t\n\t\tif ( footer ) {\n\t\t\tscroller.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollFoot } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollFootInner } )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\tfooterClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'bottom' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('tfoot')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\n\t\tvar children = scroller.children();\n\t\tvar scrollHead = children[0];\n\t\tvar scrollBody = children[1];\n\t\tvar scrollFoot = footer ? children[2] : null;\n\t\n\t\t// When the body is scrolled, then we also want to scroll the headers\n\t\tif ( scrollX ) {\n\t\t\t$(scrollBody).on( 'scroll.DT', function (e) {\n\t\t\t\tvar scrollLeft = this.scrollLeft;\n\t\n\t\t\t\tscrollHead.scrollLeft = scrollLeft;\n\t\n\t\t\t\tif ( footer ) {\n\t\t\t\t\tscrollFoot.scrollLeft = scrollLeft;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\n\t\t$(scrollBody).css(\n\t\t\tscrollY && scroll.bCollapse ? 'max-height' : 'height', \n\t\t\tscrollY\n\t\t);\n\t\n\t\tsettings.nScrollHead = scrollHead;\n\t\tsettings.nScrollBody = scrollBody;\n\t\tsettings.nScrollFoot = scrollFoot;\n\t\n\t\t// On redraw - align columns\n\t\tsettings.aoDrawCallback.push( {\n\t\t\t\"fn\": _fnScrollDraw,\n\t\t\t\"sName\": \"scrolling\"\n\t\t} );\n\t\n\t\treturn scroller[0];\n\t}\n\t\n\t\n\t\n\t/**\n\t * Update the header, footer and body tables for resizing - i.e. column\n\t * alignment.\n\t *\n\t * Welcome to the most horrible function DataTables. The process that this\n\t * function follows is basically:\n\t *   1. Re-create the table inside the scrolling div\n\t *   2. Take live measurements from the DOM\n\t *   3. Apply the measurements to align the columns\n\t *   4. Clean up\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnScrollDraw ( settings )\n\t{\n\t\t// Given that this is such a monster function, a lot of variables are use\n\t\t// to try and keep the minimised size as small as possible\n\t\tvar\n\t\t\tscroll         = settings.oScroll,\n\t\t\tscrollX        = scroll.sX,\n\t\t\tscrollXInner   = scroll.sXInner,\n\t\t\tscrollY        = scroll.sY,\n\t\t\tbarWidth       = scroll.iBarWidth,\n\t\t\tdivHeader      = $(settings.nScrollHead),\n\t\t\tdivHeaderStyle = divHeader[0].style,\n\t\t\tdivHeaderInner = divHeader.children('div'),\n\t\t\tdivHeaderInnerStyle = divHeaderInner[0].style,\n\t\t\tdivHeaderTable = divHeaderInner.children('table'),\n\t\t\tdivBodyEl      = settings.nScrollBody,\n\t\t\tdivBody        = $(divBodyEl),\n\t\t\tdivBodyStyle   = divBodyEl.style,\n\t\t\tdivFooter      = $(settings.nScrollFoot),\n\t\t\tdivFooterInner = divFooter.children('div'),\n\t\t\tdivFooterTable = divFooterInner.children('table'),\n\t\t\theader         = $(settings.nTHead),\n\t\t\ttable          = $(settings.nTable),\n\t\t\ttableEl        = table[0],\n\t\t\ttableStyle     = tableEl.style,\n\t\t\tfooter         = settings.nTFoot ? $(settings.nTFoot) : null,\n\t\t\tbrowser        = settings.oBrowser,\n\t\t\tie67           = browser.bScrollOversize,\n\t\t\tdtHeaderCells  = _pluck( settings.aoColumns, 'nTh' ),\n\t\t\theaderTrgEls, footerTrgEls,\n\t\t\theaderSrcEls, footerSrcEls,\n\t\t\theaderCopy, footerCopy,\n\t\t\theaderWidths=[], footerWidths=[],\n\t\t\theaderContent=[], footerContent=[],\n\t\t\tidx, correction, sanityWidth,\n\t\t\tzeroOut = function(nSizer) {\n\t\t\t\tvar style = nSizer.style;\n\t\t\t\tstyle.paddingTop = \"0\";\n\t\t\t\tstyle.paddingBottom = \"0\";\n\t\t\t\tstyle.borderTopWidth = \"0\";\n\t\t\t\tstyle.borderBottomWidth = \"0\";\n\t\t\t\tstyle.height = 0;\n\t\t\t};\n\t\n\t\t// If the scrollbar visibility has changed from the last draw, we need to\n\t\t// adjust the column sizes as the table width will have changed to account\n\t\t// for the scrollbar\n\t\tvar scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;\n\t\t\n\t\tif ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t\treturn; // adjust column sizing will call this function again\n\t\t}\n\t\telse {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t}\n\t\n\t\t/*\n\t\t * 1. Re-create the table inside the scrolling div\n\t\t */\n\t\n\t\t// Remove the old minimised thead and tfoot elements in the inner table\n\t\ttable.children('thead, tfoot').remove();\n\t\n\t\tif ( footer ) {\n\t\t\tfooterCopy = footer.clone().prependTo( table );\n\t\t\tfooterTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized\n\t\t\tfooterSrcEls = footerCopy.find('tr');\n\t\t}\n\t\n\t\t// Clone the current header and footer elements and then place it into the inner table\n\t\theaderCopy = header.clone().prependTo( table );\n\t\theaderTrgEls = header.find('tr'); // original header is in its own table\n\t\theaderSrcEls = headerCopy.find('tr');\n\t\theaderCopy.find('th, td').removeAttr('tabindex');\n\t\n\t\n\t\t/*\n\t\t * 2. Take live measurements from the DOM - do not alter the DOM itself!\n\t\t */\n\t\n\t\t// Remove old sizing and apply the calculated column widths\n\t\t// Get the unique column headers in the newly created (cloned) header. We want to apply the\n\t\t// calculated sizes to this header\n\t\tif ( ! scrollX )\n\t\t{\n\t\t\tdivBodyStyle.width = '100%';\n\t\t\tdivHeader[0].style.width = '100%';\n\t\t}\n\t\n\t\t$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {\n\t\t\tidx = _fnVisibleToColumnIndex( settings, i );\n\t\t\tel.style.width = settings.aoColumns[idx].sWidth;\n\t\t} );\n\t\n\t\tif ( footer ) {\n\t\t\t_fnApplyToChildren( function(n) {\n\t\t\t\tn.style.width = \"\";\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Size the table as a whole\n\t\tsanityWidth = table.outerWidth();\n\t\tif ( scrollX === \"\" ) {\n\t\t\t// No x scrolling\n\t\t\ttableStyle.width = \"100%\";\n\t\n\t\t\t// IE7 will make the width of the table when 100% include the scrollbar\n\t\t\t// - which is shouldn't. When there is a scrollbar we need to take this\n\t\t\t// into account.\n\t\t\tif ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);\n\t\t\t}\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\telse if ( scrollXInner !== \"\" ) {\n\t\t\t// legacy x scroll inner has been given - use it\n\t\t\ttableStyle.width = _fnStringToCss(scrollXInner);\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\n\t\t// Hidden header should have zero height, so remove padding and borders. Then\n\t\t// set the width based on the real headers\n\t\n\t\t// Apply all styles in one pass\n\t\t_fnApplyToChildren( zeroOut, headerSrcEls );\n\t\n\t\t// Read all widths in next pass\n\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\theaderContent.push( nSizer.innerHTML );\n\t\t\theaderWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t}, headerSrcEls );\n\t\n\t\t// Apply all widths in final pass\n\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t// Only apply widths to the DataTables detected header cells - this\n\t\t\t// prevents complex headers from having contradictory sizes applied\n\t\t\tif ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {\n\t\t\t\tnToSize.style.width = headerWidths[i];\n\t\t\t}\n\t\t}, headerTrgEls );\n\t\n\t\t$(headerSrcEls).height(0);\n\t\n\t\t/* Same again with the footer if we have one */\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( zeroOut, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\t\tfooterContent.push( nSizer.innerHTML );\n\t\t\t\tfooterWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t\t}, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t\tnToSize.style.width = footerWidths[i];\n\t\t\t}, footerTrgEls );\n\t\n\t\t\t$(footerSrcEls).height(0);\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 3. Apply the measurements\n\t\t */\n\t\n\t\t// \"Hide\" the header and footer that we used for the sizing. We need to keep\n\t\t// the content of the cell so that the width applied to the header and body\n\t\t// both match, but we want to hide it completely. We want to also fix their\n\t\t// width to what they currently are\n\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\" style=\"height:0;overflow:hidden;\">'+headerContent[i]+'</div>';\n\t\t\tnSizer.style.width = headerWidths[i];\n\t\t}, headerSrcEls );\n\t\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\" style=\"height:0;overflow:hidden;\">'+footerContent[i]+'</div>';\n\t\t\t\tnSizer.style.width = footerWidths[i];\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Sanity check that the table is of a sensible width. If not then we are going to get\n\t\t// misalignment - try to prevent this by not allowing the table to shrink below its min width\n\t\tif ( table.outerWidth() < sanityWidth )\n\t\t{\n\t\t\t// The min width depends upon if we have a vertical scrollbar visible or not */\n\t\t\tcorrection = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")) ?\n\t\t\t\t\tsanityWidth+barWidth :\n\t\t\t\t\tsanityWidth;\n\t\n\t\t\t// IE6/7 are a law unto themselves...\n\t\t\tif ( ie67 && (divBodyEl.scrollHeight >\n\t\t\t\tdivBodyEl.offsetHeight || divBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( correction-barWidth );\n\t\t\t}\n\t\n\t\t\t// And give the user a warning that we've stopped the table getting too small\n\t\t\tif ( scrollX === \"\" || scrollXInner !== \"\" ) {\n\t\t\t\t_fnLog( settings, 1, 'Possible column misalignment', 6 );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcorrection = '100%';\n\t\t}\n\t\n\t\t// Apply to the container elements\n\t\tdivBodyStyle.width = _fnStringToCss( correction );\n\t\tdivHeaderStyle.width = _fnStringToCss( correction );\n\t\n\t\tif ( footer ) {\n\t\t\tsettings.nScrollFoot.style.width = _fnStringToCss( correction );\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 4. Clean up\n\t\t */\n\t\tif ( ! scrollY ) {\n\t\t\t/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting\n\t\t\t * the scrollbar height from the visible display, rather than adding it on. We need to\n\t\t\t * set the height in order to sort this. Don't want to do it in any other browsers.\n\t\t\t */\n\t\t\tif ( ie67 ) {\n\t\t\t\tdivBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Finally set the width's of the header and footer tables */\n\t\tvar iOuterWidth = table.outerWidth();\n\t\tdivHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\tdivHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );\n\t\n\t\t// Figure out if there are scrollbar present - if so then we need a the header and footer to\n\t\t// provide a bit more space to allow \"overflow\" scrolling (i.e. past the scrollbar)\n\t\tvar bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == \"scroll\";\n\t\tvar padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );\n\t\tdivHeaderInnerStyle[ padding ] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\n\t\tif ( footer ) {\n\t\t\tdivFooterTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style[padding] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\t}\n\t\n\t\t// Correct DOM ordering for colgroup - comes before the thead\n\t\ttable.children('colgroup').insertBefore( table.children('thead') );\n\t\n\t\t/* Adjust the position of the header in case we loose the y-scrollbar */\n\t\tdivBody.scroll();\n\t\n\t\t// If sorting or filtering has occurred, jump the scrolling back to the top\n\t\t// only if we aren't holding the position\n\t\tif ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {\n\t\t\tdivBodyEl.scrollTop = 0;\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Apply a given function to the display child nodes of an element array (typically\n\t * TD children of TR rows\n\t *  @param {function} fn Method to apply to the objects\n\t *  @param array {nodes} an1 List of elements to look through for display children\n\t *  @param array {nodes} an2 Another list (identical structure to the first) - optional\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyToChildren( fn, an1, an2 )\n\t{\n\t\tvar index=0, i=0, iLen=an1.length;\n\t\tvar nNode1, nNode2;\n\t\n\t\twhile ( i < iLen ) {\n\t\t\tnNode1 = an1[i].firstChild;\n\t\t\tnNode2 = an2 ? an2[i].firstChild : null;\n\t\n\t\t\twhile ( nNode1 ) {\n\t\t\t\tif ( nNode1.nodeType === 1 ) {\n\t\t\t\t\tif ( an2 ) {\n\t\t\t\t\t\tfn( nNode1, nNode2, index );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfn( nNode1, index );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\n\t\t\t\tnNode1 = nNode1.nextSibling;\n\t\t\t\tnNode2 = an2 ? nNode2.nextSibling : null;\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t}\n\t}\n\t\n\t\n\t\n\tvar __re_html_remove = /<.*?>/g;\n\t\n\t\n\t/**\n\t * Calculate the width of columns for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCalculateColumnWidths ( oSettings )\n\t{\n\t\tvar\n\t\t\ttable = oSettings.nTable,\n\t\t\tcolumns = oSettings.aoColumns,\n\t\t\tscroll = oSettings.oScroll,\n\t\t\tscrollY = scroll.sY,\n\t\t\tscrollX = scroll.sX,\n\t\t\tscrollXInner = scroll.sXInner,\n\t\t\tcolumnCount = columns.length,\n\t\t\tvisibleColumns = _fnGetColumns( oSettings, 'bVisible' ),\n\t\t\theaderCells = $('th', oSettings.nTHead),\n\t\t\ttableWidthAttr = table.getAttribute('width'), // from DOM element\n\t\t\ttableContainer = table.parentNode,\n\t\t\tuserInputs = false,\n\t\t\ti, column, columnIdx, width, outerWidth,\n\t\t\tbrowser = oSettings.oBrowser,\n\t\t\tie67 = browser.bScrollOversize;\n\t\n\t\tvar styleWidth = table.style.width;\n\t\tif ( styleWidth && styleWidth.indexOf('%') !== -1 ) {\n\t\t\ttableWidthAttr = styleWidth;\n\t\t}\n\t\n\t\t/* Convert any user input sizes into pixel sizes */\n\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\tif ( column.sWidth !== null ) {\n\t\t\t\tcolumn.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );\n\t\n\t\t\t\tuserInputs = true;\n\t\t\t}\n\t\t}\n\t\n\t\t/* If the number of columns in the DOM equals the number that we have to\n\t\t * process in DataTables, then we can use the offsets that are created by\n\t\t * the web- browser. No custom sizes can be set in order for this to happen,\n\t\t * nor scrolling used\n\t\t */\n\t\tif ( ie67 || ! userInputs && ! scrollX && ! scrollY &&\n\t\t     columnCount == _fnVisbleColumns( oSettings ) &&\n\t\t     columnCount == headerCells.length\n\t\t) {\n\t\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\t\tvar colIdx = _fnVisibleToColumnIndex( oSettings, i );\n\t\n\t\t\t\tif ( colIdx !== null ) {\n\t\t\t\t\tcolumns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise construct a single row, worst case, table with the widest\n\t\t\t// node in the data, assign any user defined widths, then insert it into\n\t\t\t// the DOM and allow the browser to do all the hard work of calculating\n\t\t\t// table widths\n\t\t\tvar tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table\n\t\t\t\t.css( 'visibility', 'hidden' )\n\t\t\t\t.removeAttr( 'id' );\n\t\n\t\t\t// Clean up the table body\n\t\t\ttmpTable.find('tbody tr').remove();\n\t\t\tvar tr = $('<tr/>').appendTo( tmpTable.find('tbody') );\n\t\n\t\t\t// Clone the table header and footer - we can't use the header / footer\n\t\t\t// from the cloned table, since if scrolling is active, the table's\n\t\t\t// real header and footer are contained in different table tags\n\t\t\ttmpTable.find('thead, tfoot').remove();\n\t\t\ttmpTable\n\t\t\t\t.append( $(oSettings.nTHead).clone() )\n\t\t\t\t.append( $(oSettings.nTFoot).clone() );\n\t\n\t\t\t// Remove any assigned widths from the footer (from scrolling)\n\t\t\ttmpTable.find('tfoot th, tfoot td').css('width', '');\n\t\n\t\t\t// Apply custom sizing to the cloned header\n\t\t\theaderCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );\n\t\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\t\theaderCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?\n\t\t\t\t\t_fnStringToCss( column.sWidthOrig ) :\n\t\t\t\t\t'';\n\t\n\t\t\t\t// For scrollX we need to force the column width otherwise the\n\t\t\t\t// browser will collapse it. If this width is smaller than the\n\t\t\t\t// width the column requires, then it will have no effect\n\t\t\t\tif ( column.sWidthOrig && scrollX ) {\n\t\t\t\t\t$( headerCells[i] ).append( $('<div/>').css( {\n\t\t\t\t\t\twidth: column.sWidthOrig,\n\t\t\t\t\t\tmargin: 0,\n\t\t\t\t\t\tpadding: 0,\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\theight: 1\n\t\t\t\t\t} ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Find the widest cell for each column and put it into the table\n\t\t\tif ( oSettings.aoData.length ) {\n\t\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\t\tcolumnIdx = visibleColumns[i];\n\t\t\t\t\tcolumn = columns[ columnIdx ];\n\t\n\t\t\t\t\t$( _fnGetWidestNode( oSettings, columnIdx ) )\n\t\t\t\t\t\t.clone( false )\n\t\t\t\t\t\t.append( column.sContentPadding )\n\t\t\t\t\t\t.appendTo( tr );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Tidy the temporary table - remove name attributes so there aren't\n\t\t\t// duplicated in the dom (radio elements for example)\n\t\t\t$('[name]', tmpTable).removeAttr('name');\n\t\n\t\t\t// Table has been built, attach to the document so we can work with it.\n\t\t\t// A holding element is used, positioned at the top of the container\n\t\t\t// with minimal height, so it has no effect on if the container scrolls\n\t\t\t// or not. Otherwise it might trigger scrolling when it actually isn't\n\t\t\t// needed\n\t\t\tvar holder = $('<div/>').css( scrollX || scrollY ?\n\t\t\t\t\t{\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\theight: 1,\n\t\t\t\t\t\tright: 0,\n\t\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t\t} :\n\t\t\t\t\t{}\n\t\t\t\t)\n\t\t\t\t.append( tmpTable )\n\t\t\t\t.appendTo( tableContainer );\n\t\n\t\t\t// When scrolling (X or Y) we want to set the width of the table as \n\t\t\t// appropriate. However, when not scrolling leave the table width as it\n\t\t\t// is. This results in slightly different, but I think correct behaviour\n\t\t\tif ( scrollX && scrollXInner ) {\n\t\t\t\ttmpTable.width( scrollXInner );\n\t\t\t}\n\t\t\telse if ( scrollX ) {\n\t\t\t\ttmpTable.css( 'width', 'auto' );\n\t\t\t\ttmpTable.removeAttr('width');\n\t\n\t\t\t\t// If there is no width attribute or style, then allow the table to\n\t\t\t\t// collapse\n\t\t\t\tif ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {\n\t\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( scrollY ) {\n\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t}\n\t\t\telse if ( tableWidthAttr ) {\n\t\t\t\ttmpTable.width( tableWidthAttr );\n\t\t\t}\n\t\n\t\t\t// Get the width of each column in the constructed table - we need to\n\t\t\t// know the inner width (so it can be assigned to the other table's\n\t\t\t// cells) and the outer width so we can calculate the full width of the\n\t\t\t// table. This is safe since DataTables requires a unique cell for each\n\t\t\t// column, but if ever a header can span multiple columns, this will\n\t\t\t// need to be modified.\n\t\t\tvar total = 0;\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tvar cell = $(headerCells[i]);\n\t\t\t\tvar border = cell.outerWidth() - cell.width();\n\t\n\t\t\t\t// Use getBounding... where possible (not IE8-) because it can give\n\t\t\t\t// sub-pixel accuracy, which we then want to round up!\n\t\t\t\tvar bounding = browser.bBounding ?\n\t\t\t\t\tMath.ceil( headerCells[i].getBoundingClientRect().width ) :\n\t\t\t\t\tcell.outerWidth();\n\t\n\t\t\t\t// Total is tracked to remove any sub-pixel errors as the outerWidth\n\t\t\t\t// of the table might not equal the total given here (IE!).\n\t\t\t\ttotal += bounding;\n\t\n\t\t\t\t// Width for each column to use\n\t\t\t\tcolumns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );\n\t\t\t}\n\t\n\t\t\ttable.style.width = _fnStringToCss( total );\n\t\n\t\t\t// Finished with the table - ditch it\n\t\t\tholder.remove();\n\t\t}\n\t\n\t\t// If there is a width attr, we want to attach an event listener which\n\t\t// allows the table sizing to automatically adjust when the window is\n\t\t// resized. Use the width attr rather than CSS, since we can't know if the\n\t\t// CSS is a relative value or absolute - DOM read is always px.\n\t\tif ( tableWidthAttr ) {\n\t\t\ttable.style.width = _fnStringToCss( tableWidthAttr );\n\t\t}\n\t\n\t\tif ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {\n\t\t\tvar bindResize = function () {\n\t\t\t\t$(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {\n\t\t\t\t\t_fnAdjustColumnSizing( oSettings );\n\t\t\t\t} ) );\n\t\t\t};\n\t\n\t\t\t// IE6/7 will crash if we bind a resize event handler on page load.\n\t\t\t// To be removed in 1.11 which drops IE6/7 support\n\t\t\tif ( ie67 ) {\n\t\t\t\tsetTimeout( bindResize, 1000 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbindResize();\n\t\t\t}\n\t\n\t\t\toSettings._reszEvt = true;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Throttle the calls to a function. Arguments and context are maintained for\n\t * the throttled function\n\t *  @param {function} fn Function to be called\n\t *  @param {int} [freq=200] call frequency in mS\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnThrottle = DataTable.util.throttle;\n\t\n\t\n\t/**\n\t * Convert a CSS unit width to pixels (e.g. 2em)\n\t *  @param {string} width width to be converted\n\t *  @param {node} parent parent to get the with for (required for relative widths) - optional\n\t *  @returns {int} width in pixels\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnConvertToWidth ( width, parent )\n\t{\n\t\tif ( ! width ) {\n\t\t\treturn 0;\n\t\t}\n\t\n\t\tvar n = $('<div/>')\n\t\t\t.css( 'width', _fnStringToCss( width ) )\n\t\t\t.appendTo( parent || document.body );\n\t\n\t\tvar val = n[0].offsetWidth;\n\t\tn.remove();\n\t\n\t\treturn val;\n\t}\n\t\n\t\n\t/**\n\t * Get the widest node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {node} widest table node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetWidestNode( settings, colIdx )\n\t{\n\t\tvar idx = _fnGetMaxLenString( settings, colIdx );\n\t\tif ( idx < 0 ) {\n\t\t\treturn null;\n\t\t}\n\t\n\t\tvar data = settings.aoData[ idx ];\n\t\treturn ! data.nTr ? // Might not have been created when deferred rendering\n\t\t\t$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :\n\t\t\tdata.anCells[ colIdx ];\n\t}\n\t\n\t\n\t/**\n\t * Get the maximum strlen for each data column\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {string} max string length for each column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetMaxLenString( settings, colIdx )\n\t{\n\t\tvar s, max=-1, maxIdx = -1;\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\ts = _fnGetCellData( settings, i, colIdx, 'display' )+'';\n\t\t\ts = s.replace( __re_html_remove, '' );\n\t\t\ts = s.replace( /&nbsp;/g, ' ' );\n\t\n\t\t\tif ( s.length > max ) {\n\t\t\t\tmax = s.length;\n\t\t\t\tmaxIdx = i;\n\t\t\t}\n\t\t}\n\t\n\t\treturn maxIdx;\n\t}\n\t\n\t\n\t/**\n\t * Append a CSS unit (only if required) to a string\n\t *  @param {string} value to css-ify\n\t *  @returns {string} value with css unit\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnStringToCss( s )\n\t{\n\t\tif ( s === null ) {\n\t\t\treturn '0px';\n\t\t}\n\t\n\t\tif ( typeof s == 'number' ) {\n\t\t\treturn s < 0 ?\n\t\t\t\t'0px' :\n\t\t\t\ts+'px';\n\t\t}\n\t\n\t\t// Check it has a unit character already\n\t\treturn s.match(/\\d$/) ?\n\t\t\ts+'px' :\n\t\t\ts;\n\t}\n\t\n\t\n\t\n\tfunction _fnSortFlatten ( settings )\n\t{\n\t\tvar\n\t\t\ti, iLen, k, kLen,\n\t\t\taSort = [],\n\t\t\taiOrig = [],\n\t\t\taoColumns = settings.aoColumns,\n\t\t\taDataSort, iCol, sType, srcCol,\n\t\t\tfixed = settings.aaSortingFixed,\n\t\t\tfixedObj = $.isPlainObject( fixed ),\n\t\t\tnestedSort = [],\n\t\t\tadd = function ( a ) {\n\t\t\t\tif ( a.length && ! $.isArray( a[0] ) ) {\n\t\t\t\t\t// 1D array\n\t\t\t\t\tnestedSort.push( a );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// 2D array\n\t\t\t\t\t$.merge( nestedSort, a );\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t// Build the sort array, with pre-fix and post-fix options if they have been\n\t\t// specified\n\t\tif ( $.isArray( fixed ) ) {\n\t\t\tadd( fixed );\n\t\t}\n\t\n\t\tif ( fixedObj && fixed.pre ) {\n\t\t\tadd( fixed.pre );\n\t\t}\n\t\n\t\tadd( settings.aaSorting );\n\t\n\t\tif (fixedObj && fixed.post ) {\n\t\t\tadd( fixed.post );\n\t\t}\n\t\n\t\tfor ( i=0 ; i<nestedSort.length ; i++ )\n\t\t{\n\t\t\tsrcCol = nestedSort[i][0];\n\t\t\taDataSort = aoColumns[ srcCol ].aDataSort;\n\t\n\t\t\tfor ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )\n\t\t\t{\n\t\t\t\tiCol = aDataSort[k];\n\t\t\t\tsType = aoColumns[ iCol ].sType || 'string';\n\t\n\t\t\t\tif ( nestedSort[i]._idx === undefined ) {\n\t\t\t\t\tnestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );\n\t\t\t\t}\n\t\n\t\t\t\taSort.push( {\n\t\t\t\t\tsrc:       srcCol,\n\t\t\t\t\tcol:       iCol,\n\t\t\t\t\tdir:       nestedSort[i][1],\n\t\t\t\t\tindex:     nestedSort[i]._idx,\n\t\t\t\t\ttype:      sType,\n\t\t\t\t\tformatter: DataTable.ext.type.order[ sType+\"-pre\" ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\treturn aSort;\n\t}\n\t\n\t/**\n\t * Change the order of the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t *  @todo This really needs split up!\n\t */\n\tfunction _fnSort ( oSettings )\n\t{\n\t\tvar\n\t\t\ti, ien, iLen, j, jLen, k, kLen,\n\t\t\tsDataType, nTh,\n\t\t\taiOrig = [],\n\t\t\toExtSort = DataTable.ext.type.order,\n\t\t\taoData = oSettings.aoData,\n\t\t\taoColumns = oSettings.aoColumns,\n\t\t\taDataSort, data, iCol, sType, oSort,\n\t\t\tformatters = 0,\n\t\t\tsortCol,\n\t\t\tdisplayMaster = oSettings.aiDisplayMaster,\n\t\t\taSort;\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo Can this be moved into a 'data-ready' handler which is called when\n\t\t//   data is going to be used in the table?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\taSort = _fnSortFlatten( oSettings );\n\t\n\t\tfor ( i=0, ien=aSort.length ; i<ien ; i++ ) {\n\t\t\tsortCol = aSort[i];\n\t\n\t\t\t// Track if we can use the fast sort algorithm\n\t\t\tif ( sortCol.formatter ) {\n\t\t\t\tformatters++;\n\t\t\t}\n\t\n\t\t\t// Load the data needed for the sort, for each cell\n\t\t\t_fnSortData( oSettings, sortCol.col );\n\t\t}\n\t\n\t\t/* No sorting required if server-side or no sorting array */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )\n\t\t{\n\t\t\t// Create a value - key array of the current row positions such that we can use their\n\t\t\t// current position during the sort, if values match, in order to perform stable sorting\n\t\t\tfor ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {\n\t\t\t\taiOrig[ displayMaster[i] ] = i;\n\t\t\t}\n\t\n\t\t\t/* Do the sort - here we want multi-column sorting based on a given data source (column)\n\t\t\t * and sorting function (from oSort) in a certain direction. It's reasonably complex to\n\t\t\t * follow on it's own, but this is what we want (example two column sorting):\n\t\t\t *  fnLocalSorting = function(a,b){\n\t\t\t *    var iTest;\n\t\t\t *    iTest = oSort['string-asc']('data11', 'data12');\n\t\t\t *      if (iTest !== 0)\n\t\t\t *        return iTest;\n\t\t\t *    iTest = oSort['numeric-desc']('data21', 'data22');\n\t\t\t *    if (iTest !== 0)\n\t\t\t *      return iTest;\n\t\t\t *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );\n\t\t\t *  }\n\t\t\t * Basically we have a test for each sorting column, if the data in that column is equal,\n\t\t\t * test the next column. If all columns match, then we use a numeric sort on the row\n\t\t\t * positions in the original data array to provide a stable sort.\n\t\t\t *\n\t\t\t * Note - I know it seems excessive to have two sorting methods, but the first is around\n\t\t\t * 15% faster, so the second is only maintained for backwards compatibility with sorting\n\t\t\t * methods which do not have a pre-sort formatting function.\n\t\t\t */\n\t\t\tif ( formatters === aSort.length ) {\n\t\t\t\t// All sort types have formatting functions\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, test, sort,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\ttest = x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn sort.dir === 'asc' ? test : -test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Depreciated - remove in 1.11 (providing a plug-in option)\n\t\t\t\t// Not all sort types have formatting methods, so we have to call their sorting\n\t\t\t\t// methods.\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, l, test, sort, fn,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\tfn = oExtSort[ sort.type+\"-\"+sort.dir ] || oExtSort[ \"string-\"+sort.dir ];\n\t\t\t\t\t\ttest = fn( x, y );\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Tell the draw function that we have sorted the data */\n\t\toSettings.bSorted = true;\n\t}\n\t\n\t\n\tfunction _fnSortAria ( settings )\n\t{\n\t\tvar label;\n\t\tvar nextSort;\n\t\tvar columns = settings.aoColumns;\n\t\tvar aSort = _fnSortFlatten( settings );\n\t\tvar oAria = settings.oLanguage.oAria;\n\t\n\t\t// ARIA attributes - need to loop all columns, to update all (removing old\n\t\t// attributes as needed)\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar col = columns[i];\n\t\t\tvar asSorting = col.asSorting;\n\t\t\tvar sTitle = col.sTitle.replace( /<.*?>/g, \"\" );\n\t\t\tvar th = col.nTh;\n\t\n\t\t\t// IE7 is throwing an error when setting these properties with jQuery's\n\t\t\t// attr() and removeAttr() methods...\n\t\t\tth.removeAttribute('aria-sort');\n\t\n\t\t\t/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */\n\t\t\tif ( col.bSortable ) {\n\t\t\t\tif ( aSort.length > 0 && aSort[0].col == i ) {\n\t\t\t\t\tth.setAttribute('aria-sort', aSort[0].dir==\"asc\" ? \"ascending\" : \"descending\" );\n\t\t\t\t\tnextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnextSort = asSorting[0];\n\t\t\t\t}\n\t\n\t\t\t\tlabel = sTitle + ( nextSort === \"asc\" ?\n\t\t\t\t\toAria.sSortAscending :\n\t\t\t\t\toAria.sSortDescending\n\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlabel = sTitle;\n\t\t\t}\n\t\n\t\t\tth.setAttribute('aria-label', label);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Function to run on user sort request\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {boolean} [append=false] Append the requested sort to the existing\n\t *    sort if true (i.e. multi-column sort)\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortListener ( settings, colIdx, append, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\tvar sorting = settings.aaSorting;\n\t\tvar asSorting = col.asSorting;\n\t\tvar nextSortIdx;\n\t\tvar next = function ( a, overflow ) {\n\t\t\tvar idx = a._idx;\n\t\t\tif ( idx === undefined ) {\n\t\t\t\tidx = $.inArray( a[1], asSorting );\n\t\t\t}\n\t\n\t\t\treturn idx+1 < asSorting.length ?\n\t\t\t\tidx+1 :\n\t\t\t\toverflow ?\n\t\t\t\t\tnull :\n\t\t\t\t\t0;\n\t\t};\n\t\n\t\t// Convert to 2D array if needed\n\t\tif ( typeof sorting[0] === 'number' ) {\n\t\t\tsorting = settings.aaSorting = [ sorting ];\n\t\t}\n\t\n\t\t// If appending the sort then we are multi-column sorting\n\t\tif ( append && settings.oFeatures.bSortMulti ) {\n\t\t\t// Are we already doing some kind of sort on this column?\n\t\t\tvar sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );\n\t\n\t\t\tif ( sortIdx !== -1 ) {\n\t\t\t\t// Yes, modify the sort\n\t\t\t\tnextSortIdx = next( sorting[sortIdx], true );\n\t\n\t\t\t\tif ( nextSortIdx === null && sorting.length === 1 ) {\n\t\t\t\t\tnextSortIdx = 0; // can't remove sorting completely\n\t\t\t\t}\n\t\n\t\t\t\tif ( nextSortIdx === null ) {\n\t\t\t\t\tsorting.splice( sortIdx, 1 );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tsorting[sortIdx][1] = asSorting[ nextSortIdx ];\n\t\t\t\t\tsorting[sortIdx]._idx = nextSortIdx;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// No sort on this column yet\n\t\t\t\tsorting.push( [ colIdx, asSorting[0], 0 ] );\n\t\t\t\tsorting[sorting.length-1]._idx = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( sorting.length && sorting[0][0] == colIdx ) {\n\t\t\t// Single column - already sorting on this column, modify the sort\n\t\t\tnextSortIdx = next( sorting[0] );\n\t\n\t\t\tsorting.length = 1;\n\t\t\tsorting[0][1] = asSorting[ nextSortIdx ];\n\t\t\tsorting[0]._idx = nextSortIdx;\n\t\t}\n\t\telse {\n\t\t\t// Single column - sort only on this column\n\t\t\tsorting.length = 0;\n\t\t\tsorting.push( [ colIdx, asSorting[0] ] );\n\t\t\tsorting[0]._idx = 0;\n\t\t}\n\t\n\t\t// Run the sort by calling a full redraw\n\t\t_fnReDraw( settings );\n\t\n\t\t// callback used for async user interaction\n\t\tif ( typeof callback == 'function' ) {\n\t\t\tcallback( settings );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Attach a sort handler (click) to a node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortAttachListener ( settings, attachTo, colIdx, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\n\t\t_fnBindAction( attachTo, {}, function (e) {\n\t\t\t/* If the column is not sortable - don't to anything */\n\t\t\tif ( col.bSortable === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If processing is enabled use a timeout to allow the processing\n\t\t\t// display to be shown - otherwise to it synchronously\n\t\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t\tsetTimeout( function() {\n\t\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\n\t\t\t\t\t// In server-side processing, the draw callback will remove the\n\t\t\t\t\t// processing display\n\t\t\t\t\tif ( _fnDataSource( settings ) !== 'ssp' ) {\n\t\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t}\n\t\t\t\t}, 0 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Set the sorting classes on table's body, Note: it is safe to call this function\n\t * when bSort and bSortClasses are false\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortingClasses( settings )\n\t{\n\t\tvar oldSort = settings.aLastSort;\n\t\tvar sortClass = settings.oClasses.sSortColumn;\n\t\tvar sort = _fnSortFlatten( settings );\n\t\tvar features = settings.oFeatures;\n\t\tvar i, ien, colIdx;\n\t\n\t\tif ( features.bSort && features.bSortClasses ) {\n\t\t\t// Remove old sorting classes\n\t\t\tfor ( i=0, ien=oldSort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = oldSort[i].src;\n\t\n\t\t\t\t// Remove column sorting\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.removeClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\n\t\t\t// Add new column sorting\n\t\t\tfor ( i=0, ien=sort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = sort[i].src;\n\t\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.addClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aLastSort = sort;\n\t}\n\t\n\t\n\t// Get the data to sort a column, be it from cache, fresh (populating the\n\t// cache), or from a sort formatter\n\tfunction _fnSortData( settings, idx )\n\t{\n\t\t// Custom sorting function - provided by the sort data type\n\t\tvar column = settings.aoColumns[ idx ];\n\t\tvar customSort = DataTable.ext.order[ column.sSortDataType ];\n\t\tvar customData;\n\t\n\t\tif ( customSort ) {\n\t\t\tcustomData = customSort.call( settings.oInstance, settings, idx,\n\t\t\t\t_fnColumnIndexToVisible( settings, idx )\n\t\t\t);\n\t\t}\n\t\n\t\t// Use / populate cache\n\t\tvar row, cellData;\n\t\tvar formatter = DataTable.ext.type.order[ column.sType+\"-pre\" ];\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aSortData ) {\n\t\t\t\trow._aSortData = [];\n\t\t\t}\n\t\n\t\t\tif ( ! row._aSortData[idx] || customSort ) {\n\t\t\t\tcellData = customSort ?\n\t\t\t\t\tcustomData[i] : // If there was a custom sort function, use data from there\n\t\t\t\t\t_fnGetCellData( settings, i, idx, 'sort' );\n\t\n\t\t\t\trow._aSortData[ idx ] = formatter ?\n\t\t\t\t\tformatter( cellData ) :\n\t\t\t\t\tcellData;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Save the state of a table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSaveState ( settings )\n\t{\n\t\tif ( !settings.oFeatures.bStateSave || settings.bDestroying )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Store the interesting variables */\n\t\tvar state = {\n\t\t\ttime:    +new Date(),\n\t\t\tstart:   settings._iDisplayStart,\n\t\t\tlength:  settings._iDisplayLength,\n\t\t\torder:   $.extend( true, [], settings.aaSorting ),\n\t\t\tsearch:  _fnSearchToCamel( settings.oPreviousSearch ),\n\t\t\tcolumns: $.map( settings.aoColumns, function ( col, i ) {\n\t\t\t\treturn {\n\t\t\t\t\tvisible: col.bVisible,\n\t\t\t\t\tsearch: _fnSearchToCamel( settings.aoPreSearchCols[i] )\n\t\t\t\t};\n\t\t\t} )\n\t\t};\n\t\n\t\t_fnCallbackFire( settings, \"aoStateSaveParams\", 'stateSaveParams', [settings, state] );\n\t\n\t\tsettings.oSavedState = state;\n\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, state );\n\t}\n\t\n\t\n\t/**\n\t * Attempt to load a saved table state\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oInit DataTables init object so we can override settings\n\t *  @param {function} callback Callback to execute when the state has been loaded\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLoadState ( settings, oInit, callback )\n\t{\n\t\tvar i, ien;\n\t\tvar columns = settings.aoColumns;\n\t\tvar loaded = function ( s ) {\n\t\t\tif ( ! s || ! s.time ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Allow custom and plug-in manipulation functions to alter the saved data set and\n\t\t\t// cancelling of loading by returning false\n\t\t\tvar abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );\n\t\t\tif ( $.inArray( false, abStateLoad ) !== -1 ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Reject old data\n\t\t\tvar duration = settings.iStateDuration;\n\t\t\tif ( duration > 0 && s.time < +new Date() - (duration*1000) ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Number of columns have changed - all bets are off, no restore of settings\n\t\t\tif ( s.columns && columns.length !== s.columns.length ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Store the saved state so it might be accessed at any time\n\t\t\tsettings.oLoadedState = $.extend( true, {}, state );\n\t\n\t\t\t// Restore key features - todo - for 1.11 this needs to be done by\n\t\t\t// subscribed events\n\t\t\tif ( s.start !== undefined ) {\n\t\t\t\tsettings._iDisplayStart    = s.start;\n\t\t\t\tsettings.iInitDisplayStart = s.start;\n\t\t\t}\n\t\t\tif ( s.length !== undefined ) {\n\t\t\t\tsettings._iDisplayLength   = s.length;\n\t\t\t}\n\t\n\t\t\t// Order\n\t\t\tif ( s.order !== undefined ) {\n\t\t\t\tsettings.aaSorting = [];\n\t\t\t\t$.each( s.order, function ( i, col ) {\n\t\t\t\t\tsettings.aaSorting.push( col[0] >= columns.length ?\n\t\t\t\t\t\t[ 0, col[1] ] :\n\t\t\t\t\t\tcol\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Search\n\t\t\tif ( s.search !== undefined ) {\n\t\t\t\t$.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );\n\t\t\t}\n\t\n\t\t\t// Columns\n\t\t\t// \n\t\t\tif ( s.columns ) {\n\t\t\t\tfor ( i=0, ien=s.columns.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar col = s.columns[i];\n\t\n\t\t\t\t\t// Visibility\n\t\t\t\t\tif ( col.visible !== undefined ) {\n\t\t\t\t\t\tcolumns[i].bVisible = col.visible;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Search\n\t\t\t\t\tif ( col.search !== undefined ) {\n\t\t\t\t\t\t$.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );\n\t\t\tcallback();\n\t\t}\n\t\n\t\tif ( ! settings.oFeatures.bStateSave ) {\n\t\t\tcallback();\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );\n\t\n\t\tif ( state !== undefined ) {\n\t\t\tloaded( state );\n\t\t}\n\t\t// otherwise, wait for the loaded callback to be executed\n\t}\n\t\n\t\n\t/**\n\t * Return the settings object for a particular table\n\t *  @param {node} table table we are using as a dataTable\n\t *  @returns {object} Settings object - or null if not found\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSettingsFromNode ( table )\n\t{\n\t\tvar settings = DataTable.settings;\n\t\tvar idx = $.inArray( table, _pluck( settings, 'nTable' ) );\n\t\n\t\treturn idx !== -1 ?\n\t\t\tsettings[ idx ] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Log an error message\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} level log error messages, or display them to the user\n\t *  @param {string} msg error message\n\t *  @param {int} tn Technical note id to get more information about the error.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLog( settings, level, msg, tn )\n\t{\n\t\tmsg = 'DataTables warning: '+\n\t\t\t(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;\n\t\n\t\tif ( tn ) {\n\t\t\tmsg += '. For more information about this error, please see '+\n\t\t\t'http://datatables.net/tn/'+tn;\n\t\t}\n\t\n\t\tif ( ! level  ) {\n\t\t\t// Backwards compatibility pre 1.10\n\t\t\tvar ext = DataTable.ext;\n\t\t\tvar type = ext.sErrMode || ext.errMode;\n\t\n\t\t\tif ( settings ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );\n\t\t\t}\n\t\n\t\t\tif ( type == 'alert' ) {\n\t\t\t\talert( msg );\n\t\t\t}\n\t\t\telse if ( type == 'throw' ) {\n\t\t\t\tthrow new Error(msg);\n\t\t\t}\n\t\t\telse if ( typeof type == 'function' ) {\n\t\t\t\ttype( settings, tn, msg );\n\t\t\t}\n\t\t}\n\t\telse if ( window.console && console.log ) {\n\t\t\tconsole.log( msg );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * See if a property is defined on one object, if so assign it to the other object\n\t *  @param {object} ret target object\n\t *  @param {object} src source object\n\t *  @param {string} name property\n\t *  @param {string} [mappedName] name to map too - optional, name used if not given\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnMap( ret, src, name, mappedName )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\t$.each( name, function (i, val) {\n\t\t\t\tif ( $.isArray( val ) ) {\n\t\t\t\t\t_fnMap( ret, src, val[0], val[1] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_fnMap( ret, src, val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( mappedName === undefined ) {\n\t\t\tmappedName = name;\n\t\t}\n\t\n\t\tif ( src[name] !== undefined ) {\n\t\t\tret[mappedName] = src[name];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Extend objects - very similar to jQuery.extend, but deep copy objects, and\n\t * shallow copy arrays. The reason we need to do this, is that we don't want to\n\t * deep copy array init values (such as aaSorting) since the dev wouldn't be\n\t * able to override them, but we do want to deep copy arrays.\n\t *  @param {object} out Object to extend\n\t *  @param {object} extender Object from which the properties will be applied to\n\t *      out\n\t *  @param {boolean} breakRefs If true, then arrays will be sliced to take an\n\t *      independent copy with the exception of the `data` or `aaData` parameters\n\t *      if they are present. This is so you can pass in a collection to\n\t *      DataTables and have that used as your data source without breaking the\n\t *      references\n\t *  @returns {object} out Reference, just for convenience - out === the return.\n\t *  @memberof DataTable#oApi\n\t *  @todo This doesn't take account of arrays inside the deep copied objects.\n\t */\n\tfunction _fnExtend( out, extender, breakRefs )\n\t{\n\t\tvar val;\n\t\n\t\tfor ( var prop in extender ) {\n\t\t\tif ( extender.hasOwnProperty(prop) ) {\n\t\t\t\tval = extender[prop];\n\t\n\t\t\t\tif ( $.isPlainObject( val ) ) {\n\t\t\t\t\tif ( ! $.isPlainObject( out[prop] ) ) {\n\t\t\t\t\t\tout[prop] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, out[prop], val );\n\t\t\t\t}\n\t\t\t\telse if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {\n\t\t\t\t\tout[prop] = val.slice();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tout[prop] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t}\n\t\n\t\n\t/**\n\t * Bind an event handers to allow a click or return key to activate the callback.\n\t * This is good for accessibility since a return on the keyboard will have the\n\t * same effect as a click, if the element has focus.\n\t *  @param {element} n Element to bind the action to\n\t *  @param {object} oData Data object to pass to the triggered function\n\t *  @param {function} fn Callback function for when the event is triggered\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBindAction( n, oData, fn )\n\t{\n\t\t$(n)\n\t\t\t.on( 'click.DT', oData, function (e) {\n\t\t\t\t\tn.blur(); // Remove focus outline for mouse users\n\t\t\t\t\tfn(e);\n\t\t\t\t} )\n\t\t\t.on( 'keypress.DT', oData, function (e){\n\t\t\t\t\tif ( e.which === 13 ) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tfn(e);\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t.on( 'selectstart.DT', function () {\n\t\t\t\t\t/* Take the brutal approach to cancelling text selection */\n\t\t\t\t\treturn false;\n\t\t\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Register a callback function. Easily allows a callback function to be added to\n\t * an array store of callback functions that can then all be called together.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sStore Name of the array storage for the callbacks in oSettings\n\t *  @param {function} fn Function to be called back\n\t *  @param {string} sName Identifying name for the callback (i.e. a label)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackReg( oSettings, sStore, fn, sName )\n\t{\n\t\tif ( fn )\n\t\t{\n\t\t\toSettings[sStore].push( {\n\t\t\t\t\"fn\": fn,\n\t\t\t\t\"sName\": sName\n\t\t\t} );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Fire callback functions and trigger events. Note that the loop over the\n\t * callback array store is done backwards! Further note that you do not want to\n\t * fire off triggers in time sensitive applications (for example cell creation)\n\t * as its slow.\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} callbackArr Name of the array storage for the callbacks in\n\t *      oSettings\n\t *  @param {string} eventName Name of the jQuery custom event to trigger. If\n\t *      null no trigger is fired\n\t *  @param {array} args Array of arguments to pass to the callback function /\n\t *      trigger\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackFire( settings, callbackArr, eventName, args )\n\t{\n\t\tvar ret = [];\n\t\n\t\tif ( callbackArr ) {\n\t\t\tret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {\n\t\t\t\treturn val.fn.apply( settings.oInstance, args );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( eventName !== null ) {\n\t\t\tvar e = $.Event( eventName+'.dt' );\n\t\n\t\t\t$(settings.nTable).trigger( e, args );\n\t\n\t\t\tret.push( e.result );\n\t\t}\n\t\n\t\treturn ret;\n\t}\n\t\n\t\n\tfunction _fnLengthOverflow ( settings )\n\t{\n\t\tvar\n\t\t\tstart = settings._iDisplayStart,\n\t\t\tend = settings.fnDisplayEnd(),\n\t\t\tlen = settings._iDisplayLength;\n\t\n\t\t/* If we have space to show extra rows (backing up from the end point - then do so */\n\t\tif ( start >= end )\n\t\t{\n\t\t\tstart = end - len;\n\t\t}\n\t\n\t\t// Keep the start record on the current page\n\t\tstart -= (start % len);\n\t\n\t\tif ( len === -1 || start < 0 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\n\t\tsettings._iDisplayStart = start;\n\t}\n\t\n\t\n\tfunction _fnRenderer( settings, type )\n\t{\n\t\tvar renderer = settings.renderer;\n\t\tvar host = DataTable.ext.renderer[type];\n\t\n\t\tif ( $.isPlainObject( renderer ) && renderer[type] ) {\n\t\t\t// Specific renderer for this type. If available use it, otherwise use\n\t\t\t// the default.\n\t\t\treturn host[renderer[type]] || host._;\n\t\t}\n\t\telse if ( typeof renderer === 'string' ) {\n\t\t\t// Common renderer - if there is one available for this type use it,\n\t\t\t// otherwise use the default\n\t\t\treturn host[renderer] || host._;\n\t\t}\n\t\n\t\t// Use the default\n\t\treturn host._;\n\t}\n\t\n\t\n\t/**\n\t * Detect the data source being used for the table. Used to simplify the code\n\t * a little (ajax) and to make it compress a little smaller.\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {string} Data source\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDataSource ( settings )\n\t{\n\t\tif ( settings.oFeatures.bServerSide ) {\n\t\t\treturn 'ssp';\n\t\t}\n\t\telse if ( settings.ajax || settings.sAjaxSource ) {\n\t\t\treturn 'ajax';\n\t\t}\n\t\treturn 'dom';\n\t}\n\t\n\n\t\n\t\n\t/**\n\t * Computed structure of the DataTables API, defined by the options passed to\n\t * `DataTable.Api.register()` when building the API.\n\t *\n\t * The structure is built in order to speed creation and extension of the Api\n\t * objects since the extensions are effectively pre-parsed.\n\t *\n\t * The array is an array of objects with the following structure, where this\n\t * base array represents the Api prototype base:\n\t *\n\t *     [\n\t *       {\n\t *         name:      'data'                -- string   - Property name\n\t *         val:       function () {},       -- function - Api method (or undefined if just an object\n\t *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t *       },\n\t *       {\n\t *         name:     'row'\n\t *         val:       {},\n\t *         methodExt: [ ... ],\n\t *         propExt:   [\n\t *           {\n\t *             name:      'data'\n\t *             val:       function () {},\n\t *             methodExt: [ ... ],\n\t *             propExt:   [ ... ]\n\t *           },\n\t *           ...\n\t *         ]\n\t *       }\n\t *     ]\n\t *\n\t * @type {Array}\n\t * @ignore\n\t */\n\tvar __apiStruct = [];\n\t\n\t\n\t/**\n\t * `Array.prototype` reference.\n\t *\n\t * @type object\n\t * @ignore\n\t */\n\tvar __arrayProto = Array.prototype;\n\t\n\t\n\t/**\n\t * Abstraction for `context` parameter of the `Api` constructor to allow it to\n\t * take several different forms for ease of use.\n\t *\n\t * Each of the input parameter types will be converted to a DataTables settings\n\t * object where possible.\n\t *\n\t * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one\n\t *   of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t *   * `DataTables.Api` - API instance\n\t * @return {array|null} Matching DataTables settings objects. `null` or\n\t *   `undefined` is returned if no matching DataTable is found.\n\t * @ignore\n\t */\n\tvar _toSettings = function ( mixed )\n\t{\n\t\tvar idx, jq;\n\t\tvar settings = DataTable.settings;\n\t\tvar tables = $.map( settings, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\tif ( ! mixed ) {\n\t\t\treturn [];\n\t\t}\n\t\telse if ( mixed.nTable && mixed.oApi ) {\n\t\t\t// DataTables settings object\n\t\t\treturn [ mixed ];\n\t\t}\n\t\telse if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {\n\t\t\t// Table node\n\t\t\tidx = $.inArray( mixed, tables );\n\t\t\treturn idx !== -1 ? [ settings[idx] ] : null;\n\t\t}\n\t\telse if ( mixed && typeof mixed.settings === 'function' ) {\n\t\t\treturn mixed.settings().toArray();\n\t\t}\n\t\telse if ( typeof mixed === 'string' ) {\n\t\t\t// jQuery selector\n\t\t\tjq = $(mixed);\n\t\t}\n\t\telse if ( mixed instanceof $ ) {\n\t\t\t// jQuery object (also DataTables instance)\n\t\t\tjq = mixed;\n\t\t}\n\t\n\t\tif ( jq ) {\n\t\t\treturn jq.map( function(i) {\n\t\t\t\tidx = $.inArray( this, tables );\n\t\t\t\treturn idx !== -1 ? settings[idx] : null;\n\t\t\t} ).toArray();\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * DataTables API class - used to control and interface with  one or more\n\t * DataTables enhanced tables.\n\t *\n\t * The API class is heavily based on jQuery, presenting a chainable interface\n\t * that you can use to interact with tables. Each instance of the API class has\n\t * a \"context\" - i.e. the tables that it will operate on. This could be a single\n\t * table, all tables on a page or a sub-set thereof.\n\t *\n\t * Additionally the API is designed to allow you to easily work with the data in\n\t * the tables, retrieving and manipulating it as required. This is done by\n\t * presenting the API class as an array like interface. The contents of the\n\t * array depend upon the actions requested by each method (for example\n\t * `rows().nodes()` will return an array of nodes, while `rows().data()` will\n\t * return an array of objects or arrays depending upon your table's\n\t * configuration). The API object has a number of array like methods (`push`,\n\t * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,\n\t * `unique` etc) to assist your working with the data held in a table.\n\t *\n\t * Most methods (those which return an Api instance) are chainable, which means\n\t * the return from a method call also has all of the methods available that the\n\t * top level object had. For example, these two calls are equivalent:\n\t *\n\t *     // Not chained\n\t *     api.row.add( {...} );\n\t *     api.draw();\n\t *\n\t *     // Chained\n\t *     api.row.add( {...} ).draw();\n\t *\n\t * @class DataTable.Api\n\t * @param {array|object|string|jQuery} context DataTable identifier. This is\n\t *   used to define which DataTables enhanced tables this API will operate on.\n\t *   Can be one of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t * @param {array} [data] Data to initialise the Api instance with.\n\t *\n\t * @example\n\t *   // Direct initialisation during DataTables construction\n\t *   var api = $('#example').DataTable();\n\t *\n\t * @example\n\t *   // Initialisation using a DataTables jQuery object\n\t *   var api = $('#example').dataTable().api();\n\t *\n\t * @example\n\t *   // Initialisation as a constructor\n\t *   var api = new $.fn.DataTable.Api( 'table.dataTable' );\n\t */\n\t_Api = function ( context, data )\n\t{\n\t\tif ( ! (this instanceof _Api) ) {\n\t\t\treturn new _Api( context, data );\n\t\t}\n\t\n\t\tvar settings = [];\n\t\tvar ctxSettings = function ( o ) {\n\t\t\tvar a = _toSettings( o );\n\t\t\tif ( a ) {\n\t\t\t\tsettings = settings.concat( a );\n\t\t\t}\n\t\t};\n\t\n\t\tif ( $.isArray( context ) ) {\n\t\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tctxSettings( context[i] );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tctxSettings( context );\n\t\t}\n\t\n\t\t// Remove duplicates\n\t\tthis.context = _unique( settings );\n\t\n\t\t// Initial data\n\t\tif ( data ) {\n\t\t\t$.merge( this, data );\n\t\t}\n\t\n\t\t// selector\n\t\tthis.selector = {\n\t\t\trows: null,\n\t\t\tcols: null,\n\t\t\topts: null\n\t\t};\n\t\n\t\t_Api.extend( this, this, __apiStruct );\n\t};\n\t\n\tDataTable.Api = _Api;\n\t\n\t// Don't destroy the existing prototype, just extend it. Required for jQuery 2's\n\t// isPlainObject.\n\t$.extend( _Api.prototype, {\n\t\tany: function ()\n\t\t{\n\t\t\treturn this.count() !== 0;\n\t\t},\n\t\n\t\n\t\tconcat:  __arrayProto.concat,\n\t\n\t\n\t\tcontext: [], // array of table settings objects\n\t\n\t\n\t\tcount: function ()\n\t\t{\n\t\t\treturn this.flatten().length;\n\t\t},\n\t\n\t\n\t\teach: function ( fn )\n\t\t{\n\t\t\tfor ( var i=0, ien=this.length ; i<ien; i++ ) {\n\t\t\t\tfn.call( this, this[i], i, this );\n\t\t\t}\n\t\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\teq: function ( idx )\n\t\t{\n\t\t\tvar ctx = this.context;\n\t\n\t\t\treturn ctx.length > idx ?\n\t\t\t\tnew _Api( ctx[idx], this[idx] ) :\n\t\t\t\tnull;\n\t\t},\n\t\n\t\n\t\tfilter: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.filter ) {\n\t\t\t\ta = __arrayProto.filter.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( fn.call( this, this[i], i, this ) ) {\n\t\t\t\t\t\ta.push( this[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tflatten: function ()\n\t\t{\n\t\t\tvar a = [];\n\t\t\treturn new _Api( this.context, a.concat.apply( a, this.toArray() ) );\n\t\t},\n\t\n\t\n\t\tjoin:    __arrayProto.join,\n\t\n\t\n\t\tindexOf: __arrayProto.indexOf || function (obj, start)\n\t\t{\n\t\t\tfor ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {\n\t\t\t\tif ( this[i] === obj ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1;\n\t\t},\n\t\n\t\titerator: function ( flatten, type, fn, alwaysNew ) {\n\t\t\tvar\n\t\t\t\ta = [], ret,\n\t\t\t\ti, ien, j, jen,\n\t\t\t\tcontext = this.context,\n\t\t\t\trows, items, item,\n\t\t\t\tselector = this.selector;\n\t\n\t\t\t// Argument shifting\n\t\t\tif ( typeof flatten === 'string' ) {\n\t\t\t\talwaysNew = fn;\n\t\t\t\tfn = type;\n\t\t\t\ttype = flatten;\n\t\t\t\tflatten = false;\n\t\t\t}\n\t\n\t\t\tfor ( i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tvar apiInst = new _Api( context[i] );\n\t\n\t\t\t\tif ( type === 'table' ) {\n\t\t\t\t\tret = fn.call( apiInst, context[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'columns' || type === 'rows' ) {\n\t\t\t\t\t// this has same length as context - one entry for each table\n\t\t\t\t\tret = fn.call( apiInst, context[i], this[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {\n\t\t\t\t\t// columns and rows share the same structure.\n\t\t\t\t\t// 'this' is an array of column indexes for each context\n\t\t\t\t\titems = this[i];\n\t\n\t\t\t\t\tif ( type === 'column-rows' ) {\n\t\t\t\t\t\trows = _selector_row_indexes( context[i], selector.opts );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfor ( j=0, jen=items.length ; j<jen ; j++ ) {\n\t\t\t\t\t\titem = items[j];\n\t\n\t\t\t\t\t\tif ( type === 'cell' ) {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item.row, item.column, i, j );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item, i, j, rows );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( a.length || alwaysNew ) {\n\t\t\t\tvar api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );\n\t\t\t\tvar apiSelector = api.selector;\n\t\t\t\tapiSelector.rows = selector.rows;\n\t\t\t\tapiSelector.cols = selector.cols;\n\t\t\t\tapiSelector.opts = selector.opts;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\tlastIndexOf: __arrayProto.lastIndexOf || function (obj, start)\n\t\t{\n\t\t\t// Bit cheeky...\n\t\t\treturn this.indexOf.apply( this.toArray.reverse(), arguments );\n\t\t},\n\t\n\t\n\t\tlength:  0,\n\t\n\t\n\t\tmap: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.map ) {\n\t\t\t\ta = __arrayProto.map.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\ta.push( fn.call( this, this[i], i ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tpluck: function ( prop )\n\t\t{\n\t\t\treturn this.map( function ( el ) {\n\t\t\t\treturn el[ prop ];\n\t\t\t} );\n\t\t},\n\t\n\t\tpop:     __arrayProto.pop,\n\t\n\t\n\t\tpush:    __arrayProto.push,\n\t\n\t\n\t\t// Does not return an API instance\n\t\treduce: __arrayProto.reduce || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, 0, this.length, 1 );\n\t\t},\n\t\n\t\n\t\treduceRight: __arrayProto.reduceRight || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, this.length-1, -1, -1 );\n\t\t},\n\t\n\t\n\t\treverse: __arrayProto.reverse,\n\t\n\t\n\t\t// Object with rows, columns and opts\n\t\tselector: null,\n\t\n\t\n\t\tshift:   __arrayProto.shift,\n\t\n\t\n\t\tsort:    __arrayProto.sort, // ? name - order?\n\t\n\t\n\t\tsplice:  __arrayProto.splice,\n\t\n\t\n\t\ttoArray: function ()\n\t\t{\n\t\t\treturn __arrayProto.slice.call( this );\n\t\t},\n\t\n\t\n\t\tto$: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\ttoJQuery: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\tunique: function ()\n\t\t{\n\t\t\treturn new _Api( this.context, _unique(this) );\n\t\t},\n\t\n\t\n\t\tunshift: __arrayProto.unshift\n\t} );\n\t\n\t\n\t_Api.extend = function ( scope, obj, ext )\n\t{\n\t\t// Only extend API instances and static properties of the API\n\t\tif ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\tj, jen,\n\t\t\tstruct, inner,\n\t\t\tmethodScoping = function ( scope, fn, struc ) {\n\t\t\t\treturn function () {\n\t\t\t\t\tvar ret = fn.apply( scope, arguments );\n\t\n\t\t\t\t\t// Method extension\n\t\t\t\t\t_Api.extend( ret, ret, struc.methodExt );\n\t\t\t\t\treturn ret;\n\t\t\t\t};\n\t\t\t};\n\t\n\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\tstruct = ext[i];\n\t\n\t\t\t// Value\n\t\t\tobj[ struct.name ] = typeof struct.val === 'function' ?\n\t\t\t\tmethodScoping( scope, struct.val, struct ) :\n\t\t\t\t$.isPlainObject( struct.val ) ?\n\t\t\t\t\t{} :\n\t\t\t\t\tstruct.val;\n\t\n\t\t\tobj[ struct.name ].__dt_wrapper = true;\n\t\n\t\t\t// Property extension\n\t\t\t_Api.extend( scope, obj[ struct.name ], struct.propExt );\n\t\t}\n\t};\n\t\n\t\n\t// @todo - Is there need for an augment function?\n\t// _Api.augment = function ( inst, name )\n\t// {\n\t// \t// Find src object in the structure from the name\n\t// \tvar parts = name.split('.');\n\t\n\t// \t_Api.extend( inst, obj );\n\t// };\n\t\n\t\n\t//     [\n\t//       {\n\t//         name:      'data'                -- string   - Property name\n\t//         val:       function () {},       -- function - Api method (or undefined if just an object\n\t//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t//       },\n\t//       {\n\t//         name:     'row'\n\t//         val:       {},\n\t//         methodExt: [ ... ],\n\t//         propExt:   [\n\t//           {\n\t//             name:      'data'\n\t//             val:       function () {},\n\t//             methodExt: [ ... ],\n\t//             propExt:   [ ... ]\n\t//           },\n\t//           ...\n\t//         ]\n\t//       }\n\t//     ]\n\t\n\t_Api.register = _api_register = function ( name, val )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\tfor ( var j=0, jen=name.length ; j<jen ; j++ ) {\n\t\t\t\t_Api.register( name[j], val );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\their = name.split('.'),\n\t\t\tstruct = __apiStruct,\n\t\t\tkey, method;\n\t\n\t\tvar find = function ( src, name ) {\n\t\t\tfor ( var i=0, ien=src.length ; i<ien ; i++ ) {\n\t\t\t\tif ( src[i].name === name ) {\n\t\t\t\t\treturn src[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\n\t\tfor ( i=0, ien=heir.length ; i<ien ; i++ ) {\n\t\t\tmethod = heir[i].indexOf('()') !== -1;\n\t\t\tkey = method ?\n\t\t\t\their[i].replace('()', '') :\n\t\t\t\their[i];\n\t\n\t\t\tvar src = find( struct, key );\n\t\t\tif ( ! src ) {\n\t\t\t\tsrc = {\n\t\t\t\t\tname:      key,\n\t\t\t\t\tval:       {},\n\t\t\t\t\tmethodExt: [],\n\t\t\t\t\tpropExt:   []\n\t\t\t\t};\n\t\t\t\tstruct.push( src );\n\t\t\t}\n\t\n\t\t\tif ( i === ien-1 ) {\n\t\t\t\tsrc.val = val;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstruct = method ?\n\t\t\t\t\tsrc.methodExt :\n\t\t\t\t\tsrc.propExt;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\t_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {\n\t\t_Api.register( pluralName, val );\n\t\n\t\t_Api.register( singularName, function () {\n\t\t\tvar ret = val.apply( this, arguments );\n\t\n\t\t\tif ( ret === this ) {\n\t\t\t\t// Returned item is the API instance that was passed in, return it\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\telse if ( ret instanceof _Api ) {\n\t\t\t\t// New API instance returned, want the value from the first item\n\t\t\t\t// in the returned array for the singular result.\n\t\t\t\treturn ret.length ?\n\t\t\t\t\t$.isArray( ret[0] ) ?\n\t\t\t\t\t\tnew _Api( ret.context, ret[0] ) : // Array results are 'enhanced'\n\t\t\t\t\t\tret[0] :\n\t\t\t\t\tundefined;\n\t\t\t}\n\t\n\t\t\t// Non-API return - just fire it back\n\t\t\treturn ret;\n\t\t} );\n\t};\n\t\n\t\n\t/**\n\t * Selector for HTML tables. Apply the given selector to the give array of\n\t * DataTables settings objects.\n\t *\n\t * @param {string|integer} [selector] jQuery selector string or integer\n\t * @param  {array} Array of DataTables settings objects to be filtered\n\t * @return {array}\n\t * @ignore\n\t */\n\tvar __table_selector = function ( selector, a )\n\t{\n\t\t// Integer is used to pick out a table by index\n\t\tif ( typeof selector === 'number' ) {\n\t\t\treturn [ a[ selector ] ];\n\t\t}\n\t\n\t\t// Perform a jQuery selector on the table nodes\n\t\tvar nodes = $.map( a, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\treturn $(nodes)\n\t\t\t.filter( selector )\n\t\t\t.map( function (i) {\n\t\t\t\t// Need to translate back from the table node to the settings\n\t\t\t\tvar idx = $.inArray( this, nodes );\n\t\t\t\treturn a[ idx ];\n\t\t\t} )\n\t\t\t.toArray();\n\t};\n\t\n\t\n\t\n\t/**\n\t * Context selector for the API's context (i.e. the tables the API instance\n\t * refers to.\n\t *\n\t * @name    DataTable.Api#tables\n\t * @param {string|integer} [selector] Selector to pick which tables the iterator\n\t *   should operate on. If not given, all tables in the current context are\n\t *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to\n\t *   select multiple tables or as an integer to select a single table.\n\t * @returns {DataTable.Api} Returns a new API instance if a selector is given.\n\t */\n\t_api_register( 'tables()', function ( selector ) {\n\t\t// A new instance is created if there was a selector specified\n\t\treturn selector ?\n\t\t\tnew _Api( __table_selector( selector, this.context ) ) :\n\t\t\tthis;\n\t} );\n\t\n\t\n\t_api_register( 'table()', function ( selector ) {\n\t\tvar tables = this.tables( selector );\n\t\tvar ctx = tables.context;\n\t\n\t\t// Truncate to the first matched table\n\t\treturn ctx.length ?\n\t\t\tnew _Api( ctx[0] ) :\n\t\t\ttables;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTable;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().body()', 'table().body()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTBody;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().header()', 'table().header()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTHead;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTFoot;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().containers()', 'table().container()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTableWrapper;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Redraw the tables in the current context.\n\t */\n\t_api_register( 'draw()', function ( paging ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( paging === 'page' ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ( typeof paging === 'string' ) {\n\t\t\t\t\tpaging = paging === 'full-hold' ?\n\t\t\t\t\t\tfalse :\n\t\t\t\t\t\ttrue;\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, paging===false );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get the current page index.\n\t *\n\t * @return {integer} Current page index (zero based)\n\t *//**\n\t * Set the current page.\n\t *\n\t * Note that if you attempt to show a page which does not exist, DataTables will\n\t * not throw an error, but rather reset the paging.\n\t *\n\t * @param {integer|string} action The paging action to take. This can be one of:\n\t *  * `integer` - The page index to jump to\n\t *  * `string` - An action to take:\n\t *    * `first` - Jump to first page.\n\t *    * `next` - Jump to the next page\n\t *    * `previous` - Jump to previous page\n\t *    * `last` - Jump to the last page.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page()', function ( action ) {\n\t\tif ( action === undefined ) {\n\t\t\treturn this.page.info().page; // not an expensive call\n\t\t}\n\t\n\t\t// else, have an action to take on all tables\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnPageChange( settings, action );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Paging information for the first table in the current context.\n\t *\n\t * If you require paging information for another table, use the `table()` method\n\t * with a suitable selector.\n\t *\n\t * @return {object} Object with the following properties set:\n\t *  * `page` - Current page index (zero based - i.e. the first page is `0`)\n\t *  * `pages` - Total number of pages\n\t *  * `start` - Display index for the first record shown on the current page\n\t *  * `end` - Display index for the last record shown on the current page\n\t *  * `length` - Display length (number of records). Note that generally `start\n\t *    + length = end`, but this is not always true, for example if there are\n\t *    only 2 records to show on the final page, with a length of 10.\n\t *  * `recordsTotal` - Full data set length\n\t *  * `recordsDisplay` - Data set length once the current filtering criterion\n\t *    are applied.\n\t */\n\t_api_register( 'page.info()', function ( action ) {\n\t\tif ( this.context.length === 0 ) {\n\t\t\treturn undefined;\n\t\t}\n\t\n\t\tvar\n\t\t\tsettings   = this.context[0],\n\t\t\tstart      = settings._iDisplayStart,\n\t\t\tlen        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,\n\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn {\n\t\t\t\"page\":           all ? 0 : Math.floor( start / len ),\n\t\t\t\"pages\":          all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\"start\":          start,\n\t\t\t\"end\":            settings.fnDisplayEnd(),\n\t\t\t\"length\":         len,\n\t\t\t\"recordsTotal\":   settings.fnRecordsTotal(),\n\t\t\t\"recordsDisplay\": visRecords,\n\t\t\t\"serverSide\":     _fnDataSource( settings ) === 'ssp'\n\t\t};\n\t} );\n\t\n\t\n\t/**\n\t * Get the current page length.\n\t *\n\t * @return {integer} Current page length. Note `-1` indicates that all records\n\t *   are to be shown.\n\t *//**\n\t * Set the current page length.\n\t *\n\t * @param {integer} Page length to set. Use `-1` to show all records.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page.len()', function ( len ) {\n\t\t// Note that we can't call this function 'length()' because `length`\n\t\t// is a Javascript property of functions which defines how many arguments\n\t\t// the function expects.\n\t\tif ( len === undefined ) {\n\t\t\treturn this.context.length !== 0 ?\n\t\t\t\tthis.context[0]._iDisplayLength :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// else, set the page length\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnLengthChange( settings, len );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\tvar __reload = function ( settings, holdPosition, callback ) {\n\t\t// Use the draw event to trigger a callback\n\t\tif ( callback ) {\n\t\t\tvar api = new _Api( settings );\n\t\n\t\t\tapi.one( 'draw', function () {\n\t\t\t\tcallback( api.ajax.json() );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t_fnReDraw( settings, holdPosition );\n\t\t}\n\t\telse {\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t// Cancel an existing request\n\t\t\tvar xhr = settings.jqXHR;\n\t\t\tif ( xhr && xhr.readyState !== 4 ) {\n\t\t\t\txhr.abort();\n\t\t\t}\n\t\n\t\t\t// Trigger xhr\n\t\t\t_fnBuildAjax( settings, [], function( json ) {\n\t\t\t\t_fnClearTable( settings );\n\t\n\t\t\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\t_fnAddData( settings, data[i] );\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, holdPosition );\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Get the JSON response from the last Ajax request that DataTables made to the\n\t * server. Note that this returns the JSON from the first table in the current\n\t * context.\n\t *\n\t * @return {object} JSON received from the server.\n\t */\n\t_api_register( 'ajax.json()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].json;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Get the data submitted in the last Ajax request\n\t */\n\t_api_register( 'ajax.params()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].oAjaxData;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Reload tables from the Ajax data source. Note that this function will\n\t * automatically re-draw the table when the remote data has been loaded.\n\t *\n\t * @param {boolean} [reset=true] Reset (default) or hold the current paging\n\t *   position. A full re-sort and re-filter is performed when this method is\n\t *   called, which is why the pagination reset is the default action.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.reload()', function ( callback, resetPaging ) {\n\t\treturn this.iterator( 'table', function (settings) {\n\t\t\t__reload( settings, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Get the current Ajax URL. Note that this returns the URL from the first\n\t * table in the current context.\n\t *\n\t * @return {string} Current Ajax source URL\n\t *//**\n\t * Set the Ajax URL. Note that this will set the URL for all tables in the\n\t * current context.\n\t *\n\t * @param {string} url URL to set.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url()', function ( url ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( url === undefined ) {\n\t\t\t// get\n\t\t\tif ( ctx.length === 0 ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tctx = ctx[0];\n\t\n\t\t\treturn ctx.ajax ?\n\t\t\t\t$.isPlainObject( ctx.ajax ) ?\n\t\t\t\t\tctx.ajax.url :\n\t\t\t\t\tctx.ajax :\n\t\t\t\tctx.sAjaxSource;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( $.isPlainObject( settings.ajax ) ) {\n\t\t\t\tsettings.ajax.url = url;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsettings.ajax = url;\n\t\t\t}\n\t\t\t// No need to consider sAjaxSource here since DataTables gives priority\n\t\t\t// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any\n\t\t\t// value of `sAjaxSource` redundant.\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Load data from the newly set Ajax URL. Note that this method is only\n\t * available when `ajax.url()` is used to set a URL. Additionally, this method\n\t * has the same effect as calling `ajax.reload()` but is provided for\n\t * convenience when setting a new URL. Like `ajax.reload()` it will\n\t * automatically redraw the table once the remote data has been loaded.\n\t *\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {\n\t\t// Same as a reload, but makes sense to present it for easy access after a\n\t\t// url change\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\t__reload( ctx, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t\n\tvar _selector_run = function ( type, selector, selectFn, settings, opts )\n\t{\n\t\tvar\n\t\t\tout = [], res,\n\t\t\ta, i, ien, j, jen,\n\t\t\tselectorType = typeof selector;\n\t\n\t\t// Can't just check for isArray here, as an API or jQuery instance might be\n\t\t// given with their array like look\n\t\tif ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {\n\t\t\tselector = [ selector ];\n\t\t}\n\t\n\t\tfor ( i=0, ien=selector.length ; i<ien ; i++ ) {\n\t\t\t// Only split on simple strings - complex expressions will be jQuery selectors\n\t\t\ta = selector[i] && selector[i].split && ! selector[i].match(/[\\[\\(:]/) ?\n\t\t\t\tselector[i].split(',') :\n\t\t\t\t[ selector[i] ];\n\t\n\t\t\tfor ( j=0, jen=a.length ; j<jen ; j++ ) {\n\t\t\t\tres = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );\n\t\n\t\t\t\tif ( res && res.length ) {\n\t\t\t\t\tout = out.concat( res );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// selector extensions\n\t\tvar ext = _ext.selector[ type ];\n\t\tif ( ext.length ) {\n\t\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\t\tout = ext[i]( settings, opts, out );\n\t\t\t}\n\t\t}\n\t\n\t\treturn _unique( out );\n\t};\n\t\n\t\n\tvar _selector_opts = function ( opts )\n\t{\n\t\tif ( ! opts ) {\n\t\t\topts = {};\n\t\t}\n\t\n\t\t// Backwards compatibility for 1.9- which used the terminology filter rather\n\t\t// than search\n\t\tif ( opts.filter && opts.search === undefined ) {\n\t\t\topts.search = opts.filter;\n\t\t}\n\t\n\t\treturn $.extend( {\n\t\t\tsearch: 'none',\n\t\t\torder: 'current',\n\t\t\tpage: 'all'\n\t\t}, opts );\n\t};\n\t\n\t\n\tvar _selector_first = function ( inst )\n\t{\n\t\t// Reduce the API instance to the first item found\n\t\tfor ( var i=0, ien=inst.length ; i<ien ; i++ ) {\n\t\t\tif ( inst[i].length > 0 ) {\n\t\t\t\t// Assign the first element to the first item in the instance\n\t\t\t\t// and truncate the instance and context\n\t\t\t\tinst[0] = inst[i];\n\t\t\t\tinst[0].length = 1;\n\t\t\t\tinst.length = 1;\n\t\t\t\tinst.context = [ inst.context[i] ];\n\t\n\t\t\t\treturn inst;\n\t\t\t}\n\t\t}\n\t\n\t\t// Not found - return an empty instance\n\t\tinst.length = 0;\n\t\treturn inst;\n\t};\n\t\n\t\n\tvar _selector_row_indexes = function ( settings, opts )\n\t{\n\t\tvar\n\t\t\ti, ien, tmp, a=[],\n\t\t\tdisplayFiltered = settings.aiDisplay,\n\t\t\tdisplayMaster = settings.aiDisplayMaster;\n\t\n\t\tvar\n\t\t\tsearch = opts.search,  // none, applied, removed\n\t\t\torder  = opts.order,   // applied, current, index (original - compatibility with 1.9)\n\t\t\tpage   = opts.page;    // all, current\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t// In server-side processing mode, most options are irrelevant since\n\t\t\t// rows not shown don't exist and the index order is the applied order\n\t\t\t// Removed is a special case - for consistency just return an empty\n\t\t\t// array\n\t\t\treturn search === 'removed' ?\n\t\t\t\t[] :\n\t\t\t\t_range( 0, displayMaster.length );\n\t\t}\n\t\telse if ( page == 'current' ) {\n\t\t\t// Current page implies that order=current and fitler=applied, since it is\n\t\t\t// fairly senseless otherwise, regardless of what order and search actually\n\t\t\t// are\n\t\t\tfor ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {\n\t\t\t\ta.push( displayFiltered[i] );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'current' || order == 'applied' ) {\n\t\t\ta = search == 'none' ?\n\t\t\t\tdisplayMaster.slice() :                      // no search\n\t\t\t\tsearch == 'applied' ?\n\t\t\t\t\tdisplayFiltered.slice() :                // applied search\n\t\t\t\t\t$.map( displayMaster, function (el, i) { // removed search\n\t\t\t\t\t\treturn $.inArray( el, displayFiltered ) === -1 ? el : null;\n\t\t\t\t\t} );\n\t\t}\n\t\telse if ( order == 'index' || order == 'original' ) {\n\t\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tif ( search == 'none' ) {\n\t\t\t\t\ta.push( i );\n\t\t\t\t}\n\t\t\t\telse { // applied | removed\n\t\t\t\t\ttmp = $.inArray( i, displayFiltered );\n\t\n\t\t\t\t\tif ((tmp === -1 && search == 'removed') ||\n\t\t\t\t\t\t(tmp >= 0   && search == 'applied') )\n\t\t\t\t\t{\n\t\t\t\t\t\ta.push( i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn a;\n\t};\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Rows\n\t *\n\t * {}          - no selector - use all available rows\n\t * {integer}   - row aoData index\n\t * {node}      - TR node\n\t * {string}    - jQuery selector to apply to the TR elements\n\t * {array}     - jQuery array of nodes, or simply an array of TR nodes\n\t *\n\t */\n\t\n\t\n\tvar __row_selector = function ( settings, selector, opts )\n\t{\n\t\tvar rows;\n\t\tvar run = function ( sel ) {\n\t\t\tvar selInt = _intVal( sel );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Short cut - selector is a number and no options provided (default is\n\t\t\t// all records, so no need to check if the index is in there, since it\n\t\t\t// must be - dev error if the index doesn't exist).\n\t\t\tif ( selInt !== null && ! opts ) {\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\n\t\t\tif ( ! rows ) {\n\t\t\t\trows = _selector_row_indexes( settings, opts );\n\t\t\t}\n\t\n\t\t\tif ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {\n\t\t\t\t// Selector - integer\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\t\telse if ( sel === null || sel === undefined || sel === '' ) {\n\t\t\t\t// Selector - none\n\t\t\t\treturn rows;\n\t\t\t}\n\t\n\t\t\t// Selector - function\n\t\t\tif ( typeof sel === 'function' ) {\n\t\t\t\treturn $.map( rows, function (idx) {\n\t\t\t\t\tvar row = settings.aoData[ idx ];\n\t\t\t\t\treturn sel( idx, row._aData, row.nTr ) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Get nodes in the order from the `rows` array with null values removed\n\t\t\tvar nodes = _removeEmpty(\n\t\t\t\t_pluck_order( settings.aoData, rows, 'nTr' )\n\t\t\t);\n\t\n\t\t\t// Selector - node\n\t\t\tif ( sel.nodeName ) {\n\t\t\t\tif ( sel._DT_RowIndex !== undefined ) {\n\t\t\t\t\treturn [ sel._DT_RowIndex ]; // Property added by DT for fast lookup\n\t\t\t\t}\n\t\t\t\telse if ( sel._DT_CellIndex ) {\n\t\t\t\t\treturn [ sel._DT_CellIndex.row ];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tvar host = $(sel).closest('*[data-dt-row]');\n\t\t\t\t\treturn host.length ?\n\t\t\t\t\t\t[ host.data('dt-row') ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// ID selector. Want to always be able to select rows by id, regardless\n\t\t\t// of if the tr element has been created or not, so can't rely upon\n\t\t\t// jQuery here - hence a custom implementation. This does not match\n\t\t\t// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,\n\t\t\t// but to select it using a CSS selector engine (like Sizzle or\n\t\t\t// querySelect) it would need to need to be escaped for some characters.\n\t\t\t// DataTables simplifies this for row selectors since you can select\n\t\t\t// only a row. A # indicates an id any anything that follows is the id -\n\t\t\t// unescaped.\n\t\t\tif ( typeof sel === 'string' && sel.charAt(0) === '#' ) {\n\t\t\t\t// get row index from id\n\t\t\t\tvar rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];\n\t\t\t\tif ( rowObj !== undefined ) {\n\t\t\t\t\treturn [ rowObj.idx ];\n\t\t\t\t}\n\t\n\t\t\t\t// need to fall through to jQuery in case there is DOM id that\n\t\t\t\t// matches\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery selector string, array of nodes or jQuery object/\n\t\t\t// As jQuery's .filter() allows jQuery objects to be passed in filter,\n\t\t\t// it also allows arrays, so this will cope with all three options\n\t\t\treturn $(nodes)\n\t\t\t\t.filter( sel )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn this._DT_RowIndex;\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\t};\n\t\n\t\treturn _selector_run( 'row', selector, run, settings, opts );\n\t};\n\t\n\t\n\t_api_register( 'rows()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __row_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in __row_selector?\n\t\tinst.selector.rows = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_register( 'rows().nodes()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn settings.aoData[ row ].nTr || undefined;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'rows().data()', function () {\n\t\treturn this.iterator( true, 'rows', function ( settings, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, '_aData' );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\tvar r = settings.aoData[ row ];\n\t\t\treturn type === 'search' ? r._aFilterData : r._aSortData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\t_fnInvalidate( settings, row, src );\n\t\t} );\n\t} );\n\t\n\t_api_registerPlural( 'rows().indexes()', 'row().index()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn row;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {\n\t\tvar a = [];\n\t\tvar context = this.context;\n\t\n\t\t// `iterator` will drop undefined values, but in this case we want them\n\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\tfor ( var j=0, jen=this[i].length ; j<jen ; j++ ) {\n\t\t\t\tvar id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );\n\t\t\t\ta.push( (hash === true ? '#' : '' )+ id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn new _Api( context, a );\n\t} );\n\t\n\t_api_registerPlural( 'rows().remove()', 'row().remove()', function () {\n\t\tvar that = this;\n\t\n\t\tthis.iterator( 'row', function ( settings, row, thatIdx ) {\n\t\t\tvar data = settings.aoData;\n\t\t\tvar rowData = data[ row ];\n\t\t\tvar i, ien, j, jen;\n\t\t\tvar loopRow, loopCells;\n\t\n\t\t\tdata.splice( row, 1 );\n\t\n\t\t\t// Update the cached indexes\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\tloopRow = data[i];\n\t\t\t\tloopCells = loopRow.anCells;\n\t\n\t\t\t\t// Rows\n\t\t\t\tif ( loopRow.nTr !== null ) {\n\t\t\t\t\tloopRow.nTr._DT_RowIndex = i;\n\t\t\t\t}\n\t\n\t\t\t\t// Cells\n\t\t\t\tif ( loopCells !== null ) {\n\t\t\t\t\tfor ( j=0, jen=loopCells.length ; j<jen ; j++ ) {\n\t\t\t\t\t\tloopCells[j]._DT_CellIndex.row = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Delete from the display arrays\n\t\t\t_fnDeleteIndex( settings.aiDisplayMaster, row );\n\t\t\t_fnDeleteIndex( settings.aiDisplay, row );\n\t\t\t_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes\n\t\n\t\t\t// Check for an 'overflow' they case for displaying the table\n\t\t\t_fnLengthOverflow( settings );\n\t\n\t\t\t// Remove the row's ID reference if there is one\n\t\t\tvar id = settings.rowIdFn( rowData._aData );\n\t\t\tif ( id !== undefined ) {\n\t\t\t\tdelete settings.aIds[ id ];\n\t\t\t}\n\t\t} );\n\t\n\t\tthis.iterator( 'table', function ( settings ) {\n\t\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tsettings.aoData[i].idx = i;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'rows.add()', function ( rows ) {\n\t\tvar newRows = this.iterator( 'table', function ( settings ) {\n\t\t\t\tvar row, i, ien;\n\t\t\t\tvar out = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\t\t\tout.push( _fnAddTr( settings, row )[0] );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tout.push( _fnAddData( settings, row ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn out;\n\t\t\t}, 1 );\n\t\n\t\t// Return an Api.rows() extended instance, so rows().nodes() etc can be used\n\t\tvar modRows = this.rows( -1 );\n\t\tmodRows.pop();\n\t\t$.merge( modRows, newRows );\n\t\n\t\treturn modRows;\n\t} );\n\t\n\t\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( 'row()', function ( selector, opts ) {\n\t\treturn _selector_first( this.rows( selector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'row().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._aData :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\tctx[0].aoData[ this[0] ]._aData = data;\n\t\n\t\t// Automatically invalidate\n\t\t_fnInvalidate( ctx[0], this[0], 'data' );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'row().node()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\treturn ctx.length && this.length ?\n\t\t\tctx[0].aoData[ this[0] ].nTr || null :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'row.add()', function ( row ) {\n\t\t// Allow a jQuery object to be passed in - only a single row is added from\n\t\t// it though - the first element in the set\n\t\tif ( row instanceof $ && row.length ) {\n\t\t\trow = row[0];\n\t\t}\n\t\n\t\tvar rows = this.iterator( 'table', function ( settings ) {\n\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\treturn _fnAddTr( settings, row )[0];\n\t\t\t}\n\t\t\treturn _fnAddData( settings, row );\n\t\t} );\n\t\n\t\t// Return an Api.rows() extended instance, with the newly added row selected\n\t\treturn this.row( rows[0] );\n\t} );\n\t\n\t\n\t\n\tvar __details_add = function ( ctx, row, data, klass )\n\t{\n\t\t// Convert to array of TR elements\n\t\tvar rows = [];\n\t\tvar addRow = function ( r, k ) {\n\t\t\t// Recursion to allow for arrays of jQuery objects\n\t\t\tif ( $.isArray( r ) || r instanceof $ ) {\n\t\t\t\tfor ( var i=0, ien=r.length ; i<ien ; i++ ) {\n\t\t\t\t\taddRow( r[i], k );\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If we get a TR element, then just add it directly - up to the dev\n\t\t\t// to add the correct number of columns etc\n\t\t\tif ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {\n\t\t\t\trows.push( r );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Otherwise create a row with a wrapper\n\t\t\t\tvar created = $('<tr><td/></tr>').addClass( k );\n\t\t\t\t$('td', created)\n\t\t\t\t\t.addClass( k )\n\t\t\t\t\t.html( r )\n\t\t\t\t\t[0].colSpan = _fnVisbleColumns( ctx );\n\t\n\t\t\t\trows.push( created[0] );\n\t\t\t}\n\t\t};\n\t\n\t\taddRow( data, klass );\n\t\n\t\tif ( row._details ) {\n\t\t\trow._details.detach();\n\t\t}\n\t\n\t\trow._details = $(rows);\n\t\n\t\t// If the children were already shown, that state should be retained\n\t\tif ( row._detailsShow ) {\n\t\t\trow._details.insertAfter( row.nTr );\n\t\t}\n\t};\n\t\n\t\n\tvar __details_remove = function ( api, idx )\n\t{\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length ) {\n\t\t\tvar row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];\n\t\n\t\t\tif ( row && row._details ) {\n\t\t\t\trow._details.remove();\n\t\n\t\t\t\trow._detailsShow = undefined;\n\t\t\t\trow._details = undefined;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_display = function ( api, show ) {\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length && api.length ) {\n\t\t\tvar row = ctx[0].aoData[ api[0] ];\n\t\n\t\t\tif ( row._details ) {\n\t\t\t\trow._detailsShow = show;\n\t\n\t\t\t\tif ( show ) {\n\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\trow._details.detach();\n\t\t\t\t}\n\t\n\t\t\t\t__details_events( ctx[0] );\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_events = function ( settings )\n\t{\n\t\tvar api = new _Api( settings );\n\t\tvar namespace = '.dt.DT_details';\n\t\tvar drawEvent = 'draw'+namespace;\n\t\tvar colvisEvent = 'column-visibility'+namespace;\n\t\tvar destroyEvent = 'destroy'+namespace;\n\t\tvar data = settings.aoData;\n\t\n\t\tapi.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );\n\t\n\t\tif ( _pluck( data, '_details' ).length > 0 ) {\n\t\t\t// On each draw, insert the required elements into the document\n\t\t\tapi.on( drawEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tapi.rows( {page:'current'} ).eq(0).each( function (idx) {\n\t\t\t\t\t// Internal data grab\n\t\t\t\t\tvar row = data[ idx ];\n\t\n\t\t\t\t\tif ( row._detailsShow ) {\n\t\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\n\t\t\t// Column visibility change - update the colspan\n\t\t\tapi.on( colvisEvent, function ( e, ctx, idx, vis ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t// Update the colspan for the details rows (note, only if it already has\n\t\t\t\t// a colspan)\n\t\t\t\tvar row, visible = _fnVisbleColumns( ctx );\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = data[i];\n\t\n\t\t\t\t\tif ( row._details ) {\n\t\t\t\t\t\trow._details.children('td[colspan]').attr('colspan', visible );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\t// Table destroyed - nuke any child rows\n\t\t\tapi.on( destroyEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( data[i]._details ) {\n\t\t\t\t\t\t__details_remove( api, i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t// Strings for the method names to help minification\n\tvar _emp = '';\n\tvar _child_obj = _emp+'row().child';\n\tvar _child_mth = _child_obj+'()';\n\t\n\t// data can be:\n\t//  tr\n\t//  string\n\t//  jQuery or array of any of the above\n\t_api_register( _child_mth, function ( data, klass ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._details :\n\t\t\t\tundefined;\n\t\t}\n\t\telse if ( data === true ) {\n\t\t\t// show\n\t\t\tthis.child.show();\n\t\t}\n\t\telse if ( data === false ) {\n\t\t\t// remove\n\t\t\t__details_remove( this );\n\t\t}\n\t\telse if ( ctx.length && this.length ) {\n\t\t\t// set\n\t\t\t__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );\n\t\t}\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.show()',\n\t\t_child_mth+'.show()' // only when `child()` was called with parameters (without\n\t], function ( show ) {   // it returns an object and this method is not executed)\n\t\t__details_display( this, true );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.hide()',\n\t\t_child_mth+'.hide()' // only when `child()` was called with parameters (without\n\t], function () {         // it returns an object and this method is not executed)\n\t\t__details_display( this, false );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.remove()',\n\t\t_child_mth+'.remove()' // only when `child()` was called with parameters (without\n\t], function () {           // it returns an object and this method is not executed)\n\t\t__details_remove( this );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( _child_obj+'.isShown()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length && this.length ) {\n\t\t\t// _detailsShown as false or undefined will fall through to return false\n\t\t\treturn ctx[0].aoData[ this[0] ]._detailsShow || false;\n\t\t}\n\t\treturn false;\n\t} );\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Columns\n\t *\n\t * {integer}           - column index (>=0 count from left, <0 count from right)\n\t * \"{integer}:visIdx\"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)\n\t * \"{integer}:visible\" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)\n\t * \"{string}:name\"     - column name\n\t * \"{string}\"          - jQuery selector on column header nodes\n\t *\n\t */\n\t\n\t// can be an array of these items, comma separated list, or an array of comma\n\t// separated lists\n\t\n\tvar __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;\n\t\n\t\n\t// r1 and r2 are redundant - but it means that the parameters match for the\n\t// iterator callback in columns().data()\n\tvar __columnData = function ( settings, column, r1, r2, rows ) {\n\t\tvar a = [];\n\t\tfor ( var row=0, ien=rows.length ; row<ien ; row++ ) {\n\t\t\ta.push( _fnGetCellData( settings, rows[row], column ) );\n\t\t}\n\t\treturn a;\n\t};\n\t\n\t\n\tvar __column_selector = function ( settings, selector, opts )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tnames = _pluck( columns, 'sName' ),\n\t\t\tnodes = _pluck( columns, 'nTh' );\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar selInt = _intVal( s );\n\t\n\t\t\t// Selector - all\n\t\t\tif ( s === '' ) {\n\t\t\t\treturn _range( columns.length );\n\t\t\t}\n\t\n\t\t\t// Selector - index\n\t\t\tif ( selInt !== null ) {\n\t\t\t\treturn [ selInt >= 0 ?\n\t\t\t\t\tselInt : // Count from left\n\t\t\t\t\tcolumns.length + selInt // Count from right (+ because its a negative value)\n\t\t\t\t];\n\t\t\t}\n\t\n\t\t\t// Selector = function\n\t\t\tif ( typeof s === 'function' ) {\n\t\t\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\n\t\t\t\treturn $.map( columns, function (col, idx) {\n\t\t\t\t\treturn s(\n\t\t\t\t\t\t\tidx,\n\t\t\t\t\t\t\t__columnData( settings, idx, 0, 0, rows ),\n\t\t\t\t\t\t\tnodes[ idx ]\n\t\t\t\t\t\t) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// jQuery or string selector\n\t\t\tvar match = typeof s === 'string' ?\n\t\t\t\ts.match( __re_column_selector ) :\n\t\t\t\t'';\n\t\n\t\t\tif ( match ) {\n\t\t\t\tswitch( match[2] ) {\n\t\t\t\t\tcase 'visIdx':\n\t\t\t\t\tcase 'visible':\n\t\t\t\t\t\tvar idx = parseInt( match[1], 10 );\n\t\t\t\t\t\t// Visible index given, convert to column index\n\t\t\t\t\t\tif ( idx < 0 ) {\n\t\t\t\t\t\t\t// Counting from the right\n\t\t\t\t\t\t\tvar visColumns = $.map( columns, function (col,i) {\n\t\t\t\t\t\t\t\treturn col.bVisible ? i : null;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\treturn [ visColumns[ visColumns.length + idx ] ];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Counting from the left\n\t\t\t\t\t\treturn [ _fnVisibleToColumnIndex( settings, idx ) ];\n\t\n\t\t\t\t\tcase 'name':\n\t\t\t\t\t\t// match by name. `names` is column index complete and in order\n\t\t\t\t\t\treturn $.map( names, function (name, i) {\n\t\t\t\t\t\t\treturn name === match[1] ? i : null;\n\t\t\t\t\t\t} );\n\t\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Cell in the table body\n\t\t\tif ( s.nodeName && s._DT_CellIndex ) {\n\t\t\t\treturn [ s._DT_CellIndex.column ];\n\t\t\t}\n\t\n\t\t\t// jQuery selector on the TH elements for the columns\n\t\t\tvar jqResult = $( nodes )\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn $.inArray( this, nodes ); // `nodes` is column index complete and in order\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise a node which might have a `dt-column` data attribute, or be\n\t\t\t// a child or such an element\n\t\t\tvar host = $(s).closest('*[data-dt-column]');\n\t\t\treturn host.length ?\n\t\t\t\t[ host.data('dt-column') ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'column', selector, run, settings, opts );\n\t};\n\t\n\t\n\tvar __setColumnVis = function ( settings, column, vis ) {\n\t\tvar\n\t\t\tcols = settings.aoColumns,\n\t\t\tcol  = cols[ column ],\n\t\t\tdata = settings.aoData,\n\t\t\trow, cells, i, ien, tr;\n\t\n\t\t// Get\n\t\tif ( vis === undefined ) {\n\t\t\treturn col.bVisible;\n\t\t}\n\t\n\t\t// Set\n\t\t// No change\n\t\tif ( col.bVisible === vis ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( vis ) {\n\t\t\t// Insert column\n\t\t\t// Need to decide if we should use appendChild or insertBefore\n\t\t\tvar insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );\n\t\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\ttr = data[i].nTr;\n\t\t\t\tcells = data[i].anCells;\n\t\n\t\t\t\tif ( tr ) {\n\t\t\t\t\t// insertBefore can act like appendChild if 2nd arg is null\n\t\t\t\t\ttr.insertBefore( cells[ column ], cells[ insertBefore ] || null );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Remove column\n\t\t\t$( _pluck( settings.aoData, 'anCells', column ) ).detach();\n\t\t}\n\t\n\t\t// Common actions\n\t\tcol.bVisible = vis;\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t_fnSaveState( settings );\n\t};\n\t\n\t\n\t_api_register( 'columns()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __column_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in _row_selector?\n\t\tinst.selector.cols = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTh;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTf;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().data()', 'column().data()', function () {\n\t\treturn this.iterator( 'column-rows', __columnData, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].mData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows,\n\t\t\t\ttype === 'search' ? '_aFilterData' : '_aSortData', column\n\t\t\t);\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, 'anCells', column ) ;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {\n\t\tvar ret = this.iterator( 'column', function ( settings, column ) {\n\t\t\tif ( vis === undefined ) {\n\t\t\t\treturn settings.aoColumns[ column ].bVisible;\n\t\t\t} // else\n\t\t\t__setColumnVis( settings, column, vis );\n\t\t} );\n\t\n\t\t// Group the column visibility changes\n\t\tif ( vis !== undefined ) {\n\t\t\t// Second loop once the first is done for events\n\t\t\tthis.iterator( 'column', function ( settings, column ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );\n\t\t\t} );\n\t\n\t\t\tif ( calc === undefined || calc ) {\n\t\t\t\tthis.columns.adjust();\n\t\t\t}\n\t\t}\n\t\n\t\treturn ret;\n\t} );\n\t\n\t_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn type === 'visible' ?\n\t\t\t\t_fnColumnIndexToVisible( settings, column ) :\n\t\t\t\tcolumn;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'columns.adjust()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'column.index()', function ( type, idx ) {\n\t\tif ( this.context.length !== 0 ) {\n\t\t\tvar ctx = this.context[0];\n\t\n\t\t\tif ( type === 'fromVisible' || type === 'toData' ) {\n\t\t\t\treturn _fnVisibleToColumnIndex( ctx, idx );\n\t\t\t}\n\t\t\telse if ( type === 'fromData' || type === 'toVisible' ) {\n\t\t\t\treturn _fnColumnIndexToVisible( ctx, idx );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t_api_register( 'column()', function ( selector, opts ) {\n\t\treturn _selector_first( this.columns( selector, opts ) );\n\t} );\n\t\n\t\n\t\n\tvar __cell_selector = function ( settings, selector, opts )\n\t{\n\t\tvar data = settings.aoData;\n\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\tvar cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );\n\t\tvar allCells = $( [].concat.apply([], cells) );\n\t\tvar row;\n\t\tvar columns = settings.aoColumns.length;\n\t\tvar a, i, ien, j, o, host;\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar fnSelector = typeof s === 'function';\n\t\n\t\t\tif ( s === null || s === undefined || fnSelector ) {\n\t\t\t\t// All cells and function selectors\n\t\t\t\ta = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tfor ( j=0 ; j<columns ; j++ ) {\n\t\t\t\t\t\to = {\n\t\t\t\t\t\t\trow: row,\n\t\t\t\t\t\t\tcolumn: j\n\t\t\t\t\t\t};\n\t\n\t\t\t\t\t\tif ( fnSelector ) {\n\t\t\t\t\t\t\t// Selector - function\n\t\t\t\t\t\t\thost = data[ row ];\n\t\n\t\t\t\t\t\t\tif ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {\n\t\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Selector - all\n\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn a;\n\t\t\t}\n\t\t\t\n\t\t\t// Selector - index\n\t\t\tif ( $.isPlainObject( s ) ) {\n\t\t\t\treturn [s];\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery filtered cells\n\t\t\tvar jqResult = allCells\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function (i, el) {\n\t\t\t\t\treturn { // use a new object, in case someone changes the values\n\t\t\t\t\t\trow:    el._DT_CellIndex.row,\n\t\t\t\t\t\tcolumn: el._DT_CellIndex.column\n\t \t\t\t\t};\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise the selector is a node, and there is one last option - the\n\t\t\t// element might be a child of an element which has dt-row and dt-column\n\t\t\t// data attributes\n\t\t\thost = $(s).closest('*[data-dt-row]');\n\t\t\treturn host.length ?\n\t\t\t\t[ {\n\t\t\t\t\trow: host.data('dt-row'),\n\t\t\t\t\tcolumn: host.data('dt-column')\n\t\t\t\t} ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'cell', selector, run, settings, opts );\n\t};\n\t\n\t\n\t\n\t\n\t_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {\n\t\t// Argument shifting\n\t\tif ( $.isPlainObject( rowSelector ) ) {\n\t\t\t// Indexes\n\t\t\tif ( rowSelector.row === undefined ) {\n\t\t\t\t// Selector options in first parameter\n\t\t\t\topts = rowSelector;\n\t\t\t\trowSelector = null;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Cell index objects in first parameter\n\t\t\t\topts = columnSelector;\n\t\t\t\tcolumnSelector = null;\n\t\t\t}\n\t\t}\n\t\tif ( $.isPlainObject( columnSelector ) ) {\n\t\t\topts = columnSelector;\n\t\t\tcolumnSelector = null;\n\t\t}\n\t\n\t\t// Cell selector\n\t\tif ( columnSelector === null || columnSelector === undefined ) {\n\t\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t\treturn __cell_selector( settings, rowSelector, _selector_opts( opts ) );\n\t\t\t} );\n\t\t}\n\t\n\t\t// Row + column selector\n\t\tvar columns = this.columns( columnSelector, opts );\n\t\tvar rows = this.rows( rowSelector, opts );\n\t\tvar a, i, ien, j, jen;\n\t\n\t\tvar cells = this.iterator( 'table', function ( settings, idx ) {\n\t\t\ta = [];\n\t\n\t\t\tfor ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {\n\t\t\t\tfor ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {\n\t\t\t\t\ta.push( {\n\t\t\t\t\t\trow:    rows[idx][i],\n\t\t\t\t\t\tcolumn: columns[idx][j]\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn a;\n\t\t}, 1 );\n\t\n\t\t$.extend( cells.selector, {\n\t\t\tcols: columnSelector,\n\t\t\trows: rowSelector,\n\t\t\topts: opts\n\t\t} );\n\t\n\t\treturn cells;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\tvar data = settings.aoData[ row ];\n\t\n\t\t\treturn data && data.anCells ?\n\t\t\t\tdata.anCells[ column ] :\n\t\t\t\tundefined;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_register( 'cells().data()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {\n\t\ttype = type === 'search' ? '_aFilterData' : '_aSortData';\n\t\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn settings.aoData[ row ][ type ][ column ];\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column, type );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn {\n\t\t\t\trow: row,\n\t\t\t\tcolumn: column,\n\t\t\t\tcolumnVisible: _fnColumnIndexToVisible( settings, column )\n\t\t\t};\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\t_fnInvalidate( settings, row, src, column );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {\n\t\treturn _selector_first( this.cells( rowSelector, columnSelector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'cell().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\tvar cell = this[0];\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && cell.length ?\n\t\t\t\t_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\t_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );\n\t\t_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get current ordering (sorting) that has been applied to the table.\n\t *\n\t * @returns {array} 2D array containing the sorting information for the first\n\t *   table in the current context. Each element in the parent array represents\n\t *   a column being sorted upon (i.e. multi-sorting with two columns would have\n\t *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is\n\t *   the column index that the sorting condition applies to, the second is the\n\t *   direction of the sort (`desc` or `asc`) and, optionally, the third is the\n\t *   index of the sorting order from the `column.sorting` initialisation array.\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {integer} order Column index to sort upon.\n\t * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 1D array of sorting information to be applied.\n\t * @param {array} [...] Optional additional sorting conditions\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 2D array of sorting information to be applied.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order()', function ( order, dir ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( order === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].aaSorting :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\tif ( typeof order === 'number' ) {\n\t\t\t// Simple column / direction passed in\n\t\t\torder = [ [ order, dir ] ];\n\t\t}\n\t\telse if ( order.length && ! $.isArray( order[0] ) ) {\n\t\t\t// Arguments passed in (list of 1D arrays)\n\t\t\torder = Array.prototype.slice.call( arguments );\n\t\t}\n\t\t// otherwise a 2D array was passed in\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSorting = order.slice();\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Attach a sort listener to an element for a given column\n\t *\n\t * @param {node|jQuery|string} node Identifier for the element(s) to attach the\n\t *   listener to. This can take the form of a single DOM node, a jQuery\n\t *   collection of nodes or a jQuery selector which will identify the node(s).\n\t * @param {integer} column the column that a click on this node will sort on\n\t * @param {function} [callback] callback function when sort is run\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order.listener()', function ( node, column, callback ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSortAttachListener( settings, node, column, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'order.fixed()', function ( set ) {\n\t\tif ( ! set ) {\n\t\t\tvar ctx = this.context;\n\t\t\tvar fixed = ctx.length ?\n\t\t\t\tctx[0].aaSortingFixed :\n\t\t\t\tundefined;\n\t\n\t\t\treturn $.isArray( fixed ) ?\n\t\t\t\t{ pre: fixed } :\n\t\t\t\tfixed;\n\t\t}\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSortingFixed = $.extend( true, {}, set );\n\t\t} );\n\t} );\n\t\n\t\n\t// Order by the selected column(s)\n\t_api_register( [\n\t\t'columns().order()',\n\t\t'column().order()'\n\t], function ( dir ) {\n\t\tvar that = this;\n\t\n\t\treturn this.iterator( 'table', function ( settings, i ) {\n\t\t\tvar sort = [];\n\t\n\t\t\t$.each( that[i], function (j, col) {\n\t\t\t\tsort.push( [ col, dir ] );\n\t\t\t} );\n\t\n\t\t\tsettings.aaSorting = sort;\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'search()', function ( input, regex, smart, caseInsen ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( input === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].oPreviousSearch.sSearch :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {\n\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t} ), 1 );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural(\n\t\t'columns().search()',\n\t\t'column().search()',\n\t\tfunction ( input, regex, smart, caseInsen ) {\n\t\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\t\tvar preSearch = settings.aoPreSearchCols;\n\t\n\t\t\t\tif ( input === undefined ) {\n\t\t\t\t\t// get\n\t\t\t\t\treturn preSearch[ column ].sSearch;\n\t\t\t\t}\n\t\n\t\t\t\t// set\n\t\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t$.extend( preSearch[ column ], {\n\t\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t\t} );\n\t\n\t\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch, 1 );\n\t\t\t} );\n\t\t}\n\t);\n\t\n\t/*\n\t * State API methods\n\t */\n\t\n\t_api_register( 'state()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oSavedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t// Save an empty object\n\t\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, {} );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'state.loaded()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oLoadedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.save()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSaveState( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Provide a common method for plug-ins to check the version of DataTables being\n\t * used, in order to ensure compatibility.\n\t *\n\t *  @param {string} version Version string to check for, in the format \"X.Y.Z\".\n\t *    Note that the formats \"X\" and \"X.Y\" are also acceptable.\n\t *  @returns {boolean} true if this version of DataTables is greater or equal to\n\t *    the required version, or false if this version of DataTales is not\n\t *    suitable\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );\n\t */\n\tDataTable.versionCheck = DataTable.fnVersionCheck = function( version )\n\t{\n\t\tvar aThis = DataTable.version.split('.');\n\t\tvar aThat = version.split('.');\n\t\tvar iThis, iThat;\n\t\n\t\tfor ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {\n\t\t\tiThis = parseInt( aThis[i], 10 ) || 0;\n\t\t\tiThat = parseInt( aThat[i], 10 ) || 0;\n\t\n\t\t\t// Parts are the same, keep comparing\n\t\t\tif (iThis === iThat) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\t// Parts are different, return immediately\n\t\t\treturn iThis > iThat;\n\t\t}\n\t\n\t\treturn true;\n\t};\n\t\n\t\n\t/**\n\t * Check if a `<table>` node is a DataTable table already or not.\n\t *\n\t *  @param {node|jquery|string} table Table node, jQuery object or jQuery\n\t *      selector for the table to test. Note that if more than more than one\n\t *      table is passed on, only the first will be checked\n\t *  @returns {boolean} true the table given is a DataTable, or false otherwise\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {\n\t *      $('#example').dataTable();\n\t *    }\n\t */\n\tDataTable.isDataTable = DataTable.fnIsDataTable = function ( table )\n\t{\n\t\tvar t = $(table).get(0);\n\t\tvar is = false;\n\t\n\t\tif ( table instanceof DataTable.Api ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\t$.each( DataTable.settings, function (i, o) {\n\t\t\tvar head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;\n\t\t\tvar foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;\n\t\n\t\t\tif ( o.nTable === t || head === t || foot === t ) {\n\t\t\t\tis = true;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn is;\n\t};\n\t\n\t\n\t/**\n\t * Get all DataTable tables that have been initialised - optionally you can\n\t * select to get only currently visible tables.\n\t *\n\t *  @param {boolean} [visible=false] Flag to indicate if you want all (default)\n\t *    or visible tables only.\n\t *  @returns {array} Array of `table` nodes (not DataTable instances) which are\n\t *    DataTables\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    $.each( $.fn.dataTable.tables(true), function () {\n\t *      $(table).DataTable().columns.adjust();\n\t *    } );\n\t */\n\tDataTable.tables = DataTable.fnTables = function ( visible )\n\t{\n\t\tvar api = false;\n\t\n\t\tif ( $.isPlainObject( visible ) ) {\n\t\t\tapi = visible.api;\n\t\t\tvisible = visible.visible;\n\t\t}\n\t\n\t\tvar a = $.map( DataTable.settings, function (o) {\n\t\t\tif ( !visible || (visible && $(o.nTable).is(':visible')) ) {\n\t\t\t\treturn o.nTable;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn api ?\n\t\t\tnew _Api( a ) :\n\t\t\ta;\n\t};\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian notation. This is made public\n\t * for the extensions to provide the same ability as DataTables core to accept\n\t * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase\n\t * parameters.\n\t *\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t */\n\tDataTable.camelToHungarian = _fnCamelToHungarian;\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( '$()', function ( selector, opts ) {\n\t\tvar\n\t\t\trows   = this.rows( opts ).nodes(), // Get all rows\n\t\t\tjqRows = $(rows);\n\t\n\t\treturn $( [].concat(\n\t\t\tjqRows.filter( selector ).toArray(),\n\t\t\tjqRows.find( selector ).toArray()\n\t\t) );\n\t} );\n\t\n\t\n\t// jQuery functions to operate on the tables\n\t$.each( [ 'on', 'one', 'off' ], function (i, key) {\n\t\t_api_register( key+'()', function ( /* event, handler */ ) {\n\t\t\tvar args = Array.prototype.slice.call(arguments);\n\t\n\t\t\t// Add the `dt` namespace automatically if it isn't already present\n\t\t\targs[0] = $.map( args[0].split( /\\s/ ), function ( e ) {\n\t\t\t\treturn ! e.match(/\\.dt\\b/) ?\n\t\t\t\t\te+'.dt' :\n\t\t\t\t\te;\n\t\t\t\t} ).join( ' ' );\n\t\n\t\t\tvar inst = $( this.tables().nodes() );\n\t\t\tinst[key].apply( inst, args );\n\t\t\treturn this;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnClearTable( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'settings()', function () {\n\t\treturn new _Api( this.context, this.context );\n\t} );\n\t\n\t\n\t_api_register( 'init()', function () {\n\t\tvar ctx = this.context;\n\t\treturn ctx.length ? ctx[0].oInit : null;\n\t} );\n\t\n\t\n\t_api_register( 'data()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\treturn _pluck( settings.aoData, '_aData' );\n\t\t} ).flatten();\n\t} );\n\t\n\t\n\t_api_register( 'destroy()', function ( remove ) {\n\t\tremove = remove || false;\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tvar orig      = settings.nTableWrapper.parentNode;\n\t\t\tvar classes   = settings.oClasses;\n\t\t\tvar table     = settings.nTable;\n\t\t\tvar tbody     = settings.nTBody;\n\t\t\tvar thead     = settings.nTHead;\n\t\t\tvar tfoot     = settings.nTFoot;\n\t\t\tvar jqTable   = $(table);\n\t\t\tvar jqTbody   = $(tbody);\n\t\t\tvar jqWrapper = $(settings.nTableWrapper);\n\t\t\tvar rows      = $.map( settings.aoData, function (r) { return r.nTr; } );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Flag to note that the table is currently being destroyed - no action\n\t\t\t// should be taken\n\t\t\tsettings.bDestroying = true;\n\t\n\t\t\t// Fire off the destroy callbacks for plug-ins etc\n\t\t\t_fnCallbackFire( settings, \"aoDestroyCallback\", \"destroy\", [settings] );\n\t\n\t\t\t// If not being removed from the document, make all columns visible\n\t\t\tif ( ! remove ) {\n\t\t\t\tnew _Api( settings ).columns().visible( true );\n\t\t\t}\n\t\n\t\t\t// Blitz all `DT` namespaced events (these are internal events, the\n\t\t\t// lowercase, `dt` events are user subscribed and they are responsible\n\t\t\t// for removing them\n\t\t\tjqWrapper.off('.DT').find(':not(tbody *)').off('.DT');\n\t\t\t$(window).off('.DT-'+settings.sInstance);\n\t\n\t\t\t// When scrolling we had to break the table up - restore it\n\t\t\tif ( table != thead.parentNode ) {\n\t\t\t\tjqTable.children('thead').detach();\n\t\t\t\tjqTable.append( thead );\n\t\t\t}\n\t\n\t\t\tif ( tfoot && table != tfoot.parentNode ) {\n\t\t\t\tjqTable.children('tfoot').detach();\n\t\t\t\tjqTable.append( tfoot );\n\t\t\t}\n\t\n\t\t\tsettings.aaSorting = [];\n\t\t\tsettings.aaSortingFixed = [];\n\t\t\t_fnSortingClasses( settings );\n\t\n\t\t\t$( rows ).removeClass( settings.asStripeClasses.join(' ') );\n\t\n\t\t\t$('th, td', thead).removeClass( classes.sSortable+' '+\n\t\t\t\tclasses.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone\n\t\t\t);\n\t\n\t\t\tif ( settings.bJUI ) {\n\t\t\t\t$('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();\n\t\t\t\t$('th, td', thead).each( function () {\n\t\t\t\t\tvar wrapper = $('div.'+classes.sSortJUIWrapper, this);\n\t\t\t\t\t$(this).append( wrapper.contents() );\n\t\t\t\t\twrapper.detach();\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Add the TR elements back into the table in their original order\n\t\t\tjqTbody.children().detach();\n\t\t\tjqTbody.append( rows );\n\t\n\t\t\t// Remove the DataTables generated nodes, events and classes\n\t\t\tvar removedMethod = remove ? 'remove' : 'detach';\n\t\t\tjqTable[ removedMethod ]();\n\t\t\tjqWrapper[ removedMethod ]();\n\t\n\t\t\t// If we need to reattach the table to the document\n\t\t\tif ( ! remove && orig ) {\n\t\t\t\t// insertBefore acts like appendChild if !arg[1]\n\t\t\t\torig.insertBefore( table, settings.nTableReinsertBefore );\n\t\n\t\t\t\t// Restore the width of the original table - was read from the style property,\n\t\t\t\t// so we can restore directly to that\n\t\t\t\tjqTable\n\t\t\t\t\t.css( 'width', settings.sDestroyWidth )\n\t\t\t\t\t.removeClass( classes.sTable );\n\t\n\t\t\t\t// If the were originally stripe classes - then we add them back here.\n\t\t\t\t// Note this is not fool proof (for example if not all rows had stripe\n\t\t\t\t// classes - but it's a good effort without getting carried away\n\t\t\t\tien = settings.asDestroyStripes.length;\n\t\n\t\t\t\tif ( ien ) {\n\t\t\t\t\tjqTbody.children().each( function (i) {\n\t\t\t\t\t\t$(this).addClass( settings.asDestroyStripes[i % ien] );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Remove the settings object from the settings array */\n\t\t\tvar idx = $.inArray( settings, DataTable.settings );\n\t\t\tif ( idx !== -1 ) {\n\t\t\t\tDataTable.settings.splice( idx, 1 );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t// Add the `every()` method for rows, columns and cells in a compact form\n\t$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {\n\t\t_api_register( type+'s().every()', function ( fn ) {\n\t\t\tvar opts = this.selector.opts;\n\t\t\tvar api = this;\n\t\n\t\t\treturn this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {\n\t\t\t\t// Rows and columns:\n\t\t\t\t//  arg1 - index\n\t\t\t\t//  arg2 - table counter\n\t\t\t\t//  arg3 - loop counter\n\t\t\t\t//  arg4 - undefined\n\t\t\t\t// Cells:\n\t\t\t\t//  arg1 - row index\n\t\t\t\t//  arg2 - column index\n\t\t\t\t//  arg3 - table counter\n\t\t\t\t//  arg4 - loop counter\n\t\t\t\tfn.call(\n\t\t\t\t\tapi[ type ](\n\t\t\t\t\t\targ1,\n\t\t\t\t\t\ttype==='cell' ? arg2 : opts,\n\t\t\t\t\t\ttype==='cell' ? opts : undefined\n\t\t\t\t\t),\n\t\t\t\t\targ1, arg2, arg3, arg4\n\t\t\t\t);\n\t\t\t} );\n\t\t} );\n\t} );\n\t\n\t\n\t// i18n method for extensions to be able to use the language object from the\n\t// DataTable\n\t_api_register( 'i18n()', function ( token, def, plural ) {\n\t\tvar ctx = this.context[0];\n\t\tvar resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );\n\t\n\t\tif ( resolved === undefined ) {\n\t\t\tresolved = def;\n\t\t}\n\t\n\t\tif ( plural !== undefined && $.isPlainObject( resolved ) ) {\n\t\t\tresolved = resolved[ plural ] !== undefined ?\n\t\t\t\tresolved[ plural ] :\n\t\t\t\tresolved._;\n\t\t}\n\t\n\t\treturn resolved.replace( '%d', plural ); // nb: plural might be undefined,\n\t} );\n\n\t/**\n\t * Version string for plug-ins to check compatibility. Allowed format is\n\t * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used\n\t * only for non-release builds. See http://semver.org/ for more information.\n\t *  @member\n\t *  @type string\n\t *  @default Version number\n\t */\n\tDataTable.version = \"1.10.13\";\n\n\t/**\n\t * Private data store, containing all of the settings objects that are\n\t * created for the tables on a given page.\n\t *\n\t * Note that the `DataTable.settings` object is aliased to\n\t * `jQuery.fn.dataTableExt` through which it may be accessed and\n\t * manipulated, or `jQuery.fn.dataTable.settings`.\n\t *  @member\n\t *  @type array\n\t *  @default []\n\t *  @private\n\t */\n\tDataTable.settings = [];\n\n\t/**\n\t * Object models container, for the various models that DataTables has\n\t * available to it. These models define the objects that are used to hold\n\t * the active state and configuration of the table.\n\t *  @namespace\n\t */\n\tDataTable.models = {};\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * search information for the global filter and individual column filters.\n\t *  @namespace\n\t */\n\tDataTable.models.oSearch = {\n\t\t/**\n\t\t * Flag to indicate if the filtering should be case insensitive or not\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bCaseInsensitive\": true,\n\t\n\t\t/**\n\t\t * Applied search term\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sSearch\": \"\",\n\t\n\t\t/**\n\t\t * Flag to indicate if the search term should be interpreted as a\n\t\t * regular expression (true) or not (false) and therefore and special\n\t\t * regex characters escaped.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bRegex\": false,\n\t\n\t\t/**\n\t\t * Flag to indicate if DataTables is to use its smart filtering or not.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bSmart\": true\n\t};\n\t\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * each individual row. This is the object format used for the settings\n\t * aoData array.\n\t *  @namespace\n\t */\n\tDataTable.models.oRow = {\n\t\t/**\n\t\t * TR element for the row\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTr\": null,\n\t\n\t\t/**\n\t\t * Array of TD elements for each row. This is null until the row has been\n\t\t * created.\n\t\t *  @type array nodes\n\t\t *  @default []\n\t\t */\n\t\t\"anCells\": null,\n\t\n\t\t/**\n\t\t * Data object from the original data source for the row. This is either\n\t\t * an array if using the traditional form of DataTables, or an object if\n\t\t * using mData options. The exact type will depend on the passed in\n\t\t * data from the data source, or will be an array if using DOM a data\n\t\t * source.\n\t\t *  @type array|object\n\t\t *  @default []\n\t\t */\n\t\t\"_aData\": [],\n\t\n\t\t/**\n\t\t * Sorting data cache - this array is ostensibly the same length as the\n\t\t * number of columns (although each index is generated only as it is\n\t\t * needed), and holds the data that is used for sorting each column in the\n\t\t * row. We do this cache generation at the start of the sort in order that\n\t\t * the formatting of the sort data need be done only once for each cell\n\t\t * per sort. This array should not be read from or written to by anything\n\t\t * other than the master sorting methods.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aSortData\": null,\n\t\n\t\t/**\n\t\t * Per cell filtering data cache. As per the sort data cache, used to\n\t\t * increase the performance of the filtering in DataTables\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aFilterData\": null,\n\t\n\t\t/**\n\t\t * Filtering data cache. This is the same as the cell filtering cache, but\n\t\t * in this case a string rather than an array. This is easily computed with\n\t\t * a join on `_aFilterData`, but is provided as a cache so the join isn't\n\t\t * needed on every search (memory traded for performance)\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sFilterRow\": null,\n\t\n\t\t/**\n\t\t * Cache of the class name that DataTables has applied to the row, so we\n\t\t * can quickly look at this variable rather than needing to do a DOM check\n\t\t * on className for the nTr property.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *  @private\n\t\t */\n\t\t\"_sRowStripe\": \"\",\n\t\n\t\t/**\n\t\t * Denote if the original data source was from the DOM, or the data source\n\t\t * object. This is used for invalidating data, so DataTables can\n\t\t * automatically read data from the original source, unless uninstructed\n\t\t * otherwise.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"src\": null,\n\t\n\t\t/**\n\t\t * Index in the aoData array. This saves an indexOf lookup when we have the\n\t\t * object, but want to know the index\n\t\t *  @type integer\n\t\t *  @default -1\n\t\t *  @private\n\t\t */\n\t\t\"idx\": -1\n\t};\n\t\n\t\n\t/**\n\t * Template object for the column information object in DataTables. This object\n\t * is held in the settings aoColumns array and contains all the information that\n\t * DataTables needs about each individual column.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults.column}\n\t * but this one is the internal data store for DataTables's cache of columns.\n\t * It should NOT be manipulated outside of DataTables. Any configuration should\n\t * be done through the initialisation options.\n\t *  @namespace\n\t */\n\tDataTable.models.oColumn = {\n\t\t/**\n\t\t * Column index. This could be worked out on-the-fly with $.inArray, but it\n\t\t * is faster to just hold it as a variable\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"idx\": null,\n\t\n\t\t/**\n\t\t * A list of the columns that sorting should occur on when this column\n\t\t * is sorted. That this property is an array allows multi-column sorting\n\t\t * to be defined for a column (for example first name / last name columns\n\t\t * would benefit from this). The values are integers pointing to the\n\t\t * columns to be sorted on (typically it will be a single integer pointing\n\t\t * at itself, but that doesn't need to be the case).\n\t\t *  @type array\n\t\t */\n\t\t\"aDataSort\": null,\n\t\n\t\t/**\n\t\t * Define the sorting directions that are applied to the column, in sequence\n\t\t * as the column is repeatedly sorted upon - i.e. the first value is used\n\t\t * as the sorting direction when the column if first sorted (clicked on).\n\t\t * Sort it again (click again) and it will move on to the next index.\n\t\t * Repeat until loop.\n\t\t *  @type array\n\t\t */\n\t\t\"asSorting\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is searchable, and thus should be included\n\t\t * in the filtering or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSearchable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is sortable or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is currently visible in the table or not\n\t\t *  @type boolean\n\t\t */\n\t\t\"bVisible\": null,\n\t\n\t\t/**\n\t\t * Store for manual type assignment using the `column.type` option. This\n\t\t * is held in store so we can manipulate the column's `sType` property.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sManualType\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if HTML5 data attributes should be used as the data\n\t\t * source for filtering or sorting. True is either are.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @private\n\t\t */\n\t\t\"_bAttrSrc\": false,\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} nTd The TD node that has been created\n\t\t *  @param {*} sData The Data for the cell\n\t\t *  @param {array|object} oData The data for the whole row\n\t\t *  @param {int} iRow The row index for the aoData data store\n\t\t *  @default null\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\t/**\n\t\t * Function to get data from a cell in a column. You should <b>never</b>\n\t\t * access data directly through _aData internally in DataTables - always use\n\t\t * the method attached to this property. It allows mData to function as\n\t\t * required. This function is automatically assigned by the column\n\t\t * initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {string} sSpecific The specific data type you want to get -\n\t\t *    'display', 'type' 'filter' 'sort'\n\t\t *  @returns {*} The data for the cell from the given row's data\n\t\t *  @default null\n\t\t */\n\t\t\"fnGetData\": null,\n\t\n\t\t/**\n\t\t * Function to set data for a cell in the column. You should <b>never</b>\n\t\t * set the data directly to _aData internally in DataTables - always use\n\t\t * this method. It allows mData to function as required. This function\n\t\t * is automatically assigned by the column initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {*} sValue Value to set\n\t\t *  @default null\n\t\t */\n\t\t\"fnSetData\": null,\n\t\n\t\t/**\n\t\t * Property to read the value for the cells in the column from the data\n\t\t * source array / object. If null, then the default content is used, if a\n\t\t * function is given then the return from the function is used.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\t/**\n\t\t * Partner property to mData which is used (only when defined) to get\n\t\t * the data - i.e. it is basically the same as mData, but without the\n\t\t * 'set' option, and also the data fed to it is the result from mData.\n\t\t * This is the rendering method to match the data method of mData.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\t/**\n\t\t * Unique header TH/TD element for this column - this is what the sorting\n\t\t * listener is attached to (if sorting is enabled.)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTh\": null,\n\t\n\t\t/**\n\t\t * Unique footer TH/TD element for this column (if there is one). Not used\n\t\t * in DataTables as such, but can be used for plug-ins to reference the\n\t\t * footer for each column.\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTf\": null,\n\t\n\t\t/**\n\t\t * The class to apply to all TD elements in the table's TBODY for the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sClass\": null,\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t *  @type string\n\t\t */\n\t\t\"sContentPadding\": null,\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because mData\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\t/**\n\t\t * Name for the column, allowing reference to the column by name as well as\n\t\t * by index (needs a lookup to work by name).\n\t\t *  @type string\n\t\t */\n\t\t\"sName\": null,\n\t\n\t\t/**\n\t\t * Custom sorting data type - defines which of the available plug-ins in\n\t\t * afnSortData the custom sorting will use - if any is defined.\n\t\t *  @type string\n\t\t *  @default std\n\t\t */\n\t\t\"sSortDataType\": 'std',\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClass\": null,\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column -\n\t\t * when jQuery UI theming is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClassJUI\": null,\n\t\n\t\t/**\n\t\t * Title of the column - what is seen in the TH element (nTh).\n\t\t *  @type string\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\t/**\n\t\t * Column sorting and filtering type\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\t/**\n\t\t * Width of the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidth\": null,\n\t\n\t\t/**\n\t\t * Width of the column when it was first \"encountered\"\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidthOrig\": null\n\t};\n\t\n\t\n\t/*\n\t * Developer note: The properties of the object below are given in Hungarian\n\t * notation, that was used as the interface for DataTables prior to v1.10, however\n\t * from v1.10 onwards the primary interface is camel case. In order to avoid\n\t * breaking backwards compatibility utterly with this change, the Hungarian\n\t * version is still, internally the primary interface, but is is not documented\n\t * - hence the @name tags in each doc comment. This allows a Javascript function\n\t * to create a map from Hungarian notation to camel case (going the other direction\n\t * would require each property to be listed, which would at around 3K to the size\n\t * of DataTables, while this method is about a 0.5K hit.\n\t *\n\t * Ultimately this does pave the way for Hungarian notation to be dropped\n\t * completely, but that is a massive amount of work and will break current\n\t * installs (therefore is on-hold until v2).\n\t */\n\t\n\t/**\n\t * Initialisation options that can be given to DataTables at initialisation\n\t * time.\n\t *  @namespace\n\t */\n\tDataTable.defaults = {\n\t\t/**\n\t\t * An array of data to use for the table, passed in at initialisation which\n\t\t * will be used in preference to any data which is already in the DOM. This is\n\t\t * particularly useful for constructing tables purely in Javascript, for\n\t\t * example with a custom Ajax call.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.data\n\t\t *\n\t\t *  @example\n\t\t *    // Using a 2D array data source\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],\n\t\t *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\" },\n\t\t *          { \"title\": \"Browser\" },\n\t\t *          { \"title\": \"Platform\" },\n\t\t *          { \"title\": \"Version\" },\n\t\t *          { \"title\": \"Grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using an array of objects as a data source (`data`)\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 4.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  4,\n\t\t *            \"grade\":    \"X\"\n\t\t *          },\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 5.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  5,\n\t\t *            \"grade\":    \"C\"\n\t\t *          }\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\",   \"data\": \"engine\" },\n\t\t *          { \"title\": \"Browser\",  \"data\": \"browser\" },\n\t\t *          { \"title\": \"Platform\", \"data\": \"platform\" },\n\t\t *          { \"title\": \"Version\",  \"data\": \"version\" },\n\t\t *          { \"title\": \"Grade\",    \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaData\": null,\n\t\n\t\n\t\t/**\n\t\t * If ordering is enabled, then DataTables will perform a first pass sort on\n\t\t * initialisation. You can define which column(s) the sort is performed\n\t\t * upon, and the sorting direction, with this variable. The `sorting` array\n\t\t * should contain an array for each column to be sorted initially containing\n\t\t * the column's index and a direction string ('asc' or 'desc').\n\t\t *  @type array\n\t\t *  @default [[0,'asc']]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.order\n\t\t *\n\t\t *  @example\n\t\t *    // Sort by 3rd column first, and then 4th column\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": [[2,'asc'], [3,'desc']]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *    // No initial sorting\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": []\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaSorting\": [[0,'asc']],\n\t\n\t\n\t\t/**\n\t\t * This parameter is basically identical to the `sorting` parameter, but\n\t\t * cannot be overridden by user interaction with the table. What this means\n\t\t * is that you could have a column (visible or hidden) which the sorting\n\t\t * will always be forced on first - any sorting after that (from the user)\n\t\t * will then be performed as required. This can be useful for grouping rows\n\t\t * together.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.orderFixed\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderFixed\": [[0,'asc']]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\n\t\t/**\n\t\t * DataTables can be instructed to load data to display in the table from a\n\t\t * Ajax source. This option defines how that Ajax call is made and where to.\n\t\t *\n\t\t * The `ajax` property has three different modes of operation, depending on\n\t\t * how it is defined. These are:\n\t\t *\n\t\t * * `string` - Set the URL from where the data should be loaded from.\n\t\t * * `object` - Define properties for `jQuery.ajax`.\n\t\t * * `function` - Custom data get function\n\t\t *\n\t\t * `string`\n\t\t * --------\n\t\t *\n\t\t * As a string, the `ajax` property simply defines the URL from which\n\t\t * DataTables will load data.\n\t\t *\n\t\t * `object`\n\t\t * --------\n\t\t *\n\t\t * As an object, the parameters in the object are passed to\n\t\t * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control\n\t\t * of the Ajax request. DataTables has a number of default parameters which\n\t\t * you can override using this option. Please refer to the jQuery\n\t\t * documentation for a full description of the options available, although\n\t\t * the following parameters provide additional options in DataTables or\n\t\t * require special consideration:\n\t\t *\n\t\t * * `data` - As with jQuery, `data` can be provided as an object, but it\n\t\t *   can also be used as a function to manipulate the data DataTables sends\n\t\t *   to the server. The function takes a single parameter, an object of\n\t\t *   parameters with the values that DataTables has readied for sending. An\n\t\t *   object may be returned which will be merged into the DataTables\n\t\t *   defaults, or you can add the items to the object that was passed in and\n\t\t *   not return anything from the function. This supersedes `fnServerParams`\n\t\t *   from DataTables 1.9-.\n\t\t *\n\t\t * * `dataSrc` - By default DataTables will look for the property `data` (or\n\t\t *   `aaData` for compatibility with DataTables 1.9-) when obtaining data\n\t\t *   from an Ajax source or for server-side processing - this parameter\n\t\t *   allows that property to be changed. You can use Javascript dotted\n\t\t *   object notation to get a data source for multiple levels of nesting, or\n\t\t *   it my be used as a function. As a function it takes a single parameter,\n\t\t *   the JSON returned from the server, which can be manipulated as\n\t\t *   required, with the returned value being that used by DataTables as the\n\t\t *   data source for the table. This supersedes `sAjaxDataProp` from\n\t\t *   DataTables 1.9-.\n\t\t *\n\t\t * * `success` - Should not be overridden it is used internally in\n\t\t *   DataTables. To manipulate / transform the data returned by the server\n\t\t *   use `ajax.dataSrc`, or use `ajax` as a function (see below).\n\t\t *\n\t\t * `function`\n\t\t * ----------\n\t\t *\n\t\t * As a function, making the Ajax call is left up to yourself allowing\n\t\t * complete control of the Ajax request. Indeed, if desired, a method other\n\t\t * than Ajax could be used to obtain the required data, such as Web storage\n\t\t * or an AIR database.\n\t\t *\n\t\t * The function is given four parameters and no return is required. The\n\t\t * parameters are:\n\t\t *\n\t\t * 1. _object_ - Data to send to the server\n\t\t * 2. _function_ - Callback function that must be executed when the required\n\t\t *    data has been obtained. That data should be passed into the callback\n\t\t *    as the only parameter\n\t\t * 3. _object_ - DataTables settings object for the table\n\t\t *\n\t\t * Note that this supersedes `fnServerData` from DataTables 1.9-.\n\t\t *\n\t\t *  @type string|object|function\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.ajax\n\t\t *  @since 1.10.0\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax.\n\t\t *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": \"data.json\"\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to change\n\t\t *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"tableData\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to read data\n\t\t *   // from a plain array rather than an array in an object\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Manipulate the data returned from the server - add a link to data\n\t\t *   // (note this can, should, be done using `render` for the column - this\n\t\t *   // is just a simple example of how the data can be manipulated).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": function ( json ) {\n\t\t *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {\n\t\t *           json[i][0] = '<a href=\"/message/'+json[i][0]+'>View message</a>';\n\t\t *         }\n\t\t *         return json;\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Add data to the request\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"data\": function ( d ) {\n\t\t *         return {\n\t\t *           \"extra_search\": $('#extra').val()\n\t\t *         };\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Send request as POST\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"type\": \"POST\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get the data from localStorage (could interface with a form for\n\t\t *   // adding, editing and removing rows).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": function (data, callback, settings) {\n\t\t *       callback(\n\t\t *         JSON.parse( localStorage.getItem('dataTablesData') )\n\t\t *       );\n\t\t *     }\n\t\t *   } );\n\t\t */\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to readily specify the entries in the length drop\n\t\t * down menu that DataTables shows when pagination is enabled. It can be\n\t\t * either a 1D array of options which will be used for both the displayed\n\t\t * option and the value, or a 2D array which will use the array in the first\n\t\t * position as the value, and the array in the second position as the\n\t\t * displayed options (useful for language strings such as 'All').\n\t\t *\n\t\t * Note that the `pageLength` property will be automatically set to the\n\t\t * first value given in this array, unless `pageLength` is also provided.\n\t\t *  @type array\n\t\t *  @default [ 10, 25, 50, 100 ]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.lengthMenu\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthMenu\": [[10, 25, 50, -1], [10, 25, 50, \"All\"]]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aLengthMenu\": [ 10, 25, 50, 100 ],\n\t\n\t\n\t\t/**\n\t\t * The `columns` option in the initialisation parameter allows you to define\n\t\t * details about the way individual columns behave. For a full list of\n\t\t * column options that can be set, please see\n\t\t * {@link DataTable.defaults.column}. Note that if you use `columns` to\n\t\t * define your columns, you must have an entry in the array for every single\n\t\t * column that you have in your table (these can be null if you don't which\n\t\t * to specify any options).\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.column\n\t\t */\n\t\t\"aoColumns\": null,\n\t\n\t\t/**\n\t\t * Very similar to `columns`, `columnDefs` allows you to target a specific\n\t\t * column, multiple columns, or all columns, using the `targets` property of\n\t\t * each object in the array. This allows great flexibility when creating\n\t\t * tables, as the `columnDefs` arrays can be of any length, targeting the\n\t\t * columns you specifically want. `columnDefs` may use any of the column\n\t\t * options available: {@link DataTable.defaults.column}, but it _must_\n\t\t * have `targets` defined in each object in the array. Values in the `targets`\n\t\t * array may be:\n\t\t *   <ul>\n\t\t *     <li>a string - class name will be matched on the TH for the column</li>\n\t\t *     <li>0 or a positive integer - column index counting from the left</li>\n\t\t *     <li>a negative integer - column index counting from the right</li>\n\t\t *     <li>the string \"_all\" - all columns (i.e. assign a default)</li>\n\t\t *   </ul>\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.columnDefs\n\t\t */\n\t\t\"aoColumnDefs\": null,\n\t\n\t\n\t\t/**\n\t\t * Basically the same as `search`, this parameter defines the individual column\n\t\t * filtering state at initialisation time. The array must be of the same size\n\t\t * as the number of columns, and each element be an object with the parameters\n\t\t * `search` and `escapeRegex` (the latter is optional). 'null' is also\n\t\t * accepted and the default will be used.\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.searchCols\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchCols\": [\n\t\t *          null,\n\t\t *          { \"search\": \"My filter\" },\n\t\t *          null,\n\t\t *          { \"search\": \"^[0-9]\", \"escapeRegex\": false }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aoSearchCols\": [],\n\t\n\t\n\t\t/**\n\t\t * An array of CSS classes that should be applied to displayed rows. This\n\t\t * array may be of any length, and DataTables will apply each class\n\t\t * sequentially, looping when required.\n\t\t *  @type array\n\t\t *  @default null <i>Will take the values determined by the `oClasses.stripe*`\n\t\t *    options</i>\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.stripeClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stripeClasses\": [ 'strip1', 'strip2', 'strip3' ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable automatic column width calculation. This can be disabled\n\t\t * as an optimisation (it takes some time to calculate the widths) if the\n\t\t * tables widths are passed in using `columns`.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.autoWidth\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"autoWidth\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bAutoWidth\": true,\n\t\n\t\n\t\t/**\n\t\t * Deferred rendering can provide DataTables with a huge speed boost when you\n\t\t * are using an Ajax or JS data source for the table. This option, when set to\n\t\t * true, will cause DataTables to defer the creation of the table elements for\n\t\t * each row until they are needed for a draw - saving a significant amount of\n\t\t * time.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.deferRender\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajax\": \"sources/arrays.txt\",\n\t\t *        \"deferRender\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDeferRender\": false,\n\t\n\t\n\t\t/**\n\t\t * Replace a DataTable which matches the given selector and replace it with\n\t\t * one which has the properties of the new initialisation object passed. If no\n\t\t * table matches the selector, then the new DataTable will be constructed as\n\t\t * per normal.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.destroy\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"srollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      // Some time later....\n\t\t *      $('#example').dataTable( {\n\t\t *        \"filter\": false,\n\t\t *        \"destroy\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDestroy\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering of data. Filtering in DataTables is \"smart\" in\n\t\t * that it allows the end user to input multiple words (space separated) and\n\t\t * will match a row containing those words, even if not in the order that was\n\t\t * specified (this allow matching across multiple columns). Note that if you\n\t\t * wish to use filtering in DataTables this must remain 'true' - to remove the\n\t\t * default filtering input box and retain filtering abilities, please use\n\t\t * {@link DataTable.defaults.dom}.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.searching\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searching\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bFilter\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the table information display. This shows information\n\t\t * about the data that is currently visible on the page, including information\n\t\t * about filtered data if that action is being performed.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.info\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"info\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bInfo\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some\n\t\t * slightly different and additional mark-up from what DataTables has\n\t\t * traditionally used).\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.jQueryUI\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"jQueryUI\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bJQueryUI\": false,\n\t\n\t\n\t\t/**\n\t\t * Allows the end user to select the size of a formatted page from a select\n\t\t * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.lengthChange\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthChange\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bLengthChange\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable pagination.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.paging\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"paging\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bPaginate\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of a 'processing' indicator when the table is\n\t\t * being processed (e.g. a sort). This is particularly useful for tables with\n\t\t * large amounts of data where it can take a noticeable amount of time to sort\n\t\t * the entries.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.processing\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"processing\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bProcessing\": false,\n\t\n\t\n\t\t/**\n\t\t * Retrieve the DataTables object for the given selector. Note that if the\n\t\t * table has already been initialised, this parameter will cause DataTables\n\t\t * to simply return the object that has already been set up - it will not take\n\t\t * account of any changes you might have made to the initialisation object\n\t\t * passed to DataTables (setting this parameter to true is an acknowledgement\n\t\t * that you understand this). `destroy` can be used to reinitialise a table if\n\t\t * you need.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.retrieve\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      initTable();\n\t\t *      tableActions();\n\t\t *    } );\n\t\t *\n\t\t *    function initTable ()\n\t\t *    {\n\t\t *      return $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false,\n\t\t *        \"retrieve\": true\n\t\t *      } );\n\t\t *    }\n\t\t *\n\t\t *    function tableActions ()\n\t\t *    {\n\t\t *      var table = initTable();\n\t\t *      // perform API operations with oTable\n\t\t *    }\n\t\t */\n\t\t\"bRetrieve\": false,\n\t\n\t\n\t\t/**\n\t\t * When vertical (y) scrolling is enabled, DataTables will force the height of\n\t\t * the table's viewport to the given height at all times (useful for layout).\n\t\t * However, this can look odd when filtering data down to a small data set,\n\t\t * and the footer is left \"floating\" further down. This parameter (when\n\t\t * enabled) will cause DataTables to collapse the table's viewport down when\n\t\t * the result set will fit within the given Y height.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollCollapse\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200\",\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bScrollCollapse\": false,\n\t\n\t\n\t\t/**\n\t\t * Configure DataTables to use server-side processing. Note that the\n\t\t * `ajax` parameter must also be given in order to give DataTables a\n\t\t * source to obtain the required data for each draw.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverSide\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"xhr.php\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bServerSide\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable sorting of columns. Sorting of individual columns can be\n\t\t * disabled by the `sortable` option for each column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.ordering\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ordering\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSort\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or display DataTables' ability to sort multiple columns at the\n\t\t * same time (activated by shift-click by the user).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderMulti\n\t\t *\n\t\t *  @example\n\t\t *    // Disable multiple column sorting ability\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderMulti\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortMulti\": true,\n\t\n\t\n\t\t/**\n\t\t * Allows control over whether DataTables should use the top (true) unique\n\t\t * cell that is found for a single column, or the bottom (false - default).\n\t\t * This is useful when using complex headers.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderCellsTop\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderCellsTop\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortCellsTop\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the addition of the classes `sorting\\_1`, `sorting\\_2` and\n\t\t * `sorting\\_3` to the columns which are currently being sorted on. This is\n\t\t * presented as a feature switch as it can increase processing time (while\n\t\t * classes are removed and added) so for large data sets you might want to\n\t\t * turn this off.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.orderClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderClasses\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortClasses\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable state saving. When enabled HTML5 `localStorage` will be\n\t\t * used to save table display information such as pagination information,\n\t\t * display length, filtering and sorting. As such when the end user reloads\n\t\t * the page the display display will match what thy had previously set up.\n\t\t *\n\t\t * Due to the use of `localStorage` the default state saving is not supported\n\t\t * in IE6 or 7. If state saving is required in those browsers, use\n\t\t * `stateSaveCallback` to provide a storage solution such as cookies.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.stateSave\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bStateSave\": false,\n\t\n\t\n\t\t/**\n\t\t * This function is called when a TR element is created (and all TD child\n\t\t * elements have been inserted), or registered if using a DOM source, allowing\n\t\t * manipulation of the TR element (adding classes etc).\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} dataIndex The index of this row in the internal aoData array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.createdRow\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"createdRow\": function( row, data, dataIndex ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" )\n\t\t *          {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedRow\": null,\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify any aspect you want about the created DOM.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.drawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"drawCallback\": function( settings ) {\n\t\t *          alert( 'DataTables has redrawn the table' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Identical to fnHeaderCallback() but for the table footer this function\n\t\t * allows you to modify the table footer on every 'draw' event.\n\t\t *  @type function\n\t\t *  @param {node} foot \"TR\" element for the footer\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.footerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"footerCallback\": function( tfoot, data, start, end, display ) {\n\t\t *          tfoot.getElementsByTagName('th')[0].innerHTML = \"Starting index is \"+start;\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnFooterCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * When rendering large numbers in the information element for the table\n\t\t * (i.e. \"Showing 1 to 10 of 57 entries\") DataTables will render large numbers\n\t\t * to have a comma separator for the 'thousands' units (e.g. 1 million is\n\t\t * rendered as \"1,000,000\") to help readability for the end user. This\n\t\t * function will override the default method DataTables uses.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {int} toFormat number to be formatted\n\t\t *  @returns {string} formatted string for DataTables to show the number\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.formatNumber\n\t\t *\n\t\t *  @example\n\t\t *    // Format a number using a single quote for the separator (note that\n\t\t *    // this can also be done with the language.thousands option)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"formatNumber\": function ( toFormat ) {\n\t\t *          return toFormat.toString().replace(\n\t\t *            /\\B(?=(\\d{3})+(?!\\d))/g, \"'\"\n\t\t *          );\n\t\t *        };\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnFormatNumber\": function ( toFormat ) {\n\t\t\treturn toFormat.toString().replace(\n\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g,\n\t\t\t\tthis.oLanguage.sThousands\n\t\t\t);\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify the header row. This can be used to calculate and\n\t\t * display useful information about the table.\n\t\t *  @type function\n\t\t *  @param {node} head \"TR\" element for the header\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.headerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"fheaderCallback\": function( head, data, start, end, display ) {\n\t\t *          head.getElementsByTagName('th')[0].innerHTML = \"Displaying \"+(end-start)+\" records\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnHeaderCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * The information element can be used to convey information about the current\n\t\t * state of the table. Although the internationalisation options presented by\n\t\t * DataTables are quite capable of dealing with most customisations, there may\n\t\t * be times where you wish to customise the string further. This callback\n\t\t * allows you to do exactly that.\n\t\t *  @type function\n\t\t *  @param {object} oSettings DataTables settings object\n\t\t *  @param {int} start Starting position in data for the draw\n\t\t *  @param {int} end End position in data for the draw\n\t\t *  @param {int} max Total number of rows in the table (regardless of\n\t\t *    filtering)\n\t\t *  @param {int} total Total number of rows in the data set, after filtering\n\t\t *  @param {string} pre The string that DataTables has formatted using it's\n\t\t *    own rules\n\t\t *  @returns {string} The string to be displayed in the information element.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.infoCallback\n\t\t *\n\t\t *  @example\n\t\t *    $('#example').dataTable( {\n\t\t *      \"infoCallback\": function( settings, start, end, max, total, pre ) {\n\t\t *        return start +\" to \"+ end;\n\t\t *      }\n\t\t *    } );\n\t\t */\n\t\t\"fnInfoCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Called when the table has been initialised. Normally DataTables will\n\t\t * initialise sequentially and there will be no need for this function,\n\t\t * however, this does not hold true when using external language information\n\t\t * since that is obtained using an async XHR call.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} json The JSON object request from the server - only\n\t\t *    present if client-side Ajax sourced data is used\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.initComplete\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"initComplete\": function(settings, json) {\n\t\t *          alert( 'DataTables has finished its initialisation.' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnInitComplete\": null,\n\t\n\t\n\t\t/**\n\t\t * Called at the very start of each table draw and can be used to cancel the\n\t\t * draw by returning false, any other return (including undefined) results in\n\t\t * the full draw occurring).\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @returns {boolean} False will cancel the draw, anything else (including no\n\t\t *    return) will allow it to complete.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.preDrawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"preDrawCallback\": function( settings ) {\n\t\t *          if ( $('#test').val() == 1 ) {\n\t\t *            return false;\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnPreDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * This function allows you to 'post process' each row after it have been\n\t\t * generated for each table draw, but before it is rendered on screen. This\n\t\t * function might be used for setting the row class name etc.\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} displayIndex The display index for the current table draw\n\t\t *  @param {int} displayIndexFull The index of the data in the full list of\n\t\t *    rows (after filtering)\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.rowCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"rowCallback\": function( row, data, displayIndex, displayIndexFull ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" ) {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnRowCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * This parameter allows you to override the default function which obtains\n\t\t * the data from the server so something more suitable for your application.\n\t\t * For example you could use POST data, or pull information from a Gears or\n\t\t * AIR database.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {string} source HTTP source to obtain the data from (`ajax`)\n\t\t *  @param {array} data A key/value pair object containing the data to send\n\t\t *    to the server\n\t\t *  @param {function} callback to be called on completion of the data get\n\t\t *    process that will draw the data on the page.\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverData\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t *  It is often useful to send extra data to the server when making an Ajax\n\t\t * request - for example custom filtering information, and this callback\n\t\t * function makes it trivial to send extra information to the server. The\n\t\t * passed in parameter is the data set that has been constructed by\n\t\t * DataTables, and you can add to this or modify it as you require.\n\t\t *  @type function\n\t\t *  @param {array} data Data array (array of objects which are name/value\n\t\t *    pairs) that has been constructed by DataTables and will be sent to the\n\t\t *    server. In the case of Ajax sourced data with server-side processing\n\t\t *    this will be an empty array, for server-side processing there will be a\n\t\t *    significant number of parameters!\n\t\t *  @returns {undefined} Ensure that you modify the data array passed in,\n\t\t *    as this is passed by reference.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverParams\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Load the table state. With this function you can define from where, and how, the\n\t\t * state of a table is loaded. By default DataTables will load from `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} callback Callback that can be executed when done. It\n\t\t *    should be passed the loaded state object.\n\t\t *  @return {object} The DataTables state object to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadCallback\": function (settings, callback) {\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_load\",\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"success\": function (json) {\n\t\t *              callback( json );\n\t\t *            }\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadCallback\": function ( settings ) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(\n\t\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(\n\t\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the saved state prior to loading that state.\n\t\t * This callback is called when the table is loading state from the stored data, but\n\t\t * prior to the settings object being modified by the saved state. Note that for\n\t\t * plug-in authors, you should use the `stateLoadParams` event to load parameters for\n\t\t * a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that is to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never loaded\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Disallow state loading by returning false\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          return false;\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Callback that is called when the state has been loaded from the state saving method\n\t\t * and the DataTables settings object has been modified as a result of the loaded state.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that was loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoaded\n\t\t *\n\t\t *  @example\n\t\t *    // Show an alert with the filtering value that was saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoaded\": function (settings, data) {\n\t\t *          alert( 'Saved filter was: '+data.oSearch.sSearch );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoaded\": null,\n\t\n\t\n\t\t/**\n\t\t * Save the table state. This function allows you to define where and how the state\n\t\t * information for the table is stored By default DataTables will use `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveCallback\": function (settings, data) {\n\t\t *          // Send an Ajax request to the server with the state object\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_save\",\n\t\t *            \"data\": data,\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"method\": \"POST\"\n\t\t *            \"success\": function () {}\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveCallback\": function ( settings, data ) {\n\t\t\ttry {\n\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(\n\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname,\n\t\t\t\t\tJSON.stringify( data )\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the state to be saved. Called when the table\n\t\t * has changed state a new state save is required. This method allows modification of\n\t\t * the state saving object prior to actually doing the save, including addition or\n\t\t * other state properties or modification. Note that for plug-in authors, you should\n\t\t * use the `stateSaveParams` event to save parameters for a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Duration for which the saved state information is considered valid. After this period\n\t\t * has elapsed the state will be returned to the default.\n\t\t * Value is given in seconds.\n\t\t *  @type int\n\t\t *  @default 7200 <i>(2 hours)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.stateDuration\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateDuration\": 60*60*24; // 1 day\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iStateDuration\": 7200,\n\t\n\t\n\t\t/**\n\t\t * When enabled DataTables will not make a request to the server for the first\n\t\t * page draw - rather it will use the data already on the page (no sorting etc\n\t\t * will be applied to it), thus saving on an XHR at load time. `deferLoading`\n\t\t * is used to indicate that deferred loading is required, but it is also used\n\t\t * to tell DataTables how many records there are in the full table (allowing\n\t\t * the information element and pagination to be displayed correctly). In the case\n\t\t * where a filtering is applied to the table on initial load, this can be\n\t\t * indicated by giving the parameter as an array, where the first element is\n\t\t * the number of records available after filtering and the second element is the\n\t\t * number of records without filtering (allowing the table information element\n\t\t * to be shown correctly).\n\t\t *  @type int | array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.deferLoading\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records available in the table, no filtering applied\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": 57\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records after filtering, 100 without filtering (an initial filter applied)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": [ 57, 100 ],\n\t\t *        \"search\": {\n\t\t *          \"search\": \"my_filter\"\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iDeferLoading\": null,\n\t\n\t\n\t\t/**\n\t\t * Number of rows to display on a single page when using pagination. If\n\t\t * feature enabled (`lengthChange`) then the end user will be able to override\n\t\t * this to a custom setting using a pop-up menu.\n\t\t *  @type int\n\t\t *  @default 10\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pageLength\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pageLength\": 50\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayLength\": 10,\n\t\n\t\n\t\t/**\n\t\t * Define the starting point for data display when using DataTables with\n\t\t * pagination. Note that this parameter is the number of records, rather than\n\t\t * the page number, so if you have 10 records per page and want to start on\n\t\t * the third page, it should be \"20\".\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.displayStart\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"displayStart\": 20\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayStart\": 0,\n\t\n\t\n\t\t/**\n\t\t * By default DataTables allows keyboard navigation of the table (sorting, paging,\n\t\t * and filtering) by adding a `tabindex` attribute to the required elements. This\n\t\t * allows you to tab through the controls and press the enter key to activate them.\n\t\t * The tabindex is default 0, meaning that the tab follows the flow of the document.\n\t\t * You can overrule this using this parameter if you wish. Use a value of -1 to\n\t\t * disable built-in keyboard navigation.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.tabIndex\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"tabIndex\": 1\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\n\t\t/**\n\t\t * Classes that DataTables assigns to the various components and features\n\t\t * that it adds to the HTML table. This allows classes to be configured\n\t\t * during initialisation in addition to through the static\n\t\t * {@link DataTable.ext.oStdClasses} object).\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.classes\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\n\t\t/**\n\t\t * All strings that DataTables uses in the user interface that it creates\n\t\t * are defined in this object, allowing you to modified them individually or\n\t\t * completely replace them all as required.\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.language\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Strings that are used for WAI-ARIA labels and controls only (these are not\n\t\t\t * actually visible on the page, but will be read by screenreaders, and thus\n\t\t\t * must be internationalised as well).\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.aria\n\t\t\t */\n\t\t\t\"oAria\": {\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted ascending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortAscending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortAscending\": \" - click/return to sort ascending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortAscending\": \": activate to sort column ascending\",\n\t\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted descending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortDescending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortDescending\": \" - click/return to sort descending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortDescending\": \": activate to sort column descending\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * Pagination string used by DataTables for the built-in pagination\n\t\t\t * control types.\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.paginate\n\t\t\t */\n\t\t\t\"oPaginate\": {\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the first page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default First\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.first\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"first\": \"First page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sFirst\": \"First\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the last page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Last\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.last\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"last\": \"Last page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sLast\": \"Last\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'next' pagination button (to take the user to the\n\t\t\t\t * next page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Next\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.next\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"next\": \"Next page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sNext\": \"Next\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'previous' pagination button (to take the user to\n\t\t\t\t * the previous page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Previous\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.previous\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"previous\": \"Previous page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sPrevious\": \"Previous\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * This string is shown in preference to `zeroRecords` when the table is\n\t\t\t * empty of data (regardless of filtering). Note that this is an optional\n\t\t\t * parameter - if it is not given, the value of `zeroRecords` will be used\n\t\t\t * instead (either the default or given value).\n\t\t\t *  @type string\n\t\t\t *  @default No data available in table\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.emptyTable\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"emptyTable\": \"No data available in table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sEmptyTable\": \"No data available in table\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This string gives information to the end user about the information\n\t\t\t * that is current on display on the page. The following tokens can be\n\t\t\t * used in the string and will be dynamically replaced as the table\n\t\t\t * display updates. This tokens can be placed anywhere in the string, or\n\t\t\t * removed as needed by the language requires:\n\t\t\t *\n\t\t\t * * `\\_START\\_` - Display index of the first record on the current page\n\t\t\t * * `\\_END\\_` - Display index of the last record on the current page\n\t\t\t * * `\\_TOTAL\\_` - Number of records in the table after filtering\n\t\t\t * * `\\_MAX\\_` - Number of records in the table without filtering\n\t\t\t * * `\\_PAGE\\_` - Current page number\n\t\t\t * * `\\_PAGES\\_` - Total number of pages of data in the table\n\t\t\t *\n\t\t\t *  @type string\n\t\t\t *  @default Showing _START_ to _END_ of _TOTAL_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.info\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"info\": \"Showing page _PAGE_ of _PAGES_\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfo\": \"Showing _START_ to _END_ of _TOTAL_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Display information string for when the table is empty. Typically the\n\t\t\t * format of this string should match `info`.\n\t\t\t *  @type string\n\t\t\t *  @default Showing 0 to 0 of 0 entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoEmpty\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoEmpty\": \"No entries to show\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoEmpty\": \"Showing 0 to 0 of 0 entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When a user filters the information in a table, this string is appended\n\t\t\t * to the information (`info`) to give an idea of how strong the filtering\n\t\t\t * is. The variable _MAX_ is dynamically updated.\n\t\t\t *  @type string\n\t\t\t *  @default (filtered from _MAX_ total entries)\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoFiltered\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoFiltered\": \" - filtering from _MAX_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoFiltered\": \"(filtered from _MAX_ total entries)\",\n\t\n\t\n\t\t\t/**\n\t\t\t * If can be useful to append extra information to the info string at times,\n\t\t\t * and this variable does exactly that. This information will be appended to\n\t\t\t * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are\n\t\t\t * being used) at all times.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoPostFix\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoPostFix\": \"All records shown are derived from real information.\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoPostFix\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This decimal place operator is a little different from the other\n\t\t\t * language options since DataTables doesn't output floating point\n\t\t\t * numbers, so it won't ever use this for display of a number. Rather,\n\t\t\t * what this parameter does is modify the sort methods of the table so\n\t\t\t * that numbers which are in a format which has a character other than\n\t\t\t * a period (`.`) as a decimal place will be sorted numerically.\n\t\t\t *\n\t\t\t * Note that numbers with different decimal places cannot be shown in\n\t\t\t * the same table and still be sortable, the table must be consistent.\n\t\t\t * However, multiple different tables on the page can use different\n\t\t\t * decimal place characters.\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.decimal\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"decimal\": \",\"\n\t\t\t *          \"thousands\": \".\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sDecimal\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * DataTables has a build in number formatter (`formatNumber`) which is\n\t\t\t * used to format large numbers that are used in the table information.\n\t\t\t * By default a comma is used, but this can be trivially changed to any\n\t\t\t * character you wish with this parameter.\n\t\t\t *  @type string\n\t\t\t *  @default ,\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.thousands\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"thousands\": \"'\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sThousands\": \",\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Detail the action that will be taken when the drop down menu for the\n\t\t\t * pagination length option is changed. The '_MENU_' variable is replaced\n\t\t\t * with a default select list of 10, 25, 50 and 100, and can be replaced\n\t\t\t * with a custom select box if required.\n\t\t\t *  @type string\n\t\t\t *  @default Show _MENU_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.lengthMenu\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language change only\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": \"Display _MENU_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language and options change\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": 'Display <select>'+\n\t\t\t *            '<option value=\"10\">10</option>'+\n\t\t\t *            '<option value=\"20\">20</option>'+\n\t\t\t *            '<option value=\"30\">30</option>'+\n\t\t\t *            '<option value=\"40\">40</option>'+\n\t\t\t *            '<option value=\"50\">50</option>'+\n\t\t\t *            '<option value=\"-1\">All</option>'+\n\t\t\t *            '</select> records'\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLengthMenu\": \"Show _MENU_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When using Ajax sourced data and during the first draw when DataTables is\n\t\t\t * gathering the data, this message is shown in an empty row in the table to\n\t\t\t * indicate to the end user the the data is being loaded. Note that this\n\t\t\t * parameter is not used when loading data by server-side processing, just\n\t\t\t * Ajax sourced data with client-side processing.\n\t\t\t *  @type string\n\t\t\t *  @default Loading...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.loadingRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"loadingRecords\": \"Please wait - loading...\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLoadingRecords\": \"Loading...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text which is displayed when the table is processing a user action\n\t\t\t * (usually a sort command or similar).\n\t\t\t *  @type string\n\t\t\t *  @default Processing...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.processing\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"processing\": \"DataTables is currently busy\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sProcessing\": \"Processing...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Details the actions that will be taken when the user types into the\n\t\t\t * filtering input text box. The variable \"_INPUT_\", if used in the string,\n\t\t\t * is replaced with the HTML text box for the filtering input allowing\n\t\t\t * control over where it appears in the string. If \"_INPUT_\" is not given\n\t\t\t * then the input box is appended to the string automatically.\n\t\t\t *  @type string\n\t\t\t *  @default Search:\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.search\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Input text box will be appended at the end automatically\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Filter records:\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Specify where the filter should appear\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Apply filter _INPUT_ to table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sSearch\": \"Search:\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Assign a `placeholder` attribute to the search `input` element\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.searchPlaceholder\n\t\t\t */\n\t\t\t\"sSearchPlaceholder\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * All of the language information can be stored in a file on the\n\t\t\t * server-side, which DataTables will look up if this parameter is passed.\n\t\t\t * It must store the URL of the language file, which is in a JSON format,\n\t\t\t * and the object has the same properties as the oLanguage object in the\n\t\t\t * initialiser object (i.e. the above parameters). Please refer to one of\n\t\t\t * the example language files to see how this works in action.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string - i.e. disabled</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.url\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"url\": \"http://www.sprymedia.co.uk/dataTables/lang.txt\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sUrl\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text shown inside the table records when the is no information to be\n\t\t\t * displayed after filtering. `emptyTable` is shown when there is simply no\n\t\t\t * information in the table at all (regardless of filtering).\n\t\t\t *  @type string\n\t\t\t *  @default No matching records found\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.zeroRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"zeroRecords\": \"No records to display\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sZeroRecords\": \"No matching records found\"\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to have define the global filtering state at\n\t\t * initialisation time. As an object the `search` parameter must be\n\t\t * defined, but all other parameters are optional. When `regex` is true,\n\t\t * the search string will be treated as a regular expression, when false\n\t\t * (default) it will be treated as a straight string. When `smart`\n\t\t * DataTables will use it's smart filtering methods (to word match at\n\t\t * any point in the data), when false this will not be done.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.search\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"search\": {\"search\": \"Initial search\"}\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"oSearch\": $.extend( {}, DataTable.models.oSearch ),\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * By default DataTables will look for the property `data` (or `aaData` for\n\t\t * compatibility with DataTables 1.9-) when obtaining data from an Ajax\n\t\t * source or for server-side processing - this parameter allows that\n\t\t * property to be changed. You can use Javascript dotted object notation to\n\t\t * get a data source for multiple levels of nesting.\n\t\t *  @type string\n\t\t *  @default data\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxDataProp\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxDataProp\": \"data\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * You can instruct DataTables to load data from an external\n\t\t * source using this parameter (use aData if you want to pass data in you\n\t\t * already have). Simply provide a url a JSON object can be obtained from.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxSource\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\n\t\t/**\n\t\t * This initialisation variable allows you to specify exactly where in the\n\t\t * DOM you want DataTables to inject the various controls it adds to the page\n\t\t * (for example you might want the pagination controls at the top of the\n\t\t * table). DIV elements (with or without a custom class) can also be added to\n\t\t * aid styling. The follow syntax is used:\n\t\t *   <ul>\n\t\t *     <li>The following options are allowed:\n\t\t *       <ul>\n\t\t *         <li>'l' - Length changing</li>\n\t\t *         <li>'f' - Filtering input</li>\n\t\t *         <li>'t' - The table!</li>\n\t\t *         <li>'i' - Information</li>\n\t\t *         <li>'p' - Pagination</li>\n\t\t *         <li>'r' - pRocessing</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following constants are allowed:\n\t\t *       <ul>\n\t\t *         <li>'H' - jQueryUI theme \"header\" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>\n\t\t *         <li>'F' - jQueryUI theme \"footer\" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following syntax is expected:\n\t\t *       <ul>\n\t\t *         <li>'&lt;' and '&gt;' - div elements</li>\n\t\t *         <li>'&lt;\"class\" and '&gt;' - div with a class</li>\n\t\t *         <li>'&lt;\"#id\" and '&gt;' - div with an ID</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>Examples:\n\t\t *       <ul>\n\t\t *         <li>'&lt;\"wrapper\"flipt&gt;'</li>\n\t\t *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *   </ul>\n\t\t *  @type string\n\t\t *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>\n\t\t *    <\"H\"lfr>t<\"F\"ip> <i>(when `jQueryUI` is true)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.dom\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"dom\": '&lt;\"top\"i&gt;rt&lt;\"bottom\"flp&gt;&lt;\"clear\"&gt;'\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDom\": \"lfrtip\",\n\t\n\t\n\t\t/**\n\t\t * Search delay option. This will throttle full table searches that use the\n\t\t * DataTables provided search input element (it does not effect calls to\n\t\t * `dt-api search()`, providing a delay before the search is made.\n\t\t *  @type integer\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.searchDelay\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchDelay\": 200\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\n\t\t/**\n\t\t * DataTables features six different built-in options for the buttons to\n\t\t * display for pagination control:\n\t\t *\n\t\t * * `numbers` - Page number buttons only\n\t\t * * `simple` - 'Previous' and 'Next' buttons only\n\t\t * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers\n\t\t * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons\n\t\t * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers\n\t\t * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers\n\t\t *  \n\t\t * Further methods can be added using {@link DataTable.ext.oPagination}.\n\t\t *  @type string\n\t\t *  @default simple_numbers\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pagingType\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pagingType\": \"full_numbers\"\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"sPaginationType\": \"simple_numbers\",\n\t\n\t\n\t\t/**\n\t\t * Enable horizontal scrolling. When a table is too wide to fit into a\n\t\t * certain layout, or you have a large number of columns in the table, you\n\t\t * can enable x-scrolling to show the table in a viewport, which can be\n\t\t * scrolled. This property can be `true` which will allow the table to\n\t\t * scroll horizontally when needed, or any CSS unit, or a number (in which\n\t\t * case it will be treated as a pixel measurement). Setting as simply `true`\n\t\t * is recommended.\n\t\t *  @type boolean|string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollX\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": true,\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollX\": \"\",\n\t\n\t\n\t\t/**\n\t\t * This property can be used to force a DataTable to use more width than it\n\t\t * might otherwise do when x-scrolling is enabled. For example if you have a\n\t\t * table which requires to be well spaced, this parameter is useful for\n\t\t * \"over-sizing\" the table, and thus forcing scrolling. This property can by\n\t\t * any CSS unit, or a number (in which case it will be treated as a pixel\n\t\t * measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollXInner\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": \"100%\",\n\t\t *        \"scrollXInner\": \"110%\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollXInner\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Enable vertical scrolling. Vertical scrolling will constrain the DataTable\n\t\t * to the given height, and enable scrolling for any data which overflows the\n\t\t * current viewport. This can be used as an alternative to paging to display\n\t\t * a lot of data in a small area (although paging and scrolling can both be\n\t\t * enabled at the same time). This property can be any CSS unit, or a number\n\t\t * (in which case it will be treated as a pixel measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollY\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollY\": \"\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * Set the HTTP method that is used to make the Ajax call for server-side\n\t\t * processing or Ajax sourced data.\n\t\t *  @type string\n\t\t *  @default GET\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverMethod\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sServerMethod\": \"GET\",\n\t\n\t\n\t\t/**\n\t\t * DataTables makes use of renderers when displaying HTML elements for\n\t\t * a table. These renderers can be added or modified by plug-ins to\n\t\t * generate suitable mark-up for a site. For example the Bootstrap\n\t\t * integration plug-in for DataTables uses a paging button renderer to\n\t\t * display pagination buttons in the mark-up required by Bootstrap.\n\t\t *\n\t\t * For further information about the renderers available see\n\t\t * DataTable.ext.renderer\n\t\t *  @type string|object\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.renderer\n\t\t *\n\t\t */\n\t\t\"renderer\": null,\n\t\n\t\n\t\t/**\n\t\t * Set the data property name that DataTables should use to get a row's id\n\t\t * to set as the `id` property in the node.\n\t\t *  @type string\n\t\t *  @default DT_RowId\n\t\t *\n\t\t *  @name DataTable.defaults.rowId\n\t\t */\n\t\t\"rowId\": \"DT_RowId\"\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults );\n\t\n\t\n\t\n\t/*\n\t * Developer note - See note in model.defaults.js about the use of Hungarian\n\t * notation and camel case.\n\t */\n\t\n\t/**\n\t * Column options that can be given to DataTables at initialisation time.\n\t *  @namespace\n\t */\n\tDataTable.defaults.column = {\n\t\t/**\n\t\t * Define which column(s) an order will occur on for this column. This\n\t\t * allows a column's ordering to take multiple columns into account when\n\t\t * doing a sort or use the data from a different column. For example first\n\t\t * name / last name columns make sense to do a multi-column sort over the\n\t\t * two columns.\n\t\t *  @type array|int\n\t\t *  @default null <i>Takes the value of the column index automatically</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderData\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderData\": [ 0, 1 ], \"targets\": [ 0 ] },\n\t\t *          { \"orderData\": [ 1, 0 ], \"targets\": [ 1 ] },\n\t\t *          { \"orderData\": 2, \"targets\": [ 2 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderData\": [ 0, 1 ] },\n\t\t *          { \"orderData\": [ 1, 0 ] },\n\t\t *          { \"orderData\": 2 },\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aDataSort\": null,\n\t\t\"iDataSort\": -1,\n\t\n\t\n\t\t/**\n\t\t * You can control the default ordering direction, and even alter the\n\t\t * behaviour of the sort handler (i.e. only allow ascending ordering etc)\n\t\t * using this parameter.\n\t\t *  @type array\n\t\t *  @default [ 'asc', 'desc' ]\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderSequence\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderSequence\": [ \"asc\" ], \"targets\": [ 1 ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ], \"targets\": [ 2 ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ], \"targets\": [ 3 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          { \"orderSequence\": [ \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ] },\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"asSorting\": [ 'asc', 'desc' ],\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering on the data in this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.searchable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"searchable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"searchable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSearchable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable ordering on this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.visible\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"visible\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"visible\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bVisible\": true,\n\t\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} td The TD node that has been created\n\t\t *  @param {*} cellData The Data for the cell\n\t\t *  @param {array|object} rowData The data for the whole row\n\t\t *  @param {int} row The row index for the aoData data store\n\t\t *  @param {int} col The column index for aoColumns\n\t\t *\n\t\t *  @name DataTable.defaults.column.createdCell\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [3],\n\t\t *          \"createdCell\": function (td, cellData, rowData, row, col) {\n\t\t *            if ( cellData == \"1.7\" ) {\n\t\t *              $(td).css('color', 'blue')\n\t\t *            }\n\t\t *          }\n\t\t *        } ]\n\t\t *      });\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter has been replaced by `data` in DataTables to ensure naming\n\t\t * consistency. `dataProp` can still be used, as there is backwards\n\t\t * compatibility in DataTables for this option, but it is strongly\n\t\t * recommended that you use `data` in preference to `dataProp`.\n\t\t *  @name DataTable.defaults.column.dataProp\n\t\t */\n\t\n\t\n\t\t/**\n\t\t * This property can be used to read data from any data source property,\n\t\t * including deeply nested objects / properties. `data` can be given in a\n\t\t * number of different ways which effect its behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object. Note that\n\t\t *      function notation is recommended for use in `render` rather than\n\t\t *      `data` as it is much simpler to use as a renderer.\n\t\t * * `null` - use the original data source for the row rather than plucking\n\t\t *   data directly from it. This action has effects on two other\n\t\t *   initialisation options:\n\t\t *    * `defaultContent` - When null is given as the `data` option and\n\t\t *      `defaultContent` is specified for the column, the value defined by\n\t\t *      `defaultContent` will be used for the cell.\n\t\t *    * `render` - When null is used for the `data` option and the `render`\n\t\t *      option is specified for the column, the whole data source for the\n\t\t *      row is used for the renderer.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * `{array|object}` The data source for the row\n\t\t *      * `{string}` The type call data requested - this will be 'set' when\n\t\t *        setting data or 'filter', 'display', 'type', 'sort' or undefined\n\t\t *        when gathering data. Note that when `undefined` is given for the\n\t\t *        type DataTables expects to get the raw data for the object back<\n\t\t *      * `{*}` Data to set when the second parameter is 'set'.\n\t\t *    * Return:\n\t\t *      * The return value from the function is not required when 'set' is\n\t\t *        the type of call, but otherwise the return is what will be used\n\t\t *        for the data requested.\n\t\t *\n\t\t * Note that `data` is a getter and setter option. If you just require\n\t\t * formatting of data for output, you will likely want to use `render` which\n\t\t * is simply a getter and thus simpler to use.\n\t\t *\n\t\t * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The\n\t\t * name change reflects the flexibility of this property and is consistent\n\t\t * with the naming of mRender. If 'mDataProp' is given, then it will still\n\t\t * be used by DataTables, as it automatically maps the old name to the new\n\t\t * if required.\n\t\t *\n\t\t *  @type string|int|function|null\n\t\t *  @default null <i>Use automatically calculated column index</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.data\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Read table data from objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {value},\n\t\t *    //      \"version\": {value},\n\t\t *    //      \"grade\": {value}\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/objects.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform\" },\n\t\t *          { \"data\": \"version\" },\n\t\t *          { \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Read information from deeply nested objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {\n\t\t *    //         \"inner\": {value}\n\t\t *    //      },\n\t\t *    //      \"details\": [\n\t\t *    //         {value}, {value}\n\t\t *    //      ]\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform.inner\" },\n\t\t *          { \"data\": \"platform.details.0\" },\n\t\t *          { \"data\": \"platform.details.1\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `data` as a function to provide different information for\n\t\t *    // sorting, filtering and display. In this case, currency (price)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": function ( source, type, val ) {\n\t\t *            if (type === 'set') {\n\t\t *              source.price = val;\n\t\t *              // Store the computed dislay and filter values for efficiency\n\t\t *              source.price_display = val==\"\" ? \"\" : \"$\"+numberFormat(val);\n\t\t *              source.price_filter  = val==\"\" ? \"\" : \"$\"+numberFormat(val)+\" \"+val;\n\t\t *              return;\n\t\t *            }\n\t\t *            else if (type === 'display') {\n\t\t *              return source.price_display;\n\t\t *            }\n\t\t *            else if (type === 'filter') {\n\t\t *              return source.price_filter;\n\t\t *            }\n\t\t *            // 'sort', 'type' and undefined all just use the integer\n\t\t *            return source.price;\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using default content\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null,\n\t\t *          \"defaultContent\": \"Click to edit\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using array notation - outputting a list from an array\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"name[, ]\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\n\t\t/**\n\t\t * This property is the rendering partner to `data` and it is suggested that\n\t\t * when you want to manipulate data for display (including filtering,\n\t\t * sorting etc) without altering the underlying data for the table, use this\n\t\t * property. `render` can be considered to be the the read only companion to\n\t\t * `data` which is read / write (then as such more complex). Like `data`\n\t\t * this option can be given in a number of different ways to effect its\n\t\t * behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object.\n\t\t * * `object` - use different data for the different data types requested by\n\t\t *   DataTables ('filter', 'display', 'type' or 'sort'). The property names\n\t\t *   of the object is the data type the property refers to and the value can\n\t\t *   defined using an integer, string or function using the same rules as\n\t\t *   `render` normally does. Note that an `_` option _must_ be specified.\n\t\t *   This is the default value to use if you haven't specified a value for\n\t\t *   the data type requested by DataTables.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * {array|object} The data source for the row (based on `data`)\n\t\t *      * {string} The type call data requested - this will be 'filter',\n\t\t *        'display', 'type' or 'sort'.\n\t\t *      * {array|object} The full data source for the row (not based on\n\t\t *        `data`)\n\t\t *    * Return:\n\t\t *      * The return value from the function is what will be used for the\n\t\t *        data requested.\n\t\t *\n\t\t *  @type string|int|function|object|null\n\t\t *  @default null Use the data source value.\n\t\t *\n\t\t *  @name DataTable.defaults.column.render\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Create a comma separated list from an array of objects\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          {\n\t\t *            \"data\": \"platform\",\n\t\t *            \"render\": \"[, ].name\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Execute a function to obtain data\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": \"browserName()\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // As an object, extracting different data for the different types\n\t\t *    // This would be used with a data source such as:\n\t\t *    //   { \"phone\": 5552368, \"phone_filter\": \"5552368 555-2368\", \"phone_display\": \"555-2368\" }\n\t\t *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`\n\t\t *    // (which has both forms) is used for filtering for if a user inputs either format, while\n\t\t *    // the formatted phone number is the one that is shown in the table.\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": {\n\t\t *            \"_\": \"phone\",\n\t\t *            \"filter\": \"phone_filter\",\n\t\t *            \"display\": \"phone_display\"\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Use as a function to create a link from the data source\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"download_link\",\n\t\t *          \"render\": function ( data, type, full ) {\n\t\t *            return '<a href=\"'+data+'\">Download</a>';\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\n\t\t/**\n\t\t * Change the cell type created for the column - either TD cells or TH cells. This\n\t\t * can be useful as TH cells have semantic meaning in the table body, allowing them\n\t\t * to act as a header for a row (you may wish to add scope='row' to the TH elements).\n\t\t *  @type string\n\t\t *  @default td\n\t\t *\n\t\t *  @name DataTable.defaults.column.cellType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Make the first column use TH cells\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"cellType\": \"th\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sCellType\": \"td\",\n\t\n\t\n\t\t/**\n\t\t * Class to give to each cell in this column.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.class\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"class\": \"my_class\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"class\": \"my_class\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sClass\": \"\",\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t * Generally you shouldn't need this!\n\t\t *  @type string\n\t\t *  @default <i>Empty string<i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.contentPadding\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"contentPadding\": \"mmm\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sContentPadding\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because `data`\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.column.defaultContent\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\",\n\t\t *            \"targets\": [ -1 ]\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter is only used in DataTables' server-side processing. It can\n\t\t * be exceptionally useful to know what columns are being displayed on the\n\t\t * client side, and to map these to database fields. When defined, the names\n\t\t * also allow DataTables to reorder information from the server if it comes\n\t\t * back in an unexpected order (i.e. if you switch your columns around on the\n\t\t * client-side, your server-side code does not also need updating).\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.name\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"name\": \"engine\", \"targets\": [ 0 ] },\n\t\t *          { \"name\": \"browser\", \"targets\": [ 1 ] },\n\t\t *          { \"name\": \"platform\", \"targets\": [ 2 ] },\n\t\t *          { \"name\": \"version\", \"targets\": [ 3 ] },\n\t\t *          { \"name\": \"grade\", \"targets\": [ 4 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"name\": \"engine\" },\n\t\t *          { \"name\": \"browser\" },\n\t\t *          { \"name\": \"platform\" },\n\t\t *          { \"name\": \"version\" },\n\t\t *          { \"name\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sName\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Defines a data source type for the ordering which can be used to read\n\t\t * real-time information from the table (updating the internally cached\n\t\t * version) prior to ordering. This allows ordering to occur on user\n\t\t * editable elements such as form inputs.\n\t\t *  @type string\n\t\t *  @default std\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderDataType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderDataType\": \"dom-text\", \"targets\": [ 2, 3 ] },\n\t\t *          { \"type\": \"numeric\", \"targets\": [ 3 ] },\n\t\t *          { \"orderDataType\": \"dom-select\", \"targets\": [ 4 ] },\n\t\t *          { \"orderDataType\": \"dom-checkbox\", \"targets\": [ 5 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          { \"orderDataType\": \"dom-text\" },\n\t\t *          { \"orderDataType\": \"dom-text\", \"type\": \"numeric\" },\n\t\t *          { \"orderDataType\": \"dom-select\" },\n\t\t *          { \"orderDataType\": \"dom-checkbox\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sSortDataType\": \"std\",\n\t\n\t\n\t\t/**\n\t\t * The title of this column.\n\t\t *  @type string\n\t\t *  @default null <i>Derived from the 'TH' value for this column in the\n\t\t *    original HTML table.</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.title\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"title\": \"My column title\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"My column title\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\n\t\t/**\n\t\t * The type allows you to specify how the data for this column will be\n\t\t * ordered. Four types (string, numeric, date and html (which will strip\n\t\t * HTML tags before ordering)) are currently available. Note that only date\n\t\t * formats understood by Javascript's Date() object will be accepted as type\n\t\t * date. For example: \"Mar 26, 2008 5:03 PM\". May take the values: 'string',\n\t\t * 'numeric', 'date' or 'html' (by default). Further types can be adding\n\t\t * through plug-ins.\n\t\t *  @type string\n\t\t *  @default null <i>Auto-detected from raw data</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.type\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"type\": \"html\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"type\": \"html\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\n\t\t/**\n\t\t * Defining the width of the column, this parameter may take any CSS value\n\t\t * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not\n\t\t * been given a specific width through this interface ensuring that the table\n\t\t * remains readable.\n\t\t *  @type string\n\t\t *  @default null <i>Automatic</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.width\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"width\": \"20%\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"width\": \"20%\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sWidth\": null\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults.column );\n\t\n\t\n\t\n\t/**\n\t * DataTables settings object - this holds all the information needed for a\n\t * given table, including configuration, data and current application of the\n\t * table options. DataTables does not have a single instance for each DataTable\n\t * with the settings attached to that instance, but rather instances of the\n\t * DataTable \"class\" are created on-the-fly as needed (typically by a\n\t * $().dataTable() call) and the settings object is then applied to that\n\t * instance.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults} but this\n\t * one is the internal data store for DataTables's cache of columns. It should\n\t * NOT be manipulated outside of DataTables. Any configuration should be done\n\t * through the initialisation options.\n\t *  @namespace\n\t *  @todo Really should attach the settings object to individual instances so we\n\t *    don't need to create new instances on each $().dataTable() call (if the\n\t *    table already exists). It would also save passing oSettings around and\n\t *    into every single function. However, this is a very significant\n\t *    architecture change for DataTables and will almost certainly break\n\t *    backwards compatibility with older installations. This is something that\n\t *    will be done in 2.0.\n\t */\n\tDataTable.models.oSettings = {\n\t\t/**\n\t\t * Primary features of DataTables and their enablement state.\n\t\t *  @namespace\n\t\t */\n\t\t\"oFeatures\": {\n\t\n\t\t\t/**\n\t\t\t * Flag to say if DataTables should automatically try to calculate the\n\t\t\t * optimum table and columns widths (true) or not (false).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bAutoWidth\": null,\n\t\n\t\t\t/**\n\t\t\t * Delay the creation of TR and TD elements until they are actually\n\t\t\t * needed by a driven page draw. This can give a significant speed\n\t\t\t * increase for Ajax source and Javascript source data, but makes no\n\t\t\t * difference at all fro DOM and server-side processing tables.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bDeferRender\": null,\n\t\n\t\t\t/**\n\t\t\t * Enable filtering on the table or not. Note that if this is disabled\n\t\t\t * then there is no filtering at all on the table, including fnFilter.\n\t\t\t * To just remove the filtering input use sDom and remove the 'f' option.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bFilter\": null,\n\t\n\t\t\t/**\n\t\t\t * Table information element (the 'Showing x of y records' div) enable\n\t\t\t * flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bInfo\": null,\n\t\n\t\t\t/**\n\t\t\t * Present a user control allowing the end user to change the page size\n\t\t\t * when pagination is enabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bLengthChange\": null,\n\t\n\t\t\t/**\n\t\t\t * Pagination enabled or not. Note that if this is disabled then length\n\t\t\t * changing must also be disabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bPaginate\": null,\n\t\n\t\t\t/**\n\t\t\t * Processing indicator enable flag whenever DataTables is enacting a\n\t\t\t * user request - typically an Ajax request for server-side processing.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bProcessing\": null,\n\t\n\t\t\t/**\n\t\t\t * Server-side processing enabled flag - when enabled DataTables will\n\t\t\t * get all data from the server for every draw - there is no filtering,\n\t\t\t * sorting or paging done on the client-side.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bServerSide\": null,\n\t\n\t\t\t/**\n\t\t\t * Sorting enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSort\": null,\n\t\n\t\t\t/**\n\t\t\t * Multi-column sorting\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortMulti\": null,\n\t\n\t\t\t/**\n\t\t\t * Apply a class to the columns which are being sorted to provide a\n\t\t\t * visual highlight or not. This can slow things down when enabled since\n\t\t\t * there is a lot of DOM interaction.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortClasses\": null,\n\t\n\t\t\t/**\n\t\t\t * State saving enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bStateSave\": null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Scrolling settings for a table.\n\t\t *  @namespace\n\t\t */\n\t\t\"oScroll\": {\n\t\t\t/**\n\t\t\t * When the table is shorter in height than sScrollY, collapse the\n\t\t\t * table container down to the height of the table (when true).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bCollapse\": null,\n\t\n\t\t\t/**\n\t\t\t * Width of the scrollbar for the web-browser's platform. Calculated\n\t\t\t * during table initialisation.\n\t\t\t *  @type int\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"iBarWidth\": 0,\n\t\n\t\t\t/**\n\t\t\t * Viewport width for horizontal scrolling. Horizontal scrolling is\n\t\t\t * disabled if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sX\": null,\n\t\n\t\t\t/**\n\t\t\t * Width to expand the table to when using x-scrolling. Typically you\n\t\t\t * should not need to use this.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t *  @deprecated\n\t\t\t */\n\t\t\t\"sXInner\": null,\n\t\n\t\t\t/**\n\t\t\t * Viewport height for vertical scrolling. Vertical scrolling is disabled\n\t\t\t * if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sY\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Language information for the table.\n\t\t *  @namespace\n\t\t *  @extends DataTable.defaults.oLanguage\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Information callback function. See\n\t\t\t * {@link DataTable.defaults.fnInfoCallback}\n\t\t\t *  @type function\n\t\t\t *  @default null\n\t\t\t */\n\t\t\t\"fnInfoCallback\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Browser support parameters\n\t\t *  @namespace\n\t\t */\n\t\t\"oBrowser\": {\n\t\t\t/**\n\t\t\t * Indicate if the browser incorrectly calculates width:100% inside a\n\t\t\t * scrolling element (IE6/7)\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollOversize\": false,\n\t\n\t\t\t/**\n\t\t\t * Determine if the vertical scrollbar is on the right or left of the\n\t\t\t * scrolling container - needed for rtl language layout, although not\n\t\t\t * all browsers move the scrollbar (Safari).\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollbarLeft\": false,\n\t\n\t\t\t/**\n\t\t\t * Flag for if `getBoundingClientRect` is fully supported or not\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bBounding\": false,\n\t\n\t\t\t/**\n\t\t\t * Browser scrollbar width\n\t\t\t *  @type integer\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"barWidth\": 0\n\t\t},\n\t\n\t\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * Array referencing the nodes which are used for the features. The\n\t\t * parameters of this object match what is allowed by sDom - i.e.\n\t\t *   <ul>\n\t\t *     <li>'l' - Length changing</li>\n\t\t *     <li>'f' - Filtering input</li>\n\t\t *     <li>'t' - The table!</li>\n\t\t *     <li>'i' - Information</li>\n\t\t *     <li>'p' - Pagination</li>\n\t\t *     <li>'r' - pRocessing</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aanFeatures\": [],\n\t\n\t\t/**\n\t\t * Store data information - see {@link DataTable.models.oRow} for detailed\n\t\t * information.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoData\": [],\n\t\n\t\t/**\n\t\t * Array of indexes which are in the current display (after filtering etc)\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplay\": [],\n\t\n\t\t/**\n\t\t * Array of indexes for display - no filtering\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplayMaster\": [],\n\t\n\t\t/**\n\t\t * Map of row ids to data indexes\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"aIds\": {},\n\t\n\t\t/**\n\t\t * Store information about each column that is in use\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoColumns\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's header\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeader\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's footer\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooter\": [],\n\t\n\t\t/**\n\t\t * Store the applied global search information in case we want to force a\n\t\t * research or compare the old search to a new one.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t */\n\t\t\"oPreviousSearch\": {},\n\t\n\t\t/**\n\t\t * Store the applied search for each column - see\n\t\t * {@link DataTable.models.oSearch} for the format that is used for the\n\t\t * filtering information for each column.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreSearchCols\": [],\n\t\n\t\t/**\n\t\t * Sorting that is applied to the table. Note that the inner arrays are\n\t\t * used in the following manner:\n\t\t * <ul>\n\t\t *   <li>Index 0 - column number</li>\n\t\t *   <li>Index 1 - current sorting direction</li>\n\t\t * </ul>\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @todo These inner arrays should really be objects\n\t\t */\n\t\t\"aaSorting\": null,\n\t\n\t\t/**\n\t\t * Sorting that is always applied to the table (i.e. prefixed in front of\n\t\t * aaSorting).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\t/**\n\t\t * Classes to use for the striping of a table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its striping classes as well\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asDestroyStripes\": [],\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its width\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"sDestroyWidth\": 0,\n\t\n\t\t/**\n\t\t * Callback functions array for every time a row is inserted (i.e. on a draw).\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for the header on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeaderCallback\": [],\n\t\n\t\t/**\n\t\t * Callback function for the footer on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooterCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for draw callback functions\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for row created function\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCreatedCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for just before the table is redrawn. A return of\n\t\t * false will be used to cancel the draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for when the table has been initialised.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoInitComplete\": [],\n\t\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings to be stored for state saving, prior to\n\t\t * saving state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSaveParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings that have been stored for state saving\n\t\t * prior to using the stored values to restore the state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoadParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for operating on the settings object once the saved state has been\n\t\t * loaded\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoaded\": [],\n\t\n\t\t/**\n\t\t * Cache the table ID for quick access\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sTableId\": \"\",\n\t\n\t\t/**\n\t\t * The TABLE node for the main table\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTable\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the thead element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTHead\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tfoot element - if it exists\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTFoot\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tbody element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTBody\": null,\n\t\n\t\t/**\n\t\t * Cache the wrapper node (contains all DataTables controlled elements)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTableWrapper\": null,\n\t\n\t\t/**\n\t\t * Indicate if when using server-side processing the loading of data\n\t\t * should be deferred until the second draw.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDeferLoading\": false,\n\t\n\t\t/**\n\t\t * Indicate if all required information has been read in\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bInitialised\": false,\n\t\n\t\t/**\n\t\t * Information about open rows. Each object in the array has the parameters\n\t\t * 'nTr' and 'nParent'\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoOpenRows\": [],\n\t\n\t\t/**\n\t\t * Dictate the positioning of DataTables' control elements - see\n\t\t * {@link DataTable.model.oInit.sDom}.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDom\": null,\n\t\n\t\t/**\n\t\t * Search delay (in mS)\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\t/**\n\t\t * Which type of pagination should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default two_button\n\t\t */\n\t\t\"sPaginationType\": \"two_button\",\n\t\n\t\t/**\n\t\t * The state duration (for `stateSave`) in seconds.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iStateDuration\": 0,\n\t\n\t\t/**\n\t\t * Array of callback functions for state saving. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the JSON string to save that has been thus far created. Returns\n\t\t *       a JSON string to be inserted into a json object\n\t\t *       (i.e. '\"param\": [ 0, 1, 2]')</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSave\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for state loading. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the object stored. May return false to cancel state loading</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoad\": [],\n\t\n\t\t/**\n\t\t * State that was saved. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oSavedState\": null,\n\t\n\t\t/**\n\t\t * State that was loaded. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oLoadedState\": null,\n\t\n\t\t/**\n\t\t * Source url for AJAX data for the table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\t/**\n\t\t * Property from a given object from which to read the table data from. This\n\t\t * can be an empty string (when not server-side processing), in which case\n\t\t * it is  assumed an an array is given directly.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sAjaxDataProp\": null,\n\t\n\t\t/**\n\t\t * Note if draw should be blocked while getting data\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bAjaxDataGet\": true,\n\t\n\t\t/**\n\t\t * The last jQuery XHR object that was used for server-side data gathering.\n\t\t * This can be used for working with the XHR information in one of the\n\t\t * callbacks\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"jqXHR\": null,\n\t\n\t\t/**\n\t\t * JSON returned from the server in the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"json\": undefined,\n\t\n\t\t/**\n\t\t * Data submitted as part of the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"oAjaxData\": undefined,\n\t\n\t\t/**\n\t\t * Function to get the server-side data.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\t/**\n\t\t * Functions which are called prior to sending an Ajax request so extra\n\t\t * parameters can easily be sent to the server\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoServerParams\": [],\n\t\n\t\t/**\n\t\t * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if\n\t\t * required).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sServerMethod\": null,\n\t\n\t\t/**\n\t\t * Format numbers for display.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnFormatNumber\": null,\n\t\n\t\t/**\n\t\t * List of options that can be used for the user selectable length menu.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLengthMenu\": null,\n\t\n\t\t/**\n\t\t * Counter for the draws that the table does. Also used as a tracker for\n\t\t * server-side processing\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iDraw\": 0,\n\t\n\t\t/**\n\t\t * Indicate if a redraw is being done - useful for Ajax\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDrawing\": false,\n\t\n\t\t/**\n\t\t * Draw index (iDraw) of the last error when parsing the returned data\n\t\t *  @type int\n\t\t *  @default -1\n\t\t */\n\t\t\"iDrawError\": -1,\n\t\n\t\t/**\n\t\t * Paging display length\n\t\t *  @type int\n\t\t *  @default 10\n\t\t */\n\t\t\"_iDisplayLength\": 10,\n\t\n\t\t/**\n\t\t * Paging start point - aiDisplay index\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"_iDisplayStart\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the result set\n\t\t * (i.e. before filtering), Use fnRecordsTotal rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsTotal\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the current display set\n\t\t * (i.e. after filtering). Use fnRecordsDisplay rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type boolean\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsDisplay\": 0,\n\t\n\t\t/**\n\t\t * Flag to indicate if jQuery UI marking and classes should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bJUI\": null,\n\t\n\t\t/**\n\t\t * The classes to use for the table\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if filtering has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bFiltered\": false,\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if sorting has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bSorted\": false,\n\t\n\t\t/**\n\t\t * Indicate that if multiple rows are in the header and there is more than\n\t\t * one unique cell per column, if the top one (true) or bottom one (false)\n\t\t * should be used for sorting / title by DataTables.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortCellsTop\": null,\n\t\n\t\t/**\n\t\t * Initialisation object that is used for the table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInit\": null,\n\t\n\t\t/**\n\t\t * Destroy callback functions - for plug-ins to attach themselves to the\n\t\t * destroy so they can clean up markup and events.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDestroyCallback\": [],\n\t\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, before filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsTotal\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsTotal * 1 :\n\t\t\t\tthis.aiDisplayMaster.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, after filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsDisplay\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsDisplay * 1 :\n\t\t\t\tthis.aiDisplay.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the display end point - aiDisplay index\n\t\t *  @type function\n\t\t */\n\t\t\"fnDisplayEnd\": function ()\n\t\t{\n\t\t\tvar\n\t\t\t\tlen      = this._iDisplayLength,\n\t\t\t\tstart    = this._iDisplayStart,\n\t\t\t\tcalc     = start + len,\n\t\t\t\trecords  = this.aiDisplay.length,\n\t\t\t\tfeatures = this.oFeatures,\n\t\t\t\tpaginate = features.bPaginate;\n\t\n\t\t\tif ( features.bServerSide ) {\n\t\t\t\treturn paginate === false || len === -1 ?\n\t\t\t\t\tstart + records :\n\t\t\t\t\tMath.min( start+len, this._iRecordsDisplay );\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn ! paginate || calc>records || len===-1 ?\n\t\t\t\t\trecords :\n\t\t\t\t\tcalc;\n\t\t\t}\n\t\t},\n\t\n\t\t/**\n\t\t * The DataTables object for this table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInstance\": null,\n\t\n\t\t/**\n\t\t * Unique identifier for each instance of the DataTables object. If there\n\t\t * is an ID on the table node, then it takes that value, otherwise an\n\t\t * incrementing internal counter is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sInstance\": null,\n\t\n\t\t/**\n\t\t * tabindex attribute value that is added to DataTables control elements, allowing\n\t\t * keyboard navigation of the table and its controls.\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollHead\": null,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollFoot\": null,\n\t\n\t\t/**\n\t\t * Last applied sort\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLastSort\": [],\n\t\n\t\t/**\n\t\t * Stored plug-in instances\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oPlugins\": {},\n\t\n\t\t/**\n\t\t * Function used to get a row's id from the row's data\n\t\t *  @type function\n\t\t *  @default null\n\t\t */\n\t\t\"rowIdFn\": null,\n\t\n\t\t/**\n\t\t * Data location where to store a row's id\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"rowId\": null\n\t};\n\n\t/**\n\t * Extension object for DataTables that is used to provide all extension\n\t * options.\n\t *\n\t * Note that the `DataTable.ext` object is available through\n\t * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is\n\t * also aliased to `jQuery.fn.dataTableExt` for historic reasons.\n\t *  @namespace\n\t *  @extends DataTable.models.ext\n\t */\n\t\n\t\n\t/**\n\t * DataTables extensions\n\t * \n\t * This namespace acts as a collection area for plug-ins that can be used to\n\t * extend DataTables capabilities. Indeed many of the build in methods\n\t * use this method to provide their own capabilities (sorting methods for\n\t * example).\n\t *\n\t * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy\n\t * reasons\n\t *\n\t *  @namespace\n\t */\n\tDataTable.ext = _ext = {\n\t\t/**\n\t\t * Buttons. For use with the Buttons extension for DataTables. This is\n\t\t * defined here so other extensions can define buttons regardless of load\n\t\t * order. It is _not_ used by DataTables core.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tbuttons: {},\n\t\n\t\n\t\t/**\n\t\t * Element class names\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tclasses: {},\n\t\n\t\n\t\t/**\n\t\t * DataTables build type (expanded by the download builder)\n\t\t *\n\t\t *  @type string\n\t\t */\n\t\tbuilder: \"-source-\",\n\t\n\t\n\t\t/**\n\t\t * Error reporting.\n\t\t * \n\t\t * How should DataTables report an error. Can take the value 'alert',\n\t\t * 'throw', 'none' or a function.\n\t\t *\n\t\t *  @type string|function\n\t\t *  @default alert\n\t\t */\n\t\terrMode: \"alert\",\n\t\n\t\n\t\t/**\n\t\t * Feature plug-ins.\n\t\t * \n\t\t * This is an array of objects which describe the feature plug-ins that are\n\t\t * available to DataTables. These feature plug-ins are then available for\n\t\t * use through the `dom` initialisation option.\n\t\t * \n\t\t * Each feature plug-in is described by an object which must have the\n\t\t * following properties:\n\t\t * \n\t\t * * `fnInit` - function that is used to initialise the plug-in,\n\t\t * * `cFeature` - a character so the feature can be enabled by the `dom`\n\t\t *   instillation option. This is case sensitive.\n\t\t *\n\t\t * The `fnInit` function has the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *\n\t\t * And the following return is expected:\n\t\t * \n\t\t * * {node|null} The element which contains your feature. Note that the\n\t\t *   return may also be void if your plug-in does not require to inject any\n\t\t *   DOM elements into DataTables control (`dom`) - for example this might\n\t\t *   be useful when developing a plug-in which allows table control via\n\t\t *   keyboard entry\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    $.fn.dataTable.ext.features.push( {\n\t\t *      \"fnInit\": function( oSettings ) {\n\t\t *        return new TableTools( { \"oDTSettings\": oSettings } );\n\t\t *      },\n\t\t *      \"cFeature\": \"T\"\n\t\t *    } );\n\t\t */\n\t\tfeature: [],\n\t\n\t\n\t\t/**\n\t\t * Row searching.\n\t\t * \n\t\t * This method of searching is complimentary to the default type based\n\t\t * searching, and a lot more comprehensive as it allows you complete control\n\t\t * over the searching logic. Each element in this array is a function\n\t\t * (parameters described below) that is called for every row in the table,\n\t\t * and your logic decides if it should be included in the searching data set\n\t\t * or not.\n\t\t *\n\t\t * Searching functions have the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{array|object}` Data for the row to be processed (same as the\n\t\t *    original format that was passed in as the data source, or an array\n\t\t *    from a DOM data source\n\t\t * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which\n\t\t *    can be useful to retrieve the `TR` element if you need DOM interaction.\n\t\t *\n\t\t * And the following return is expected:\n\t\t *\n\t\t * * {boolean} Include the row in the searched result set (true) or not\n\t\t *   (false)\n\t\t *\n\t\t * Note that as with the main search ability in DataTables, technically this\n\t\t * is \"filtering\", since it is subtractive. However, for consistency in\n\t\t * naming we call it searching here.\n\t\t *\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @example\n\t\t *    // The following example shows custom search being applied to the\n\t\t *    // fourth column (i.e. the data[3] index) based on two input values\n\t\t *    // from the end-user, matching the data in a certain range.\n\t\t *    $.fn.dataTable.ext.search.push(\n\t\t *      function( settings, data, dataIndex ) {\n\t\t *        var min = document.getElementById('min').value * 1;\n\t\t *        var max = document.getElementById('max').value * 1;\n\t\t *        var version = data[3] == \"-\" ? 0 : data[3]*1;\n\t\t *\n\t\t *        if ( min == \"\" && max == \"\" ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min == \"\" && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && \"\" == max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        return false;\n\t\t *      }\n\t\t *    );\n\t\t */\n\t\tsearch: [],\n\t\n\t\n\t\t/**\n\t\t * Selector extensions\n\t\t *\n\t\t * The `selector` option can be used to extend the options available for the\n\t\t * selector modifier options (`selector-modifier` object data type) that\n\t\t * each of the three built in selector types offer (row, column and cell +\n\t\t * their plural counterparts). For example the Select extension uses this\n\t\t * mechanism to provide an option to select only rows, columns and cells\n\t\t * that have been marked as selected by the end user (`{selected: true}`),\n\t\t * which can be used in conjunction with the existing built in selector\n\t\t * options.\n\t\t *\n\t\t * Each property is an array to which functions can be pushed. The functions\n\t\t * take three attributes:\n\t\t *\n\t\t * * Settings object for the host table\n\t\t * * Options object (`selector-modifier` object type)\n\t\t * * Array of selected item indexes\n\t\t *\n\t\t * The return is an array of the resulting item indexes after the custom\n\t\t * selector has been applied.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tselector: {\n\t\t\tcell: [],\n\t\t\tcolumn: [],\n\t\t\trow: []\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Internal functions, exposed for used in plug-ins.\n\t\t * \n\t\t * Please note that you should not need to use the internal methods for\n\t\t * anything other than a plug-in (and even then, try to avoid if possible).\n\t\t * The internal function may change between releases.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tinternal: {},\n\t\n\t\n\t\t/**\n\t\t * Legacy configuration options. Enable and disable legacy options that\n\t\t * are available in DataTables.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tlegacy: {\n\t\t\t/**\n\t\t\t * Enable / disable DataTables 1.9 compatible server-side processing\n\t\t\t * requests\n\t\t\t *\n\t\t\t *  @type boolean\n\t\t\t *  @default null\n\t\t\t */\n\t\t\tajax: null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Pagination plug-in methods.\n\t\t * \n\t\t * Each entry in this object is a function and defines which buttons should\n\t\t * be shown by the pagination rendering method that is used for the table:\n\t\t * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the\n\t\t * buttons are displayed in the document, while the functions here tell it\n\t\t * what buttons to display. This is done by returning an array of button\n\t\t * descriptions (what each button will do).\n\t\t *\n\t\t * Pagination types (the four built in options and any additional plug-in\n\t\t * options defined here) can be used through the `paginationType`\n\t\t * initialisation parameter.\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{int} page` The current page index\n\t\t * 2. `{int} pages` The number of pages in the table\n\t\t *\n\t\t * Each function is expected to return an array where each element of the\n\t\t * array can be one of:\n\t\t *\n\t\t * * `first` - Jump to first page when activated\n\t\t * * `last` - Jump to last page when activated\n\t\t * * `previous` - Show previous page when activated\n\t\t * * `next` - Show next page when activated\n\t\t * * `{int}` - Show page of the index given\n\t\t * * `{array}` - A nested array containing the above elements to add a\n\t\t *   containing 'DIV' element (might be useful for styling).\n\t\t *\n\t\t * Note that DataTables v1.9- used this object slightly differently whereby\n\t\t * an object with two functions would be defined for each plug-in. That\n\t\t * ability is still supported by DataTables 1.10+ to provide backwards\n\t\t * compatibility, but this option of use is now decremented and no longer\n\t\t * documented in DataTables 1.10+.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t *\n\t\t *  @example\n\t\t *    // Show previous, next and current page buttons only\n\t\t *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {\n\t\t *      return [ 'previous', page, 'next' ];\n\t\t *    };\n\t\t */\n\t\tpager: {},\n\t\n\t\n\t\trenderer: {\n\t\t\tpageButton: {},\n\t\t\theader: {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Ordering plug-ins - custom data source\n\t\t * \n\t\t * The extension options for ordering of data available here is complimentary\n\t\t * to the default type based ordering that DataTables typically uses. It\n\t\t * allows much greater control over the the data that is being used to\n\t\t * order a column, but is necessarily therefore more complex.\n\t\t * \n\t\t * This type of ordering is useful if you want to do ordering based on data\n\t\t * live from the DOM (for example the contents of an 'input' element) rather\n\t\t * than just the static string that DataTables knows of.\n\t\t * \n\t\t * The way these plug-ins work is that you create an array of the values you\n\t\t * wish to be ordering for the column in question and then return that\n\t\t * array. The data in the array much be in the index order of the rows in\n\t\t * the table (not the currently ordering order!). Which order data gathering\n\t\t * function is run here depends on the `dt-init columns.orderDataType`\n\t\t * parameter that is used for the column (if any).\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{int}` Target column index\n\t\t *\n\t\t * Each function is expected to return an array:\n\t\t *\n\t\t * * `{array}` Data for the column to be ordering upon\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    // Ordering using `input` node values\n\t\t *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )\n\t\t *    {\n\t\t *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {\n\t\t *        return $('input', td).val();\n\t\t *      } );\n\t\t *    }\n\t\t */\n\t\torder: {},\n\t\n\t\n\t\t/**\n\t\t * Type based plug-ins.\n\t\t *\n\t\t * Each column in DataTables has a type assigned to it, either by automatic\n\t\t * detection or by direct assignment using the `type` option for the column.\n\t\t * The type of a column will effect how it is ordering and search (plug-ins\n\t\t * can also make use of the column type if required).\n\t\t *\n\t\t * @namespace\n\t\t */\n\t\ttype: {\n\t\t\t/**\n\t\t\t * Type detection functions.\n\t\t\t *\n\t\t\t * The functions defined in this object are used to automatically detect\n\t\t\t * a column's type, making initialisation of DataTables super easy, even\n\t\t\t * when complex data is in the table.\n\t\t\t *\n\t\t\t * The functions defined take two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be analysed\n\t\t     *  2. `{settings}` DataTables settings object. This can be used to\n\t\t     *     perform context specific type detection - for example detection\n\t\t     *     based on language settings such as using a comma for a decimal\n\t\t     *     place. Generally speaking the options from the settings will not\n\t\t     *     be required\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Data type detected, or null if unknown (and thus\n\t\t\t *   pass it on to the other type detection functions.\n\t\t\t *\n\t\t\t *  @type array\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Currency type detection plug-in:\n\t\t\t *    $.fn.dataTable.ext.type.detect.push(\n\t\t\t *      function ( data, settings ) {\n\t\t\t *        // Check the numeric part\n\t\t\t *        if ( ! $.isNumeric( data.substring(1) ) ) {\n\t\t\t *          return null;\n\t\t\t *        }\n\t\t\t *\n\t\t\t *        // Check prefixed by currency\n\t\t\t *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {\n\t\t\t *          return 'currency';\n\t\t\t *        }\n\t\t\t *        return null;\n\t\t\t *      }\n\t\t\t *    );\n\t\t\t */\n\t\t\tdetect: [],\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based search formatting.\n\t\t\t *\n\t\t\t * The type based searching functions can be used to pre-format the\n\t\t\t * data to be search on. For example, it can be used to strip HTML\n\t\t\t * tags or to de-format telephone numbers for numeric only searching.\n\t\t\t *\n\t\t\t * Note that is a search is not defined for a column of a given type,\n\t\t\t * no search formatting will be performed.\n\t\t\t * \n\t\t\t * Pre-processing of searching data plug-ins - When you assign the sType\n\t\t\t * for a column (or have it automatically detected for you by DataTables\n\t\t\t * or a type detection plug-in), you will typically be using this for\n\t\t\t * custom sorting, but it can also be used to provide custom searching\n\t\t\t * by allowing you to pre-processing the data and returning the data in\n\t\t\t * the format that should be searched upon. This is done by adding\n\t\t\t * functions this object with a parameter name which matches the sType\n\t\t\t * for that target column. This is the corollary of <i>afnSortData</i>\n\t\t\t * for searching data.\n\t\t\t *\n\t\t\t * The functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for searching\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Formatted string that will be used for the searching.\n\t\t\t *\n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {\n\t\t\t *      return d.replace(/\\n/g,\" \").replace( /<.*?>/g, \"\" );\n\t\t\t *    }\n\t\t\t */\n\t\t\tsearch: {},\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based ordering.\n\t\t\t *\n\t\t\t * The column type tells DataTables what ordering to apply to the table\n\t\t\t * when a column is sorted upon. The order for each type that is defined,\n\t\t\t * is defined by the functions available in this object.\n\t\t\t *\n\t\t\t * Each ordering option can be described by three properties added to\n\t\t\t * this object:\n\t\t\t *\n\t\t\t * * `{type}-pre` - Pre-formatting function\n\t\t\t * * `{type}-asc` - Ascending order function\n\t\t\t * * `{type}-desc` - Descending order function\n\t\t\t *\n\t\t\t * All three can be used together, only `{type}-pre` or only\n\t\t\t * `{type}-asc` and `{type}-desc` together. It is generally recommended\n\t\t\t * that only `{type}-pre` is used, as this provides the optimal\n\t\t\t * implementation in terms of speed, although the others are provided\n\t\t\t * for compatibility with existing Javascript sort functions.\n\t\t\t *\n\t\t\t * `{type}-pre`: Functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for ordering\n\t\t\t *\n\t\t\t * And return:\n\t\t\t *\n\t\t\t * * `{*}` Data to be sorted upon\n\t\t\t *\n\t\t\t * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort\n\t\t\t * functions, taking two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data to compare to the second parameter\n\t\t     *  2. `{*}` Data to compare to the first parameter\n\t\t\t *\n\t\t\t * And returning:\n\t\t\t *\n\t\t\t * * `{*}` Ordering match: <0 if first parameter should be sorted lower\n\t\t\t *   than the second parameter, ===0 if the two parameters are equal and\n\t\t\t *   >0 if the first parameter should be sorted height than the second\n\t\t\t *   parameter.\n\t\t\t * \n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Numeric ordering of formatted numbers with a pre-formatter\n\t\t\t *    $.extend( $.fn.dataTable.ext.type.order, {\n\t\t\t *      \"string-pre\": function(x) {\n\t\t\t *        a = (a === \"-\" || a === \"\") ? 0 : a.replace( /[^\\d\\-\\.]/g, \"\" );\n\t\t\t *        return parseFloat( a );\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Case-sensitive string ordering, with no pre-formatting method\n\t\t\t *    $.extend( $.fn.dataTable.ext.order, {\n\t\t\t *      \"string-case-asc\": function(x,y) {\n\t\t\t *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t\t *      },\n\t\t\t *      \"string-case-desc\": function(x,y) {\n\t\t\t *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t */\n\t\t\torder: {}\n\t\t},\n\t\n\t\t/**\n\t\t * Unique DataTables instance counter\n\t\t *\n\t\t * @type int\n\t\t * @private\n\t\t */\n\t\t_unique: 0,\n\t\n\t\n\t\t//\n\t\t// Depreciated\n\t\t// The following properties are retained for backwards compatiblity only.\n\t\t// The should not be used in new projects and will be removed in a future\n\t\t// version\n\t\t//\n\t\n\t\t/**\n\t\t * Version check function.\n\t\t *  @type function\n\t\t *  @depreciated Since 1.10\n\t\t */\n\t\tfnVersionCheck: DataTable.fnVersionCheck,\n\t\n\t\n\t\t/**\n\t\t * Index for what 'this' index API functions should use\n\t\t *  @type int\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tiApiIndex: 0,\n\t\n\t\n\t\t/**\n\t\t * jQuery UI class container\n\t\t *  @type object\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\toJUIClasses: {},\n\t\n\t\n\t\t/**\n\t\t * Software version\n\t\t *  @type string\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tsVersion: DataTable.version\n\t};\n\t\n\t\n\t//\n\t// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts\n\t//\n\t$.extend( _ext, {\n\t\tafnFiltering: _ext.search,\n\t\taTypes:       _ext.type.detect,\n\t\tofnSearch:    _ext.type.search,\n\t\toSort:        _ext.type.order,\n\t\tafnSortData:  _ext.order,\n\t\taoFeatures:   _ext.feature,\n\t\toApi:         _ext.internal,\n\t\toStdClasses:  _ext.classes,\n\t\toPagination:  _ext.pager\n\t} );\n\t\n\t\n\t$.extend( DataTable.ext.classes, {\n\t\t\"sTable\": \"dataTable\",\n\t\t\"sNoFooter\": \"no-footer\",\n\t\n\t\t/* Paging buttons */\n\t\t\"sPageButton\": \"paginate_button\",\n\t\t\"sPageButtonActive\": \"current\",\n\t\t\"sPageButtonDisabled\": \"disabled\",\n\t\n\t\t/* Striping classes */\n\t\t\"sStripeOdd\": \"odd\",\n\t\t\"sStripeEven\": \"even\",\n\t\n\t\t/* Empty row */\n\t\t\"sRowEmpty\": \"dataTables_empty\",\n\t\n\t\t/* Features */\n\t\t\"sWrapper\": \"dataTables_wrapper\",\n\t\t\"sFilter\": \"dataTables_filter\",\n\t\t\"sInfo\": \"dataTables_info\",\n\t\t\"sPaging\": \"dataTables_paginate paging_\", /* Note that the type is postfixed */\n\t\t\"sLength\": \"dataTables_length\",\n\t\t\"sProcessing\": \"dataTables_processing\",\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\": \"sorting_asc\",\n\t\t\"sSortDesc\": \"sorting_desc\",\n\t\t\"sSortable\": \"sorting\", /* Sortable in both directions */\n\t\t\"sSortableAsc\": \"sorting_asc_disabled\",\n\t\t\"sSortableDesc\": \"sorting_desc_disabled\",\n\t\t\"sSortableNone\": \"sorting_disabled\",\n\t\t\"sSortColumn\": \"sorting_\", /* Note that an int is postfixed for the sorting order */\n\t\n\t\t/* Filtering */\n\t\t\"sFilterInput\": \"\",\n\t\n\t\t/* Page length */\n\t\t\"sLengthSelect\": \"\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollWrapper\": \"dataTables_scroll\",\n\t\t\"sScrollHead\": \"dataTables_scrollHead\",\n\t\t\"sScrollHeadInner\": \"dataTables_scrollHeadInner\",\n\t\t\"sScrollBody\": \"dataTables_scrollBody\",\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot\",\n\t\t\"sScrollFootInner\": \"dataTables_scrollFootInner\",\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\": \"\",\n\t\t\"sFooterTH\": \"\",\n\t\n\t\t// Deprecated\n\t\t\"sSortJUIAsc\": \"\",\n\t\t\"sSortJUIDesc\": \"\",\n\t\t\"sSortJUI\": \"\",\n\t\t\"sSortJUIAscAllowed\": \"\",\n\t\t\"sSortJUIDescAllowed\": \"\",\n\t\t\"sSortJUIWrapper\": \"\",\n\t\t\"sSortIcon\": \"\",\n\t\t\"sJUIHeader\": \"\",\n\t\t\"sJUIFooter\": \"\"\n\t} );\n\t\n\t\n\t(function() {\n\t\n\t// Reused strings for better compression. Closure compiler appears to have a\n\t// weird edge case where it is trying to expand strings rather than use the\n\t// variable version. This results in about 200 bytes being added, for very\n\t// little preference benefit since it this run on script load only.\n\tvar _empty = '';\n\t_empty = '';\n\t\n\tvar _stateDefault = _empty + 'ui-state-default';\n\tvar _sortIcon     = _empty + 'css_right ui-icon ui-icon-';\n\tvar _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';\n\t\n\t$.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {\n\t\t/* Full numbers paging buttons */\n\t\t\"sPageButton\":         \"fg-button ui-button \"+_stateDefault,\n\t\t\"sPageButtonActive\":   \"ui-state-disabled\",\n\t\t\"sPageButtonDisabled\": \"ui-state-disabled\",\n\t\n\t\t/* Features */\n\t\t\"sPaging\": \"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi \"+\n\t\t\t\"ui-buttonset-multi paging_\", /* Note that the type is postfixed */\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\":            _stateDefault+\" sorting_asc\",\n\t\t\"sSortDesc\":           _stateDefault+\" sorting_desc\",\n\t\t\"sSortable\":           _stateDefault+\" sorting\",\n\t\t\"sSortableAsc\":        _stateDefault+\" sorting_asc_disabled\",\n\t\t\"sSortableDesc\":       _stateDefault+\" sorting_desc_disabled\",\n\t\t\"sSortableNone\":       _stateDefault+\" sorting_disabled\",\n\t\t\"sSortJUIAsc\":         _sortIcon+\"triangle-1-n\",\n\t\t\"sSortJUIDesc\":        _sortIcon+\"triangle-1-s\",\n\t\t\"sSortJUI\":            _sortIcon+\"carat-2-n-s\",\n\t\t\"sSortJUIAscAllowed\":  _sortIcon+\"carat-1-n\",\n\t\t\"sSortJUIDescAllowed\": _sortIcon+\"carat-1-s\",\n\t\t\"sSortJUIWrapper\":     \"DataTables_sort_wrapper\",\n\t\t\"sSortIcon\":           \"DataTables_sort_icon\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollHead\": \"dataTables_scrollHead \"+_stateDefault,\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot \"+_stateDefault,\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\":  _stateDefault,\n\t\t\"sFooterTH\":  _stateDefault,\n\t\t\"sJUIHeader\": _headerFooter+\" ui-corner-tl ui-corner-tr\",\n\t\t\"sJUIFooter\": _headerFooter+\" ui-corner-bl ui-corner-br\"\n\t} );\n\t\n\t}());\n\t\n\t\n\t\n\tvar extPagination = DataTable.ext.pager;\n\t\n\tfunction _numbers ( page, pages ) {\n\t\tvar\n\t\t\tnumbers = [],\n\t\t\tbuttons = extPagination.numbers_length,\n\t\t\thalf = Math.floor( buttons / 2 ),\n\t\t\ti = 1;\n\t\n\t\tif ( pages <= buttons ) {\n\t\t\tnumbers = _range( 0, pages );\n\t\t}\n\t\telse if ( page <= half ) {\n\t\t\tnumbers = _range( 0, buttons-2 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t}\n\t\telse if ( page >= pages - 1 - half ) {\n\t\t\tnumbers = _range( pages-(buttons-2), pages );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\telse {\n\t\t\tnumbers = _range( page-half+2, page+half-1 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' );\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\n\t\tnumbers.DT_el = 'span';\n\t\treturn numbers;\n\t}\n\t\n\t\n\t$.extend( extPagination, {\n\t\tsimple: function ( page, pages ) {\n\t\t\treturn [ 'previous', 'next' ];\n\t\t},\n\t\n\t\tfull: function ( page, pages ) {\n\t\t\treturn [  'first', 'previous', 'next', 'last' ];\n\t\t},\n\t\n\t\tnumbers: function ( page, pages ) {\n\t\t\treturn [ _numbers(page, pages) ];\n\t\t},\n\t\n\t\tsimple_numbers: function ( page, pages ) {\n\t\t\treturn [ 'previous', _numbers(page, pages), 'next' ];\n\t\t},\n\t\n\t\tfull_numbers: function ( page, pages ) {\n\t\t\treturn [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];\n\t\t},\n\t\t\n\t\tfirst_last_numbers: function (page, pages) {\n\t \t\treturn ['first', _numbers(page, pages), 'last'];\n\t \t},\n\t\n\t\t// For testing and plug-ins to use\n\t\t_numbers: _numbers,\n\t\n\t\t// Number of number buttons (including ellipsis) to show. _Must be odd!_\n\t\tnumbers_length: 7\n\t} );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\tpageButton: {\n\t\t\t_: function ( settings, host, idx, buttons, page, pages ) {\n\t\t\t\tvar classes = settings.oClasses;\n\t\t\t\tvar lang = settings.oLanguage.oPaginate;\n\t\t\t\tvar aria = settings.oLanguage.oAria.paginate || {};\n\t\t\t\tvar btnDisplay, btnClass, counter=0;\n\t\n\t\t\t\tvar attach = function( container, buttons ) {\n\t\t\t\t\tvar i, ien, node, button;\n\t\t\t\t\tvar clickHandler = function ( e ) {\n\t\t\t\t\t\t_fnPageChange( settings, e.data.action, true );\n\t\t\t\t\t};\n\t\n\t\t\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tbutton = buttons[i];\n\t\n\t\t\t\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\t\t\t\tvar inner = $( '<'+(button.DT_el || 'div')+'/>' )\n\t\t\t\t\t\t\t\t.appendTo( container );\n\t\t\t\t\t\t\tattach( inner, button );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tbtnDisplay = null;\n\t\t\t\t\t\t\tbtnClass = '';\n\t\n\t\t\t\t\t\t\tswitch ( button ) {\n\t\t\t\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\t\t\t\tcontainer.append('<span class=\"ellipsis\">&#x2026;</span>');\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'first':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'next':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'last':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t\t\t\tclasses.sPageButtonActive : '';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\tif ( btnDisplay !== null ) {\n\t\t\t\t\t\t\t\tnode = $('<a>', {\n\t\t\t\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t\t\t\t.appendTo( container );\n\t\n\t\t\t\t\t\t\t\t_fnBindAction(\n\t\t\t\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t\t\t\t);\n\t\n\t\t\t\t\t\t\t\tcounter++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame. Try / catch the error. Not good for\n\t\t\t\t// accessibility, but neither are frames.\n\t\t\t\tvar activeEl;\n\t\n\t\t\t\ttry {\n\t\t\t\t\t// Because this approach is destroying and recreating the paging\n\t\t\t\t\t// elements, focus is lost on the select button which is bad for\n\t\t\t\t\t// accessibility. So we want to restore focus once the draw has\n\t\t\t\t\t// completed\n\t\t\t\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t\t\t\t}\n\t\t\t\tcatch (e) {}\n\t\n\t\t\t\tattach( $(host).empty(), buttons );\n\t\n\t\t\t\tif ( activeEl !== undefined ) {\n\t\t\t\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t\n\t\n\t// Built in type detection. See model.ext.aTypes for information about\n\t// what is required from this methods.\n\t$.extend( DataTable.ext.type.detect, [\n\t\t// Plain numbers - first since V8 detects some plain numbers as dates\n\t\t// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal ) ? 'num'+decimal : null;\n\t\t},\n\t\n\t\t// Dates (only those recognised by the browser's Date.parse)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\t// V8 tries _very_ hard to make a string passed into `Date.parse()`\n\t\t\t// valid, so we need to use a regex to restrict date formats. Use a\n\t\t\t// plug-in for anything other than ISO8601 style strings\n\t\t\tif ( d && !(d instanceof Date) && ! _re_date.test(d) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tvar parsed = Date.parse(d);\n\t\t\treturn (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;\n\t\t},\n\t\n\t\t// Formatted numbers\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric, formatted\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML (this is strict checking - there must be html)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\treturn _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?\n\t\t\t\t'html' : null;\n\t\t}\n\t] );\n\t\n\t\n\t\n\t// Filter formatting functions. See model.ext.ofnSearch for information about\n\t// what is required from these methods.\n\t// \n\t// Note that additional search methods are added for the html numbers and\n\t// html formatted numbers by `_addNumericSort()` when we know what the decimal\n\t// place is\n\t\n\t\n\t$.extend( DataTable.ext.type.search, {\n\t\thtml: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata\n\t\t\t\t\t\t.replace( _re_new_lines, \" \" )\n\t\t\t\t\t\t.replace( _re_html, \"\" ) :\n\t\t\t\t\t'';\n\t\t},\n\t\n\t\tstring: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata.replace( _re_new_lines, \" \" ) :\n\t\t\t\t\tdata;\n\t\t}\n\t} );\n\t\n\t\n\t\n\tvar __numericReplace = function ( d, decimalPlace, re1, re2 ) {\n\t\tif ( d !== 0 && (!d || d === '-') ) {\n\t\t\treturn -Infinity;\n\t\t}\n\t\n\t\t// If a decimal place other than `.` is used, it needs to be given to the\n\t\t// function so we can detect it and replace with a `.` which is the only\n\t\t// decimal place Javascript recognises - it is not locale aware.\n\t\tif ( decimalPlace ) {\n\t\t\td = _numToDecimal( d, decimalPlace );\n\t\t}\n\t\n\t\tif ( d.replace ) {\n\t\t\tif ( re1 ) {\n\t\t\t\td = d.replace( re1, '' );\n\t\t\t}\n\t\n\t\t\tif ( re2 ) {\n\t\t\t\td = d.replace( re2, '' );\n\t\t\t}\n\t\t}\n\t\n\t\treturn d * 1;\n\t};\n\t\n\t\n\t// Add the numeric 'deformatting' functions for sorting and search. This is done\n\t// in a function to provide an easy ability for the language options to add\n\t// additional methods if a non-period decimal place is used.\n\tfunction _addNumericSort ( decimalPlace ) {\n\t\t$.each(\n\t\t\t{\n\t\t\t\t// Plain numbers\n\t\t\t\t\"num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace );\n\t\t\t\t},\n\t\n\t\t\t\t// Formatted numbers\n\t\t\t\t\"num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_formatted_numeric );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric\n\t\t\t\t\"html-num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric, formatted\n\t\t\t\t\"html-num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );\n\t\t\t\t}\n\t\t\t},\n\t\t\tfunction ( key, fn ) {\n\t\t\t\t// Add the ordering method\n\t\t\t\t_ext.type.order[ key+decimalPlace+'-pre' ] = fn;\n\t\n\t\t\t\t// For HTML types add a search formatter that will strip the HTML\n\t\t\t\tif ( key.match(/^html\\-/) ) {\n\t\t\t\t\t_ext.type.search[ key+decimalPlace ] = _ext.type.search.html;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\t\n\t\n\t// Default sort methods\n\t$.extend( _ext.type.order, {\n\t\t// Dates\n\t\t\"date-pre\": function ( d ) {\n\t\t\treturn Date.parse( d ) || -Infinity;\n\t\t},\n\t\n\t\t// html\n\t\t\"html-pre\": function ( a ) {\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ta.replace ?\n\t\t\t\t\ta.replace( /<.*?>/g, \"\" ).toLowerCase() :\n\t\t\t\t\ta+'';\n\t\t},\n\t\n\t\t// string\n\t\t\"string-pre\": function ( a ) {\n\t\t\t// This is a little complex, but faster than always calling toString,\n\t\t\t// http://jsperf.com/tostring-v-check\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ttypeof a === 'string' ?\n\t\t\t\t\ta.toLowerCase() :\n\t\t\t\t\t! a.toString ?\n\t\t\t\t\t\t'' :\n\t\t\t\t\t\ta.toString();\n\t\t},\n\t\n\t\t// string-asc and -desc are retained only for compatibility with the old\n\t\t// sort methods\n\t\t\"string-asc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t},\n\t\n\t\t\"string-desc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t}\n\t} );\n\t\n\t\n\t// Numeric sorting types - order doesn't matter here\n\t_addNumericSort( '' );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\theader: {\n\t\t\t_: function ( settings, cell, column, classes ) {\n\t\t\t\t// No additional mark-up required\n\t\t\t\t// Attach a sort listener to update on sort - note that using the\n\t\t\t\t// `DT` namespace will allow the event to be removed automatically\n\t\t\t\t// on destroy, while the `dt` namespaced event is the one we are\n\t\t\t\t// listening for\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) { // need to check this this is the host\n\t\t\t\t\t\treturn;               // table, not a nested one\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tcolumn.sSortingClass +' '+\n\t\t\t\t\t\t\tclasses.sSortAsc +' '+\n\t\t\t\t\t\t\tclasses.sSortDesc\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t},\n\t\n\t\t\tjqueryui: function ( settings, cell, column, classes ) {\n\t\t\t\t$('<div/>')\n\t\t\t\t\t.addClass( classes.sSortJUIWrapper )\n\t\t\t\t\t.append( cell.contents() )\n\t\t\t\t\t.append( $('<span/>')\n\t\t\t\t\t\t.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo( cell );\n\t\n\t\t\t\t// Attach a sort listener to update on sort\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.find( 'span.'+classes.sSortIcon )\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tclasses.sSortJUIAsc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDesc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUI +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIAscAllowed +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDescAllowed\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortJUIAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortJUIDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClassJUI\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t/*\n\t * Public helper functions. These aren't used internally by DataTables, or\n\t * called by any of the options passed into DataTables, but they can be used\n\t * externally by developers working with DataTables. They are helper functions\n\t * to make working with DataTables a little bit easier.\n\t */\n\t\n\tvar __htmlEscapeEntities = function ( d ) {\n\t\treturn typeof d === 'string' ?\n\t\t\td.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;') :\n\t\t\td;\n\t};\n\t\n\t/**\n\t * Helpers for `columns.render`.\n\t *\n\t * The options defined here can be used with the `columns.render` initialisation\n\t * option to provide a display renderer. The following functions are defined:\n\t *\n\t * * `number` - Will format numeric data (defined by `columns.data`) for\n\t *   display, retaining the original unformatted data for sorting and filtering.\n\t *   It takes 5 parameters:\n\t *   * `string` - Thousands grouping separator\n\t *   * `string` - Decimal point indicator\n\t *   * `integer` - Number of decimal points to show\n\t *   * `string` (optional) - Prefix.\n\t *   * `string` (optional) - Postfix (/suffix).\n\t * * `text` - Escape HTML to help prevent XSS attacks. It has no optional\n\t *   parameters.\n\t *\n\t * @example\n\t *   // Column definition using the number renderer\n\t *   {\n\t *     data: \"salary\",\n\t *     render: $.fn.dataTable.render.number( '\\'', '.', 0, '$' )\n\t *   }\n\t *\n\t * @namespace\n\t */\n\tDataTable.render = {\n\t\tnumber: function ( thousands, decimal, precision, prefix, postfix ) {\n\t\t\treturn {\n\t\t\t\tdisplay: function ( d ) {\n\t\t\t\t\tif ( typeof d !== 'number' && typeof d !== 'string' ) {\n\t\t\t\t\t\treturn d;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar negative = d < 0 ? '-' : '';\n\t\t\t\t\tvar flo = parseFloat( d );\n\t\n\t\t\t\t\t// If NaN then there isn't much formatting that we can do - just\n\t\t\t\t\t// return immediately, escaping any HTML (this was supposed to\n\t\t\t\t\t// be a number after all)\n\t\t\t\t\tif ( isNaN( flo ) ) {\n\t\t\t\t\t\treturn __htmlEscapeEntities( d );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tflo = flo.toFixed( precision );\n\t\t\t\t\td = Math.abs( flo );\n\t\n\t\t\t\t\tvar intPart = parseInt( d, 10 );\n\t\t\t\t\tvar floatPart = precision ?\n\t\t\t\t\t\tdecimal+(d - intPart).toFixed( precision ).substring( 2 ):\n\t\t\t\t\t\t'';\n\t\n\t\t\t\t\treturn negative + (prefix||'') +\n\t\t\t\t\t\tintPart.toString().replace(\n\t\t\t\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g, thousands\n\t\t\t\t\t\t) +\n\t\t\t\t\t\tfloatPart +\n\t\t\t\t\t\t(postfix||'');\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\ttext: function () {\n\t\t\treturn {\n\t\t\t\tdisplay: __htmlEscapeEntities\n\t\t\t};\n\t\t}\n\t};\n\t\n\t\n\t/*\n\t * This is really a good bit rubbish this method of exposing the internal methods\n\t * publicly... - To be fixed in 2.0 using methods on the prototype\n\t */\n\t\n\t\n\t/**\n\t * Create a wrapper function for exporting an internal functions to an external API.\n\t *  @param {string} fn API function name\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#internal\n\t */\n\tfunction _fnExternApiFunc (fn)\n\t{\n\t\treturn function() {\n\t\t\tvar args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(\n\t\t\t\tArray.prototype.slice.call(arguments)\n\t\t\t);\n\t\t\treturn DataTable.ext.internal[fn].apply( this, args );\n\t\t};\n\t}\n\t\n\t\n\t/**\n\t * Reference to internal functions for use by plug-in developers. Note that\n\t * these methods are references to internal functions and are considered to be\n\t * private. If you use these methods, be aware that they are liable to change\n\t * between versions.\n\t *  @namespace\n\t */\n\t$.extend( DataTable.ext.internal, {\n\t\t_fnExternApiFunc: _fnExternApiFunc,\n\t\t_fnBuildAjax: _fnBuildAjax,\n\t\t_fnAjaxUpdate: _fnAjaxUpdate,\n\t\t_fnAjaxParameters: _fnAjaxParameters,\n\t\t_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,\n\t\t_fnAjaxDataSrc: _fnAjaxDataSrc,\n\t\t_fnAddColumn: _fnAddColumn,\n\t\t_fnColumnOptions: _fnColumnOptions,\n\t\t_fnAdjustColumnSizing: _fnAdjustColumnSizing,\n\t\t_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,\n\t\t_fnColumnIndexToVisible: _fnColumnIndexToVisible,\n\t\t_fnVisbleColumns: _fnVisbleColumns,\n\t\t_fnGetColumns: _fnGetColumns,\n\t\t_fnColumnTypes: _fnColumnTypes,\n\t\t_fnApplyColumnDefs: _fnApplyColumnDefs,\n\t\t_fnHungarianMap: _fnHungarianMap,\n\t\t_fnCamelToHungarian: _fnCamelToHungarian,\n\t\t_fnLanguageCompat: _fnLanguageCompat,\n\t\t_fnBrowserDetect: _fnBrowserDetect,\n\t\t_fnAddData: _fnAddData,\n\t\t_fnAddTr: _fnAddTr,\n\t\t_fnNodeToDataIndex: _fnNodeToDataIndex,\n\t\t_fnNodeToColumnIndex: _fnNodeToColumnIndex,\n\t\t_fnGetCellData: _fnGetCellData,\n\t\t_fnSetCellData: _fnSetCellData,\n\t\t_fnSplitObjNotation: _fnSplitObjNotation,\n\t\t_fnGetObjectDataFn: _fnGetObjectDataFn,\n\t\t_fnSetObjectDataFn: _fnSetObjectDataFn,\n\t\t_fnGetDataMaster: _fnGetDataMaster,\n\t\t_fnClearTable: _fnClearTable,\n\t\t_fnDeleteIndex: _fnDeleteIndex,\n\t\t_fnInvalidate: _fnInvalidate,\n\t\t_fnGetRowElements: _fnGetRowElements,\n\t\t_fnCreateTr: _fnCreateTr,\n\t\t_fnBuildHead: _fnBuildHead,\n\t\t_fnDrawHead: _fnDrawHead,\n\t\t_fnDraw: _fnDraw,\n\t\t_fnReDraw: _fnReDraw,\n\t\t_fnAddOptionsHtml: _fnAddOptionsHtml,\n\t\t_fnDetectHeader: _fnDetectHeader,\n\t\t_fnGetUniqueThs: _fnGetUniqueThs,\n\t\t_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,\n\t\t_fnFilterComplete: _fnFilterComplete,\n\t\t_fnFilterCustom: _fnFilterCustom,\n\t\t_fnFilterColumn: _fnFilterColumn,\n\t\t_fnFilter: _fnFilter,\n\t\t_fnFilterCreateSearch: _fnFilterCreateSearch,\n\t\t_fnEscapeRegex: _fnEscapeRegex,\n\t\t_fnFilterData: _fnFilterData,\n\t\t_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,\n\t\t_fnUpdateInfo: _fnUpdateInfo,\n\t\t_fnInfoMacros: _fnInfoMacros,\n\t\t_fnInitialise: _fnInitialise,\n\t\t_fnInitComplete: _fnInitComplete,\n\t\t_fnLengthChange: _fnLengthChange,\n\t\t_fnFeatureHtmlLength: _fnFeatureHtmlLength,\n\t\t_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,\n\t\t_fnPageChange: _fnPageChange,\n\t\t_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,\n\t\t_fnProcessingDisplay: _fnProcessingDisplay,\n\t\t_fnFeatureHtmlTable: _fnFeatureHtmlTable,\n\t\t_fnScrollDraw: _fnScrollDraw,\n\t\t_fnApplyToChildren: _fnApplyToChildren,\n\t\t_fnCalculateColumnWidths: _fnCalculateColumnWidths,\n\t\t_fnThrottle: _fnThrottle,\n\t\t_fnConvertToWidth: _fnConvertToWidth,\n\t\t_fnGetWidestNode: _fnGetWidestNode,\n\t\t_fnGetMaxLenString: _fnGetMaxLenString,\n\t\t_fnStringToCss: _fnStringToCss,\n\t\t_fnSortFlatten: _fnSortFlatten,\n\t\t_fnSort: _fnSort,\n\t\t_fnSortAria: _fnSortAria,\n\t\t_fnSortListener: _fnSortListener,\n\t\t_fnSortAttachListener: _fnSortAttachListener,\n\t\t_fnSortingClasses: _fnSortingClasses,\n\t\t_fnSortData: _fnSortData,\n\t\t_fnSaveState: _fnSaveState,\n\t\t_fnLoadState: _fnLoadState,\n\t\t_fnSettingsFromNode: _fnSettingsFromNode,\n\t\t_fnLog: _fnLog,\n\t\t_fnMap: _fnMap,\n\t\t_fnBindAction: _fnBindAction,\n\t\t_fnCallbackReg: _fnCallbackReg,\n\t\t_fnCallbackFire: _fnCallbackFire,\n\t\t_fnLengthOverflow: _fnLengthOverflow,\n\t\t_fnRenderer: _fnRenderer,\n\t\t_fnDataSource: _fnDataSource,\n\t\t_fnRowAttributes: _fnRowAttributes,\n\t\t_fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant\n\t\t                                // in 1.10, so this dead-end function is\n\t\t                                // added to prevent errors\n\t} );\n\t\n\n\t// jQuery access\n\t$.fn.dataTable = DataTable;\n\n\t// Provide access to the host jQuery object (circular reference)\n\tDataTable.$ = $;\n\n\t// Legacy aliases\n\t$.fn.dataTableSettings = DataTable.settings;\n\t$.fn.dataTableExt = DataTable.ext;\n\n\t// With a capital `D` we return a DataTables API instance rather than a\n\t// jQuery object\n\t$.fn.DataTable = function ( opts ) {\n\t\treturn $(this).dataTable( opts ).api();\n\t};\n\n\t// All properties that are available to $.fn.dataTable should also be\n\t// available on $.fn.DataTable\n\t$.each( DataTable, function ( prop, val ) {\n\t\t$.fn.DataTable[ prop ] = val;\n\t} );\n\n\n\t// Information about events fired by DataTables - for documentation.\n\t/**\n\t * Draw event, fired whenever the table is redrawn on the page, at the same\n\t * point as fnDrawCallback. This may be useful for binding events or\n\t * performing calculations when the table is altered at all.\n\t *  @name DataTable#draw.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Search event, fired when the searching applied to the table (using the\n\t * built-in global search, or column filters) is altered.\n\t *  @name DataTable#search.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page change event, fired when the paging of the table is altered.\n\t *  @name DataTable#page.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Order event, fired when the ordering applied to the table is altered.\n\t *  @name DataTable#order.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * DataTables initialisation complete event, fired when the table is fully\n\t * drawn, including Ajax data loaded, if Ajax data is required.\n\t *  @name DataTable#init.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The JSON object request from the server - only\n\t *    present if client-side Ajax sourced data is used</li></ol>\n\t */\n\n\t/**\n\t * State save event, fired when the table has changed state a new state save\n\t * is required. This event allows modification of the state saving object\n\t * prior to actually doing the save, including addition or other state\n\t * properties (for plug-ins) or modification of a DataTables core property.\n\t *  @name DataTable#stateSaveParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The state information to be saved\n\t */\n\n\t/**\n\t * State load event, fired when the table is loading state from the stored\n\t * data, but prior to the settings object being modified by the saved state\n\t * - allowing modification of the saved state is required or loading of\n\t * state for a plug-in.\n\t *  @name DataTable#stateLoadParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * State loaded event, fired when state has been loaded from stored data and\n\t * the settings object has been modified by the loaded data.\n\t *  @name DataTable#stateLoaded.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * Processing event, fired when DataTables is doing some kind of processing\n\t * (be it, order, searcg or anything else). It can be used to indicate to\n\t * the end user that there is something happening, or that something has\n\t * finished.\n\t *  @name DataTable#processing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {boolean} bShow Flag for if DataTables is doing processing or not\n\t */\n\n\t/**\n\t * Ajax (XHR) event, fired whenever an Ajax request is completed from a\n\t * request to made to the server for new data. This event is called before\n\t * DataTables processed the returned data, so it can also be used to pre-\n\t * process the data returned from the server, if needed.\n\t *\n\t * Note that this trigger is called in `fnServerData`, if you override\n\t * `fnServerData` and which to use this event, you need to trigger it in you\n\t * success function.\n\t *  @name DataTable#xhr.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {object} json JSON returned from the server\n\t *\n\t *  @example\n\t *     // Use a custom property returned from the server in another DOM element\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       $('#status').html( json.status );\n\t *     } );\n\t *\n\t *  @example\n\t *     // Pre-process the data returned from the server\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {\n\t *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;\n\t *       }\n\t *       // Note no return - manipulate the data directly in the JSON object.\n\t *     } );\n\t */\n\n\t/**\n\t * Destroy event, fired when the DataTable is destroyed by calling fnDestroy\n\t * or passing the bDestroy:true parameter in the initialisation object. This\n\t * can be used to remove bound events, added DOM nodes, etc.\n\t *  @name DataTable#destroy.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page length change event, fired when number of records to show on each\n\t * page (the length) is changed.\n\t *  @name DataTable#length.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {integer} len New length\n\t */\n\n\t/**\n\t * Column sizing has changed.\n\t *  @name DataTable#column-sizing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Column visibility has changed.\n\t *  @name DataTable#column-visibility.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {int} column Column index\n\t *  @param {bool} vis `false` if column now hidden, or `true` if visible\n\t */\n\n\treturn $.fn.dataTable;\n}));\n"
  },
  {
    "path": "platforms/android/assets/www/lib/DataTables/datatables.css",
    "content": "/*\n * This combined file was created by the DataTables downloader builder:\n *   https://datatables.net/download\n *\n * To rebuild or modify this file with the latest versions of the included\n * software please visit:\n *   https://datatables.net/download/#dt/dt-1.10.13\n *\n * Included libraries:\n *   DataTables 1.10.13\n */\n\n/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px;\n  border-bottom: 1px solid #111;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n  border-top: 1px solid #111;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc {\n  cursor: pointer;\n  *cursor: hand;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"DataTables-1.10.13/images/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"DataTables-1.10.13/images/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"DataTables-1.10.13/images/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"DataTables-1.10.13/images/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"DataTables-1.10.13/images/sort_desc_disabled.png\");\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: #f6f6f6;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #fafafa;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #fafafa;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fcfcfc;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fefefe;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ececec;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #efefef;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em 1em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #979797;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  color: white !important;\n  border: 1px solid #111;\n  background-color: #585858;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #585858 0%, #111 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #585858 0%, #111 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #585858 0%, #111 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #585858 0%, #111 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  background-color: #2b2b2b;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);\n  /* W3C */\n  box-shadow: inset 0 0 3px #111;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td {\n  vertical-align: middle;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}\n\n\n"
  },
  {
    "path": "platforms/android/assets/www/lib/DataTables/datatables.js",
    "content": "/*\n * This combined file was created by the DataTables downloader builder:\n *   https://datatables.net/download\n *\n * To rebuild or modify this file with the latest versions of the included\n * software please visit:\n *   https://datatables.net/download/#dt/dt-1.10.13\n *\n * Included libraries:\n *   DataTables 1.10.13\n */\n\n/*! DataTables 1.10.13\n * ©2008-2016 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     DataTables\n * @description Paginate, search and order HTML tables\n * @version     1.10.13\n * @file        jquery.dataTables.js\n * @author      SpryMedia Ltd\n * @contact     www.datatables.net\n * @copyright   Copyright 2008-2016 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n/*jslint evil: true, undef: true, browser: true */\n/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/\n\n(function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\t// CommonJS environments without a window global must pass a\n\t\t\t\t// root. This will give an error otherwise\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ ) {\n\t\t\t\t$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window\n\t\t\t\t\trequire('jquery') :\n\t\t\t\t\trequire('jquery')( root );\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}\n(function( $, window, document, undefined ) {\n\t\"use strict\";\n\n\t/**\n\t * DataTables is a plug-in for the jQuery Javascript library. It is a highly\n\t * flexible tool, based upon the foundations of progressive enhancement,\n\t * which will add advanced interaction controls to any HTML table. For a\n\t * full list of features please refer to\n\t * [DataTables.net](href=\"http://datatables.net).\n\t *\n\t * Note that the `DataTable` object is not a global variable but is aliased\n\t * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may\n\t * be  accessed.\n\t *\n\t *  @class\n\t *  @param {object} [init={}] Configuration object for DataTables. Options\n\t *    are defined by {@link DataTable.defaults}\n\t *  @requires jQuery 1.7+\n\t *\n\t *  @example\n\t *    // Basic initialisation\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable();\n\t *    } );\n\t *\n\t *  @example\n\t *    // Initialisation with configuration options - in this case, disable\n\t *    // pagination and sorting.\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable( {\n\t *        \"paginate\": false,\n\t *        \"sort\": false\n\t *      } );\n\t *    } );\n\t */\n\tvar DataTable = function ( options )\n\t{\n\t\t/**\n\t\t * Perform a jQuery selector action on the table's TR elements (from the tbody) and\n\t\t * return the resulting jQuery object.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter\n\t\t *    criterion (\"applied\") or all TR elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {object} jQuery object, filtered by the given selector.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Highlight every second row\n\t\t *      oTable.$('tr:odd').css('backgroundColor', 'blue');\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to rows with 'Webkit' in them, add a background colour and then\n\t\t *      // remove the filter, thus highlighting the 'Webkit' rows only.\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      oTable.$('tr', {\"search\": \"applied\"}).css('backgroundColor', 'blue');\n\t\t *      oTable.fnFilter('');\n\t\t *    } );\n\t\t */\n\t\tthis.$ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).$( sSelector, oOpts );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Almost identical to $ in operation, but in this case returns the data for the matched\n\t\t * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes\n\t\t * rather than any descendants, so the data can be obtained for the row/cell. If matching\n\t\t * rows are found, the data returned is the original data array/object that was used to\n\t\t * create the row (or a generated array if from a DOM source).\n\t\t *\n\t\t * This method is often useful in-combination with $ where both functions are given the\n\t\t * same parameters and the array indexes will match identically.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select elements that meet the current filter\n\t\t *    criterion (\"applied\") or all elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the data in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {array} Data for the matched elements. If any elements, as a result of the\n\t\t *    selector, were not TR, TD or TH elements in the DataTable, they will have a null\n\t\t *    entry in the array.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the data from the first row in the table\n\t\t *      var data = oTable._('tr:first');\n\t\t *\n\t\t *      // Do something useful with the data\n\t\t *      alert( \"First cell is: \"+data[0] );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to 'Webkit' and get all data for\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      var data = oTable._('tr', {\"search\": \"applied\"});\n\t\t *\n\t\t *      // Do something with the data\n\t\t *      alert( data.length+\" rows matched the search\" );\n\t\t *    } );\n\t\t */\n\t\tthis._ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).rows( sSelector, oOpts ).data();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Create a DataTables Api instance, with the currently selected tables for\n\t\t * the Api's context.\n\t\t * @param {boolean} [traditional=false] Set the API instance's context to be\n\t\t *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was\n\t\t *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),\n\t\t *   or if all tables captured in the jQuery object should be used.\n\t\t * @return {DataTables.Api}\n\t\t */\n\t\tthis.api = function ( traditional )\n\t\t{\n\t\t\treturn traditional ?\n\t\t\t\tnew _Api(\n\t\t\t\t\t_fnSettingsFromNode( this[ _ext.iApiIndex ] )\n\t\t\t\t) :\n\t\t\t\tnew _Api( this );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Add a single new row or multiple rows of data to the table. Please note\n\t\t * that this is suitable for client-side processing only - if you are using\n\t\t * server-side processing (i.e. \"bServerSide\": true), then to add data, you\n\t\t * must add it to the data source, i.e. the server-side, through an Ajax call.\n\t\t *  @param {array|object} data The data to be added to the table. This can be:\n\t\t *    <ul>\n\t\t *      <li>1D array of data - add a single row with the data provided</li>\n\t\t *      <li>2D array of arrays - add multiple rows in a single call</li>\n\t\t *      <li>object - data object when using <i>mData</i></li>\n\t\t *      <li>array of objects - multiple data objects when using <i>mData</i></li>\n\t\t *    </ul>\n\t\t *  @param {bool} [redraw=true] redraw the table or not\n\t\t *  @returns {array} An array of integers, representing the list of indexes in\n\t\t *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to\n\t\t *    the table.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Global var for counter\n\t\t *    var giCount = 2;\n\t\t *\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example').dataTable();\n\t\t *    } );\n\t\t *\n\t\t *    function fnClickAddRow() {\n\t\t *      $('#example').dataTable().fnAddData( [\n\t\t *        giCount+\".1\",\n\t\t *        giCount+\".2\",\n\t\t *        giCount+\".3\",\n\t\t *        giCount+\".4\" ]\n\t\t *      );\n\t\t *\n\t\t *      giCount++;\n\t\t *    }\n\t\t */\n\t\tthis.fnAddData = function( data, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\t/* Check if we want to add multiple rows or not */\n\t\t\tvar rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?\n\t\t\t\tapi.rows.add( data ) :\n\t\t\t\tapi.row.add( data );\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn rows.flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will make DataTables recalculate the column sizes, based on the data\n\t\t * contained in the table and the sizes applied to the columns (in the DOM, CSS or\n\t\t * through the sWidth parameter). This can be useful when the width of the table's\n\t\t * parent element changes (for example a window resize).\n\t\t *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable( {\n\t\t *        \"sScrollY\": \"200px\",\n\t\t *        \"bPaginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      $(window).on('resize', function () {\n\t\t *        oTable.fnAdjustColumnSizing();\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnAdjustColumnSizing = function ( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).columns.adjust();\n\t\t\tvar settings = api.settings()[0];\n\t\t\tvar scroll = settings.oScroll;\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw( false );\n\t\t\t}\n\t\t\telse if ( scroll.sX !== \"\" || scroll.sY !== \"\" ) {\n\t\t\t\t/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */\n\t\t\t\t_fnScrollDraw( settings );\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Quickly and simply clear a table\n\t\t *  @param {bool} [bRedraw=true] redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)\n\t\t *      oTable.fnClearTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClearTable = function( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).clear();\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * The exact opposite of 'opening' a row, this function will close any rows which\n\t\t * are currently 'open'.\n\t\t *  @param {node} nTr the table row to 'close'\n\t\t *  @returns {int} 0 on success, or 1 if failed (can't find the row)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClose = function( nTr )\n\t\t{\n\t\t\tthis.api( true ).row( nTr ).child.hide();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Remove a row for the table\n\t\t *  @param {mixed} target The index of the row from aoData to be deleted, or\n\t\t *    the TR element you want to delete\n\t\t *  @param {function|null} [callBack] Callback function\n\t\t *  @param {bool} [redraw=true] Redraw the table or not\n\t\t *  @returns {array} The row that was deleted\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately remove the first row\n\t\t *      oTable.fnDeleteRow( 0 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnDeleteRow = function( target, callback, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar rows = api.rows( target );\n\t\t\tvar settings = rows.settings()[0];\n\t\t\tvar data = settings.aoData[ rows[0][0] ];\n\t\t\n\t\t\trows.remove();\n\t\t\n\t\t\tif ( callback ) {\n\t\t\t\tcallback.call( this, settings, data );\n\t\t\t}\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn data;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Restore the table to it's original state in the DOM by removing all of DataTables\n\t\t * enhancements, alterations to the DOM structure of the table and event listeners.\n\t\t *  @param {boolean} [remove=false] Completely remove the table from the DOM\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      // This example is fairly pointless in reality, but shows how fnDestroy can be used\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnDestroy();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDestroy = function ( remove )\n\t\t{\n\t\t\tthis.api( true ).destroy( remove );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Redraw the table\n\t\t *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)\n\t\t *      oTable.fnDraw();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDraw = function( complete )\n\t\t{\n\t\t\t// Note that this isn't an exact match to the old call to _fnDraw - it takes\n\t\t\t// into account the new data, but can hold position.\n\t\t\tthis.api( true ).draw( complete );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Filter the input based on data\n\t\t *  @param {string} sInput String to filter the table on\n\t\t *  @param {int|null} [iColumn] Column to limit filtering to\n\t\t *  @param {bool} [bRegex=false] Treat as regular expression or not\n\t\t *  @param {bool} [bSmart=true] Perform smart filtering or not\n\t\t *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)\n\t\t *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sometime later - filter...\n\t\t *      oTable.fnFilter( 'test string' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === null || iColumn === undefined ) {\n\t\t\t\tapi.search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\n\t\t\tapi.draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the data for the whole table, an individual row or an individual cell based on the\n\t\t * provided parameters.\n\t\t *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as\n\t\t *    a TR node then the data source for the whole row will be returned. If given as a\n\t\t *    TD/TH cell node then iCol will be automatically calculated and the data for the\n\t\t *    cell returned. If given as an integer, then this is treated as the aoData internal\n\t\t *    data index for the row (see fnGetPosition) and the data for that row used.\n\t\t *  @param {int} [col] Optional column index that you want the data of.\n\t\t *  @returns {array|object|string} If mRow is undefined, then the data for all rows is\n\t\t *    returned. If mRow is defined, just data for that row, and is iCol is\n\t\t *    defined, only data for the designated cell is returned.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Row data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('tr').click( function () {\n\t\t *        var data = oTable.fnGetData( this );\n\t\t *        // ... do something with the array / object of data for the row\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Individual cell data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('td').click( function () {\n\t\t *        var sData = oTable.fnGetData( this );\n\t\t *        alert( 'The cell clicked on had the value of '+sData );\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetData = function( src, col )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( src !== undefined ) {\n\t\t\t\tvar type = src.nodeName ? src.nodeName.toLowerCase() : '';\n\t\t\n\t\t\t\treturn col !== undefined || type == 'td' || type == 'th' ?\n\t\t\t\t\tapi.cell( src, col ).data() :\n\t\t\t\t\tapi.row( src ).data() || null;\n\t\t\t}\n\t\t\n\t\t\treturn api.data().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get an array of the TR nodes that are used in the table's body. Note that you will\n\t\t * typically want to use the '$' API method in preference to this as it is more\n\t\t * flexible.\n\t\t *  @param {int} [iRow] Optional row index for the TR element you want\n\t\t *  @returns {array|node} If iRow is undefined, returns an array of all TR elements\n\t\t *    in the table's body, or iRow is defined, just the TR element requested.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the nodes from the table\n\t\t *      var nNodes = oTable.fnGetNodes( );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetNodes = function( iRow )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\treturn iRow !== undefined ?\n\t\t\t\tapi.row( iRow ).node() :\n\t\t\t\tapi.rows().nodes().flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the array indexes of a particular cell from it's DOM element\n\t\t * and column index including hidden columns\n\t\t *  @param {node} node this can either be a TR, TD or TH in the table's body\n\t\t *  @returns {int} If nNode is given as a TR, then a single index is returned, or\n\t\t *    if given as a cell, an array of [row index, column index (visible),\n\t\t *    column index (all)] is given.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example tbody td').click( function () {\n\t\t *        // Get the position of the current data from the node\n\t\t *        var aPos = oTable.fnGetPosition( this );\n\t\t *\n\t\t *        // Get the data array for this row\n\t\t *        var aData = oTable.fnGetData( aPos[0] );\n\t\t *\n\t\t *        // Update the data array and return the value\n\t\t *        aData[ aPos[1] ] = 'clicked';\n\t\t *        this.innerHTML = 'clicked';\n\t\t *      } );\n\t\t *\n\t\t *      // Init DataTables\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetPosition = function( node )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar nodeName = node.nodeName.toUpperCase();\n\t\t\n\t\t\tif ( nodeName == 'TR' ) {\n\t\t\t\treturn api.row( node ).index();\n\t\t\t}\n\t\t\telse if ( nodeName == 'TD' || nodeName == 'TH' ) {\n\t\t\t\tvar cell = api.cell( node ).index();\n\t\t\n\t\t\t\treturn [\n\t\t\t\t\tcell.row,\n\t\t\t\t\tcell.columnVisible,\n\t\t\t\t\tcell.column\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Check to see if a row is 'open' or not.\n\t\t *  @param {node} nTr the table row to check\n\t\t *  @returns {boolean} true if the row is currently open, false otherwise\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnIsOpen = function( nTr )\n\t\t{\n\t\t\treturn this.api( true ).row( nTr ).child.isShown();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will place a new row directly after a row which is currently\n\t\t * on display on the page, with the HTML contents that is passed into the\n\t\t * function. This can be used, for example, to ask for confirmation that a\n\t\t * particular record should be deleted.\n\t\t *  @param {node} nTr The table row to 'open'\n\t\t *  @param {string|node|jQuery} mHtml The HTML to put into the row\n\t\t *  @param {string} sClass Class to give the new TD cell\n\t\t *  @returns {node} The row opened. Note that if the table row passed in as the\n\t\t *    first parameter, is not found in the table, this method will silently\n\t\t *    return.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnOpen = function( nTr, mHtml, sClass )\n\t\t{\n\t\t\treturn this.api( true )\n\t\t\t\t.row( nTr )\n\t\t\t\t.child( mHtml, sClass )\n\t\t\t\t.show()\n\t\t\t\t.child()[0];\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Change the pagination - provides the internal logic for pagination in a simple API\n\t\t * function. With this function you can have a DataTables table go to the next,\n\t\t * previous, first or last pages.\n\t\t *  @param {string|int} mAction Paging action to take: \"first\", \"previous\", \"next\" or \"last\"\n\t\t *    or page number to jump to (integer), note that page 0 is the first page.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnPageChange( 'next' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnPageChange = function ( mAction, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).page( mAction );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw(false);\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Show a particular column\n\t\t *  @param {int} iCol The column whose display should be changed\n\t\t *  @param {bool} bShow Show (true) or hide (false) the column\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Hide the second column after initialisation\n\t\t *      oTable.fnSetColumnVis( 1, false );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSetColumnVis = function ( iCol, bShow, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).column( iCol ).visible( bShow );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.columns.adjust().draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the settings for a particular table for external manipulation\n\t\t *  @returns {object} DataTables settings object. See\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      var oSettings = oTable.fnSettings();\n\t\t *\n\t\t *      // Show an example parameter from the settings\n\t\t *      alert( oSettings._iDisplayStart );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSettings = function()\n\t\t{\n\t\t\treturn _fnSettingsFromNode( this[_ext.iApiIndex] );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Sort the table by a particular column\n\t\t *  @param {int} iCol the data index to sort on. Note that this will not match the\n\t\t *    'display index' if you have hidden data entries\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort immediately with columns 0 and 1\n\t\t *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSort = function( aaSort )\n\t\t{\n\t\t\tthis.api( true ).order( aaSort ).draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Attach a sort listener to an element for a given column\n\t\t *  @param {node} nNode the element to attach the sort listener to\n\t\t *  @param {int} iColumn the column that a click on this node will sort on\n\t\t *  @param {function} [fnCallback] callback function when sort is run\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort on column 1, when 'sorter' is clicked on\n\t\t *      oTable.fnSortListener( document.getElementById('sorter'), 1 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSortListener = function( nNode, iColumn, fnCallback )\n\t\t{\n\t\t\tthis.api( true ).order.listener( nNode, iColumn, fnCallback );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Update a table cell or row - this method will accept either a single value to\n\t\t * update the cell with, an array of values with one element for each column or\n\t\t * an object in the same format as the original data source. The function is\n\t\t * self-referencing in order to make the multi column updates easier.\n\t\t *  @param {object|array|string} mData Data to update the cell/row with\n\t\t *  @param {node|int} mRow TR element you want to update or the aoData index\n\t\t *  @param {int} [iColumn] The column to update, give as null or undefined to\n\t\t *    update a whole row.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @param {bool} [bAction=true] Perform pre-draw actions or not\n\t\t *  @returns {int} 0 on success, 1 on error\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell\n\t\t *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row\n\t\t *    } );\n\t\t */\n\t\tthis.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === undefined || iColumn === null ) {\n\t\t\t\tapi.row( mRow ).data( mData );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.cell( mRow, iColumn ).data( mData );\n\t\t\t}\n\t\t\n\t\t\tif ( bAction === undefined || bAction ) {\n\t\t\t\tapi.columns.adjust();\n\t\t\t}\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Provide a common method for plug-ins to check the version of DataTables being used, in order\n\t\t * to ensure compatibility.\n\t\t *  @param {string} sVersion Version string to check for, in the format \"X.Y.Z\". Note that the\n\t\t *    formats \"X\" and \"X.Y\" are also acceptable.\n\t\t *  @returns {boolean} true if this version of DataTables is greater or equal to the required\n\t\t *    version, or false if this version of DataTales is not suitable\n\t\t *  @method\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      alert( oTable.fnVersionCheck( '1.9.0' ) );\n\t\t *    } );\n\t\t */\n\t\tthis.fnVersionCheck = _ext.fnVersionCheck;\n\t\t\n\n\t\tvar _that = this;\n\t\tvar emptyInit = options === undefined;\n\t\tvar len = this.length;\n\n\t\tif ( emptyInit ) {\n\t\t\toptions = {};\n\t\t}\n\n\t\tthis.oApi = this.internal = _ext.internal;\n\n\t\t// Extend with old style plug-in API methods\n\t\tfor ( var fn in DataTable.ext.internal ) {\n\t\t\tif ( fn ) {\n\t\t\t\tthis[fn] = _fnExternApiFunc(fn);\n\t\t\t}\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\t// For each initialisation we want to give it a clean initialisation\n\t\t\t// object that can be bashed around\n\t\t\tvar o = {};\n\t\t\tvar oInit = len > 1 ? // optimisation for single table case\n\t\t\t\t_fnExtend( o, options, true ) :\n\t\t\t\toptions;\n\n\t\t\t/*global oInit,_that,emptyInit*/\n\t\t\tvar i=0, iLen, j, jLen, k, kLen;\n\t\t\tvar sId = this.getAttribute( 'id' );\n\t\t\tvar bInitHandedOff = false;\n\t\t\tvar defaults = DataTable.defaults;\n\t\t\tvar $this = $(this);\n\t\t\t\n\t\t\t\n\t\t\t/* Sanity check */\n\t\t\tif ( this.nodeName.toLowerCase() != 'table' )\n\t\t\t{\n\t\t\t\t_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/* Backwards compatibility for the defaults */\n\t\t\t_fnCompatOpts( defaults );\n\t\t\t_fnCompatCols( defaults.column );\n\t\t\t\n\t\t\t/* Convert the camel-case defaults to Hungarian */\n\t\t\t_fnCamelToHungarian( defaults, defaults, true );\n\t\t\t_fnCamelToHungarian( defaults.column, defaults.column, true );\n\t\t\t\n\t\t\t/* Setting up the initialisation object */\n\t\t\t_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/* Check to see if we are re-initialising a table */\n\t\t\tvar allSettings = DataTable.settings;\n\t\t\tfor ( i=0, iLen=allSettings.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tvar s = allSettings[i];\n\t\t\t\n\t\t\t\t/* Base check on table node */\n\t\t\t\tif ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )\n\t\t\t\t{\n\t\t\t\t\tvar bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;\n\t\t\t\t\tvar bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;\n\t\t\t\n\t\t\t\t\tif ( emptyInit || bRetrieve )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn s.oInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( bDestroy )\n\t\t\t\t\t{\n\t\t\t\t\t\ts.oInstance.fnDestroy();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* If the element we are initialising has the same ID as a table which was previously\n\t\t\t\t * initialised, but the table nodes don't match (from before) then we destroy the old\n\t\t\t\t * instance by simply deleting it. This is under the assumption that the table has been\n\t\t\t\t * destroyed by other methods. Anyone using non-id selectors will need to do this manually\n\t\t\t\t */\n\t\t\t\tif ( s.sTableId == this.id )\n\t\t\t\t{\n\t\t\t\t\tallSettings.splice( i, 1 );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Ensure the table has an ID - required for accessibility */\n\t\t\tif ( sId === null || sId === \"\" )\n\t\t\t{\n\t\t\t\tsId = \"DataTables_Table_\"+(DataTable.ext._unique++);\n\t\t\t\tthis.id = sId;\n\t\t\t}\n\t\t\t\n\t\t\t/* Create the settings object for this table and set some of the default parameters */\n\t\t\tvar oSettings = $.extend( true, {}, DataTable.models.oSettings, {\n\t\t\t\t\"sDestroyWidth\": $this[0].style.width,\n\t\t\t\t\"sInstance\":     sId,\n\t\t\t\t\"sTableId\":      sId\n\t\t\t} );\n\t\t\toSettings.nTable = this;\n\t\t\toSettings.oApi   = _that.internal;\n\t\t\toSettings.oInit  = oInit;\n\t\t\t\n\t\t\tallSettings.push( oSettings );\n\t\t\t\n\t\t\t// Need to add the instance after the instance after the settings object has been added\n\t\t\t// to the settings array, so we can self reference the table instance if more than one\n\t\t\toSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();\n\t\t\t\n\t\t\t// Backwards compatibility, before we apply all the defaults\n\t\t\t_fnCompatOpts( oInit );\n\t\t\t\n\t\t\tif ( oInit.oLanguage )\n\t\t\t{\n\t\t\t\t_fnLanguageCompat( oInit.oLanguage );\n\t\t\t}\n\t\t\t\n\t\t\t// If the length menu is given, but the init display length is not, use the length menu\n\t\t\tif ( oInit.aLengthMenu && ! oInit.iDisplayLength )\n\t\t\t{\n\t\t\t\toInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?\n\t\t\t\t\toInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];\n\t\t\t}\n\t\t\t\n\t\t\t// Apply the defaults and init options to make a single init object will all\n\t\t\t// options defined from defaults and instance options.\n\t\t\toInit = _fnExtend( $.extend( true, {}, defaults ), oInit );\n\t\t\t\n\t\t\t\n\t\t\t// Map the initialisation options onto the settings object\n\t\t\t_fnMap( oSettings.oFeatures, oInit, [\n\t\t\t\t\"bPaginate\",\n\t\t\t\t\"bLengthChange\",\n\t\t\t\t\"bFilter\",\n\t\t\t\t\"bSort\",\n\t\t\t\t\"bSortMulti\",\n\t\t\t\t\"bInfo\",\n\t\t\t\t\"bProcessing\",\n\t\t\t\t\"bAutoWidth\",\n\t\t\t\t\"bSortClasses\",\n\t\t\t\t\"bServerSide\",\n\t\t\t\t\"bDeferRender\"\n\t\t\t] );\n\t\t\t_fnMap( oSettings, oInit, [\n\t\t\t\t\"asStripeClasses\",\n\t\t\t\t\"ajax\",\n\t\t\t\t\"fnServerData\",\n\t\t\t\t\"fnFormatNumber\",\n\t\t\t\t\"sServerMethod\",\n\t\t\t\t\"aaSorting\",\n\t\t\t\t\"aaSortingFixed\",\n\t\t\t\t\"aLengthMenu\",\n\t\t\t\t\"sPaginationType\",\n\t\t\t\t\"sAjaxSource\",\n\t\t\t\t\"sAjaxDataProp\",\n\t\t\t\t\"iStateDuration\",\n\t\t\t\t\"sDom\",\n\t\t\t\t\"bSortCellsTop\",\n\t\t\t\t\"iTabIndex\",\n\t\t\t\t\"fnStateLoadCallback\",\n\t\t\t\t\"fnStateSaveCallback\",\n\t\t\t\t\"renderer\",\n\t\t\t\t\"searchDelay\",\n\t\t\t\t\"rowId\",\n\t\t\t\t[ \"iCookieDuration\", \"iStateDuration\" ], // backwards compat\n\t\t\t\t[ \"oSearch\", \"oPreviousSearch\" ],\n\t\t\t\t[ \"aoSearchCols\", \"aoPreSearchCols\" ],\n\t\t\t\t[ \"iDisplayLength\", \"_iDisplayLength\" ],\n\t\t\t\t[ \"bJQueryUI\", \"bJUI\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oScroll, oInit, [\n\t\t\t\t[ \"sScrollX\", \"sX\" ],\n\t\t\t\t[ \"sScrollXInner\", \"sXInner\" ],\n\t\t\t\t[ \"sScrollY\", \"sY\" ],\n\t\t\t\t[ \"bScrollCollapse\", \"bCollapse\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oLanguage, oInit, \"fnInfoCallback\" );\n\t\t\t\n\t\t\t/* Callback functions which are array driven */\n\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );\n\t\t\t\n\t\t\toSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );\n\t\t\t\n\t\t\t/* Browser support detection */\n\t\t\t_fnBrowserDetect( oSettings );\n\t\t\t\n\t\t\tvar oClasses = oSettings.oClasses;\n\t\t\t\n\t\t\t// @todo Remove in 1.11\n\t\t\tif ( oInit.bJQueryUI )\n\t\t\t{\n\t\t\t\t/* Use the JUI classes object for display. You could clone the oStdClasses object if\n\t\t\t\t * you want to have multiple tables with multiple independent classes\n\t\t\t\t */\n\t\t\t\t$.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );\n\t\t\t\n\t\t\t\tif ( oInit.sDom === defaults.sDom && defaults.sDom === \"lfrtip\" )\n\t\t\t\t{\n\t\t\t\t\t/* Set the DOM to use a layout suitable for jQuery UI's theming */\n\t\t\t\t\toSettings.sDom = '<\"H\"lfr>t<\"F\"ip>';\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( ! oSettings.renderer ) {\n\t\t\t\t\toSettings.renderer = 'jqueryui';\n\t\t\t\t}\n\t\t\t\telse if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {\n\t\t\t\t\toSettings.renderer.header = 'jqueryui';\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );\n\t\t\t}\n\t\t\t$this.addClass( oClasses.sTable );\n\t\t\t\n\t\t\t\n\t\t\tif ( oSettings.iInitDisplayStart === undefined )\n\t\t\t{\n\t\t\t\t/* Display start point, taking into account the save saving */\n\t\t\t\toSettings.iInitDisplayStart = oInit.iDisplayStart;\n\t\t\t\toSettings._iDisplayStart = oInit.iDisplayStart;\n\t\t\t}\n\t\t\t\n\t\t\tif ( oInit.iDeferLoading !== null )\n\t\t\t{\n\t\t\t\toSettings.bDeferLoading = true;\n\t\t\t\tvar tmp = $.isArray( oInit.iDeferLoading );\n\t\t\t\toSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;\n\t\t\t\toSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;\n\t\t\t}\n\t\t\t\n\t\t\t/* Language definitions */\n\t\t\tvar oLanguage = oSettings.oLanguage;\n\t\t\t$.extend( true, oLanguage, oInit.oLanguage );\n\t\t\t\n\t\t\tif ( oLanguage.sUrl )\n\t\t\t{\n\t\t\t\t/* Get the language definitions from a file - because this Ajax call makes the language\n\t\t\t\t * get async to the remainder of this function we use bInitHandedOff to indicate that\n\t\t\t\t * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor\n\t\t\t\t */\n\t\t\t\t$.ajax( {\n\t\t\t\t\tdataType: 'json',\n\t\t\t\t\turl: oLanguage.sUrl,\n\t\t\t\t\tsuccess: function ( json ) {\n\t\t\t\t\t\t_fnLanguageCompat( json );\n\t\t\t\t\t\t_fnCamelToHungarian( defaults.oLanguage, json );\n\t\t\t\t\t\t$.extend( true, oLanguage, json );\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t},\n\t\t\t\t\terror: function () {\n\t\t\t\t\t\t// Error occurred loading language file, continue on as best we can\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tbInitHandedOff = true;\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Stripes\n\t\t\t */\n\t\t\tif ( oInit.asStripeClasses === null )\n\t\t\t{\n\t\t\t\toSettings.asStripeClasses =[\n\t\t\t\t\toClasses.sStripeOdd,\n\t\t\t\t\toClasses.sStripeEven\n\t\t\t\t];\n\t\t\t}\n\t\t\t\n\t\t\t/* Remove row stripe classes if they are already on the table row */\n\t\t\tvar stripeClasses = oSettings.asStripeClasses;\n\t\t\tvar rowOne = $this.children('tbody').find('tr').eq(0);\n\t\t\tif ( $.inArray( true, $.map( stripeClasses, function(el, i) {\n\t\t\t\treturn rowOne.hasClass(el);\n\t\t\t} ) ) !== -1 ) {\n\t\t\t\t$('tbody tr', this).removeClass( stripeClasses.join(' ') );\n\t\t\t\toSettings.asDestroyStripes = stripeClasses.slice();\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Columns\n\t\t\t * See if we should load columns automatically or use defined ones\n\t\t\t */\n\t\t\tvar anThs = [];\n\t\t\tvar aoColumnsInit;\n\t\t\tvar nThead = this.getElementsByTagName('thead');\n\t\t\tif ( nThead.length !== 0 )\n\t\t\t{\n\t\t\t\t_fnDetectHeader( oSettings.aoHeader, nThead[0] );\n\t\t\t\tanThs = _fnGetUniqueThs( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* If not given a column array, generate one with nulls */\n\t\t\tif ( oInit.aoColumns === null )\n\t\t\t{\n\t\t\t\taoColumnsInit = [];\n\t\t\t\tfor ( i=0, iLen=anThs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\taoColumnsInit.push( null );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoColumnsInit = oInit.aoColumns;\n\t\t\t}\n\t\t\t\n\t\t\t/* Add the columns */\n\t\t\tfor ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t_fnAddColumn( oSettings, anThs ? anThs[i] : null );\n\t\t\t}\n\t\t\t\n\t\t\t/* Apply the column definitions */\n\t\t\t_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {\n\t\t\t\t_fnColumnOptions( oSettings, iCol, oDef );\n\t\t\t} );\n\t\t\t\n\t\t\t/* HTML5 attribute detection - build an mData object automatically if the\n\t\t\t * attributes are found\n\t\t\t */\n\t\t\tif ( rowOne.length ) {\n\t\t\t\tvar a = function ( cell, name ) {\n\t\t\t\t\treturn cell.getAttribute( 'data-'+name ) !== null ? name : null;\n\t\t\t\t};\n\t\t\t\n\t\t\t\t$( rowOne[0] ).children('th, td').each( function (i, cell) {\n\t\t\t\t\tvar col = oSettings.aoColumns[i];\n\t\t\t\n\t\t\t\t\tif ( col.mData === i ) {\n\t\t\t\t\t\tvar sort = a( cell, 'sort' ) || a( cell, 'order' );\n\t\t\t\t\t\tvar filter = a( cell, 'filter' ) || a( cell, 'search' );\n\t\t\t\n\t\t\t\t\t\tif ( sort !== null || filter !== null ) {\n\t\t\t\t\t\t\tcol.mData = {\n\t\t\t\t\t\t\t\t_:      i+'.display',\n\t\t\t\t\t\t\t\tsort:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\ttype:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\tfilter: filter !== null ? i+'.@data-'+filter : undefined\n\t\t\t\t\t\t\t};\n\t\t\t\n\t\t\t\t\t\t\t_fnColumnOptions( oSettings, i );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\t\n\t\t\tvar features = oSettings.oFeatures;\n\t\t\tvar loadedInit = function () {\n\t\t\t\t/*\n\t\t\t\t * Sorting\n\t\t\t\t * @todo For modularisation (1.11) this needs to do into a sort start up handler\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// If aaSorting is not defined, then we use the first indicator in asSorting\n\t\t\t\t// in case that has been altered, so the default sort reflects that option\n\t\t\t\tif ( oInit.aaSorting === undefined ) {\n\t\t\t\t\tvar sorting = oSettings.aaSorting;\n\t\t\t\t\tfor ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {\n\t\t\t\t\t\tsorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Do a first pass on the sorting classes (allows any size changes to be taken into\n\t\t\t\t * account, and also will apply sorting disabled classes if disabled\n\t\t\t\t */\n\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\n\t\t\t\tif ( features.bSort ) {\n\t\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\t\tif ( oSettings.bSorted ) {\n\t\t\t\t\t\t\tvar aSort = _fnSortFlatten( oSettings );\n\t\t\t\t\t\t\tvar sortedColumns = {};\n\t\t\t\n\t\t\t\t\t\t\t$.each( aSort, function (i, val) {\n\t\t\t\t\t\t\t\tsortedColumns[ val.src ] = val.dir;\n\t\t\t\t\t\t\t} );\n\t\t\t\n\t\t\t\t\t\t\t_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );\n\t\t\t\t\t\t\t_fnSortAria( oSettings );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\tif ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {\n\t\t\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\t\t}\n\t\t\t\t}, 'sc' );\n\t\t\t\n\t\t\t\n\t\t\t\t/*\n\t\t\t\t * Final init\n\t\t\t\t * Cache the header, body and footer as required, creating them if needed\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// Work around for Webkit bug 83867 - store the caption-side before removing from doc\n\t\t\t\tvar captions = $this.children('caption').each( function () {\n\t\t\t\t\tthis._captionSide = $(this).css('caption-side');\n\t\t\t\t} );\n\t\t\t\n\t\t\t\tvar thead = $this.children('thead');\n\t\t\t\tif ( thead.length === 0 ) {\n\t\t\t\t\tthead = $('<thead/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTHead = thead[0];\n\t\t\t\n\t\t\t\tvar tbody = $this.children('tbody');\n\t\t\t\tif ( tbody.length === 0 ) {\n\t\t\t\t\ttbody = $('<tbody/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTBody = tbody[0];\n\t\t\t\n\t\t\t\tvar tfoot = $this.children('tfoot');\n\t\t\t\tif ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\") ) {\n\t\t\t\t\t// If we are a scrolling table, and no footer has been given, then we need to create\n\t\t\t\t\t// a tfoot element for the caption element to be appended to\n\t\t\t\t\ttfoot = $('<tfoot/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( tfoot.length === 0 || tfoot.children().length === 0 ) {\n\t\t\t\t\t$this.addClass( oClasses.sNoFooter );\n\t\t\t\t}\n\t\t\t\telse if ( tfoot.length > 0 ) {\n\t\t\t\t\toSettings.nTFoot = tfoot[0];\n\t\t\t\t\t_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Check if there is data passing into the constructor */\n\t\t\t\tif ( oInit.aaData ) {\n\t\t\t\t\tfor ( i=0 ; i<oInit.aaData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( oSettings, oInit.aaData[ i ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {\n\t\t\t\t\t/* Grab the data from the page - only do this when deferred loading or no Ajax\n\t\t\t\t\t * source since there is no point in reading the DOM data if we are then going\n\t\t\t\t\t * to replace it with Ajax data\n\t\t\t\t\t */\n\t\t\t\t\t_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Copy the data index array */\n\t\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\n\t\t\t\t/* Initialisation complete - table can be drawn */\n\t\t\t\toSettings.bInitialised = true;\n\t\t\t\n\t\t\t\t/* Check if we need to initialise the table (it might not have been handed off to the\n\t\t\t\t * language processor)\n\t\t\t\t */\n\t\t\t\tif ( bInitHandedOff === false ) {\n\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\t/* Must be done after everything which can be overridden by the state saving! */\n\t\t\tif ( oInit.bStateSave )\n\t\t\t{\n\t\t\t\tfeatures.bStateSave = true;\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );\n\t\t\t\t_fnLoadState( oSettings, oInit, loadedInit );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadedInit();\n\t\t\t}\n\t\t\t\n\t\t} );\n\t\t_that = null;\n\t\treturn this;\n\t};\n\n\t\n\t/*\n\t * It is useful to have variables which are scoped locally so only the\n\t * DataTables functions can access them and they don't leak into global space.\n\t * At the same time these functions are often useful over multiple files in the\n\t * core and API, so we list, or at least document, all variables which are used\n\t * by DataTables as private variables here. This also ensures that there is no\n\t * clashing of variable names and that they can easily referenced for reuse.\n\t */\n\t\n\t\n\t// Defined else where\n\t//  _selector_run\n\t//  _selector_opts\n\t//  _selector_first\n\t//  _selector_row_indexes\n\t\n\tvar _ext; // DataTable.ext\n\tvar _Api; // DataTable.Api\n\tvar _api_register; // DataTable.Api.register\n\tvar _api_registerPlural; // DataTable.Api.registerPlural\n\t\n\tvar _re_dic = {};\n\tvar _re_new_lines = /[\\r\\n]/g;\n\tvar _re_html = /<.*?>/g;\n\t\n\t// This is not strict ISO8601 - Date.parse() is quite lax, although\n\t// implementations differ between browsers.\n\tvar _re_date = /^\\d{2,4}[\\.\\/\\-]\\d{1,2}[\\.\\/\\-]\\d{1,2}([T ]{1}\\d{1,2}[:\\.]\\d{2}([\\.:]\\d{2})?)?$/;\n\t\n\t// Escape regular expression special characters\n\tvar _re_escape_regex = new RegExp( '(\\\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\\\', '$', '^', '-' ].join('|\\\\') + ')', 'g' );\n\t\n\t// http://en.wikipedia.org/wiki/Foreign_exchange_market\n\t// - \\u20BD - Russian ruble.\n\t// - \\u20a9 - South Korean Won\n\t// - \\u20BA - Turkish Lira\n\t// - \\u20B9 - Indian Rupee\n\t// - R - Brazil (R$) and South Africa\n\t// - fr - Swiss Franc\n\t// - kr - Swedish krona, Norwegian krone and Danish krone\n\t// - \\u2009 is thin space and \\u202F is narrow no-break space, both used in many\n\t//   standards as thousands separators.\n\tvar _re_formatted_numeric = /[',$£€¥%\\u2009\\u202F\\u20BD\\u20a9\\u20BArfk]/gi;\n\t\n\t\n\tvar _empty = function ( d ) {\n\t\treturn !d || d === true || d === '-' ? true : false;\n\t};\n\t\n\t\n\tvar _intVal = function ( s ) {\n\t\tvar integer = parseInt( s, 10 );\n\t\treturn !isNaN(integer) && isFinite(s) ? integer : null;\n\t};\n\t\n\t// Convert from a formatted number with characters other than `.` as the\n\t// decimal place, to a Javascript number\n\tvar _numToDecimal = function ( num, decimalPoint ) {\n\t\t// Cache created regular expressions for speed as this function is called often\n\t\tif ( ! _re_dic[ decimalPoint ] ) {\n\t\t\t_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );\n\t\t}\n\t\treturn typeof num === 'string' && decimalPoint !== '.' ?\n\t\t\tnum.replace( /\\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :\n\t\t\tnum;\n\t};\n\t\n\t\n\tvar _isNumber = function ( d, decimalPoint, formatted ) {\n\t\tvar strType = typeof d === 'string';\n\t\n\t\t// If empty return immediately so there must be a number if it is a\n\t\t// formatted string (this stops the string \"k\", or \"kr\", etc being detected\n\t\t// as a formatted number for currency\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tif ( decimalPoint && strType ) {\n\t\t\td = _numToDecimal( d, decimalPoint );\n\t\t}\n\t\n\t\tif ( formatted && strType ) {\n\t\t\td = d.replace( _re_formatted_numeric, '' );\n\t\t}\n\t\n\t\treturn !isNaN( parseFloat(d) ) && isFinite( d );\n\t};\n\t\n\t\n\t// A string without HTML in it can be considered to be HTML still\n\tvar _isHtml = function ( d ) {\n\t\treturn _empty( d ) || typeof d === 'string';\n\t};\n\t\n\t\n\tvar _htmlNumeric = function ( d, decimalPoint, formatted ) {\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tvar html = _isHtml( d );\n\t\treturn ! html ?\n\t\t\tnull :\n\t\t\t_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?\n\t\t\t\ttrue :\n\t\t\t\tnull;\n\t};\n\t\n\t\n\tvar _pluck = function ( a, prop, prop2 ) {\n\t\tvar out = [];\n\t\tvar i=0, ien=a.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] && a[i][ prop ] ) {\n\t\t\t\t\tout.push( a[i][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] ) {\n\t\t\t\t\tout.push( a[i][ prop ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t// Basically the same as _pluck, but rather than looping over `a` we use `order`\n\t// as the indexes to pick from `a`\n\tvar _pluck_order = function ( a, order, prop, prop2 )\n\t{\n\t\tvar out = [];\n\t\tvar i=0, ien=order.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[ order[i] ][ prop ] ) {\n\t\t\t\t\tout.push( a[ order[i] ][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tout.push( a[ order[i] ][ prop ] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _range = function ( len, start )\n\t{\n\t\tvar out = [];\n\t\tvar end;\n\t\n\t\tif ( start === undefined ) {\n\t\t\tstart = 0;\n\t\t\tend = len;\n\t\t}\n\t\telse {\n\t\t\tend = start;\n\t\t\tstart = len;\n\t\t}\n\t\n\t\tfor ( var i=start ; i<end ; i++ ) {\n\t\t\tout.push( i );\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _removeEmpty = function ( a )\n\t{\n\t\tvar out = [];\n\t\n\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\tif ( a[i] ) { // careful - will remove all falsy values!\n\t\t\t\tout.push( a[i] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _stripHtml = function ( d ) {\n\t\treturn d.replace( _re_html, '' );\n\t};\n\t\n\t\n\t/**\n\t * Find the unique elements in a source array.\n\t *\n\t * @param  {array} src Source array\n\t * @return {array} Array of unique items\n\t * @ignore\n\t */\n\tvar _unique = function ( src )\n\t{\n\t\t// A faster unique method is to use object keys to identify used values,\n\t\t// but this doesn't work with arrays or objects, which we must also\n\t\t// consider. See jsperf.com/compare-array-unique-versions/4 for more\n\t\t// information.\n\t\tvar\n\t\t\tout = [],\n\t\t\tval,\n\t\t\ti, ien=src.length,\n\t\t\tj, k=0;\n\t\n\t\tagain: for ( i=0 ; i<ien ; i++ ) {\n\t\t\tval = src[i];\n\t\n\t\t\tfor ( j=0 ; j<k ; j++ ) {\n\t\t\t\tif ( out[j] === val ) {\n\t\t\t\t\tcontinue again;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tout.push( val );\n\t\t\tk++;\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t/**\n\t * DataTables utility methods\n\t * \n\t * This namespace provides helper methods that DataTables uses internally to\n\t * create a DataTable, but which are not exclusively used only for DataTables.\n\t * These methods can be used by extension authors to save the duplication of\n\t * code.\n\t *\n\t *  @namespace\n\t */\n\tDataTable.util = {\n\t\t/**\n\t\t * Throttle the calls to a function. Arguments and context are maintained\n\t\t * for the throttled function.\n\t\t *\n\t\t * @param {function} fn Function to be called\n\t\t * @param {integer} freq Call frequency in mS\n\t\t * @return {function} Wrapped function\n\t\t */\n\t\tthrottle: function ( fn, freq ) {\n\t\t\tvar\n\t\t\t\tfrequency = freq !== undefined ? freq : 200,\n\t\t\t\tlast,\n\t\t\t\ttimer;\n\t\n\t\t\treturn function () {\n\t\t\t\tvar\n\t\t\t\t\tthat = this,\n\t\t\t\t\tnow  = +new Date(),\n\t\t\t\t\targs = arguments;\n\t\n\t\t\t\tif ( last && now < last + frequency ) {\n\t\t\t\t\tclearTimeout( timer );\n\t\n\t\t\t\t\ttimer = setTimeout( function () {\n\t\t\t\t\t\tlast = undefined;\n\t\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t\t}, frequency );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlast = now;\n\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Escape a string such that it can be used in a regular expression\n\t\t *\n\t\t *  @param {string} val string to escape\n\t\t *  @returns {string} escaped string\n\t\t */\n\t\tescapeRegex: function ( val ) {\n\t\t\treturn val.replace( _re_escape_regex, '\\\\$1' );\n\t\t}\n\t};\n\t\n\t\n\t\n\t/**\n\t * Create a mapping object that allows camel case parameters to be looked up\n\t * for their Hungarian counterparts. The mapping is stored in a private\n\t * parameter called `_hungarianMap` which can be accessed on the source object.\n\t *  @param {object} o\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnHungarianMap ( o )\n\t{\n\t\tvar\n\t\t\thungarian = 'a aa ai ao as b fn i m o s ',\n\t\t\tmatch,\n\t\t\tnewKey,\n\t\t\tmap = {};\n\t\n\t\t$.each( o, function (key, val) {\n\t\t\tmatch = key.match(/^([^A-Z]+?)([A-Z])/);\n\t\n\t\t\tif ( match && hungarian.indexOf(match[1]+' ') !== -1 )\n\t\t\t{\n\t\t\t\tnewKey = key.replace( match[0], match[2].toLowerCase() );\n\t\t\t\tmap[ newKey ] = key;\n\t\n\t\t\t\tif ( match[1] === 'o' )\n\t\t\t\t{\n\t\t\t\t\t_fnHungarianMap( o[key] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\n\t\to._hungarianMap = map;\n\t}\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian, based on a Hungarian map\n\t * created by _fnHungarianMap.\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCamelToHungarian ( src, user, force )\n\t{\n\t\tif ( ! src._hungarianMap ) {\n\t\t\t_fnHungarianMap( src );\n\t\t}\n\t\n\t\tvar hungarianKey;\n\t\n\t\t$.each( user, function (key, val) {\n\t\t\thungarianKey = src._hungarianMap[ key ];\n\t\n\t\t\tif ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )\n\t\t\t{\n\t\t\t\t// For objects, we need to buzz down into the object to copy parameters\n\t\t\t\tif ( hungarianKey.charAt(0) === 'o' )\n\t\t\t\t{\n\t\t\t\t\t// Copy the camelCase options over to the hungarian\n\t\t\t\t\tif ( ! user[ hungarianKey ] ) {\n\t\t\t\t\t\tuser[ hungarianKey ] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, user[hungarianKey], user[key] );\n\t\n\t\t\t\t\t_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tuser[hungarianKey] = user[ key ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Language compatibility - when certain options are given, and others aren't, we\n\t * need to duplicate the values over, in order to provide backwards compatibility\n\t * with older language files.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLanguageCompat( lang )\n\t{\n\t\tvar defaults = DataTable.defaults.oLanguage;\n\t\tvar zeroRecords = lang.sZeroRecords;\n\t\n\t\t/* Backwards compatibility - if there is no sEmptyTable given, then use the same as\n\t\t * sZeroRecords - assuming that is given.\n\t\t */\n\t\tif ( ! lang.sEmptyTable && zeroRecords &&\n\t\t\tdefaults.sEmptyTable === \"No data available in table\" )\n\t\t{\n\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );\n\t\t}\n\t\n\t\t/* Likewise with loading records */\n\t\tif ( ! lang.sLoadingRecords && zeroRecords &&\n\t\t\tdefaults.sLoadingRecords === \"Loading...\" )\n\t\t{\n\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );\n\t\t}\n\t\n\t\t// Old parameter name of the thousands separator mapped onto the new\n\t\tif ( lang.sInfoThousands ) {\n\t\t\tlang.sThousands = lang.sInfoThousands;\n\t\t}\n\t\n\t\tvar decimal = lang.sDecimal;\n\t\tif ( decimal ) {\n\t\t\t_addNumericSort( decimal );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Map one parameter onto another\n\t *  @param {object} o Object to map\n\t *  @param {*} knew The new parameter name\n\t *  @param {*} old The old parameter name\n\t */\n\tvar _fnCompatMap = function ( o, knew, old ) {\n\t\tif ( o[ knew ] !== undefined ) {\n\t\t\to[ old ] = o[ knew ];\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for the main DT options. Note that the new\n\t * options are mapped onto the old parameters, so this is an external interface\n\t * change only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatOpts ( init )\n\t{\n\t\t_fnCompatMap( init, 'ordering',      'bSort' );\n\t\t_fnCompatMap( init, 'orderMulti',    'bSortMulti' );\n\t\t_fnCompatMap( init, 'orderClasses',  'bSortClasses' );\n\t\t_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );\n\t\t_fnCompatMap( init, 'order',         'aaSorting' );\n\t\t_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );\n\t\t_fnCompatMap( init, 'paging',        'bPaginate' );\n\t\t_fnCompatMap( init, 'pagingType',    'sPaginationType' );\n\t\t_fnCompatMap( init, 'pageLength',    'iDisplayLength' );\n\t\t_fnCompatMap( init, 'searching',     'bFilter' );\n\t\n\t\t// Boolean initialisation of x-scrolling\n\t\tif ( typeof init.sScrollX === 'boolean' ) {\n\t\t\tinit.sScrollX = init.sScrollX ? '100%' : '';\n\t\t}\n\t\tif ( typeof init.scrollX === 'boolean' ) {\n\t\t\tinit.scrollX = init.scrollX ? '100%' : '';\n\t\t}\n\t\n\t\t// Column search objects are in an array, so it needs to be converted\n\t\t// element by element\n\t\tvar searchCols = init.aoSearchCols;\n\t\n\t\tif ( searchCols ) {\n\t\t\tfor ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {\n\t\t\t\tif ( searchCols[i] ) {\n\t\t\t\t\t_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for column options. Note that the new options\n\t * are mapped onto the old parameters, so this is an external interface change\n\t * only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatCols ( init )\n\t{\n\t\t_fnCompatMap( init, 'orderable',     'bSortable' );\n\t\t_fnCompatMap( init, 'orderData',     'aDataSort' );\n\t\t_fnCompatMap( init, 'orderSequence', 'asSorting' );\n\t\t_fnCompatMap( init, 'orderDataType', 'sortDataType' );\n\t\n\t\t// orderData can be given as an integer\n\t\tvar dataSort = init.aDataSort;\n\t\tif ( dataSort && ! $.isArray( dataSort ) ) {\n\t\t\tinit.aDataSort = [ dataSort ];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Browser feature detection for capabilities, quirks\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBrowserDetect( settings )\n\t{\n\t\t// We don't need to do this every time DataTables is constructed, the values\n\t\t// calculated are specific to the browser and OS configuration which we\n\t\t// don't expect to change between initialisations\n\t\tif ( ! DataTable.__browser ) {\n\t\t\tvar browser = {};\n\t\t\tDataTable.__browser = browser;\n\t\n\t\t\t// Scrolling feature / quirks detection\n\t\t\tvar n = $('<div/>')\n\t\t\t\t.css( {\n\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: $(window).scrollLeft()*-1, // allow for scrolling\n\t\t\t\t\theight: 1,\n\t\t\t\t\twidth: 1,\n\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t} )\n\t\t\t\t.append(\n\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\ttop: 1,\n\t\t\t\t\t\t\tleft: 1,\n\t\t\t\t\t\t\twidth: 100,\n\t\t\t\t\t\t\toverflow: 'scroll'\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t\t\t\theight: 10\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t.appendTo( 'body' );\n\t\n\t\t\tvar outer = n.children();\n\t\t\tvar inner = outer.children();\n\t\n\t\t\t// Numbers below, in order, are:\n\t\t\t// inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth\n\t\t\t//\n\t\t\t// IE6 XP:                           100 100 100  83\n\t\t\t// IE7 Vista:                        100 100 100  83\n\t\t\t// IE 8+ Windows:                     83  83 100  83\n\t\t\t// Evergreen Windows:                 83  83 100  83\n\t\t\t// Evergreen Mac with scrollbars:     85  85 100  85\n\t\t\t// Evergreen Mac without scrollbars: 100 100 100 100\n\t\n\t\t\t// Get scrollbar width\n\t\t\tbrowser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;\n\t\n\t\t\t// IE6/7 will oversize a width 100% element inside a scrolling element, to\n\t\t\t// include the width of the scrollbar, while other browsers ensure the inner\n\t\t\t// element is contained without forcing scrolling\n\t\t\tbrowser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;\n\t\n\t\t\t// In rtl text layout, some browsers (most, but not all) will place the\n\t\t\t// scrollbar on the left, rather than the right.\n\t\t\tbrowser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;\n\t\n\t\t\t// IE8- don't provide height and width for getBoundingClientRect\n\t\t\tbrowser.bBounding = n[0].getBoundingClientRect().width ? true : false;\n\t\n\t\t\tn.remove();\n\t\t}\n\t\n\t\t$.extend( settings.oBrowser, DataTable.__browser );\n\t\tsettings.oScroll.iBarWidth = DataTable.__browser.barWidth;\n\t}\n\t\n\t\n\t/**\n\t * Array.prototype reduce[Right] method, used for browsers which don't support\n\t * JS 1.6. Done this way to reduce code size, since we iterate either way\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReduce ( that, fn, init, start, end, inc )\n\t{\n\t\tvar\n\t\t\ti = start,\n\t\t\tvalue,\n\t\t\tisSet = false;\n\t\n\t\tif ( init !== undefined ) {\n\t\t\tvalue = init;\n\t\t\tisSet = true;\n\t\t}\n\t\n\t\twhile ( i !== end ) {\n\t\t\tif ( ! that.hasOwnProperty(i) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\tvalue = isSet ?\n\t\t\t\tfn( value, that[i], i, that ) :\n\t\t\t\tthat[i];\n\t\n\t\t\tisSet = true;\n\t\t\ti += inc;\n\t\t}\n\t\n\t\treturn value;\n\t}\n\t\n\t/**\n\t * Add a column to the list used for the table with default values\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nTh The th element for this column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddColumn( oSettings, nTh )\n\t{\n\t\t// Add column to aoColumns array\n\t\tvar oDefaults = DataTable.defaults.column;\n\t\tvar iCol = oSettings.aoColumns.length;\n\t\tvar oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {\n\t\t\t\"nTh\": nTh ? nTh : document.createElement('th'),\n\t\t\t\"sTitle\":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',\n\t\t\t\"aDataSort\": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],\n\t\t\t\"mData\": oDefaults.mData ? oDefaults.mData : iCol,\n\t\t\tidx: iCol\n\t\t} );\n\t\toSettings.aoColumns.push( oCol );\n\t\n\t\t// Add search object for column specific search. Note that the `searchCols[ iCol ]`\n\t\t// passed into extend can be undefined. This allows the user to give a default\n\t\t// with only some of the parameters defined, and also not give a default\n\t\tvar searchCols = oSettings.aoPreSearchCols;\n\t\tsearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );\n\t\n\t\t// Use the default column options function to initialise classes etc\n\t\t_fnColumnOptions( oSettings, iCol, $(nTh).data() );\n\t}\n\t\n\t\n\t/**\n\t * Apply options for a column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iCol column index to consider\n\t *  @param {object} oOptions object with sType, bVisible and bSearchable etc\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnOptions( oSettings, iCol, oOptions )\n\t{\n\t\tvar oCol = oSettings.aoColumns[ iCol ];\n\t\tvar oClasses = oSettings.oClasses;\n\t\tvar th = $(oCol.nTh);\n\t\n\t\t// Try to get width information from the DOM. We can't get it from CSS\n\t\t// as we'd need to parse the CSS stylesheet. `width` option can override\n\t\tif ( ! oCol.sWidthOrig ) {\n\t\t\t// Width attribute\n\t\t\toCol.sWidthOrig = th.attr('width') || null;\n\t\n\t\t\t// Style attribute\n\t\t\tvar t = (th.attr('style') || '').match(/width:\\s*(\\d+[pxem%]+)/);\n\t\t\tif ( t ) {\n\t\t\t\toCol.sWidthOrig = t[1];\n\t\t\t}\n\t\t}\n\t\n\t\t/* User specified column options */\n\t\tif ( oOptions !== undefined && oOptions !== null )\n\t\t{\n\t\t\t// Backwards compatibility\n\t\t\t_fnCompatCols( oOptions );\n\t\n\t\t\t// Map camel case parameters to their Hungarian counterparts\n\t\t\t_fnCamelToHungarian( DataTable.defaults.column, oOptions );\n\t\n\t\t\t/* Backwards compatibility for mDataProp */\n\t\t\tif ( oOptions.mDataProp !== undefined && !oOptions.mData )\n\t\t\t{\n\t\t\t\toOptions.mData = oOptions.mDataProp;\n\t\t\t}\n\t\n\t\t\tif ( oOptions.sType )\n\t\t\t{\n\t\t\t\toCol._sManualType = oOptions.sType;\n\t\t\t}\n\t\n\t\t\t// `class` is a reserved word in Javascript, so we need to provide\n\t\t\t// the ability to use a valid name for the camel case input\n\t\t\tif ( oOptions.className && ! oOptions.sClass )\n\t\t\t{\n\t\t\t\toOptions.sClass = oOptions.className;\n\t\t\t}\n\t\n\t\t\t$.extend( oCol, oOptions );\n\t\t\t_fnMap( oCol, oOptions, \"sWidth\", \"sWidthOrig\" );\n\t\n\t\t\t/* iDataSort to be applied (backwards compatibility), but aDataSort will take\n\t\t\t * priority if defined\n\t\t\t */\n\t\t\tif ( oOptions.iDataSort !== undefined )\n\t\t\t{\n\t\t\t\toCol.aDataSort = [ oOptions.iDataSort ];\n\t\t\t}\n\t\t\t_fnMap( oCol, oOptions, \"aDataSort\" );\n\t\t}\n\t\n\t\t/* Cache the data get and set functions for speed */\n\t\tvar mDataSrc = oCol.mData;\n\t\tvar mData = _fnGetObjectDataFn( mDataSrc );\n\t\tvar mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;\n\t\n\t\tvar attrTest = function( src ) {\n\t\t\treturn typeof src === 'string' && src.indexOf('@') !== -1;\n\t\t};\n\t\toCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (\n\t\t\tattrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)\n\t\t);\n\t\toCol._setter = null;\n\t\n\t\toCol.fnGetData = function (rowData, type, meta) {\n\t\t\tvar innerData = mData( rowData, type, undefined, meta );\n\t\n\t\t\treturn mRender && type ?\n\t\t\t\tmRender( innerData, type, rowData, meta ) :\n\t\t\t\tinnerData;\n\t\t};\n\t\toCol.fnSetData = function ( rowData, val, meta ) {\n\t\t\treturn _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );\n\t\t};\n\t\n\t\t// Indicate if DataTables should read DOM data as an object or array\n\t\t// Used in _fnGetRowElements\n\t\tif ( typeof mDataSrc !== 'number' ) {\n\t\t\toSettings._rowReadObject = true;\n\t\t}\n\t\n\t\t/* Feature sorting overrides column specific when off */\n\t\tif ( !oSettings.oFeatures.bSort )\n\t\t{\n\t\t\toCol.bSortable = false;\n\t\t\tth.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called\n\t\t}\n\t\n\t\t/* Check that the class assignment is correct for sorting */\n\t\tvar bAsc = $.inArray('asc', oCol.asSorting) !== -1;\n\t\tvar bDesc = $.inArray('desc', oCol.asSorting) !== -1;\n\t\tif ( !oCol.bSortable || (!bAsc && !bDesc) )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableNone;\n\t\t\toCol.sSortingClassJUI = \"\";\n\t\t}\n\t\telse if ( bAsc && !bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableAsc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;\n\t\t}\n\t\telse if ( !bAsc && bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableDesc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;\n\t\t}\n\t\telse\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortable;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUI;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Adjust the table column widths for new data. Note: you would probably want to\n\t * do a redraw after calling this function!\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAdjustColumnSizing ( settings )\n\t{\n\t\t/* Not interested in doing column width calculation if auto-width is disabled */\n\t\tif ( settings.oFeatures.bAutoWidth !== false )\n\t\t{\n\t\t\tvar columns = settings.aoColumns;\n\t\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t\tfor ( var i=0 , iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tcolumns[i].nTh.style.width = columns[i].sWidth;\n\t\t\t}\n\t\t}\n\t\n\t\tvar scroll = settings.oScroll;\n\t\tif ( scroll.sY !== '' || scroll.sX !== '')\n\t\t{\n\t\t\t_fnScrollDraw( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'column-sizing', [settings] );\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of a visible column to the index in the data array (take account\n\t * of hidden columns)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iMatch Visible column index to lookup\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisibleToColumnIndex( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\n\t\treturn typeof aiVis[iMatch] === 'number' ?\n\t\t\taiVis[iMatch] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of an index in the data array and convert it to the visible\n\t *   column index (take account of hidden columns)\n\t *  @param {int} iMatch Column index to lookup\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnIndexToVisible( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\tvar iPos = $.inArray( iMatch, aiVis );\n\t\n\t\treturn iPos !== -1 ? iPos : null;\n\t}\n\t\n\t\n\t/**\n\t * Get the number of visible columns\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the number of visible columns\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisbleColumns( oSettings )\n\t{\n\t\tvar vis = 0;\n\t\n\t\t// No reduce in IE8, use a loop for now\n\t\t$.each( oSettings.aoColumns, function ( i, col ) {\n\t\t\tif ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {\n\t\t\t\tvis++;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn vis;\n\t}\n\t\n\t\n\t/**\n\t * Get an array of column indexes that match a given property\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sParam Parameter in aoColumns to look for - typically\n\t *    bVisible or bSearchable\n\t *  @returns {array} Array of indexes with matched properties\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetColumns( oSettings, sParam )\n\t{\n\t\tvar a = [];\n\t\n\t\t$.map( oSettings.aoColumns, function(val, i) {\n\t\t\tif ( val[sParam] ) {\n\t\t\t\ta.push( i );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn a;\n\t}\n\t\n\t\n\t/**\n\t * Calculate the 'type' of a column\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnTypes ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar data = settings.aoData;\n\t\tvar types = DataTable.ext.type.detect;\n\t\tvar i, ien, j, jen, k, ken;\n\t\tvar col, cell, detectedType, cache;\n\t\n\t\t// For each column, spin over the \n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcol = columns[i];\n\t\t\tcache = [];\n\t\n\t\t\tif ( ! col.sType && col._sManualType ) {\n\t\t\t\tcol.sType = col._sManualType;\n\t\t\t}\n\t\t\telse if ( ! col.sType ) {\n\t\t\t\tfor ( j=0, jen=types.length ; j<jen ; j++ ) {\n\t\t\t\t\tfor ( k=0, ken=data.length ; k<ken ; k++ ) {\n\t\t\t\t\t\t// Use a cache array so we only need to get the type data\n\t\t\t\t\t\t// from the formatter once (when using multiple detectors)\n\t\t\t\t\t\tif ( cache[k] === undefined ) {\n\t\t\t\t\t\t\tcache[k] = _fnGetCellData( settings, k, i, 'type' );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tdetectedType = types[j]( cache[k], settings );\n\t\n\t\t\t\t\t\t// If null, then this type can't apply to this column, so\n\t\t\t\t\t\t// rather than testing all cells, break out. There is an\n\t\t\t\t\t\t// exception for the last type which is `html`. We need to\n\t\t\t\t\t\t// scan all rows since it is possible to mix string and HTML\n\t\t\t\t\t\t// types\n\t\t\t\t\t\tif ( ! detectedType && j !== types.length-1 ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Only a single match is needed for html type since it is\n\t\t\t\t\t\t// bottom of the pile and very similar to string\n\t\t\t\t\t\tif ( detectedType === 'html' ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Type is valid for all data points in the column - use this\n\t\t\t\t\t// type\n\t\t\t\t\tif ( detectedType ) {\n\t\t\t\t\t\tcol.sType = detectedType;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Fall back - if no type was detected, always use string\n\t\t\t\tif ( ! col.sType ) {\n\t\t\t\t\tcol.sType = 'string';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Take the column definitions and static columns arrays and calculate how\n\t * they relate to column indexes. The callback function will then apply the\n\t * definition found for a column to a suitable configuration object.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aoColDefs The aoColumnDefs array that is to be applied\n\t *  @param {array} aoCols The aoColumns array that defines columns individually\n\t *  @param {function} fn Callback function - takes two parameters, the calculated\n\t *    column index and the definition for that column.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, def;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Column definitions with aTargets\n\t\tif ( aoColDefs )\n\t\t{\n\t\t\t/* Loop over the definitions array - loop in reverse so first instance has priority */\n\t\t\tfor ( i=aoColDefs.length-1 ; i>=0 ; i-- )\n\t\t\t{\n\t\t\t\tdef = aoColDefs[i];\n\t\n\t\t\t\t/* Each definition can target multiple columns, as it is an array */\n\t\t\t\tvar aTargets = def.targets !== undefined ?\n\t\t\t\t\tdef.targets :\n\t\t\t\t\tdef.aTargets;\n\t\n\t\t\t\tif ( ! $.isArray( aTargets ) )\n\t\t\t\t{\n\t\t\t\t\taTargets = [ aTargets ];\n\t\t\t\t}\n\t\n\t\t\t\tfor ( j=0, jLen=aTargets.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Add columns that we don't yet know about */\n\t\t\t\t\t\twhile( columns.length <= aTargets[j] )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_fnAddColumn( oSettings );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t/* Integer, basic index */\n\t\t\t\t\t\tfn( aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Negative integer, right to left column counting */\n\t\t\t\t\t\tfn( columns.length+aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'string' )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Class name matching on TH element */\n\t\t\t\t\t\tfor ( k=0, kLen=columns.length ; k<kLen ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( aTargets[j] == \"_all\" ||\n\t\t\t\t\t\t\t     $(columns[k].nTh).hasClass( aTargets[j] ) )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfn( k, def );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// Statically defined columns array\n\t\tif ( aoCols )\n\t\t{\n\t\t\tfor ( i=0, iLen=aoCols.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfn( i, aoCols[i] );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * Add a data array to the table, creating DOM node etc. This is the parallel to\n\t * _fnGatherData, but for adding rows from a Javascript source, rather than a\n\t * DOM source.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aData data array to be added\n\t *  @param {node} [nTr] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddData ( oSettings, aDataIn, nTr, anTds )\n\t{\n\t\t/* Create the object for storing information about this new row */\n\t\tvar iRow = oSettings.aoData.length;\n\t\tvar oData = $.extend( true, {}, DataTable.models.oRow, {\n\t\t\tsrc: nTr ? 'dom' : 'data',\n\t\t\tidx: iRow\n\t\t} );\n\t\n\t\toData._aData = aDataIn;\n\t\toSettings.aoData.push( oData );\n\t\n\t\t/* Create the cells */\n\t\tvar nTd, sThisType;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Invalidate the column types as the new data needs to be revalidated\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tcolumns[i].sType = null;\n\t\t}\n\t\n\t\t/* Add to the display array */\n\t\toSettings.aiDisplayMaster.push( iRow );\n\t\n\t\tvar id = oSettings.rowIdFn( aDataIn );\n\t\tif ( id !== undefined ) {\n\t\t\toSettings.aIds[ id ] = oData;\n\t\t}\n\t\n\t\t/* Create the DOM information, or register it if already present */\n\t\tif ( nTr || ! oSettings.oFeatures.bDeferRender )\n\t\t{\n\t\t\t_fnCreateTr( oSettings, iRow, nTr, anTds );\n\t\t}\n\t\n\t\treturn iRow;\n\t}\n\t\n\t\n\t/**\n\t * Add one or more TR elements to the table. Generally we'd expect to\n\t * use this for reading data from a DOM sourced table, but it could be\n\t * used for an TR element. Note that if a TR is given, it is used (i.e.\n\t * it is not cloned).\n\t *  @param {object} settings dataTables settings object\n\t *  @param {array|node|jQuery} trs The TR element(s) to add to the table\n\t *  @returns {array} Array of indexes for the added rows\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddTr( settings, trs )\n\t{\n\t\tvar row;\n\t\n\t\t// Allow an individual node to be passed in\n\t\tif ( ! (trs instanceof $) ) {\n\t\t\ttrs = $(trs);\n\t\t}\n\t\n\t\treturn trs.map( function (i, el) {\n\t\t\trow = _fnGetRowElements( settings, el );\n\t\t\treturn _fnAddData( settings, row.data, el, row.cells );\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Take a TR element and convert it to an index in aoData\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} n the TR element to find\n\t *  @returns {int} index if the node is found, null if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToDataIndex( oSettings, n )\n\t{\n\t\treturn (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;\n\t}\n\t\n\t\n\t/**\n\t * Take a TD element and convert it into a column data index (not the visible index)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow The row number the TD/TH can be found in\n\t *  @param {node} n The TD/TH element to find\n\t *  @returns {int} index if the node is found, -1 if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToColumnIndex( oSettings, iRow, n )\n\t{\n\t\treturn $.inArray( n, oSettings.aoData[ iRow ].anCells );\n\t}\n\t\n\t\n\t/**\n\t * Get the data for a given cell from the internal cache, taking into account data mapping\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {string} type data get type ('display', 'type' 'filter' 'sort')\n\t *  @returns {*} Cell data\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetCellData( settings, rowIdx, colIdx, type )\n\t{\n\t\tvar draw           = settings.iDraw;\n\t\tvar col            = settings.aoColumns[colIdx];\n\t\tvar rowData        = settings.aoData[rowIdx]._aData;\n\t\tvar defaultContent = col.sDefaultContent;\n\t\tvar cellData       = col.fnGetData( rowData, type, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t} );\n\t\n\t\tif ( cellData === undefined ) {\n\t\t\tif ( settings.iDrawError != draw && defaultContent === null ) {\n\t\t\t\t_fnLog( settings, 0, \"Requested unknown parameter \"+\n\t\t\t\t\t(typeof col.mData=='function' ? '{function}' : \"'\"+col.mData+\"'\")+\n\t\t\t\t\t\" for row \"+rowIdx+\", column \"+colIdx, 4 );\n\t\t\t\tsettings.iDrawError = draw;\n\t\t\t}\n\t\t\treturn defaultContent;\n\t\t}\n\t\n\t\t// When the data source is null and a specific data type is requested (i.e.\n\t\t// not the original data), we can use default column data\n\t\tif ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {\n\t\t\tcellData = defaultContent;\n\t\t}\n\t\telse if ( typeof cellData === 'function' ) {\n\t\t\t// If the data source is a function, then we run it and use the return,\n\t\t\t// executing in the scope of the data object (for instances)\n\t\t\treturn cellData.call( rowData );\n\t\t}\n\t\n\t\tif ( cellData === null && type == 'display' ) {\n\t\t\treturn '';\n\t\t}\n\t\treturn cellData;\n\t}\n\t\n\t\n\t/**\n\t * Set the value for a specific cell, into the internal data cache\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {*} val Value to set\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetCellData( settings, rowIdx, colIdx, val )\n\t{\n\t\tvar col     = settings.aoColumns[colIdx];\n\t\tvar rowData = settings.aoData[rowIdx]._aData;\n\t\n\t\tcol.fnSetData( rowData, val, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t}  );\n\t}\n\t\n\t\n\t// Private variable that is used to match action syntax in the data property object\n\tvar __reArray = /\\[.*?\\]$/;\n\tvar __reFn = /\\(\\)$/;\n\t\n\t/**\n\t * Split string on periods, taking into account escaped periods\n\t * @param  {string} str String to split\n\t * @return {array} Split string\n\t */\n\tfunction _fnSplitObjNotation( str )\n\t{\n\t\treturn $.map( str.match(/(\\\\.|[^\\.])+/g) || [''], function ( s ) {\n\t\t\treturn s.replace(/\\\\\\./g, '.');\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to get data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data get function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Build an object of get functions, and wrap them in a single call */\n\t\t\tvar o = {};\n\t\t\t$.each( mSource, function (key, val) {\n\t\t\t\tif ( val ) {\n\t\t\t\t\to[key] = _fnGetObjectDataFn( val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\tvar t = o[type] || o._;\n\t\t\t\treturn t !== undefined ?\n\t\t\t\t\tt(data, type, row, meta) :\n\t\t\t\t\tdata;\n\t\t\t};\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Give an empty string for rendering / sorting etc */\n\t\t\treturn function (data) { // type, row and meta also passed, but not used\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\treturn mSource( data, type, row, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* If there is a . in the source string then the data source is in a\n\t\t\t * nested object so we loop over the data for each level to get the next\n\t\t\t * level down. On each loop we test for undefined, and if found immediately\n\t\t\t * return. This allows entire objects to be missing and sDefaultContent to\n\t\t\t * be used if defined, rather than throwing an error\n\t\t\t */\n\t\t\tvar fetchData = function (data, type, src) {\n\t\t\t\tvar arrayNotation, funcNotation, out, innerSrc;\n\t\n\t\t\t\tif ( src !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tvar a = _fnSplitObjNotation( src );\n\t\n\t\t\t\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if we are dealing with special notation\n\t\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Array notation\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\n\t\t\t\t\t\t\t// Condition allows simply [] to be passed in\n\t\t\t\t\t\t\tif ( a[i] !== \"\" ) {\n\t\t\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tout = [];\n\t\n\t\t\t\t\t\t\t// Get the remainder of the nested object to get\n\t\t\t\t\t\t\ta.splice( 0, i+1 );\n\t\t\t\t\t\t\tinnerSrc = a.join('.');\n\t\n\t\t\t\t\t\t\t// Traverse each entry in the array getting the properties requested\n\t\t\t\t\t\t\tif ( $.isArray( data ) ) {\n\t\t\t\t\t\t\t\tfor ( var j=0, jLen=data.length ; j<jLen ; j++ ) {\n\t\t\t\t\t\t\t\t\tout.push( fetchData( data[j], type, innerSrc ) );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\t// If a string is given in between the array notation indicators, that\n\t\t\t\t\t\t\t// is used to join the strings together, otherwise an array is returned\n\t\t\t\t\t\t\tvar join = arrayNotation[0].substring(1, arrayNotation[0].length-1);\n\t\t\t\t\t\t\tdata = (join===\"\") ? out : out.join(join);\n\t\n\t\t\t\t\t\t\t// The inner call to fetchData has already traversed through the remainder\n\t\t\t\t\t\t\t// of the source requested, so we exit from the loop\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Function call\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\t\tdata = data[ a[i] ]();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( data === null || data[ a[i] ] === undefined )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn data;\n\t\t\t};\n\t\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn fetchData( data, type, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn data[mSource];\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to set data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data set function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Unlike get, only the underscore (global) option is used for for\n\t\t\t * setting data since we don't know the type here. This is why an object\n\t\t\t * option is not documented for `mData` (which is read/write), but it is\n\t\t\t * for `mRender` which is read only.\n\t\t\t */\n\t\t\treturn _fnSetObjectDataFn( mSource._ );\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Nothing to do when the data source is null */\n\t\t\treturn function () {};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, val, meta) {\n\t\t\t\tmSource( data, 'set', val, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* Like the get, we need to get data from a nested object */\n\t\t\tvar setData = function (data, val, src) {\n\t\t\t\tvar a = _fnSplitObjNotation( src ), b;\n\t\t\t\tvar aLast = a[a.length-1];\n\t\t\t\tvar arrayNotation, funcNotation, o, innerSrc;\n\t\n\t\t\t\tfor ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\t// Check if we are dealing with an array notation request\n\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\t\t\t\t\tdata[ a[i] ] = [];\n\t\n\t\t\t\t\t\t// Get the remainder of the nested object to set so we can recurse\n\t\t\t\t\t\tb = a.slice();\n\t\t\t\t\t\tb.splice( 0, i+1 );\n\t\t\t\t\t\tinnerSrc = b.join('.');\n\t\n\t\t\t\t\t\t// Traverse each entry in the array setting the properties requested\n\t\t\t\t\t\tif ( $.isArray( val ) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor ( var j=0, jLen=val.length ; j<jLen ; j++ )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\to = {};\n\t\t\t\t\t\t\t\tsetData( o, val[j], innerSrc );\n\t\t\t\t\t\t\t\tdata[ a[i] ].push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We've been asked to save data to an array, but it\n\t\t\t\t\t\t\t// isn't array data to be saved. Best that can be done\n\t\t\t\t\t\t\t// is to just save the value.\n\t\t\t\t\t\t\tdata[ a[i] ] = val;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// The inner call to setData has already traversed through the remainder\n\t\t\t\t\t\t// of the source and has set the data, thus we can exit here\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Function call\n\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\tdata = data[ a[i] ]( val );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If the nested object doesn't currently exist - since we are\n\t\t\t\t\t// trying to set the value - create it\n\t\t\t\t\tif ( data[ a[i] ] === null || data[ a[i] ] === undefined )\n\t\t\t\t\t{\n\t\t\t\t\t\tdata[ a[i] ] = {};\n\t\t\t\t\t}\n\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t}\n\t\n\t\t\t\t// Last item in the input - i.e, the actual set\n\t\t\t\tif ( aLast.match(__reFn ) )\n\t\t\t\t{\n\t\t\t\t\t// Function call\n\t\t\t\t\tdata = data[ aLast.replace(__reFn, '') ]( val );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// If array notation is used, we just want to strip it and use the property name\n\t\t\t\t\t// and assign the value. If it isn't used, then we get the result we want anyway\n\t\t\t\t\tdata[ aLast.replace(__reArray, '') ] = val;\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\treturn setData( data, val, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\tdata[mSource] = val;\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return an array with the full table data\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns array {array} aData Master data array\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetDataMaster ( settings )\n\t{\n\t\treturn _pluck( settings.aoData, '_aData' );\n\t}\n\t\n\t\n\t/**\n\t * Nuke the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnClearTable( settings )\n\t{\n\t\tsettings.aoData.length = 0;\n\t\tsettings.aiDisplayMaster.length = 0;\n\t\tsettings.aiDisplay.length = 0;\n\t\tsettings.aIds = {};\n\t}\n\t\n\t\n\t /**\n\t * Take an array of integers (index array) and remove a target integer (value - not\n\t * the key!)\n\t *  @param {array} a Index array to target\n\t *  @param {int} iTarget value to find\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDeleteIndex( a, iTarget, splice )\n\t{\n\t\tvar iTargetIndex = -1;\n\t\n\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( a[i] == iTarget )\n\t\t\t{\n\t\t\t\tiTargetIndex = i;\n\t\t\t}\n\t\t\telse if ( a[i] > iTarget )\n\t\t\t{\n\t\t\t\ta[i]--;\n\t\t\t}\n\t\t}\n\t\n\t\tif ( iTargetIndex != -1 && splice === undefined )\n\t\t{\n\t\t\ta.splice( iTargetIndex, 1 );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Mark cached data as invalid such that a re-read of the data will occur when\n\t * the cached data is next requested. Also update from the data source object.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {int}    rowIdx   Row index to invalidate\n\t * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'\n\t *     or 'data'\n\t * @param {int}    [colIdx] Column index to invalidate. If undefined the whole\n\t *     row will be invalidated\n\t * @memberof DataTable#oApi\n\t *\n\t * @todo For the modularisation of v1.11 this will need to become a callback, so\n\t *   the sort and filter methods can subscribe to it. That will required\n\t *   initialisation options for sorting, which is why it is not already baked in\n\t */\n\tfunction _fnInvalidate( settings, rowIdx, src, colIdx )\n\t{\n\t\tvar row = settings.aoData[ rowIdx ];\n\t\tvar i, ien;\n\t\tvar cellWrite = function ( cell, col ) {\n\t\t\t// This is very frustrating, but in IE if you just write directly\n\t\t\t// to innerHTML, and elements that are overwritten are GC'ed,\n\t\t\t// even if there is a reference to them elsewhere\n\t\t\twhile ( cell.childNodes.length ) {\n\t\t\t\tcell.removeChild( cell.firstChild );\n\t\t\t}\n\t\n\t\t\tcell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );\n\t\t};\n\t\n\t\t// Are we reading last data from DOM or the data object?\n\t\tif ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {\n\t\t\t// Read the data from the DOM\n\t\t\trow._aData = _fnGetRowElements(\n\t\t\t\t\tsettings, row, colIdx, colIdx === undefined ? undefined : row._aData\n\t\t\t\t)\n\t\t\t\t.data;\n\t\t}\n\t\telse {\n\t\t\t// Reading from data object, update the DOM\n\t\t\tvar cells = row.anCells;\n\t\n\t\t\tif ( cells ) {\n\t\t\t\tif ( colIdx !== undefined ) {\n\t\t\t\t\tcellWrite( cells[colIdx], colIdx );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tcellWrite( cells[i], i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// For both row and cell invalidation, the cached data for sorting and\n\t\t// filtering is nulled out\n\t\trow._aSortData = null;\n\t\trow._aFilterData = null;\n\t\n\t\t// Invalidate the type for a specific column (if given) or all columns since\n\t\t// the data might have changed\n\t\tvar cols = settings.aoColumns;\n\t\tif ( colIdx !== undefined ) {\n\t\t\tcols[ colIdx ].sType = null;\n\t\t}\n\t\telse {\n\t\t\tfor ( i=0, ien=cols.length ; i<ien ; i++ ) {\n\t\t\t\tcols[i].sType = null;\n\t\t\t}\n\t\n\t\t\t// Update DataTables special `DT_*` attributes for the row\n\t\t\t_fnRowAttributes( settings, row );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a data source object from an HTML row, reading the contents of the\n\t * cells that are in the row.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {node|object} TR element from which to read data or existing row\n\t *   object from which to re-read the data from the cells\n\t * @param {int} [colIdx] Optional column index\n\t * @param {array|object} [d] Data source object. If `colIdx` is given then this\n\t *   parameter should also be given and will be used to write the data into.\n\t *   Only the column in question will be written\n\t * @returns {object} Object with two parameters: `data` the data read, in\n\t *   document order, and `cells` and array of nodes (they can be useful to the\n\t *   caller, so rather than needing a second traversal to get them, just return\n\t *   them from here).\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetRowElements( settings, row, colIdx, d )\n\t{\n\t\tvar\n\t\t\ttds = [],\n\t\t\ttd = row.firstChild,\n\t\t\tname, col, o, i=0, contents,\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tobjectRead = settings._rowReadObject;\n\t\n\t\t// Allow the data object to be passed in, or construct\n\t\td = d !== undefined ?\n\t\t\td :\n\t\t\tobjectRead ?\n\t\t\t\t{} :\n\t\t\t\t[];\n\t\n\t\tvar attr = function ( str, td  ) {\n\t\t\tif ( typeof str === 'string' ) {\n\t\t\t\tvar idx = str.indexOf('@');\n\t\n\t\t\t\tif ( idx !== -1 ) {\n\t\t\t\t\tvar attr = str.substring( idx+1 );\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( str );\n\t\t\t\t\tsetter( d, td.getAttribute( attr ) );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\n\t\t// Read data from a cell and store into the data object\n\t\tvar cellProcess = function ( cell ) {\n\t\t\tif ( colIdx === undefined || colIdx === i ) {\n\t\t\t\tcol = columns[i];\n\t\t\t\tcontents = $.trim(cell.innerHTML);\n\t\n\t\t\t\tif ( col && col._bAttrSrc ) {\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( col.mData._ );\n\t\t\t\t\tsetter( d, contents );\n\t\n\t\t\t\t\tattr( col.mData.sort, cell );\n\t\t\t\t\tattr( col.mData.type, cell );\n\t\t\t\t\tattr( col.mData.filter, cell );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Depending on the `data` option for the columns the data can\n\t\t\t\t\t// be read to either an object or an array.\n\t\t\t\t\tif ( objectRead ) {\n\t\t\t\t\t\tif ( ! col._setter ) {\n\t\t\t\t\t\t\t// Cache the setter function\n\t\t\t\t\t\t\tcol._setter = _fnSetObjectDataFn( col.mData );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcol._setter( d, contents );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\td[i] = contents;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t};\n\t\n\t\tif ( td ) {\n\t\t\t// `tr` element was passed in\n\t\t\twhile ( td ) {\n\t\t\t\tname = td.nodeName.toUpperCase();\n\t\n\t\t\t\tif ( name == \"TD\" || name == \"TH\" ) {\n\t\t\t\t\tcellProcess( td );\n\t\t\t\t\ttds.push( td );\n\t\t\t\t}\n\t\n\t\t\t\ttd = td.nextSibling;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Existing row object passed in\n\t\t\ttds = row.anCells;\n\t\n\t\t\tfor ( var j=0, jen=tds.length ; j<jen ; j++ ) {\n\t\t\t\tcellProcess( tds[j] );\n\t\t\t}\n\t\t}\n\t\n\t\t// Read the ID from the DOM if present\n\t\tvar rowNode = row.firstChild ? row : row.nTr;\n\t\n\t\tif ( rowNode ) {\n\t\t\tvar id = rowNode.getAttribute( 'id' );\n\t\n\t\t\tif ( id ) {\n\t\t\t\t_fnSetObjectDataFn( settings.rowId )( d, id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn {\n\t\t\tdata: d,\n\t\t\tcells: tds\n\t\t};\n\t}\n\t/**\n\t * Create a new TR element (and it's TD children) for a row\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow Row to consider\n\t *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCreateTr ( oSettings, iRow, nTrIn, anTds )\n\t{\n\t\tvar\n\t\t\trow = oSettings.aoData[iRow],\n\t\t\trowData = row._aData,\n\t\t\tcells = [],\n\t\t\tnTr, nTd, oCol,\n\t\t\ti, iLen;\n\t\n\t\tif ( row.nTr === null )\n\t\t{\n\t\t\tnTr = nTrIn || document.createElement('tr');\n\t\n\t\t\trow.nTr = nTr;\n\t\t\trow.anCells = cells;\n\t\n\t\t\t/* Use a private property on the node to allow reserve mapping from the node\n\t\t\t * to the aoData array for fast look up\n\t\t\t */\n\t\t\tnTr._DT_RowIndex = iRow;\n\t\n\t\t\t/* Special parameters can be given by the data source to be used on the row */\n\t\t\t_fnRowAttributes( oSettings, row );\n\t\n\t\t\t/* Process each column */\n\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toCol = oSettings.aoColumns[i];\n\t\n\t\t\t\tnTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );\n\t\t\t\tnTd._DT_CellIndex = {\n\t\t\t\t\trow: iRow,\n\t\t\t\t\tcolumn: i\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tcells.push( nTd );\n\t\n\t\t\t\t// Need to create the HTML if new, or if a rendering function is defined\n\t\t\t\tif ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&\n\t\t\t\t\t (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')\n\t\t\t\t) {\n\t\t\t\t\tnTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );\n\t\t\t\t}\n\t\n\t\t\t\t/* Add user defined class */\n\t\t\t\tif ( oCol.sClass )\n\t\t\t\t{\n\t\t\t\t\tnTd.className += ' '+oCol.sClass;\n\t\t\t\t}\n\t\n\t\t\t\t// Visibility - add or remove as required\n\t\t\t\tif ( oCol.bVisible && ! nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTr.appendChild( nTd );\n\t\t\t\t}\n\t\t\t\telse if ( ! oCol.bVisible && nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTd.parentNode.removeChild( nTd );\n\t\t\t\t}\n\t\n\t\t\t\tif ( oCol.fnCreatedCell )\n\t\t\t\t{\n\t\t\t\t\toCol.fnCreatedCell.call( oSettings.oInstance,\n\t\t\t\t\t\tnTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );\n\t\t}\n\t\n\t\t// Remove once webkit bug 131819 and Chromium bug 365619 have been resolved\n\t\t// and deployed\n\t\trow.nTr.setAttribute( 'role', 'row' );\n\t}\n\t\n\t\n\t/**\n\t * Add attributes to a row based on the special `DT_*` parameters in a data\n\t * source object.\n\t *  @param {object} settings DataTables settings object\n\t *  @param {object} DataTables row object for the row to be modified\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnRowAttributes( settings, row )\n\t{\n\t\tvar tr = row.nTr;\n\t\tvar data = row._aData;\n\t\n\t\tif ( tr ) {\n\t\t\tvar id = settings.rowIdFn( data );\n\t\n\t\t\tif ( id ) {\n\t\t\t\ttr.id = id;\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowClass ) {\n\t\t\t\t// Remove any classes added by DT_RowClass before\n\t\t\t\tvar a = data.DT_RowClass.split(' ');\n\t\t\t\trow.__rowc = row.__rowc ?\n\t\t\t\t\t_unique( row.__rowc.concat( a ) ) :\n\t\t\t\t\ta;\n\t\n\t\t\t\t$(tr)\n\t\t\t\t\t.removeClass( row.__rowc.join(' ') )\n\t\t\t\t\t.addClass( data.DT_RowClass );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowAttr ) {\n\t\t\t\t$(tr).attr( data.DT_RowAttr );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowData ) {\n\t\t\t\t$(tr).data( data.DT_RowData );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Create the HTML header for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBuildHead( oSettings )\n\t{\n\t\tvar i, ien, cell, row, column;\n\t\tvar thead = oSettings.nTHead;\n\t\tvar tfoot = oSettings.nTFoot;\n\t\tvar createHeader = $('th, td', thead).length === 0;\n\t\tvar classes = oSettings.oClasses;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\tif ( createHeader ) {\n\t\t\trow = $('<tr/>').appendTo( thead );\n\t\t}\n\t\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcell = $( column.nTh ).addClass( column.sClass );\n\t\n\t\t\tif ( createHeader ) {\n\t\t\t\tcell.appendTo( row );\n\t\t\t}\n\t\n\t\t\t// 1.11 move into sorting\n\t\t\tif ( oSettings.oFeatures.bSort ) {\n\t\t\t\tcell.addClass( column.sSortingClass );\n\t\n\t\t\t\tif ( column.bSortable !== false ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.attr( 'tabindex', oSettings.iTabIndex )\n\t\t\t\t\t\t.attr( 'aria-controls', oSettings.sTableId );\n\t\n\t\t\t\t\t_fnSortAttachListener( oSettings, column.nTh, i );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( column.sTitle != cell[0].innerHTML ) {\n\t\t\t\tcell.html( column.sTitle );\n\t\t\t}\n\t\n\t\t\t_fnRenderer( oSettings, 'header' )(\n\t\t\t\toSettings, cell, column, classes\n\t\t\t);\n\t\t}\n\t\n\t\tif ( createHeader ) {\n\t\t\t_fnDetectHeader( oSettings.aoHeader, thead );\n\t\t}\n\t\t\n\t\t/* ARIA role for the rows */\n\t \t$(thead).find('>tr').attr('role', 'row');\n\t\n\t\t/* Deal with the footer - add classes if required */\n\t\t$(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );\n\t\t$(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );\n\t\n\t\t// Cache the footer cells. Note that we only take the cells from the first\n\t\t// row in the footer. If there is more than one row the user wants to\n\t\t// interact with, they need to use the table().foot() method. Note also this\n\t\t// allows cells to be used for multiple columns using colspan\n\t\tif ( tfoot !== null ) {\n\t\t\tvar cells = oSettings.aoFooter[0];\n\t\n\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tcolumn = columns[i];\n\t\t\t\tcolumn.nTf = cells[i].cell;\n\t\n\t\t\t\tif ( column.sClass ) {\n\t\t\t\t\t$(column.nTf).addClass( column.sClass );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the header (or footer) element based on the column visibility states. The\n\t * methodology here is to use the layout array from _fnDetectHeader, modified for\n\t * the instantaneous column visibility, to construct the new layout. The grid is\n\t * traversed over cell at a time in a rows x columns grid fashion, although each\n\t * cell insert can cover multiple elements in the grid - which is tracks using the\n\t * aApplied array. Cell inserts in the grid will only occur where there isn't\n\t * already a cell in that position.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param array {objects} aoSource Layout array from _fnDetectHeader\n\t *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDrawHead( oSettings, aoSource, bIncludeHidden )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, n, nLocalTr;\n\t\tvar aoLocal = [];\n\t\tvar aApplied = [];\n\t\tvar iColumns = oSettings.aoColumns.length;\n\t\tvar iRowspan, iColspan;\n\t\n\t\tif ( ! aoSource )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif (  bIncludeHidden === undefined )\n\t\t{\n\t\t\tbIncludeHidden = false;\n\t\t}\n\t\n\t\t/* Make a copy of the master layout array, but without the visible columns in it */\n\t\tfor ( i=0, iLen=aoSource.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taoLocal[i] = aoSource[i].slice();\n\t\t\taoLocal[i].nTr = aoSource[i].nTr;\n\t\n\t\t\t/* Remove any columns which are currently hidden */\n\t\t\tfor ( j=iColumns-1 ; j>=0 ; j-- )\n\t\t\t{\n\t\t\t\tif ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )\n\t\t\t\t{\n\t\t\t\t\taoLocal[i].splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Prep the applied array - it needs an element for each row */\n\t\t\taApplied.push( [] );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnLocalTr = aoLocal[i].nTr;\n\t\n\t\t\t/* All cells are going to be replaced, so empty out the row */\n\t\t\tif ( nLocalTr )\n\t\t\t{\n\t\t\t\twhile( (n = nLocalTr.firstChild) )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.removeChild( n );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tfor ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tiRowspan = 1;\n\t\t\t\tiColspan = 1;\n\t\n\t\t\t\t/* Check to see if there is already a cell (row/colspan) covering our target\n\t\t\t\t * insert point. If there is, then there is nothing to do.\n\t\t\t\t */\n\t\t\t\tif ( aApplied[i][j] === undefined )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.appendChild( aoLocal[i][j].cell );\n\t\t\t\t\taApplied[i][j] = 1;\n\t\n\t\t\t\t\t/* Expand the cell to cover as many rows as needed */\n\t\t\t\t\twhile ( aoLocal[i+iRowspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\taApplied[i+iRowspan][j] = 1;\n\t\t\t\t\t\tiRowspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Expand the cell to cover as many columns as needed */\n\t\t\t\t\twhile ( aoLocal[i][j+iColspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Must update the applied array over the rows for the columns */\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taApplied[i+k][j+iColspan] = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiColspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Do the actual expansion in the DOM */\n\t\t\t\t\t$(aoLocal[i][j].cell)\n\t\t\t\t\t\t.attr('rowspan', iRowspan)\n\t\t\t\t\t\t.attr('colspan', iColspan);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Insert the required TR nodes into the table for display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDraw( oSettings )\n\t{\n\t\t/* Provide a pre-callback function which can be used to cancel the draw is false is returned */\n\t\tvar aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );\n\t\tif ( $.inArray( false, aPreDraw ) !== -1 )\n\t\t{\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar i, iLen, n;\n\t\tvar anRows = [];\n\t\tvar iRowCount = 0;\n\t\tvar asStripeClasses = oSettings.asStripeClasses;\n\t\tvar iStripes = asStripeClasses.length;\n\t\tvar iOpenRows = oSettings.aoOpenRows.length;\n\t\tvar oLang = oSettings.oLanguage;\n\t\tvar iInitDisplayStart = oSettings.iInitDisplayStart;\n\t\tvar bServerSide = _fnDataSource( oSettings ) == 'ssp';\n\t\tvar aiDisplay = oSettings.aiDisplay;\n\t\n\t\toSettings.bDrawing = true;\n\t\n\t\t/* Check and see if we have an initial draw position from state saving */\n\t\tif ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )\n\t\t{\n\t\t\toSettings._iDisplayStart = bServerSide ?\n\t\t\t\tiInitDisplayStart :\n\t\t\t\tiInitDisplayStart >= oSettings.fnRecordsDisplay() ?\n\t\t\t\t\t0 :\n\t\t\t\t\tiInitDisplayStart;\n\t\n\t\t\toSettings.iInitDisplayStart = -1;\n\t\t}\n\t\n\t\tvar iDisplayStart = oSettings._iDisplayStart;\n\t\tvar iDisplayEnd = oSettings.fnDisplayEnd();\n\t\n\t\t/* Server-side processing draw intercept */\n\t\tif ( oSettings.bDeferLoading )\n\t\t{\n\t\t\toSettings.bDeferLoading = false;\n\t\t\toSettings.iDraw++;\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t}\n\t\telse if ( !bServerSide )\n\t\t{\n\t\t\toSettings.iDraw++;\n\t\t}\n\t\telse if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( aiDisplay.length !== 0 )\n\t\t{\n\t\t\tvar iStart = bServerSide ? 0 : iDisplayStart;\n\t\t\tvar iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;\n\t\n\t\t\tfor ( var j=iStart ; j<iEnd ; j++ )\n\t\t\t{\n\t\t\t\tvar iDataIndex = aiDisplay[j];\n\t\t\t\tvar aoData = oSettings.aoData[ iDataIndex ];\n\t\t\t\tif ( aoData.nTr === null )\n\t\t\t\t{\n\t\t\t\t\t_fnCreateTr( oSettings, iDataIndex );\n\t\t\t\t}\n\t\n\t\t\t\tvar nRow = aoData.nTr;\n\t\n\t\t\t\t/* Remove the old striping classes and then add the new one */\n\t\t\t\tif ( iStripes !== 0 )\n\t\t\t\t{\n\t\t\t\t\tvar sStripe = asStripeClasses[ iRowCount % iStripes ];\n\t\t\t\t\tif ( aoData._sRowStripe != sStripe )\n\t\t\t\t\t{\n\t\t\t\t\t\t$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );\n\t\t\t\t\t\taoData._sRowStripe = sStripe;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Row callback functions - might want to manipulate the row\n\t\t\t\t// iRowCount and j are not currently documented. Are they at all\n\t\t\t\t// useful?\n\t\t\t\t_fnCallbackFire( oSettings, 'aoRowCallback', null,\n\t\t\t\t\t[nRow, aoData._aData, iRowCount, j] );\n\t\n\t\t\t\tanRows.push( nRow );\n\t\t\t\tiRowCount++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Table is empty - create a row with an empty message in it */\n\t\t\tvar sZero = oLang.sZeroRecords;\n\t\t\tif ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )\n\t\t\t{\n\t\t\t\tsZero = oLang.sLoadingRecords;\n\t\t\t}\n\t\t\telse if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )\n\t\t\t{\n\t\t\t\tsZero = oLang.sEmptyTable;\n\t\t\t}\n\t\n\t\t\tanRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )\n\t\t\t\t.append( $('<td />', {\n\t\t\t\t\t'valign':  'top',\n\t\t\t\t\t'colSpan': _fnVisbleColumns( oSettings ),\n\t\t\t\t\t'class':   oSettings.oClasses.sRowEmpty\n\t\t\t\t} ).html( sZero ) )[0];\n\t\t}\n\t\n\t\t/* Header and footer callbacks */\n\t\t_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\t_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\tvar body = $(oSettings.nTBody);\n\t\n\t\tbody.children().detach();\n\t\tbody.append( $(anRows) );\n\t\n\t\t/* Call all required callback functions for the end of a draw */\n\t\t_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );\n\t\n\t\t/* Draw is complete, sorting and filtering must be as well */\n\t\toSettings.bSorted = false;\n\t\toSettings.bFiltered = false;\n\t\toSettings.bDrawing = false;\n\t}\n\t\n\t\n\t/**\n\t * Redraw the table - taking account of the various features which are enabled\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {boolean} [holdPosition] Keep the current paging position. By default\n\t *    the paging is reset to the first page\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReDraw( settings, holdPosition )\n\t{\n\t\tvar\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tsort     = features.bSort,\n\t\t\tfilter   = features.bFilter;\n\t\n\t\tif ( sort ) {\n\t\t\t_fnSort( settings );\n\t\t}\n\t\n\t\tif ( filter ) {\n\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch );\n\t\t}\n\t\telse {\n\t\t\t// No filtering, so we want to just use the display master\n\t\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\t}\n\t\n\t\tif ( holdPosition !== true ) {\n\t\t\tsettings._iDisplayStart = 0;\n\t\t}\n\t\n\t\t// Let any modules know about the draw hold position state (used by\n\t\t// scrolling internally)\n\t\tsettings._drawHold = holdPosition;\n\t\n\t\t_fnDraw( settings );\n\t\n\t\tsettings._drawHold = false;\n\t}\n\t\n\t\n\t/**\n\t * Add the options to the page HTML for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddOptionsHtml ( oSettings )\n\t{\n\t\tvar classes = oSettings.oClasses;\n\t\tvar table = $(oSettings.nTable);\n\t\tvar holding = $('<div/>').insertBefore( table ); // Holding element for speed\n\t\tvar features = oSettings.oFeatures;\n\t\n\t\t// All DataTables are wrapped in a div\n\t\tvar insert = $('<div/>', {\n\t\t\tid:      oSettings.sTableId+'_wrapper',\n\t\t\t'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)\n\t\t} );\n\t\n\t\toSettings.nHolding = holding[0];\n\t\toSettings.nTableWrapper = insert[0];\n\t\toSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;\n\t\n\t\t/* Loop over the user set positioning and place the elements as needed */\n\t\tvar aDom = oSettings.sDom.split('');\n\t\tvar featureNode, cOption, nNewNode, cNext, sAttr, j;\n\t\tfor ( var i=0 ; i<aDom.length ; i++ )\n\t\t{\n\t\t\tfeatureNode = null;\n\t\t\tcOption = aDom[i];\n\t\n\t\t\tif ( cOption == '<' )\n\t\t\t{\n\t\t\t\t/* New container div */\n\t\t\t\tnNewNode = $('<div/>')[0];\n\t\n\t\t\t\t/* Check to see if we should append an id and/or a class name to the container */\n\t\t\t\tcNext = aDom[i+1];\n\t\t\t\tif ( cNext == \"'\" || cNext == '\"' )\n\t\t\t\t{\n\t\t\t\t\tsAttr = \"\";\n\t\t\t\t\tj = 2;\n\t\t\t\t\twhile ( aDom[i+j] != cNext )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr += aDom[i+j];\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Replace jQuery UI constants @todo depreciated */\n\t\t\t\t\tif ( sAttr == \"H\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIHeader;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr == \"F\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIFooter;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* The attribute can be in the format of \"#id.class\", \"#id\" or \"class\" This logic\n\t\t\t\t\t * breaks the string into parts and applies them as needed\n\t\t\t\t\t */\n\t\t\t\t\tif ( sAttr.indexOf('.') != -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar aSplit = sAttr.split('.');\n\t\t\t\t\t\tnNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);\n\t\t\t\t\t\tnNewNode.className = aSplit[1];\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr.charAt(0) == \"#\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.id = sAttr.substr(1, sAttr.length-1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.className = sAttr;\n\t\t\t\t\t}\n\t\n\t\t\t\t\ti += j; /* Move along the position array */\n\t\t\t\t}\n\t\n\t\t\t\tinsert.append( nNewNode );\n\t\t\t\tinsert = $(nNewNode);\n\t\t\t}\n\t\t\telse if ( cOption == '>' )\n\t\t\t{\n\t\t\t\t/* End container div */\n\t\t\t\tinsert = insert.parent();\n\t\t\t}\n\t\t\t// @todo Move options into their own plugins?\n\t\t\telse if ( cOption == 'l' && features.bPaginate && features.bLengthChange )\n\t\t\t{\n\t\t\t\t/* Length */\n\t\t\t\tfeatureNode = _fnFeatureHtmlLength( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'f' && features.bFilter )\n\t\t\t{\n\t\t\t\t/* Filter */\n\t\t\t\tfeatureNode = _fnFeatureHtmlFilter( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'r' && features.bProcessing )\n\t\t\t{\n\t\t\t\t/* pRocessing */\n\t\t\t\tfeatureNode = _fnFeatureHtmlProcessing( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 't' )\n\t\t\t{\n\t\t\t\t/* Table */\n\t\t\t\tfeatureNode = _fnFeatureHtmlTable( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption ==  'i' && features.bInfo )\n\t\t\t{\n\t\t\t\t/* Info */\n\t\t\t\tfeatureNode = _fnFeatureHtmlInfo( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'p' && features.bPaginate )\n\t\t\t{\n\t\t\t\t/* Pagination */\n\t\t\t\tfeatureNode = _fnFeatureHtmlPaginate( oSettings );\n\t\t\t}\n\t\t\telse if ( DataTable.ext.feature.length !== 0 )\n\t\t\t{\n\t\t\t\t/* Plug-in features */\n\t\t\t\tvar aoFeatures = DataTable.ext.feature;\n\t\t\t\tfor ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )\n\t\t\t\t{\n\t\t\t\t\tif ( cOption == aoFeatures[k].cFeature )\n\t\t\t\t\t{\n\t\t\t\t\t\tfeatureNode = aoFeatures[k].fnInit( oSettings );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Add to the 2D features array */\n\t\t\tif ( featureNode )\n\t\t\t{\n\t\t\t\tvar aanFeatures = oSettings.aanFeatures;\n\t\n\t\t\t\tif ( ! aanFeatures[cOption] )\n\t\t\t\t{\n\t\t\t\t\taanFeatures[cOption] = [];\n\t\t\t\t}\n\t\n\t\t\t\taanFeatures[cOption].push( featureNode );\n\t\t\t\tinsert.append( featureNode );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Built our DOM structure - replace the holding div with what we want */\n\t\tholding.replaceWith( insert );\n\t\toSettings.nHolding = null;\n\t}\n\t\n\t\n\t/**\n\t * Use the DOM source to create up an array of header cells. The idea here is to\n\t * create a layout grid (array) of rows x columns, which contains a reference\n\t * to the cell that that point in the grid (regardless of col/rowspan), such that\n\t * any column / row could be removed and the new grid constructed\n\t *  @param array {object} aLayout Array to store the calculated layout in\n\t *  @param {node} nThead The header/footer element for the table\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDetectHeader ( aLayout, nThead )\n\t{\n\t\tvar nTrs = $(nThead).children('tr');\n\t\tvar nTr, nCell;\n\t\tvar i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;\n\t\tvar bUnique;\n\t\tvar fnShiftCol = function ( a, i, j ) {\n\t\t\tvar k = a[i];\n\t                while ( k[j] ) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\treturn j;\n\t\t};\n\t\n\t\taLayout.splice( 0, aLayout.length );\n\t\n\t\t/* We know how many rows there are in the layout - so prep it */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taLayout.push( [] );\n\t\t}\n\t\n\t\t/* Calculate a layout array */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnTr = nTrs[i];\n\t\t\tiColumn = 0;\n\t\n\t\t\t/* For every cell in the row... */\n\t\t\tnCell = nTr.firstChild;\n\t\t\twhile ( nCell ) {\n\t\t\t\tif ( nCell.nodeName.toUpperCase() == \"TD\" ||\n\t\t\t\t     nCell.nodeName.toUpperCase() == \"TH\" )\n\t\t\t\t{\n\t\t\t\t\t/* Get the col and rowspan attributes from the DOM and sanitise them */\n\t\t\t\t\tiColspan = nCell.getAttribute('colspan') * 1;\n\t\t\t\t\tiRowspan = nCell.getAttribute('rowspan') * 1;\n\t\t\t\t\tiColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;\n\t\t\t\t\tiRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;\n\t\n\t\t\t\t\t/* There might be colspan cells already in this row, so shift our target\n\t\t\t\t\t * accordingly\n\t\t\t\t\t */\n\t\t\t\t\tiColShifted = fnShiftCol( aLayout, i, iColumn );\n\t\n\t\t\t\t\t/* Cache calculation for unique columns */\n\t\t\t\t\tbUnique = iColspan === 1 ? true : false;\n\t\n\t\t\t\t\t/* If there is col / rowspan, copy the information into the layout grid */\n\t\t\t\t\tfor ( l=0 ; l<iColspan ; l++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taLayout[i+k][iColShifted+l] = {\n\t\t\t\t\t\t\t\t\"cell\": nCell,\n\t\t\t\t\t\t\t\t\"unique\": bUnique\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\taLayout[i+k].nTr = nTr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnCell = nCell.nextSibling;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Get an array of unique th elements, one for each column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nHeader automatically detect the layout from this node - optional\n\t *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional\n\t *  @returns array {node} aReturn list of unique th's\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetUniqueThs ( oSettings, nHeader, aLayout )\n\t{\n\t\tvar aReturn = [];\n\t\tif ( !aLayout )\n\t\t{\n\t\t\taLayout = oSettings.aoHeader;\n\t\t\tif ( nHeader )\n\t\t\t{\n\t\t\t\taLayout = [];\n\t\t\t\t_fnDetectHeader( aLayout, nHeader );\n\t\t\t}\n\t\t}\n\t\n\t\tfor ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfor ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( aLayout[i][j].unique &&\n\t\t\t\t\t (!aReturn[j] || !oSettings.bSortCellsTop) )\n\t\t\t\t{\n\t\t\t\t\taReturn[j] = aLayout[i][j].cell;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn aReturn;\n\t}\n\t\n\t/**\n\t * Create an Ajax call based on the table's settings, taking into account that\n\t * parameters can have multiple forms, and backwards compatibility.\n\t *\n\t * @param {object} oSettings dataTables settings object\n\t * @param {array} data Data to send to the server, required by\n\t *     DataTables - may be augmented by developer callbacks\n\t * @param {function} fn Callback function to run when data is obtained\n\t */\n\tfunction _fnBuildAjax( oSettings, data, fn )\n\t{\n\t\t// Compatibility with 1.9-, allow fnServerData and event to manipulate\n\t\t_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );\n\t\n\t\t// Convert to object based for 1.10+ if using the old array scheme which can\n\t\t// come from server-side processing or serverParams\n\t\tif ( data && $.isArray(data) ) {\n\t\t\tvar tmp = {};\n\t\t\tvar rbracket = /(.*?)\\[\\]$/;\n\t\n\t\t\t$.each( data, function (key, val) {\n\t\t\t\tvar match = val.name.match(rbracket);\n\t\n\t\t\t\tif ( match ) {\n\t\t\t\t\t// Support for arrays\n\t\t\t\t\tvar name = match[0];\n\t\n\t\t\t\t\tif ( ! tmp[ name ] ) {\n\t\t\t\t\t\ttmp[ name ] = [];\n\t\t\t\t\t}\n\t\t\t\t\ttmp[ name ].push( val.value );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttmp[val.name] = val.value;\n\t\t\t\t}\n\t\t\t} );\n\t\t\tdata = tmp;\n\t\t}\n\t\n\t\tvar ajaxData;\n\t\tvar ajax = oSettings.ajax;\n\t\tvar instance = oSettings.oInstance;\n\t\tvar callback = function ( json ) {\n\t\t\t_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );\n\t\t\tfn( json );\n\t\t};\n\t\n\t\tif ( $.isPlainObject( ajax ) && ajax.data )\n\t\t{\n\t\t\tajaxData = ajax.data;\n\t\n\t\t\tvar newData = $.isFunction( ajaxData ) ?\n\t\t\t\tajaxData( data, oSettings ) :  // fn can manipulate data or return\n\t\t\t\tajaxData;                      // an object object or array to merge\n\t\n\t\t\t// If the function returned something, use that alone\n\t\t\tdata = $.isFunction( ajaxData ) && newData ?\n\t\t\t\tnewData :\n\t\t\t\t$.extend( true, data, newData );\n\t\n\t\t\t// Remove the data property as we've resolved it already and don't want\n\t\t\t// jQuery to do it again (it is restored at the end of the function)\n\t\t\tdelete ajax.data;\n\t\t}\n\t\n\t\tvar baseAjax = {\n\t\t\t\"data\": data,\n\t\t\t\"success\": function (json) {\n\t\t\t\tvar error = json.error || json.sError;\n\t\t\t\tif ( error ) {\n\t\t\t\t\t_fnLog( oSettings, 0, error );\n\t\t\t\t}\n\t\n\t\t\t\toSettings.json = json;\n\t\t\t\tcallback( json );\n\t\t\t},\n\t\t\t\"dataType\": \"json\",\n\t\t\t\"cache\": false,\n\t\t\t\"type\": oSettings.sServerMethod,\n\t\t\t\"error\": function (xhr, error, thrown) {\n\t\t\t\tvar ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );\n\t\n\t\t\t\tif ( $.inArray( true, ret ) === -1 ) {\n\t\t\t\t\tif ( error == \"parsererror\" ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Invalid JSON response', 1 );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( xhr.readyState === 4 ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Ajax error', 7 );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\t}\n\t\t};\n\t\n\t\t// Store the data submitted for the API\n\t\toSettings.oAjaxData = data;\n\t\n\t\t// Allow plug-ins and external processes to modify the data\n\t\t_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );\n\t\n\t\tif ( oSettings.fnServerData )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.fnServerData.call( instance,\n\t\t\t\toSettings.sAjaxSource,\n\t\t\t\t$.map( data, function (val, key) { // Need to convert back to 1.9 trad format\n\t\t\t\t\treturn { name: key, value: val };\n\t\t\t\t} ),\n\t\t\t\tcallback,\n\t\t\t\toSettings\n\t\t\t);\n\t\t}\n\t\telse if ( oSettings.sAjaxSource || typeof ajax === 'string' )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, {\n\t\t\t\turl: ajax || oSettings.sAjaxSource\n\t\t\t} ) );\n\t\t}\n\t\telse if ( $.isFunction( ajax ) )\n\t\t{\n\t\t\t// Is a function - let the caller define what needs to be done\n\t\t\toSettings.jqXHR = ajax.call( instance, data, callback, oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Object to extend the base settings\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );\n\t\n\t\t\t// Restore for next time around\n\t\t\tajax.data = ajaxData;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Update the table using an Ajax call\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {boolean} Block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdate( settings )\n\t{\n\t\tif ( settings.bAjaxDataGet ) {\n\t\t\tsettings.iDraw++;\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t_fnBuildAjax(\n\t\t\t\tsettings,\n\t\t\t\t_fnAjaxParameters( settings ),\n\t\t\t\tfunction(json) {\n\t\t\t\t\t_fnAjaxUpdateDraw( settings, json );\n\t\t\t\t}\n\t\t\t);\n\t\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\t\n\t/**\n\t * Build up the parameters in an object needed for a server-side processing\n\t * request. Note that this is basically done twice, is different ways - a modern\n\t * method which is used by default in DataTables 1.10 which uses objects and\n\t * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if\n\t * the sAjaxSource option is used in the initialisation, or the legacyAjax\n\t * option is set.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {bool} block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxParameters( settings )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tcolumnCount = columns.length,\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tpreSearch = settings.oPreviousSearch,\n\t\t\tpreColSearch = settings.aoPreSearchCols,\n\t\t\ti, data = [], dataProp, column, columnSearch,\n\t\t\tsort = _fnSortFlatten( settings ),\n\t\t\tdisplayStart = settings._iDisplayStart,\n\t\t\tdisplayLength = features.bPaginate !== false ?\n\t\t\t\tsettings._iDisplayLength :\n\t\t\t\t-1;\n\t\n\t\tvar param = function ( name, value ) {\n\t\t\tdata.push( { 'name': name, 'value': value } );\n\t\t};\n\t\n\t\t// DataTables 1.9- compatible method\n\t\tparam( 'sEcho',          settings.iDraw );\n\t\tparam( 'iColumns',       columnCount );\n\t\tparam( 'sColumns',       _pluck( columns, 'sName' ).join(',') );\n\t\tparam( 'iDisplayStart',  displayStart );\n\t\tparam( 'iDisplayLength', displayLength );\n\t\n\t\t// DataTables 1.10+ method\n\t\tvar d = {\n\t\t\tdraw:    settings.iDraw,\n\t\t\tcolumns: [],\n\t\t\torder:   [],\n\t\t\tstart:   displayStart,\n\t\t\tlength:  displayLength,\n\t\t\tsearch:  {\n\t\t\t\tvalue: preSearch.sSearch,\n\t\t\t\tregex: preSearch.bRegex\n\t\t\t}\n\t\t};\n\t\n\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcolumnSearch = preColSearch[i];\n\t\t\tdataProp = typeof column.mData==\"function\" ? 'function' : column.mData ;\n\t\n\t\t\td.columns.push( {\n\t\t\t\tdata:       dataProp,\n\t\t\t\tname:       column.sName,\n\t\t\t\tsearchable: column.bSearchable,\n\t\t\t\torderable:  column.bSortable,\n\t\t\t\tsearch:     {\n\t\t\t\t\tvalue: columnSearch.sSearch,\n\t\t\t\t\tregex: columnSearch.bRegex\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\tparam( \"mDataProp_\"+i, dataProp );\n\t\n\t\t\tif ( features.bFilter ) {\n\t\t\t\tparam( 'sSearch_'+i,     columnSearch.sSearch );\n\t\t\t\tparam( 'bRegex_'+i,      columnSearch.bRegex );\n\t\t\t\tparam( 'bSearchable_'+i, column.bSearchable );\n\t\t\t}\n\t\n\t\t\tif ( features.bSort ) {\n\t\t\t\tparam( 'bSortable_'+i, column.bSortable );\n\t\t\t}\n\t\t}\n\t\n\t\tif ( features.bFilter ) {\n\t\t\tparam( 'sSearch', preSearch.sSearch );\n\t\t\tparam( 'bRegex', preSearch.bRegex );\n\t\t}\n\t\n\t\tif ( features.bSort ) {\n\t\t\t$.each( sort, function ( i, val ) {\n\t\t\t\td.order.push( { column: val.col, dir: val.dir } );\n\t\n\t\t\t\tparam( 'iSortCol_'+i, val.col );\n\t\t\t\tparam( 'sSortDir_'+i, val.dir );\n\t\t\t} );\n\t\n\t\t\tparam( 'iSortingCols', sort.length );\n\t\t}\n\t\n\t\t// If the legacy.ajax parameter is null, then we automatically decide which\n\t\t// form to use, based on sAjaxSource\n\t\tvar legacy = DataTable.ext.legacy.ajax;\n\t\tif ( legacy === null ) {\n\t\t\treturn settings.sAjaxSource ? data : d;\n\t\t}\n\t\n\t\t// Otherwise, if legacy has been specified then we use that to decide on the\n\t\t// form\n\t\treturn legacy ? data : d;\n\t}\n\t\n\t\n\t/**\n\t * Data the data from the server (nuking the old) and redraw the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} json json data return from the server.\n\t *  @param {string} json.sEcho Tracking flag for DataTables to match requests\n\t *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering\n\t *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering\n\t *  @param {array} json.aaData The data to display on this page\n\t *  @param {string} [json.sColumns] Column ordering (sName, comma separated)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdateDraw ( settings, json )\n\t{\n\t\t// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.\n\t\t// Support both\n\t\tvar compat = function ( old, modern ) {\n\t\t\treturn json[old] !== undefined ? json[old] : json[modern];\n\t\t};\n\t\n\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\tvar draw            = compat( 'sEcho',                'draw' );\n\t\tvar recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );\n\t\tvar recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );\n\t\n\t\tif ( draw ) {\n\t\t\t// Protect against out of sequence returns\n\t\t\tif ( draw*1 < settings.iDraw ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettings.iDraw = draw * 1;\n\t\t}\n\t\n\t\t_fnClearTable( settings );\n\t\tsettings._iRecordsTotal   = parseInt(recordsTotal, 10);\n\t\tsettings._iRecordsDisplay = parseInt(recordsFiltered, 10);\n\t\n\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t_fnAddData( settings, data[i] );\n\t\t}\n\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\n\t\tsettings.bAjaxDataGet = false;\n\t\t_fnDraw( settings );\n\t\n\t\tif ( ! settings._bInitComplete ) {\n\t\t\t_fnInitComplete( settings, json );\n\t\t}\n\t\n\t\tsettings.bAjaxDataGet = true;\n\t\t_fnProcessingDisplay( settings, false );\n\t}\n\t\n\t\n\t/**\n\t * Get the data from the JSON data source to use for drawing a table. Using\n\t * `_fnGetObjectDataFn` allows the data to be sourced from a property of the\n\t * source object, or from a processing function.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param  {object} json Data source object / array from the server\n\t *  @return {array} Array of data to use\n\t */\n\tfunction _fnAjaxDataSrc ( oSettings, json )\n\t{\n\t\tvar dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?\n\t\t\toSettings.ajax.dataSrc :\n\t\t\toSettings.sAjaxDataProp; // Compatibility with 1.9-.\n\t\n\t\t// Compatibility with 1.9-. In order to read from aaData, check if the\n\t\t// default has been changed, if not, check for aaData\n\t\tif ( dataSrc === 'data' ) {\n\t\t\treturn json.aaData || json[dataSrc];\n\t\t}\n\t\n\t\treturn dataSrc !== \"\" ?\n\t\t\t_fnGetObjectDataFn( dataSrc )( json ) :\n\t\t\tjson;\n\t}\n\t\n\t/**\n\t * Generate the node required for filtering text\n\t *  @returns {node} Filter control element\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlFilter ( settings )\n\t{\n\t\tvar classes = settings.oClasses;\n\t\tvar tableId = settings.sTableId;\n\t\tvar language = settings.oLanguage;\n\t\tvar previousSearch = settings.oPreviousSearch;\n\t\tvar features = settings.aanFeatures;\n\t\tvar input = '<input type=\"search\" class=\"'+classes.sFilterInput+'\"/>';\n\t\n\t\tvar str = language.sSearch;\n\t\tstr = str.match(/_INPUT_/) ?\n\t\t\tstr.replace('_INPUT_', input) :\n\t\t\tstr+input;\n\t\n\t\tvar filter = $('<div/>', {\n\t\t\t\t'id': ! features.f ? tableId+'_filter' : null,\n\t\t\t\t'class': classes.sFilter\n\t\t\t} )\n\t\t\t.append( $('<label/>' ).append( str ) );\n\t\n\t\tvar searchFn = function() {\n\t\t\t/* Update all other filter input elements for the new display */\n\t\t\tvar n = features.f;\n\t\t\tvar val = !this.value ? \"\" : this.value; // mental IE8 fix :-(\n\t\n\t\t\t/* Now do the filter */\n\t\t\tif ( val != previousSearch.sSearch ) {\n\t\t\t\t_fnFilterComplete( settings, {\n\t\t\t\t\t\"sSearch\": val,\n\t\t\t\t\t\"bRegex\": previousSearch.bRegex,\n\t\t\t\t\t\"bSmart\": previousSearch.bSmart ,\n\t\t\t\t\t\"bCaseInsensitive\": previousSearch.bCaseInsensitive\n\t\t\t\t} );\n\t\n\t\t\t\t// Need to redraw, without resorting\n\t\t\t\tsettings._iDisplayStart = 0;\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t};\n\t\n\t\tvar searchDelay = settings.searchDelay !== null ?\n\t\t\tsettings.searchDelay :\n\t\t\t_fnDataSource( settings ) === 'ssp' ?\n\t\t\t\t400 :\n\t\t\t\t0;\n\t\n\t\tvar jqFilter = $('input', filter)\n\t\t\t.val( previousSearch.sSearch )\n\t\t\t.attr( 'placeholder', language.sSearchPlaceholder )\n\t\t\t.on(\n\t\t\t\t'keyup.DT search.DT input.DT paste.DT cut.DT',\n\t\t\t\tsearchDelay ?\n\t\t\t\t\t_fnThrottle( searchFn, searchDelay ) :\n\t\t\t\t\tsearchFn\n\t\t\t)\n\t\t\t.on( 'keypress.DT', function(e) {\n\t\t\t\t/* Prevent form submission */\n\t\t\t\tif ( e.keyCode == 13 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.attr('aria-controls', tableId);\n\t\n\t\t// Update the input elements whenever the table is filtered\n\t\t$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame...\n\t\t\t\ttry {\n\t\t\t\t\tif ( jqFilter[0] !== document.activeElement ) {\n\t\t\t\t\t\tjqFilter.val( previousSearch.sSearch );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch ( e ) {}\n\t\t\t}\n\t\t} );\n\t\n\t\treturn filter[0];\n\t}\n\t\n\t\n\t/**\n\t * Filter the table using both the global filter and column based filtering\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oSearch search information\n\t *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterComplete ( oSettings, oInput, iForce )\n\t{\n\t\tvar oPrevSearch = oSettings.oPreviousSearch;\n\t\tvar aoPrevSearch = oSettings.aoPreSearchCols;\n\t\tvar fnSaveFilter = function ( oFilter ) {\n\t\t\t/* Save the filtering values */\n\t\t\toPrevSearch.sSearch = oFilter.sSearch;\n\t\t\toPrevSearch.bRegex = oFilter.bRegex;\n\t\t\toPrevSearch.bSmart = oFilter.bSmart;\n\t\t\toPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;\n\t\t};\n\t\tvar fnRegex = function ( o ) {\n\t\t\t// Backwards compatibility with the bEscapeRegex option\n\t\t\treturn o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;\n\t\t};\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo As per sort - can this be moved into an event handler?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\t/* In server-side processing all filtering is done by the server, so no point hanging around here */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' )\n\t\t{\n\t\t\t/* Global filter */\n\t\t\t_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );\n\t\t\tfnSaveFilter( oInput );\n\t\n\t\t\t/* Now do the individual column filter */\n\t\t\tfor ( var i=0 ; i<aoPrevSearch.length ; i++ )\n\t\t\t{\n\t\t\t\t_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),\n\t\t\t\t\taoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );\n\t\t\t}\n\t\n\t\t\t/* Custom filtering */\n\t\t\t_fnFilterCustom( oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfnSaveFilter( oInput );\n\t\t}\n\t\n\t\t/* Tell the draw function we have been filtering */\n\t\toSettings.bFiltered = true;\n\t\t_fnCallbackFire( oSettings, null, 'search', [oSettings] );\n\t}\n\t\n\t\n\t/**\n\t * Apply custom filtering functions\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCustom( settings )\n\t{\n\t\tvar filters = DataTable.ext.search;\n\t\tvar displayRows = settings.aiDisplay;\n\t\tvar row, rowIdx;\n\t\n\t\tfor ( var i=0, ien=filters.length ; i<ien ; i++ ) {\n\t\t\tvar rows = [];\n\t\n\t\t\t// Loop over each row and see if it should be included\n\t\t\tfor ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {\n\t\t\t\trowIdx = displayRows[ j ];\n\t\t\t\trow = settings.aoData[ rowIdx ];\n\t\n\t\t\t\tif ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {\n\t\t\t\t\trows.push( rowIdx );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// So the array reference doesn't break set the results into the\n\t\t\t// existing array\n\t\t\tdisplayRows.length = 0;\n\t\t\t$.merge( displayRows, rows );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Filter the table on a per-column basis\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sInput string to filter on\n\t *  @param {int} iColumn column to filter\n\t *  @param {bool} bRegex treat search string as a regular expression or not\n\t *  @param {bool} bSmart use smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )\n\t{\n\t\tif ( searchStr === '' ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar data;\n\t\tvar out = [];\n\t\tvar display = settings.aiDisplay;\n\t\tvar rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );\n\t\n\t\tfor ( var i=0 ; i<display.length ; i++ ) {\n\t\t\tdata = settings.aoData[ display[i] ]._aFilterData[ colIdx ];\n\t\n\t\t\tif ( rpSearch.test( data ) ) {\n\t\t\t\tout.push( display[i] );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aiDisplay = out;\n\t}\n\t\n\t\n\t/**\n\t * Filter the data table based on user input and draw the table\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} input string to filter on\n\t *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)\n\t *  @param {bool} regex treat as a regular expression or not\n\t *  @param {bool} smart perform smart filtering or not\n\t *  @param {bool} caseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilter( settings, input, force, regex, smart, caseInsensitive )\n\t{\n\t\tvar rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );\n\t\tvar prevSearch = settings.oPreviousSearch.sSearch;\n\t\tvar displayMaster = settings.aiDisplayMaster;\n\t\tvar display, invalidated, i;\n\t\tvar filtered = [];\n\t\n\t\t// Need to take account of custom filtering functions - always filter\n\t\tif ( DataTable.ext.search.length !== 0 ) {\n\t\t\tforce = true;\n\t\t}\n\t\n\t\t// Check if any of the rows were invalidated\n\t\tinvalidated = _fnFilterData( settings );\n\t\n\t\t// If the input is blank - we just want the full data set\n\t\tif ( input.length <= 0 ) {\n\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t}\n\t\telse {\n\t\t\t// New search - start from the master array\n\t\t\tif ( invalidated ||\n\t\t\t\t force ||\n\t\t\t\t prevSearch.length > input.length ||\n\t\t\t\t input.indexOf(prevSearch) !== 0 ||\n\t\t\t\t settings.bSorted // On resort, the display master needs to be\n\t\t\t\t                  // re-filtered since indexes will have changed\n\t\t\t) {\n\t\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t\t}\n\t\n\t\t\t// Search the display array\n\t\t\tdisplay = settings.aiDisplay;\n\t\n\t\t\tfor ( i=0 ; i<display.length ; i++ ) {\n\t\t\t\tif ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {\n\t\t\t\t\tfiltered.push( display[i] );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tsettings.aiDisplay = filtered;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a regular expression object suitable for searching a table\n\t *  @param {string} sSearch string to search for\n\t *  @param {bool} bRegex treat as a regular expression or not\n\t *  @param {bool} bSmart perform smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insensitive matching or not\n\t *  @returns {RegExp} constructed object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCreateSearch( search, regex, smart, caseInsensitive )\n\t{\n\t\tsearch = regex ?\n\t\t\tsearch :\n\t\t\t_fnEscapeRegex( search );\n\t\t\n\t\tif ( smart ) {\n\t\t\t/* For smart filtering we want to allow the search to work regardless of\n\t\t\t * word order. We also want double quoted text to be preserved, so word\n\t\t\t * order is important - a la google. So this is what we want to\n\t\t\t * generate:\n\t\t\t * \n\t\t\t * ^(?=.*?\\bone\\b)(?=.*?\\btwo three\\b)(?=.*?\\bfour\\b).*$\n\t\t\t */\n\t\t\tvar a = $.map( search.match( /\"[^\"]+\"|[^ ]+/g ) || [''], function ( word ) {\n\t\t\t\tif ( word.charAt(0) === '\"' ) {\n\t\t\t\t\tvar m = word.match( /^\"(.*)\"$/ );\n\t\t\t\t\tword = m ? m[1] : word;\n\t\t\t\t}\n\t\n\t\t\t\treturn word.replace('\"', '');\n\t\t\t} );\n\t\n\t\t\tsearch = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';\n\t\t}\n\t\n\t\treturn new RegExp( search, caseInsensitive ? 'i' : '' );\n\t}\n\t\n\t\n\t/**\n\t * Escape a string such that it can be used in a regular expression\n\t *  @param {string} sVal string to escape\n\t *  @returns {string} escaped string\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnEscapeRegex = DataTable.util.escapeRegex;\n\t\n\tvar __filter_div = $('<div>')[0];\n\tvar __filter_div_textContent = __filter_div.textContent !== undefined;\n\t\n\t// Update the filtering data for each row if needed (by invalidation or first run)\n\tfunction _fnFilterData ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar column;\n\t\tvar i, j, ien, jen, filterData, cellData, row;\n\t\tvar fomatters = DataTable.ext.type.search;\n\t\tvar wasInvalidated = false;\n\t\n\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aFilterData ) {\n\t\t\t\tfilterData = [];\n\t\n\t\t\t\tfor ( j=0, jen=columns.length ; j<jen ; j++ ) {\n\t\t\t\t\tcolumn = columns[j];\n\t\n\t\t\t\t\tif ( column.bSearchable ) {\n\t\t\t\t\t\tcellData = _fnGetCellData( settings, i, j, 'filter' );\n\t\n\t\t\t\t\t\tif ( fomatters[ column.sType ] ) {\n\t\t\t\t\t\t\tcellData = fomatters[ column.sType ]( cellData );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Search in DataTables 1.10 is string based. In 1.11 this\n\t\t\t\t\t\t// should be altered to also allow strict type checking.\n\t\t\t\t\t\tif ( cellData === null ) {\n\t\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( typeof cellData !== 'string' && cellData.toString ) {\n\t\t\t\t\t\t\tcellData = cellData.toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If it looks like there is an HTML entity in the string,\n\t\t\t\t\t// attempt to decode it so sorting works as expected. Note that\n\t\t\t\t\t// we could use a single line of jQuery to do this, but the DOM\n\t\t\t\t\t// method used here is much faster http://jsperf.com/html-decode\n\t\t\t\t\tif ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {\n\t\t\t\t\t\t__filter_div.innerHTML = cellData;\n\t\t\t\t\t\tcellData = __filter_div_textContent ?\n\t\t\t\t\t\t\t__filter_div.textContent :\n\t\t\t\t\t\t\t__filter_div.innerText;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tif ( cellData.replace ) {\n\t\t\t\t\t\tcellData = cellData.replace(/[\\r\\n]/g, '');\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfilterData.push( cellData );\n\t\t\t\t}\n\t\n\t\t\t\trow._aFilterData = filterData;\n\t\t\t\trow._sFilterRow = filterData.join('  ');\n\t\t\t\twasInvalidated = true;\n\t\t\t}\n\t\t}\n\t\n\t\treturn wasInvalidated;\n\t}\n\t\n\t\n\t/**\n\t * Convert from the internal Hungarian notation to camelCase for external\n\t * interaction\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToCamel ( obj )\n\t{\n\t\treturn {\n\t\t\tsearch:          obj.sSearch,\n\t\t\tsmart:           obj.bSmart,\n\t\t\tregex:           obj.bRegex,\n\t\t\tcaseInsensitive: obj.bCaseInsensitive\n\t\t};\n\t}\n\t\n\t\n\t\n\t/**\n\t * Convert from camelCase notation to the internal Hungarian. We could use the\n\t * Hungarian convert function here, but this is cleaner\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToHung ( obj )\n\t{\n\t\treturn {\n\t\t\tsSearch:          obj.search,\n\t\t\tbSmart:           obj.smart,\n\t\t\tbRegex:           obj.regex,\n\t\t\tbCaseInsensitive: obj.caseInsensitive\n\t\t};\n\t}\n\t\n\t/**\n\t * Generate the node required for the info display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Information element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlInfo ( settings )\n\t{\n\t\tvar\n\t\t\ttid = settings.sTableId,\n\t\t\tnodes = settings.aanFeatures.i,\n\t\t\tn = $('<div/>', {\n\t\t\t\t'class': settings.oClasses.sInfo,\n\t\t\t\t'id': ! nodes ? tid+'_info' : null\n\t\t\t} );\n\t\n\t\tif ( ! nodes ) {\n\t\t\t// Update display on each draw\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": _fnUpdateInfo,\n\t\t\t\t\"sName\": \"information\"\n\t\t\t} );\n\t\n\t\t\tn\n\t\t\t\t.attr( 'role', 'status' )\n\t\t\t\t.attr( 'aria-live', 'polite' );\n\t\n\t\t\t// Table is described by our info div\n\t\t\t$(settings.nTable).attr( 'aria-describedby', tid+'_info' );\n\t\t}\n\t\n\t\treturn n[0];\n\t}\n\t\n\t\n\t/**\n\t * Update the information elements in the display\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnUpdateInfo ( settings )\n\t{\n\t\t/* Show information about the table */\n\t\tvar nodes = settings.aanFeatures.i;\n\t\tif ( nodes.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\tlang  = settings.oLanguage,\n\t\t\tstart = settings._iDisplayStart+1,\n\t\t\tend   = settings.fnDisplayEnd(),\n\t\t\tmax   = settings.fnRecordsTotal(),\n\t\t\ttotal = settings.fnRecordsDisplay(),\n\t\t\tout   = total ?\n\t\t\t\tlang.sInfo :\n\t\t\t\tlang.sInfoEmpty;\n\t\n\t\tif ( total !== max ) {\n\t\t\t/* Record set after filtering */\n\t\t\tout += ' ' + lang.sInfoFiltered;\n\t\t}\n\t\n\t\t// Convert the macros\n\t\tout += lang.sInfoPostFix;\n\t\tout = _fnInfoMacros( settings, out );\n\t\n\t\tvar callback = lang.fnInfoCallback;\n\t\tif ( callback !== null ) {\n\t\t\tout = callback.call( settings.oInstance,\n\t\t\t\tsettings, start, end, max, total, out\n\t\t\t);\n\t\t}\n\t\n\t\t$(nodes).html( out );\n\t}\n\t\n\t\n\tfunction _fnInfoMacros ( settings, str )\n\t{\n\t\t// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only\n\t\t// internally\n\t\tvar\n\t\t\tformatter  = settings.fnFormatNumber,\n\t\t\tstart      = settings._iDisplayStart+1,\n\t\t\tlen        = settings._iDisplayLength,\n\t\t\tvis        = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn str.\n\t\t\treplace(/_START_/g, formatter.call( settings, start ) ).\n\t\t\treplace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).\n\t\t\treplace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).\n\t\t\treplace(/_TOTAL_/g, formatter.call( settings, vis ) ).\n\t\t\treplace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).\n\t\t\treplace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );\n\t}\n\t\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitialise ( settings )\n\t{\n\t\tvar i, iLen, iAjaxStart=settings.iInitDisplayStart;\n\t\tvar columns = settings.aoColumns, column;\n\t\tvar features = settings.oFeatures;\n\t\tvar deferLoading = settings.bDeferLoading; // value modified by the draw\n\t\n\t\t/* Ensure that the table data is fully initialised */\n\t\tif ( ! settings.bInitialised ) {\n\t\t\tsetTimeout( function(){ _fnInitialise( settings ); }, 200 );\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Show the display HTML options */\n\t\t_fnAddOptionsHtml( settings );\n\t\n\t\t/* Build and draw the header / footer for the table */\n\t\t_fnBuildHead( settings );\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t/* Okay to show that something is going on now */\n\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t/* Calculate sizes for columns */\n\t\tif ( features.bAutoWidth ) {\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\n\t\t\tif ( column.sWidth ) {\n\t\t\t\tcolumn.nTh.style.width = _fnStringToCss( column.sWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'preInit', [settings] );\n\t\n\t\t// If there is default sorting required - let's do it. The sort function\n\t\t// will do the drawing for us. Otherwise we draw the table regardless of the\n\t\t// Ajax source - this allows the table to look initialised for Ajax sourcing\n\t\t// data (show 'loading' message possibly)\n\t\t_fnReDraw( settings );\n\t\n\t\t// Server-side processing init complete is done by _fnAjaxUpdateDraw\n\t\tvar dataSrc = _fnDataSource( settings );\n\t\tif ( dataSrc != 'ssp' || deferLoading ) {\n\t\t\t// if there is an ajax source load the data\n\t\t\tif ( dataSrc == 'ajax' ) {\n\t\t\t\t_fnBuildAjax( settings, [], function(json) {\n\t\t\t\t\tvar aData = _fnAjaxDataSrc( settings, json );\n\t\n\t\t\t\t\t// Got the data - add it to the table\n\t\t\t\t\tfor ( i=0 ; i<aData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( settings, aData[i] );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Reset the init display for cookie saving. We've already done\n\t\t\t\t\t// a filter, and therefore cleared it before. So we need to make\n\t\t\t\t\t// it appear 'fresh'\n\t\t\t\t\tsettings.iInitDisplayStart = iAjaxStart;\n\t\n\t\t\t\t\t_fnReDraw( settings );\n\t\n\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t_fnInitComplete( settings, json );\n\t\t\t\t}, settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t_fnInitComplete( settings );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} [json] JSON from the server that completed the table, if using Ajax source\n\t *    with client-side processing (optional)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitComplete ( settings, json )\n\t{\n\t\tsettings._bInitComplete = true;\n\t\n\t\t// When data was added after the initialisation (data or Ajax) we need to\n\t\t// calculate the column sizing\n\t\tif ( json || settings.oInit.aaData ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'plugin-init', [settings, json] );\n\t\t_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );\n\t}\n\t\n\t\n\tfunction _fnLengthChange ( settings, val )\n\t{\n\t\tvar len = parseInt( val, 10 );\n\t\tsettings._iDisplayLength = len;\n\t\n\t\t_fnLengthOverflow( settings );\n\t\n\t\t// Fire length change event\n\t\t_fnCallbackFire( settings, null, 'length', [settings, len] );\n\t}\n\t\n\t\n\t/**\n\t * Generate the node required for user display length changing\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Display length feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlLength ( settings )\n\t{\n\t\tvar\n\t\t\tclasses  = settings.oClasses,\n\t\t\ttableId  = settings.sTableId,\n\t\t\tmenu     = settings.aLengthMenu,\n\t\t\td2       = $.isArray( menu[0] ),\n\t\t\tlengths  = d2 ? menu[0] : menu,\n\t\t\tlanguage = d2 ? menu[1] : menu;\n\t\n\t\tvar select = $('<select/>', {\n\t\t\t'name':          tableId+'_length',\n\t\t\t'aria-controls': tableId,\n\t\t\t'class':         classes.sLengthSelect\n\t\t} );\n\t\n\t\tfor ( var i=0, ien=lengths.length ; i<ien ; i++ ) {\n\t\t\tselect[0][ i ] = new Option( language[i], lengths[i] );\n\t\t}\n\t\n\t\tvar div = $('<div><label/></div>').addClass( classes.sLength );\n\t\tif ( ! settings.aanFeatures.l ) {\n\t\t\tdiv[0].id = tableId+'_length';\n\t\t}\n\t\n\t\tdiv.children().append(\n\t\t\tsettings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )\n\t\t);\n\t\n\t\t// Can't use `select` variable as user might provide their own and the\n\t\t// reference is broken by the use of outerHTML\n\t\t$('select', div)\n\t\t\t.val( settings._iDisplayLength )\n\t\t\t.on( 'change.DT', function(e) {\n\t\t\t\t_fnLengthChange( settings, $(this).val() );\n\t\t\t\t_fnDraw( settings );\n\t\t\t} );\n\t\n\t\t// Update node value whenever anything changes the table's length\n\t\t$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t$('select', div).val( len );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn div[0];\n\t}\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Note that most of the paging logic is done in\n\t * DataTable.ext.pager\n\t */\n\t\n\t/**\n\t * Generate the node required for default pagination\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Pagination feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlPaginate ( settings )\n\t{\n\t\tvar\n\t\t\ttype   = settings.sPaginationType,\n\t\t\tplugin = DataTable.ext.pager[ type ],\n\t\t\tmodern = typeof plugin === 'function',\n\t\t\tredraw = function( settings ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t},\n\t\t\tnode = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],\n\t\t\tfeatures = settings.aanFeatures;\n\t\n\t\tif ( ! modern ) {\n\t\t\tplugin.fnInit( settings, node, redraw );\n\t\t}\n\t\n\t\t/* Add a draw callback for the pagination on first instance, to update the paging display */\n\t\tif ( ! features.p )\n\t\t{\n\t\t\tnode.id = settings.sTableId+'_paginate';\n\t\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": function( settings ) {\n\t\t\t\t\tif ( modern ) {\n\t\t\t\t\t\tvar\n\t\t\t\t\t\t\tstart      = settings._iDisplayStart,\n\t\t\t\t\t\t\tlen        = settings._iDisplayLength,\n\t\t\t\t\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\t\t\t\t\tall        = len === -1,\n\t\t\t\t\t\t\tpage = all ? 0 : Math.ceil( start / len ),\n\t\t\t\t\t\t\tpages = all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\t\t\t\tbuttons = plugin(page, pages),\n\t\t\t\t\t\t\ti, ien;\n\t\n\t\t\t\t\t\tfor ( i=0, ien=features.p.length ; i<ien ; i++ ) {\n\t\t\t\t\t\t\t_fnRenderer( settings, 'pageButton' )(\n\t\t\t\t\t\t\t\tsettings, features.p[i], i, buttons, page, pages\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tplugin.fnUpdate( settings, redraw );\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"sName\": \"pagination\"\n\t\t\t} );\n\t\t}\n\t\n\t\treturn node;\n\t}\n\t\n\t\n\t/**\n\t * Alter the display settings to change the page\n\t *  @param {object} settings DataTables settings object\n\t *  @param {string|int} action Paging action to take: \"first\", \"previous\",\n\t *    \"next\" or \"last\" or page number to jump to (integer)\n\t *  @param [bool] redraw Automatically draw the update or not\n\t *  @returns {bool} true page has changed, false - no change\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnPageChange ( settings, action, redraw )\n\t{\n\t\tvar\n\t\t\tstart     = settings._iDisplayStart,\n\t\t\tlen       = settings._iDisplayLength,\n\t\t\trecords   = settings.fnRecordsDisplay();\n\t\n\t\tif ( records === 0 || len === -1 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( typeof action === \"number\" )\n\t\t{\n\t\t\tstart = action * len;\n\t\n\t\t\tif ( start > records )\n\t\t\t{\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"first\" )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( action == \"previous\" )\n\t\t{\n\t\t\tstart = len >= 0 ?\n\t\t\t\tstart - len :\n\t\t\t\t0;\n\t\n\t\t\tif ( start < 0 )\n\t\t\t{\n\t\t\t  start = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"next\" )\n\t\t{\n\t\t\tif ( start + len < records )\n\t\t\t{\n\t\t\t\tstart += len;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"last\" )\n\t\t{\n\t\t\tstart = Math.floor( (records-1) / len) * len;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_fnLog( settings, 0, \"Unknown paging action: \"+action, 5 );\n\t\t}\n\t\n\t\tvar changed = settings._iDisplayStart !== start;\n\t\tsettings._iDisplayStart = start;\n\t\n\t\tif ( changed ) {\n\t\t\t_fnCallbackFire( settings, null, 'page', [settings] );\n\t\n\t\t\tif ( redraw ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t}\n\t\n\t\treturn changed;\n\t}\n\t\n\t\n\t\n\t/**\n\t * Generate the node required for the processing node\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Processing element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlProcessing ( settings )\n\t{\n\t\treturn $('<div/>', {\n\t\t\t\t'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,\n\t\t\t\t'class': settings.oClasses.sProcessing\n\t\t\t} )\n\t\t\t.html( settings.oLanguage.sProcessing )\n\t\t\t.insertBefore( settings.nTable )[0];\n\t}\n\t\n\t\n\t/**\n\t * Display or hide the processing indicator\n\t *  @param {object} settings dataTables settings object\n\t *  @param {bool} show Show the processing indicator (true) or not (false)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnProcessingDisplay ( settings, show )\n\t{\n\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t$(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'processing', [settings, show] );\n\t}\n\t\n\t/**\n\t * Add any control elements for the table - specifically scrolling\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Node to add to the DOM\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlTable ( settings )\n\t{\n\t\tvar table = $(settings.nTable);\n\t\n\t\t// Add the ARIA grid role to the table\n\t\ttable.attr( 'role', 'grid' );\n\t\n\t\t// Scrolling from here on in\n\t\tvar scroll = settings.oScroll;\n\t\n\t\tif ( scroll.sX === '' && scroll.sY === '' ) {\n\t\t\treturn settings.nTable;\n\t\t}\n\t\n\t\tvar scrollX = scroll.sX;\n\t\tvar scrollY = scroll.sY;\n\t\tvar classes = settings.oClasses;\n\t\tvar caption = table.children('caption');\n\t\tvar captionSide = caption.length ? caption[0]._captionSide : null;\n\t\tvar headerClone = $( table[0].cloneNode(false) );\n\t\tvar footerClone = $( table[0].cloneNode(false) );\n\t\tvar footer = table.children('tfoot');\n\t\tvar _div = '<div/>';\n\t\tvar size = function ( s ) {\n\t\t\treturn !s ? null : _fnStringToCss( s );\n\t\t};\n\t\n\t\tif ( ! footer.length ) {\n\t\t\tfooter = null;\n\t\t}\n\t\n\t\t/*\n\t\t * The HTML structure that we want to generate in this function is:\n\t\t *  div - scroller\n\t\t *    div - scroll head\n\t\t *      div - scroll head inner\n\t\t *        table - scroll head table\n\t\t *          thead - thead\n\t\t *    div - scroll body\n\t\t *      table - table (master table)\n\t\t *        thead - thead clone for sizing\n\t\t *        tbody - tbody\n\t\t *    div - scroll foot\n\t\t *      div - scroll foot inner\n\t\t *        table - scroll foot table\n\t\t *          tfoot - tfoot\n\t\t */\n\t\tvar scroller = $( _div, { 'class': classes.sScrollWrapper } )\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollHead } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollHeadInner } )\n\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t'box-sizing': 'content-box',\n\t\t\t\t\t\t\t\twidth: scroll.sXInner || '100%'\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\theaderClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'top' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('thead')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t)\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollBody } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\toverflow: 'auto',\n\t\t\t\t\t\twidth: size( scrollX )\n\t\t\t\t\t} )\n\t\t\t\t\t.append( table )\n\t\t\t);\n\t\n\t\tif ( footer ) {\n\t\t\tscroller.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollFoot } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollFootInner } )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\tfooterClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'bottom' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('tfoot')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\n\t\tvar children = scroller.children();\n\t\tvar scrollHead = children[0];\n\t\tvar scrollBody = children[1];\n\t\tvar scrollFoot = footer ? children[2] : null;\n\t\n\t\t// When the body is scrolled, then we also want to scroll the headers\n\t\tif ( scrollX ) {\n\t\t\t$(scrollBody).on( 'scroll.DT', function (e) {\n\t\t\t\tvar scrollLeft = this.scrollLeft;\n\t\n\t\t\t\tscrollHead.scrollLeft = scrollLeft;\n\t\n\t\t\t\tif ( footer ) {\n\t\t\t\t\tscrollFoot.scrollLeft = scrollLeft;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\n\t\t$(scrollBody).css(\n\t\t\tscrollY && scroll.bCollapse ? 'max-height' : 'height', \n\t\t\tscrollY\n\t\t);\n\t\n\t\tsettings.nScrollHead = scrollHead;\n\t\tsettings.nScrollBody = scrollBody;\n\t\tsettings.nScrollFoot = scrollFoot;\n\t\n\t\t// On redraw - align columns\n\t\tsettings.aoDrawCallback.push( {\n\t\t\t\"fn\": _fnScrollDraw,\n\t\t\t\"sName\": \"scrolling\"\n\t\t} );\n\t\n\t\treturn scroller[0];\n\t}\n\t\n\t\n\t\n\t/**\n\t * Update the header, footer and body tables for resizing - i.e. column\n\t * alignment.\n\t *\n\t * Welcome to the most horrible function DataTables. The process that this\n\t * function follows is basically:\n\t *   1. Re-create the table inside the scrolling div\n\t *   2. Take live measurements from the DOM\n\t *   3. Apply the measurements to align the columns\n\t *   4. Clean up\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnScrollDraw ( settings )\n\t{\n\t\t// Given that this is such a monster function, a lot of variables are use\n\t\t// to try and keep the minimised size as small as possible\n\t\tvar\n\t\t\tscroll         = settings.oScroll,\n\t\t\tscrollX        = scroll.sX,\n\t\t\tscrollXInner   = scroll.sXInner,\n\t\t\tscrollY        = scroll.sY,\n\t\t\tbarWidth       = scroll.iBarWidth,\n\t\t\tdivHeader      = $(settings.nScrollHead),\n\t\t\tdivHeaderStyle = divHeader[0].style,\n\t\t\tdivHeaderInner = divHeader.children('div'),\n\t\t\tdivHeaderInnerStyle = divHeaderInner[0].style,\n\t\t\tdivHeaderTable = divHeaderInner.children('table'),\n\t\t\tdivBodyEl      = settings.nScrollBody,\n\t\t\tdivBody        = $(divBodyEl),\n\t\t\tdivBodyStyle   = divBodyEl.style,\n\t\t\tdivFooter      = $(settings.nScrollFoot),\n\t\t\tdivFooterInner = divFooter.children('div'),\n\t\t\tdivFooterTable = divFooterInner.children('table'),\n\t\t\theader         = $(settings.nTHead),\n\t\t\ttable          = $(settings.nTable),\n\t\t\ttableEl        = table[0],\n\t\t\ttableStyle     = tableEl.style,\n\t\t\tfooter         = settings.nTFoot ? $(settings.nTFoot) : null,\n\t\t\tbrowser        = settings.oBrowser,\n\t\t\tie67           = browser.bScrollOversize,\n\t\t\tdtHeaderCells  = _pluck( settings.aoColumns, 'nTh' ),\n\t\t\theaderTrgEls, footerTrgEls,\n\t\t\theaderSrcEls, footerSrcEls,\n\t\t\theaderCopy, footerCopy,\n\t\t\theaderWidths=[], footerWidths=[],\n\t\t\theaderContent=[], footerContent=[],\n\t\t\tidx, correction, sanityWidth,\n\t\t\tzeroOut = function(nSizer) {\n\t\t\t\tvar style = nSizer.style;\n\t\t\t\tstyle.paddingTop = \"0\";\n\t\t\t\tstyle.paddingBottom = \"0\";\n\t\t\t\tstyle.borderTopWidth = \"0\";\n\t\t\t\tstyle.borderBottomWidth = \"0\";\n\t\t\t\tstyle.height = 0;\n\t\t\t};\n\t\n\t\t// If the scrollbar visibility has changed from the last draw, we need to\n\t\t// adjust the column sizes as the table width will have changed to account\n\t\t// for the scrollbar\n\t\tvar scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;\n\t\t\n\t\tif ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t\treturn; // adjust column sizing will call this function again\n\t\t}\n\t\telse {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t}\n\t\n\t\t/*\n\t\t * 1. Re-create the table inside the scrolling div\n\t\t */\n\t\n\t\t// Remove the old minimised thead and tfoot elements in the inner table\n\t\ttable.children('thead, tfoot').remove();\n\t\n\t\tif ( footer ) {\n\t\t\tfooterCopy = footer.clone().prependTo( table );\n\t\t\tfooterTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized\n\t\t\tfooterSrcEls = footerCopy.find('tr');\n\t\t}\n\t\n\t\t// Clone the current header and footer elements and then place it into the inner table\n\t\theaderCopy = header.clone().prependTo( table );\n\t\theaderTrgEls = header.find('tr'); // original header is in its own table\n\t\theaderSrcEls = headerCopy.find('tr');\n\t\theaderCopy.find('th, td').removeAttr('tabindex');\n\t\n\t\n\t\t/*\n\t\t * 2. Take live measurements from the DOM - do not alter the DOM itself!\n\t\t */\n\t\n\t\t// Remove old sizing and apply the calculated column widths\n\t\t// Get the unique column headers in the newly created (cloned) header. We want to apply the\n\t\t// calculated sizes to this header\n\t\tif ( ! scrollX )\n\t\t{\n\t\t\tdivBodyStyle.width = '100%';\n\t\t\tdivHeader[0].style.width = '100%';\n\t\t}\n\t\n\t\t$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {\n\t\t\tidx = _fnVisibleToColumnIndex( settings, i );\n\t\t\tel.style.width = settings.aoColumns[idx].sWidth;\n\t\t} );\n\t\n\t\tif ( footer ) {\n\t\t\t_fnApplyToChildren( function(n) {\n\t\t\t\tn.style.width = \"\";\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Size the table as a whole\n\t\tsanityWidth = table.outerWidth();\n\t\tif ( scrollX === \"\" ) {\n\t\t\t// No x scrolling\n\t\t\ttableStyle.width = \"100%\";\n\t\n\t\t\t// IE7 will make the width of the table when 100% include the scrollbar\n\t\t\t// - which is shouldn't. When there is a scrollbar we need to take this\n\t\t\t// into account.\n\t\t\tif ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);\n\t\t\t}\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\telse if ( scrollXInner !== \"\" ) {\n\t\t\t// legacy x scroll inner has been given - use it\n\t\t\ttableStyle.width = _fnStringToCss(scrollXInner);\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\n\t\t// Hidden header should have zero height, so remove padding and borders. Then\n\t\t// set the width based on the real headers\n\t\n\t\t// Apply all styles in one pass\n\t\t_fnApplyToChildren( zeroOut, headerSrcEls );\n\t\n\t\t// Read all widths in next pass\n\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\theaderContent.push( nSizer.innerHTML );\n\t\t\theaderWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t}, headerSrcEls );\n\t\n\t\t// Apply all widths in final pass\n\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t// Only apply widths to the DataTables detected header cells - this\n\t\t\t// prevents complex headers from having contradictory sizes applied\n\t\t\tif ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {\n\t\t\t\tnToSize.style.width = headerWidths[i];\n\t\t\t}\n\t\t}, headerTrgEls );\n\t\n\t\t$(headerSrcEls).height(0);\n\t\n\t\t/* Same again with the footer if we have one */\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( zeroOut, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\t\tfooterContent.push( nSizer.innerHTML );\n\t\t\t\tfooterWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t\t}, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t\tnToSize.style.width = footerWidths[i];\n\t\t\t}, footerTrgEls );\n\t\n\t\t\t$(footerSrcEls).height(0);\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 3. Apply the measurements\n\t\t */\n\t\n\t\t// \"Hide\" the header and footer that we used for the sizing. We need to keep\n\t\t// the content of the cell so that the width applied to the header and body\n\t\t// both match, but we want to hide it completely. We want to also fix their\n\t\t// width to what they currently are\n\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\" style=\"height:0;overflow:hidden;\">'+headerContent[i]+'</div>';\n\t\t\tnSizer.style.width = headerWidths[i];\n\t\t}, headerSrcEls );\n\t\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\" style=\"height:0;overflow:hidden;\">'+footerContent[i]+'</div>';\n\t\t\t\tnSizer.style.width = footerWidths[i];\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Sanity check that the table is of a sensible width. If not then we are going to get\n\t\t// misalignment - try to prevent this by not allowing the table to shrink below its min width\n\t\tif ( table.outerWidth() < sanityWidth )\n\t\t{\n\t\t\t// The min width depends upon if we have a vertical scrollbar visible or not */\n\t\t\tcorrection = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")) ?\n\t\t\t\t\tsanityWidth+barWidth :\n\t\t\t\t\tsanityWidth;\n\t\n\t\t\t// IE6/7 are a law unto themselves...\n\t\t\tif ( ie67 && (divBodyEl.scrollHeight >\n\t\t\t\tdivBodyEl.offsetHeight || divBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( correction-barWidth );\n\t\t\t}\n\t\n\t\t\t// And give the user a warning that we've stopped the table getting too small\n\t\t\tif ( scrollX === \"\" || scrollXInner !== \"\" ) {\n\t\t\t\t_fnLog( settings, 1, 'Possible column misalignment', 6 );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcorrection = '100%';\n\t\t}\n\t\n\t\t// Apply to the container elements\n\t\tdivBodyStyle.width = _fnStringToCss( correction );\n\t\tdivHeaderStyle.width = _fnStringToCss( correction );\n\t\n\t\tif ( footer ) {\n\t\t\tsettings.nScrollFoot.style.width = _fnStringToCss( correction );\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 4. Clean up\n\t\t */\n\t\tif ( ! scrollY ) {\n\t\t\t/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting\n\t\t\t * the scrollbar height from the visible display, rather than adding it on. We need to\n\t\t\t * set the height in order to sort this. Don't want to do it in any other browsers.\n\t\t\t */\n\t\t\tif ( ie67 ) {\n\t\t\t\tdivBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Finally set the width's of the header and footer tables */\n\t\tvar iOuterWidth = table.outerWidth();\n\t\tdivHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\tdivHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );\n\t\n\t\t// Figure out if there are scrollbar present - if so then we need a the header and footer to\n\t\t// provide a bit more space to allow \"overflow\" scrolling (i.e. past the scrollbar)\n\t\tvar bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == \"scroll\";\n\t\tvar padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );\n\t\tdivHeaderInnerStyle[ padding ] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\n\t\tif ( footer ) {\n\t\t\tdivFooterTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style[padding] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\t}\n\t\n\t\t// Correct DOM ordering for colgroup - comes before the thead\n\t\ttable.children('colgroup').insertBefore( table.children('thead') );\n\t\n\t\t/* Adjust the position of the header in case we loose the y-scrollbar */\n\t\tdivBody.scroll();\n\t\n\t\t// If sorting or filtering has occurred, jump the scrolling back to the top\n\t\t// only if we aren't holding the position\n\t\tif ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {\n\t\t\tdivBodyEl.scrollTop = 0;\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Apply a given function to the display child nodes of an element array (typically\n\t * TD children of TR rows\n\t *  @param {function} fn Method to apply to the objects\n\t *  @param array {nodes} an1 List of elements to look through for display children\n\t *  @param array {nodes} an2 Another list (identical structure to the first) - optional\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyToChildren( fn, an1, an2 )\n\t{\n\t\tvar index=0, i=0, iLen=an1.length;\n\t\tvar nNode1, nNode2;\n\t\n\t\twhile ( i < iLen ) {\n\t\t\tnNode1 = an1[i].firstChild;\n\t\t\tnNode2 = an2 ? an2[i].firstChild : null;\n\t\n\t\t\twhile ( nNode1 ) {\n\t\t\t\tif ( nNode1.nodeType === 1 ) {\n\t\t\t\t\tif ( an2 ) {\n\t\t\t\t\t\tfn( nNode1, nNode2, index );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfn( nNode1, index );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\n\t\t\t\tnNode1 = nNode1.nextSibling;\n\t\t\t\tnNode2 = an2 ? nNode2.nextSibling : null;\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t}\n\t}\n\t\n\t\n\t\n\tvar __re_html_remove = /<.*?>/g;\n\t\n\t\n\t/**\n\t * Calculate the width of columns for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCalculateColumnWidths ( oSettings )\n\t{\n\t\tvar\n\t\t\ttable = oSettings.nTable,\n\t\t\tcolumns = oSettings.aoColumns,\n\t\t\tscroll = oSettings.oScroll,\n\t\t\tscrollY = scroll.sY,\n\t\t\tscrollX = scroll.sX,\n\t\t\tscrollXInner = scroll.sXInner,\n\t\t\tcolumnCount = columns.length,\n\t\t\tvisibleColumns = _fnGetColumns( oSettings, 'bVisible' ),\n\t\t\theaderCells = $('th', oSettings.nTHead),\n\t\t\ttableWidthAttr = table.getAttribute('width'), // from DOM element\n\t\t\ttableContainer = table.parentNode,\n\t\t\tuserInputs = false,\n\t\t\ti, column, columnIdx, width, outerWidth,\n\t\t\tbrowser = oSettings.oBrowser,\n\t\t\tie67 = browser.bScrollOversize;\n\t\n\t\tvar styleWidth = table.style.width;\n\t\tif ( styleWidth && styleWidth.indexOf('%') !== -1 ) {\n\t\t\ttableWidthAttr = styleWidth;\n\t\t}\n\t\n\t\t/* Convert any user input sizes into pixel sizes */\n\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\tif ( column.sWidth !== null ) {\n\t\t\t\tcolumn.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );\n\t\n\t\t\t\tuserInputs = true;\n\t\t\t}\n\t\t}\n\t\n\t\t/* If the number of columns in the DOM equals the number that we have to\n\t\t * process in DataTables, then we can use the offsets that are created by\n\t\t * the web- browser. No custom sizes can be set in order for this to happen,\n\t\t * nor scrolling used\n\t\t */\n\t\tif ( ie67 || ! userInputs && ! scrollX && ! scrollY &&\n\t\t     columnCount == _fnVisbleColumns( oSettings ) &&\n\t\t     columnCount == headerCells.length\n\t\t) {\n\t\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\t\tvar colIdx = _fnVisibleToColumnIndex( oSettings, i );\n\t\n\t\t\t\tif ( colIdx !== null ) {\n\t\t\t\t\tcolumns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise construct a single row, worst case, table with the widest\n\t\t\t// node in the data, assign any user defined widths, then insert it into\n\t\t\t// the DOM and allow the browser to do all the hard work of calculating\n\t\t\t// table widths\n\t\t\tvar tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table\n\t\t\t\t.css( 'visibility', 'hidden' )\n\t\t\t\t.removeAttr( 'id' );\n\t\n\t\t\t// Clean up the table body\n\t\t\ttmpTable.find('tbody tr').remove();\n\t\t\tvar tr = $('<tr/>').appendTo( tmpTable.find('tbody') );\n\t\n\t\t\t// Clone the table header and footer - we can't use the header / footer\n\t\t\t// from the cloned table, since if scrolling is active, the table's\n\t\t\t// real header and footer are contained in different table tags\n\t\t\ttmpTable.find('thead, tfoot').remove();\n\t\t\ttmpTable\n\t\t\t\t.append( $(oSettings.nTHead).clone() )\n\t\t\t\t.append( $(oSettings.nTFoot).clone() );\n\t\n\t\t\t// Remove any assigned widths from the footer (from scrolling)\n\t\t\ttmpTable.find('tfoot th, tfoot td').css('width', '');\n\t\n\t\t\t// Apply custom sizing to the cloned header\n\t\t\theaderCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );\n\t\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\t\theaderCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?\n\t\t\t\t\t_fnStringToCss( column.sWidthOrig ) :\n\t\t\t\t\t'';\n\t\n\t\t\t\t// For scrollX we need to force the column width otherwise the\n\t\t\t\t// browser will collapse it. If this width is smaller than the\n\t\t\t\t// width the column requires, then it will have no effect\n\t\t\t\tif ( column.sWidthOrig && scrollX ) {\n\t\t\t\t\t$( headerCells[i] ).append( $('<div/>').css( {\n\t\t\t\t\t\twidth: column.sWidthOrig,\n\t\t\t\t\t\tmargin: 0,\n\t\t\t\t\t\tpadding: 0,\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\theight: 1\n\t\t\t\t\t} ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Find the widest cell for each column and put it into the table\n\t\t\tif ( oSettings.aoData.length ) {\n\t\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\t\tcolumnIdx = visibleColumns[i];\n\t\t\t\t\tcolumn = columns[ columnIdx ];\n\t\n\t\t\t\t\t$( _fnGetWidestNode( oSettings, columnIdx ) )\n\t\t\t\t\t\t.clone( false )\n\t\t\t\t\t\t.append( column.sContentPadding )\n\t\t\t\t\t\t.appendTo( tr );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Tidy the temporary table - remove name attributes so there aren't\n\t\t\t// duplicated in the dom (radio elements for example)\n\t\t\t$('[name]', tmpTable).removeAttr('name');\n\t\n\t\t\t// Table has been built, attach to the document so we can work with it.\n\t\t\t// A holding element is used, positioned at the top of the container\n\t\t\t// with minimal height, so it has no effect on if the container scrolls\n\t\t\t// or not. Otherwise it might trigger scrolling when it actually isn't\n\t\t\t// needed\n\t\t\tvar holder = $('<div/>').css( scrollX || scrollY ?\n\t\t\t\t\t{\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\theight: 1,\n\t\t\t\t\t\tright: 0,\n\t\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t\t} :\n\t\t\t\t\t{}\n\t\t\t\t)\n\t\t\t\t.append( tmpTable )\n\t\t\t\t.appendTo( tableContainer );\n\t\n\t\t\t// When scrolling (X or Y) we want to set the width of the table as \n\t\t\t// appropriate. However, when not scrolling leave the table width as it\n\t\t\t// is. This results in slightly different, but I think correct behaviour\n\t\t\tif ( scrollX && scrollXInner ) {\n\t\t\t\ttmpTable.width( scrollXInner );\n\t\t\t}\n\t\t\telse if ( scrollX ) {\n\t\t\t\ttmpTable.css( 'width', 'auto' );\n\t\t\t\ttmpTable.removeAttr('width');\n\t\n\t\t\t\t// If there is no width attribute or style, then allow the table to\n\t\t\t\t// collapse\n\t\t\t\tif ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {\n\t\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( scrollY ) {\n\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t}\n\t\t\telse if ( tableWidthAttr ) {\n\t\t\t\ttmpTable.width( tableWidthAttr );\n\t\t\t}\n\t\n\t\t\t// Get the width of each column in the constructed table - we need to\n\t\t\t// know the inner width (so it can be assigned to the other table's\n\t\t\t// cells) and the outer width so we can calculate the full width of the\n\t\t\t// table. This is safe since DataTables requires a unique cell for each\n\t\t\t// column, but if ever a header can span multiple columns, this will\n\t\t\t// need to be modified.\n\t\t\tvar total = 0;\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tvar cell = $(headerCells[i]);\n\t\t\t\tvar border = cell.outerWidth() - cell.width();\n\t\n\t\t\t\t// Use getBounding... where possible (not IE8-) because it can give\n\t\t\t\t// sub-pixel accuracy, which we then want to round up!\n\t\t\t\tvar bounding = browser.bBounding ?\n\t\t\t\t\tMath.ceil( headerCells[i].getBoundingClientRect().width ) :\n\t\t\t\t\tcell.outerWidth();\n\t\n\t\t\t\t// Total is tracked to remove any sub-pixel errors as the outerWidth\n\t\t\t\t// of the table might not equal the total given here (IE!).\n\t\t\t\ttotal += bounding;\n\t\n\t\t\t\t// Width for each column to use\n\t\t\t\tcolumns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );\n\t\t\t}\n\t\n\t\t\ttable.style.width = _fnStringToCss( total );\n\t\n\t\t\t// Finished with the table - ditch it\n\t\t\tholder.remove();\n\t\t}\n\t\n\t\t// If there is a width attr, we want to attach an event listener which\n\t\t// allows the table sizing to automatically adjust when the window is\n\t\t// resized. Use the width attr rather than CSS, since we can't know if the\n\t\t// CSS is a relative value or absolute - DOM read is always px.\n\t\tif ( tableWidthAttr ) {\n\t\t\ttable.style.width = _fnStringToCss( tableWidthAttr );\n\t\t}\n\t\n\t\tif ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {\n\t\t\tvar bindResize = function () {\n\t\t\t\t$(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {\n\t\t\t\t\t_fnAdjustColumnSizing( oSettings );\n\t\t\t\t} ) );\n\t\t\t};\n\t\n\t\t\t// IE6/7 will crash if we bind a resize event handler on page load.\n\t\t\t// To be removed in 1.11 which drops IE6/7 support\n\t\t\tif ( ie67 ) {\n\t\t\t\tsetTimeout( bindResize, 1000 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbindResize();\n\t\t\t}\n\t\n\t\t\toSettings._reszEvt = true;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Throttle the calls to a function. Arguments and context are maintained for\n\t * the throttled function\n\t *  @param {function} fn Function to be called\n\t *  @param {int} [freq=200] call frequency in mS\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnThrottle = DataTable.util.throttle;\n\t\n\t\n\t/**\n\t * Convert a CSS unit width to pixels (e.g. 2em)\n\t *  @param {string} width width to be converted\n\t *  @param {node} parent parent to get the with for (required for relative widths) - optional\n\t *  @returns {int} width in pixels\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnConvertToWidth ( width, parent )\n\t{\n\t\tif ( ! width ) {\n\t\t\treturn 0;\n\t\t}\n\t\n\t\tvar n = $('<div/>')\n\t\t\t.css( 'width', _fnStringToCss( width ) )\n\t\t\t.appendTo( parent || document.body );\n\t\n\t\tvar val = n[0].offsetWidth;\n\t\tn.remove();\n\t\n\t\treturn val;\n\t}\n\t\n\t\n\t/**\n\t * Get the widest node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {node} widest table node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetWidestNode( settings, colIdx )\n\t{\n\t\tvar idx = _fnGetMaxLenString( settings, colIdx );\n\t\tif ( idx < 0 ) {\n\t\t\treturn null;\n\t\t}\n\t\n\t\tvar data = settings.aoData[ idx ];\n\t\treturn ! data.nTr ? // Might not have been created when deferred rendering\n\t\t\t$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :\n\t\t\tdata.anCells[ colIdx ];\n\t}\n\t\n\t\n\t/**\n\t * Get the maximum strlen for each data column\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {string} max string length for each column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetMaxLenString( settings, colIdx )\n\t{\n\t\tvar s, max=-1, maxIdx = -1;\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\ts = _fnGetCellData( settings, i, colIdx, 'display' )+'';\n\t\t\ts = s.replace( __re_html_remove, '' );\n\t\t\ts = s.replace( /&nbsp;/g, ' ' );\n\t\n\t\t\tif ( s.length > max ) {\n\t\t\t\tmax = s.length;\n\t\t\t\tmaxIdx = i;\n\t\t\t}\n\t\t}\n\t\n\t\treturn maxIdx;\n\t}\n\t\n\t\n\t/**\n\t * Append a CSS unit (only if required) to a string\n\t *  @param {string} value to css-ify\n\t *  @returns {string} value with css unit\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnStringToCss( s )\n\t{\n\t\tif ( s === null ) {\n\t\t\treturn '0px';\n\t\t}\n\t\n\t\tif ( typeof s == 'number' ) {\n\t\t\treturn s < 0 ?\n\t\t\t\t'0px' :\n\t\t\t\ts+'px';\n\t\t}\n\t\n\t\t// Check it has a unit character already\n\t\treturn s.match(/\\d$/) ?\n\t\t\ts+'px' :\n\t\t\ts;\n\t}\n\t\n\t\n\t\n\tfunction _fnSortFlatten ( settings )\n\t{\n\t\tvar\n\t\t\ti, iLen, k, kLen,\n\t\t\taSort = [],\n\t\t\taiOrig = [],\n\t\t\taoColumns = settings.aoColumns,\n\t\t\taDataSort, iCol, sType, srcCol,\n\t\t\tfixed = settings.aaSortingFixed,\n\t\t\tfixedObj = $.isPlainObject( fixed ),\n\t\t\tnestedSort = [],\n\t\t\tadd = function ( a ) {\n\t\t\t\tif ( a.length && ! $.isArray( a[0] ) ) {\n\t\t\t\t\t// 1D array\n\t\t\t\t\tnestedSort.push( a );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// 2D array\n\t\t\t\t\t$.merge( nestedSort, a );\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t// Build the sort array, with pre-fix and post-fix options if they have been\n\t\t// specified\n\t\tif ( $.isArray( fixed ) ) {\n\t\t\tadd( fixed );\n\t\t}\n\t\n\t\tif ( fixedObj && fixed.pre ) {\n\t\t\tadd( fixed.pre );\n\t\t}\n\t\n\t\tadd( settings.aaSorting );\n\t\n\t\tif (fixedObj && fixed.post ) {\n\t\t\tadd( fixed.post );\n\t\t}\n\t\n\t\tfor ( i=0 ; i<nestedSort.length ; i++ )\n\t\t{\n\t\t\tsrcCol = nestedSort[i][0];\n\t\t\taDataSort = aoColumns[ srcCol ].aDataSort;\n\t\n\t\t\tfor ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )\n\t\t\t{\n\t\t\t\tiCol = aDataSort[k];\n\t\t\t\tsType = aoColumns[ iCol ].sType || 'string';\n\t\n\t\t\t\tif ( nestedSort[i]._idx === undefined ) {\n\t\t\t\t\tnestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );\n\t\t\t\t}\n\t\n\t\t\t\taSort.push( {\n\t\t\t\t\tsrc:       srcCol,\n\t\t\t\t\tcol:       iCol,\n\t\t\t\t\tdir:       nestedSort[i][1],\n\t\t\t\t\tindex:     nestedSort[i]._idx,\n\t\t\t\t\ttype:      sType,\n\t\t\t\t\tformatter: DataTable.ext.type.order[ sType+\"-pre\" ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\treturn aSort;\n\t}\n\t\n\t/**\n\t * Change the order of the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t *  @todo This really needs split up!\n\t */\n\tfunction _fnSort ( oSettings )\n\t{\n\t\tvar\n\t\t\ti, ien, iLen, j, jLen, k, kLen,\n\t\t\tsDataType, nTh,\n\t\t\taiOrig = [],\n\t\t\toExtSort = DataTable.ext.type.order,\n\t\t\taoData = oSettings.aoData,\n\t\t\taoColumns = oSettings.aoColumns,\n\t\t\taDataSort, data, iCol, sType, oSort,\n\t\t\tformatters = 0,\n\t\t\tsortCol,\n\t\t\tdisplayMaster = oSettings.aiDisplayMaster,\n\t\t\taSort;\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo Can this be moved into a 'data-ready' handler which is called when\n\t\t//   data is going to be used in the table?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\taSort = _fnSortFlatten( oSettings );\n\t\n\t\tfor ( i=0, ien=aSort.length ; i<ien ; i++ ) {\n\t\t\tsortCol = aSort[i];\n\t\n\t\t\t// Track if we can use the fast sort algorithm\n\t\t\tif ( sortCol.formatter ) {\n\t\t\t\tformatters++;\n\t\t\t}\n\t\n\t\t\t// Load the data needed for the sort, for each cell\n\t\t\t_fnSortData( oSettings, sortCol.col );\n\t\t}\n\t\n\t\t/* No sorting required if server-side or no sorting array */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )\n\t\t{\n\t\t\t// Create a value - key array of the current row positions such that we can use their\n\t\t\t// current position during the sort, if values match, in order to perform stable sorting\n\t\t\tfor ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {\n\t\t\t\taiOrig[ displayMaster[i] ] = i;\n\t\t\t}\n\t\n\t\t\t/* Do the sort - here we want multi-column sorting based on a given data source (column)\n\t\t\t * and sorting function (from oSort) in a certain direction. It's reasonably complex to\n\t\t\t * follow on it's own, but this is what we want (example two column sorting):\n\t\t\t *  fnLocalSorting = function(a,b){\n\t\t\t *    var iTest;\n\t\t\t *    iTest = oSort['string-asc']('data11', 'data12');\n\t\t\t *      if (iTest !== 0)\n\t\t\t *        return iTest;\n\t\t\t *    iTest = oSort['numeric-desc']('data21', 'data22');\n\t\t\t *    if (iTest !== 0)\n\t\t\t *      return iTest;\n\t\t\t *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );\n\t\t\t *  }\n\t\t\t * Basically we have a test for each sorting column, if the data in that column is equal,\n\t\t\t * test the next column. If all columns match, then we use a numeric sort on the row\n\t\t\t * positions in the original data array to provide a stable sort.\n\t\t\t *\n\t\t\t * Note - I know it seems excessive to have two sorting methods, but the first is around\n\t\t\t * 15% faster, so the second is only maintained for backwards compatibility with sorting\n\t\t\t * methods which do not have a pre-sort formatting function.\n\t\t\t */\n\t\t\tif ( formatters === aSort.length ) {\n\t\t\t\t// All sort types have formatting functions\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, test, sort,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\ttest = x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn sort.dir === 'asc' ? test : -test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Depreciated - remove in 1.11 (providing a plug-in option)\n\t\t\t\t// Not all sort types have formatting methods, so we have to call their sorting\n\t\t\t\t// methods.\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, l, test, sort, fn,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\tfn = oExtSort[ sort.type+\"-\"+sort.dir ] || oExtSort[ \"string-\"+sort.dir ];\n\t\t\t\t\t\ttest = fn( x, y );\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Tell the draw function that we have sorted the data */\n\t\toSettings.bSorted = true;\n\t}\n\t\n\t\n\tfunction _fnSortAria ( settings )\n\t{\n\t\tvar label;\n\t\tvar nextSort;\n\t\tvar columns = settings.aoColumns;\n\t\tvar aSort = _fnSortFlatten( settings );\n\t\tvar oAria = settings.oLanguage.oAria;\n\t\n\t\t// ARIA attributes - need to loop all columns, to update all (removing old\n\t\t// attributes as needed)\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar col = columns[i];\n\t\t\tvar asSorting = col.asSorting;\n\t\t\tvar sTitle = col.sTitle.replace( /<.*?>/g, \"\" );\n\t\t\tvar th = col.nTh;\n\t\n\t\t\t// IE7 is throwing an error when setting these properties with jQuery's\n\t\t\t// attr() and removeAttr() methods...\n\t\t\tth.removeAttribute('aria-sort');\n\t\n\t\t\t/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */\n\t\t\tif ( col.bSortable ) {\n\t\t\t\tif ( aSort.length > 0 && aSort[0].col == i ) {\n\t\t\t\t\tth.setAttribute('aria-sort', aSort[0].dir==\"asc\" ? \"ascending\" : \"descending\" );\n\t\t\t\t\tnextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnextSort = asSorting[0];\n\t\t\t\t}\n\t\n\t\t\t\tlabel = sTitle + ( nextSort === \"asc\" ?\n\t\t\t\t\toAria.sSortAscending :\n\t\t\t\t\toAria.sSortDescending\n\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlabel = sTitle;\n\t\t\t}\n\t\n\t\t\tth.setAttribute('aria-label', label);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Function to run on user sort request\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {boolean} [append=false] Append the requested sort to the existing\n\t *    sort if true (i.e. multi-column sort)\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortListener ( settings, colIdx, append, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\tvar sorting = settings.aaSorting;\n\t\tvar asSorting = col.asSorting;\n\t\tvar nextSortIdx;\n\t\tvar next = function ( a, overflow ) {\n\t\t\tvar idx = a._idx;\n\t\t\tif ( idx === undefined ) {\n\t\t\t\tidx = $.inArray( a[1], asSorting );\n\t\t\t}\n\t\n\t\t\treturn idx+1 < asSorting.length ?\n\t\t\t\tidx+1 :\n\t\t\t\toverflow ?\n\t\t\t\t\tnull :\n\t\t\t\t\t0;\n\t\t};\n\t\n\t\t// Convert to 2D array if needed\n\t\tif ( typeof sorting[0] === 'number' ) {\n\t\t\tsorting = settings.aaSorting = [ sorting ];\n\t\t}\n\t\n\t\t// If appending the sort then we are multi-column sorting\n\t\tif ( append && settings.oFeatures.bSortMulti ) {\n\t\t\t// Are we already doing some kind of sort on this column?\n\t\t\tvar sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );\n\t\n\t\t\tif ( sortIdx !== -1 ) {\n\t\t\t\t// Yes, modify the sort\n\t\t\t\tnextSortIdx = next( sorting[sortIdx], true );\n\t\n\t\t\t\tif ( nextSortIdx === null && sorting.length === 1 ) {\n\t\t\t\t\tnextSortIdx = 0; // can't remove sorting completely\n\t\t\t\t}\n\t\n\t\t\t\tif ( nextSortIdx === null ) {\n\t\t\t\t\tsorting.splice( sortIdx, 1 );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tsorting[sortIdx][1] = asSorting[ nextSortIdx ];\n\t\t\t\t\tsorting[sortIdx]._idx = nextSortIdx;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// No sort on this column yet\n\t\t\t\tsorting.push( [ colIdx, asSorting[0], 0 ] );\n\t\t\t\tsorting[sorting.length-1]._idx = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( sorting.length && sorting[0][0] == colIdx ) {\n\t\t\t// Single column - already sorting on this column, modify the sort\n\t\t\tnextSortIdx = next( sorting[0] );\n\t\n\t\t\tsorting.length = 1;\n\t\t\tsorting[0][1] = asSorting[ nextSortIdx ];\n\t\t\tsorting[0]._idx = nextSortIdx;\n\t\t}\n\t\telse {\n\t\t\t// Single column - sort only on this column\n\t\t\tsorting.length = 0;\n\t\t\tsorting.push( [ colIdx, asSorting[0] ] );\n\t\t\tsorting[0]._idx = 0;\n\t\t}\n\t\n\t\t// Run the sort by calling a full redraw\n\t\t_fnReDraw( settings );\n\t\n\t\t// callback used for async user interaction\n\t\tif ( typeof callback == 'function' ) {\n\t\t\tcallback( settings );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Attach a sort handler (click) to a node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortAttachListener ( settings, attachTo, colIdx, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\n\t\t_fnBindAction( attachTo, {}, function (e) {\n\t\t\t/* If the column is not sortable - don't to anything */\n\t\t\tif ( col.bSortable === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If processing is enabled use a timeout to allow the processing\n\t\t\t// display to be shown - otherwise to it synchronously\n\t\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t\tsetTimeout( function() {\n\t\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\n\t\t\t\t\t// In server-side processing, the draw callback will remove the\n\t\t\t\t\t// processing display\n\t\t\t\t\tif ( _fnDataSource( settings ) !== 'ssp' ) {\n\t\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t}\n\t\t\t\t}, 0 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Set the sorting classes on table's body, Note: it is safe to call this function\n\t * when bSort and bSortClasses are false\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortingClasses( settings )\n\t{\n\t\tvar oldSort = settings.aLastSort;\n\t\tvar sortClass = settings.oClasses.sSortColumn;\n\t\tvar sort = _fnSortFlatten( settings );\n\t\tvar features = settings.oFeatures;\n\t\tvar i, ien, colIdx;\n\t\n\t\tif ( features.bSort && features.bSortClasses ) {\n\t\t\t// Remove old sorting classes\n\t\t\tfor ( i=0, ien=oldSort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = oldSort[i].src;\n\t\n\t\t\t\t// Remove column sorting\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.removeClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\n\t\t\t// Add new column sorting\n\t\t\tfor ( i=0, ien=sort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = sort[i].src;\n\t\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.addClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aLastSort = sort;\n\t}\n\t\n\t\n\t// Get the data to sort a column, be it from cache, fresh (populating the\n\t// cache), or from a sort formatter\n\tfunction _fnSortData( settings, idx )\n\t{\n\t\t// Custom sorting function - provided by the sort data type\n\t\tvar column = settings.aoColumns[ idx ];\n\t\tvar customSort = DataTable.ext.order[ column.sSortDataType ];\n\t\tvar customData;\n\t\n\t\tif ( customSort ) {\n\t\t\tcustomData = customSort.call( settings.oInstance, settings, idx,\n\t\t\t\t_fnColumnIndexToVisible( settings, idx )\n\t\t\t);\n\t\t}\n\t\n\t\t// Use / populate cache\n\t\tvar row, cellData;\n\t\tvar formatter = DataTable.ext.type.order[ column.sType+\"-pre\" ];\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aSortData ) {\n\t\t\t\trow._aSortData = [];\n\t\t\t}\n\t\n\t\t\tif ( ! row._aSortData[idx] || customSort ) {\n\t\t\t\tcellData = customSort ?\n\t\t\t\t\tcustomData[i] : // If there was a custom sort function, use data from there\n\t\t\t\t\t_fnGetCellData( settings, i, idx, 'sort' );\n\t\n\t\t\t\trow._aSortData[ idx ] = formatter ?\n\t\t\t\t\tformatter( cellData ) :\n\t\t\t\t\tcellData;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Save the state of a table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSaveState ( settings )\n\t{\n\t\tif ( !settings.oFeatures.bStateSave || settings.bDestroying )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Store the interesting variables */\n\t\tvar state = {\n\t\t\ttime:    +new Date(),\n\t\t\tstart:   settings._iDisplayStart,\n\t\t\tlength:  settings._iDisplayLength,\n\t\t\torder:   $.extend( true, [], settings.aaSorting ),\n\t\t\tsearch:  _fnSearchToCamel( settings.oPreviousSearch ),\n\t\t\tcolumns: $.map( settings.aoColumns, function ( col, i ) {\n\t\t\t\treturn {\n\t\t\t\t\tvisible: col.bVisible,\n\t\t\t\t\tsearch: _fnSearchToCamel( settings.aoPreSearchCols[i] )\n\t\t\t\t};\n\t\t\t} )\n\t\t};\n\t\n\t\t_fnCallbackFire( settings, \"aoStateSaveParams\", 'stateSaveParams', [settings, state] );\n\t\n\t\tsettings.oSavedState = state;\n\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, state );\n\t}\n\t\n\t\n\t/**\n\t * Attempt to load a saved table state\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oInit DataTables init object so we can override settings\n\t *  @param {function} callback Callback to execute when the state has been loaded\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLoadState ( settings, oInit, callback )\n\t{\n\t\tvar i, ien;\n\t\tvar columns = settings.aoColumns;\n\t\tvar loaded = function ( s ) {\n\t\t\tif ( ! s || ! s.time ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Allow custom and plug-in manipulation functions to alter the saved data set and\n\t\t\t// cancelling of loading by returning false\n\t\t\tvar abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );\n\t\t\tif ( $.inArray( false, abStateLoad ) !== -1 ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Reject old data\n\t\t\tvar duration = settings.iStateDuration;\n\t\t\tif ( duration > 0 && s.time < +new Date() - (duration*1000) ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Number of columns have changed - all bets are off, no restore of settings\n\t\t\tif ( s.columns && columns.length !== s.columns.length ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Store the saved state so it might be accessed at any time\n\t\t\tsettings.oLoadedState = $.extend( true, {}, state );\n\t\n\t\t\t// Restore key features - todo - for 1.11 this needs to be done by\n\t\t\t// subscribed events\n\t\t\tif ( s.start !== undefined ) {\n\t\t\t\tsettings._iDisplayStart    = s.start;\n\t\t\t\tsettings.iInitDisplayStart = s.start;\n\t\t\t}\n\t\t\tif ( s.length !== undefined ) {\n\t\t\t\tsettings._iDisplayLength   = s.length;\n\t\t\t}\n\t\n\t\t\t// Order\n\t\t\tif ( s.order !== undefined ) {\n\t\t\t\tsettings.aaSorting = [];\n\t\t\t\t$.each( s.order, function ( i, col ) {\n\t\t\t\t\tsettings.aaSorting.push( col[0] >= columns.length ?\n\t\t\t\t\t\t[ 0, col[1] ] :\n\t\t\t\t\t\tcol\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Search\n\t\t\tif ( s.search !== undefined ) {\n\t\t\t\t$.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );\n\t\t\t}\n\t\n\t\t\t// Columns\n\t\t\t// \n\t\t\tif ( s.columns ) {\n\t\t\t\tfor ( i=0, ien=s.columns.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar col = s.columns[i];\n\t\n\t\t\t\t\t// Visibility\n\t\t\t\t\tif ( col.visible !== undefined ) {\n\t\t\t\t\t\tcolumns[i].bVisible = col.visible;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Search\n\t\t\t\t\tif ( col.search !== undefined ) {\n\t\t\t\t\t\t$.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );\n\t\t\tcallback();\n\t\t}\n\t\n\t\tif ( ! settings.oFeatures.bStateSave ) {\n\t\t\tcallback();\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );\n\t\n\t\tif ( state !== undefined ) {\n\t\t\tloaded( state );\n\t\t}\n\t\t// otherwise, wait for the loaded callback to be executed\n\t}\n\t\n\t\n\t/**\n\t * Return the settings object for a particular table\n\t *  @param {node} table table we are using as a dataTable\n\t *  @returns {object} Settings object - or null if not found\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSettingsFromNode ( table )\n\t{\n\t\tvar settings = DataTable.settings;\n\t\tvar idx = $.inArray( table, _pluck( settings, 'nTable' ) );\n\t\n\t\treturn idx !== -1 ?\n\t\t\tsettings[ idx ] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Log an error message\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} level log error messages, or display them to the user\n\t *  @param {string} msg error message\n\t *  @param {int} tn Technical note id to get more information about the error.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLog( settings, level, msg, tn )\n\t{\n\t\tmsg = 'DataTables warning: '+\n\t\t\t(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;\n\t\n\t\tif ( tn ) {\n\t\t\tmsg += '. For more information about this error, please see '+\n\t\t\t'http://datatables.net/tn/'+tn;\n\t\t}\n\t\n\t\tif ( ! level  ) {\n\t\t\t// Backwards compatibility pre 1.10\n\t\t\tvar ext = DataTable.ext;\n\t\t\tvar type = ext.sErrMode || ext.errMode;\n\t\n\t\t\tif ( settings ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );\n\t\t\t}\n\t\n\t\t\tif ( type == 'alert' ) {\n\t\t\t\talert( msg );\n\t\t\t}\n\t\t\telse if ( type == 'throw' ) {\n\t\t\t\tthrow new Error(msg);\n\t\t\t}\n\t\t\telse if ( typeof type == 'function' ) {\n\t\t\t\ttype( settings, tn, msg );\n\t\t\t}\n\t\t}\n\t\telse if ( window.console && console.log ) {\n\t\t\tconsole.log( msg );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * See if a property is defined on one object, if so assign it to the other object\n\t *  @param {object} ret target object\n\t *  @param {object} src source object\n\t *  @param {string} name property\n\t *  @param {string} [mappedName] name to map too - optional, name used if not given\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnMap( ret, src, name, mappedName )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\t$.each( name, function (i, val) {\n\t\t\t\tif ( $.isArray( val ) ) {\n\t\t\t\t\t_fnMap( ret, src, val[0], val[1] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_fnMap( ret, src, val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( mappedName === undefined ) {\n\t\t\tmappedName = name;\n\t\t}\n\t\n\t\tif ( src[name] !== undefined ) {\n\t\t\tret[mappedName] = src[name];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Extend objects - very similar to jQuery.extend, but deep copy objects, and\n\t * shallow copy arrays. The reason we need to do this, is that we don't want to\n\t * deep copy array init values (such as aaSorting) since the dev wouldn't be\n\t * able to override them, but we do want to deep copy arrays.\n\t *  @param {object} out Object to extend\n\t *  @param {object} extender Object from which the properties will be applied to\n\t *      out\n\t *  @param {boolean} breakRefs If true, then arrays will be sliced to take an\n\t *      independent copy with the exception of the `data` or `aaData` parameters\n\t *      if they are present. This is so you can pass in a collection to\n\t *      DataTables and have that used as your data source without breaking the\n\t *      references\n\t *  @returns {object} out Reference, just for convenience - out === the return.\n\t *  @memberof DataTable#oApi\n\t *  @todo This doesn't take account of arrays inside the deep copied objects.\n\t */\n\tfunction _fnExtend( out, extender, breakRefs )\n\t{\n\t\tvar val;\n\t\n\t\tfor ( var prop in extender ) {\n\t\t\tif ( extender.hasOwnProperty(prop) ) {\n\t\t\t\tval = extender[prop];\n\t\n\t\t\t\tif ( $.isPlainObject( val ) ) {\n\t\t\t\t\tif ( ! $.isPlainObject( out[prop] ) ) {\n\t\t\t\t\t\tout[prop] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, out[prop], val );\n\t\t\t\t}\n\t\t\t\telse if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {\n\t\t\t\t\tout[prop] = val.slice();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tout[prop] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t}\n\t\n\t\n\t/**\n\t * Bind an event handers to allow a click or return key to activate the callback.\n\t * This is good for accessibility since a return on the keyboard will have the\n\t * same effect as a click, if the element has focus.\n\t *  @param {element} n Element to bind the action to\n\t *  @param {object} oData Data object to pass to the triggered function\n\t *  @param {function} fn Callback function for when the event is triggered\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBindAction( n, oData, fn )\n\t{\n\t\t$(n)\n\t\t\t.on( 'click.DT', oData, function (e) {\n\t\t\t\t\tn.blur(); // Remove focus outline for mouse users\n\t\t\t\t\tfn(e);\n\t\t\t\t} )\n\t\t\t.on( 'keypress.DT', oData, function (e){\n\t\t\t\t\tif ( e.which === 13 ) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tfn(e);\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t.on( 'selectstart.DT', function () {\n\t\t\t\t\t/* Take the brutal approach to cancelling text selection */\n\t\t\t\t\treturn false;\n\t\t\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Register a callback function. Easily allows a callback function to be added to\n\t * an array store of callback functions that can then all be called together.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sStore Name of the array storage for the callbacks in oSettings\n\t *  @param {function} fn Function to be called back\n\t *  @param {string} sName Identifying name for the callback (i.e. a label)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackReg( oSettings, sStore, fn, sName )\n\t{\n\t\tif ( fn )\n\t\t{\n\t\t\toSettings[sStore].push( {\n\t\t\t\t\"fn\": fn,\n\t\t\t\t\"sName\": sName\n\t\t\t} );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Fire callback functions and trigger events. Note that the loop over the\n\t * callback array store is done backwards! Further note that you do not want to\n\t * fire off triggers in time sensitive applications (for example cell creation)\n\t * as its slow.\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} callbackArr Name of the array storage for the callbacks in\n\t *      oSettings\n\t *  @param {string} eventName Name of the jQuery custom event to trigger. If\n\t *      null no trigger is fired\n\t *  @param {array} args Array of arguments to pass to the callback function /\n\t *      trigger\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackFire( settings, callbackArr, eventName, args )\n\t{\n\t\tvar ret = [];\n\t\n\t\tif ( callbackArr ) {\n\t\t\tret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {\n\t\t\t\treturn val.fn.apply( settings.oInstance, args );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( eventName !== null ) {\n\t\t\tvar e = $.Event( eventName+'.dt' );\n\t\n\t\t\t$(settings.nTable).trigger( e, args );\n\t\n\t\t\tret.push( e.result );\n\t\t}\n\t\n\t\treturn ret;\n\t}\n\t\n\t\n\tfunction _fnLengthOverflow ( settings )\n\t{\n\t\tvar\n\t\t\tstart = settings._iDisplayStart,\n\t\t\tend = settings.fnDisplayEnd(),\n\t\t\tlen = settings._iDisplayLength;\n\t\n\t\t/* If we have space to show extra rows (backing up from the end point - then do so */\n\t\tif ( start >= end )\n\t\t{\n\t\t\tstart = end - len;\n\t\t}\n\t\n\t\t// Keep the start record on the current page\n\t\tstart -= (start % len);\n\t\n\t\tif ( len === -1 || start < 0 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\n\t\tsettings._iDisplayStart = start;\n\t}\n\t\n\t\n\tfunction _fnRenderer( settings, type )\n\t{\n\t\tvar renderer = settings.renderer;\n\t\tvar host = DataTable.ext.renderer[type];\n\t\n\t\tif ( $.isPlainObject( renderer ) && renderer[type] ) {\n\t\t\t// Specific renderer for this type. If available use it, otherwise use\n\t\t\t// the default.\n\t\t\treturn host[renderer[type]] || host._;\n\t\t}\n\t\telse if ( typeof renderer === 'string' ) {\n\t\t\t// Common renderer - if there is one available for this type use it,\n\t\t\t// otherwise use the default\n\t\t\treturn host[renderer] || host._;\n\t\t}\n\t\n\t\t// Use the default\n\t\treturn host._;\n\t}\n\t\n\t\n\t/**\n\t * Detect the data source being used for the table. Used to simplify the code\n\t * a little (ajax) and to make it compress a little smaller.\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {string} Data source\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDataSource ( settings )\n\t{\n\t\tif ( settings.oFeatures.bServerSide ) {\n\t\t\treturn 'ssp';\n\t\t}\n\t\telse if ( settings.ajax || settings.sAjaxSource ) {\n\t\t\treturn 'ajax';\n\t\t}\n\t\treturn 'dom';\n\t}\n\t\n\n\t\n\t\n\t/**\n\t * Computed structure of the DataTables API, defined by the options passed to\n\t * `DataTable.Api.register()` when building the API.\n\t *\n\t * The structure is built in order to speed creation and extension of the Api\n\t * objects since the extensions are effectively pre-parsed.\n\t *\n\t * The array is an array of objects with the following structure, where this\n\t * base array represents the Api prototype base:\n\t *\n\t *     [\n\t *       {\n\t *         name:      'data'                -- string   - Property name\n\t *         val:       function () {},       -- function - Api method (or undefined if just an object\n\t *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t *       },\n\t *       {\n\t *         name:     'row'\n\t *         val:       {},\n\t *         methodExt: [ ... ],\n\t *         propExt:   [\n\t *           {\n\t *             name:      'data'\n\t *             val:       function () {},\n\t *             methodExt: [ ... ],\n\t *             propExt:   [ ... ]\n\t *           },\n\t *           ...\n\t *         ]\n\t *       }\n\t *     ]\n\t *\n\t * @type {Array}\n\t * @ignore\n\t */\n\tvar __apiStruct = [];\n\t\n\t\n\t/**\n\t * `Array.prototype` reference.\n\t *\n\t * @type object\n\t * @ignore\n\t */\n\tvar __arrayProto = Array.prototype;\n\t\n\t\n\t/**\n\t * Abstraction for `context` parameter of the `Api` constructor to allow it to\n\t * take several different forms for ease of use.\n\t *\n\t * Each of the input parameter types will be converted to a DataTables settings\n\t * object where possible.\n\t *\n\t * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one\n\t *   of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t *   * `DataTables.Api` - API instance\n\t * @return {array|null} Matching DataTables settings objects. `null` or\n\t *   `undefined` is returned if no matching DataTable is found.\n\t * @ignore\n\t */\n\tvar _toSettings = function ( mixed )\n\t{\n\t\tvar idx, jq;\n\t\tvar settings = DataTable.settings;\n\t\tvar tables = $.map( settings, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\tif ( ! mixed ) {\n\t\t\treturn [];\n\t\t}\n\t\telse if ( mixed.nTable && mixed.oApi ) {\n\t\t\t// DataTables settings object\n\t\t\treturn [ mixed ];\n\t\t}\n\t\telse if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {\n\t\t\t// Table node\n\t\t\tidx = $.inArray( mixed, tables );\n\t\t\treturn idx !== -1 ? [ settings[idx] ] : null;\n\t\t}\n\t\telse if ( mixed && typeof mixed.settings === 'function' ) {\n\t\t\treturn mixed.settings().toArray();\n\t\t}\n\t\telse if ( typeof mixed === 'string' ) {\n\t\t\t// jQuery selector\n\t\t\tjq = $(mixed);\n\t\t}\n\t\telse if ( mixed instanceof $ ) {\n\t\t\t// jQuery object (also DataTables instance)\n\t\t\tjq = mixed;\n\t\t}\n\t\n\t\tif ( jq ) {\n\t\t\treturn jq.map( function(i) {\n\t\t\t\tidx = $.inArray( this, tables );\n\t\t\t\treturn idx !== -1 ? settings[idx] : null;\n\t\t\t} ).toArray();\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * DataTables API class - used to control and interface with  one or more\n\t * DataTables enhanced tables.\n\t *\n\t * The API class is heavily based on jQuery, presenting a chainable interface\n\t * that you can use to interact with tables. Each instance of the API class has\n\t * a \"context\" - i.e. the tables that it will operate on. This could be a single\n\t * table, all tables on a page or a sub-set thereof.\n\t *\n\t * Additionally the API is designed to allow you to easily work with the data in\n\t * the tables, retrieving and manipulating it as required. This is done by\n\t * presenting the API class as an array like interface. The contents of the\n\t * array depend upon the actions requested by each method (for example\n\t * `rows().nodes()` will return an array of nodes, while `rows().data()` will\n\t * return an array of objects or arrays depending upon your table's\n\t * configuration). The API object has a number of array like methods (`push`,\n\t * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,\n\t * `unique` etc) to assist your working with the data held in a table.\n\t *\n\t * Most methods (those which return an Api instance) are chainable, which means\n\t * the return from a method call also has all of the methods available that the\n\t * top level object had. For example, these two calls are equivalent:\n\t *\n\t *     // Not chained\n\t *     api.row.add( {...} );\n\t *     api.draw();\n\t *\n\t *     // Chained\n\t *     api.row.add( {...} ).draw();\n\t *\n\t * @class DataTable.Api\n\t * @param {array|object|string|jQuery} context DataTable identifier. This is\n\t *   used to define which DataTables enhanced tables this API will operate on.\n\t *   Can be one of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t * @param {array} [data] Data to initialise the Api instance with.\n\t *\n\t * @example\n\t *   // Direct initialisation during DataTables construction\n\t *   var api = $('#example').DataTable();\n\t *\n\t * @example\n\t *   // Initialisation using a DataTables jQuery object\n\t *   var api = $('#example').dataTable().api();\n\t *\n\t * @example\n\t *   // Initialisation as a constructor\n\t *   var api = new $.fn.DataTable.Api( 'table.dataTable' );\n\t */\n\t_Api = function ( context, data )\n\t{\n\t\tif ( ! (this instanceof _Api) ) {\n\t\t\treturn new _Api( context, data );\n\t\t}\n\t\n\t\tvar settings = [];\n\t\tvar ctxSettings = function ( o ) {\n\t\t\tvar a = _toSettings( o );\n\t\t\tif ( a ) {\n\t\t\t\tsettings = settings.concat( a );\n\t\t\t}\n\t\t};\n\t\n\t\tif ( $.isArray( context ) ) {\n\t\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tctxSettings( context[i] );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tctxSettings( context );\n\t\t}\n\t\n\t\t// Remove duplicates\n\t\tthis.context = _unique( settings );\n\t\n\t\t// Initial data\n\t\tif ( data ) {\n\t\t\t$.merge( this, data );\n\t\t}\n\t\n\t\t// selector\n\t\tthis.selector = {\n\t\t\trows: null,\n\t\t\tcols: null,\n\t\t\topts: null\n\t\t};\n\t\n\t\t_Api.extend( this, this, __apiStruct );\n\t};\n\t\n\tDataTable.Api = _Api;\n\t\n\t// Don't destroy the existing prototype, just extend it. Required for jQuery 2's\n\t// isPlainObject.\n\t$.extend( _Api.prototype, {\n\t\tany: function ()\n\t\t{\n\t\t\treturn this.count() !== 0;\n\t\t},\n\t\n\t\n\t\tconcat:  __arrayProto.concat,\n\t\n\t\n\t\tcontext: [], // array of table settings objects\n\t\n\t\n\t\tcount: function ()\n\t\t{\n\t\t\treturn this.flatten().length;\n\t\t},\n\t\n\t\n\t\teach: function ( fn )\n\t\t{\n\t\t\tfor ( var i=0, ien=this.length ; i<ien; i++ ) {\n\t\t\t\tfn.call( this, this[i], i, this );\n\t\t\t}\n\t\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\teq: function ( idx )\n\t\t{\n\t\t\tvar ctx = this.context;\n\t\n\t\t\treturn ctx.length > idx ?\n\t\t\t\tnew _Api( ctx[idx], this[idx] ) :\n\t\t\t\tnull;\n\t\t},\n\t\n\t\n\t\tfilter: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.filter ) {\n\t\t\t\ta = __arrayProto.filter.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( fn.call( this, this[i], i, this ) ) {\n\t\t\t\t\t\ta.push( this[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tflatten: function ()\n\t\t{\n\t\t\tvar a = [];\n\t\t\treturn new _Api( this.context, a.concat.apply( a, this.toArray() ) );\n\t\t},\n\t\n\t\n\t\tjoin:    __arrayProto.join,\n\t\n\t\n\t\tindexOf: __arrayProto.indexOf || function (obj, start)\n\t\t{\n\t\t\tfor ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {\n\t\t\t\tif ( this[i] === obj ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1;\n\t\t},\n\t\n\t\titerator: function ( flatten, type, fn, alwaysNew ) {\n\t\t\tvar\n\t\t\t\ta = [], ret,\n\t\t\t\ti, ien, j, jen,\n\t\t\t\tcontext = this.context,\n\t\t\t\trows, items, item,\n\t\t\t\tselector = this.selector;\n\t\n\t\t\t// Argument shifting\n\t\t\tif ( typeof flatten === 'string' ) {\n\t\t\t\talwaysNew = fn;\n\t\t\t\tfn = type;\n\t\t\t\ttype = flatten;\n\t\t\t\tflatten = false;\n\t\t\t}\n\t\n\t\t\tfor ( i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tvar apiInst = new _Api( context[i] );\n\t\n\t\t\t\tif ( type === 'table' ) {\n\t\t\t\t\tret = fn.call( apiInst, context[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'columns' || type === 'rows' ) {\n\t\t\t\t\t// this has same length as context - one entry for each table\n\t\t\t\t\tret = fn.call( apiInst, context[i], this[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {\n\t\t\t\t\t// columns and rows share the same structure.\n\t\t\t\t\t// 'this' is an array of column indexes for each context\n\t\t\t\t\titems = this[i];\n\t\n\t\t\t\t\tif ( type === 'column-rows' ) {\n\t\t\t\t\t\trows = _selector_row_indexes( context[i], selector.opts );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfor ( j=0, jen=items.length ; j<jen ; j++ ) {\n\t\t\t\t\t\titem = items[j];\n\t\n\t\t\t\t\t\tif ( type === 'cell' ) {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item.row, item.column, i, j );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item, i, j, rows );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( a.length || alwaysNew ) {\n\t\t\t\tvar api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );\n\t\t\t\tvar apiSelector = api.selector;\n\t\t\t\tapiSelector.rows = selector.rows;\n\t\t\t\tapiSelector.cols = selector.cols;\n\t\t\t\tapiSelector.opts = selector.opts;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\tlastIndexOf: __arrayProto.lastIndexOf || function (obj, start)\n\t\t{\n\t\t\t// Bit cheeky...\n\t\t\treturn this.indexOf.apply( this.toArray.reverse(), arguments );\n\t\t},\n\t\n\t\n\t\tlength:  0,\n\t\n\t\n\t\tmap: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.map ) {\n\t\t\t\ta = __arrayProto.map.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\ta.push( fn.call( this, this[i], i ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tpluck: function ( prop )\n\t\t{\n\t\t\treturn this.map( function ( el ) {\n\t\t\t\treturn el[ prop ];\n\t\t\t} );\n\t\t},\n\t\n\t\tpop:     __arrayProto.pop,\n\t\n\t\n\t\tpush:    __arrayProto.push,\n\t\n\t\n\t\t// Does not return an API instance\n\t\treduce: __arrayProto.reduce || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, 0, this.length, 1 );\n\t\t},\n\t\n\t\n\t\treduceRight: __arrayProto.reduceRight || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, this.length-1, -1, -1 );\n\t\t},\n\t\n\t\n\t\treverse: __arrayProto.reverse,\n\t\n\t\n\t\t// Object with rows, columns and opts\n\t\tselector: null,\n\t\n\t\n\t\tshift:   __arrayProto.shift,\n\t\n\t\n\t\tsort:    __arrayProto.sort, // ? name - order?\n\t\n\t\n\t\tsplice:  __arrayProto.splice,\n\t\n\t\n\t\ttoArray: function ()\n\t\t{\n\t\t\treturn __arrayProto.slice.call( this );\n\t\t},\n\t\n\t\n\t\tto$: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\ttoJQuery: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\tunique: function ()\n\t\t{\n\t\t\treturn new _Api( this.context, _unique(this) );\n\t\t},\n\t\n\t\n\t\tunshift: __arrayProto.unshift\n\t} );\n\t\n\t\n\t_Api.extend = function ( scope, obj, ext )\n\t{\n\t\t// Only extend API instances and static properties of the API\n\t\tif ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\tj, jen,\n\t\t\tstruct, inner,\n\t\t\tmethodScoping = function ( scope, fn, struc ) {\n\t\t\t\treturn function () {\n\t\t\t\t\tvar ret = fn.apply( scope, arguments );\n\t\n\t\t\t\t\t// Method extension\n\t\t\t\t\t_Api.extend( ret, ret, struc.methodExt );\n\t\t\t\t\treturn ret;\n\t\t\t\t};\n\t\t\t};\n\t\n\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\tstruct = ext[i];\n\t\n\t\t\t// Value\n\t\t\tobj[ struct.name ] = typeof struct.val === 'function' ?\n\t\t\t\tmethodScoping( scope, struct.val, struct ) :\n\t\t\t\t$.isPlainObject( struct.val ) ?\n\t\t\t\t\t{} :\n\t\t\t\t\tstruct.val;\n\t\n\t\t\tobj[ struct.name ].__dt_wrapper = true;\n\t\n\t\t\t// Property extension\n\t\t\t_Api.extend( scope, obj[ struct.name ], struct.propExt );\n\t\t}\n\t};\n\t\n\t\n\t// @todo - Is there need for an augment function?\n\t// _Api.augment = function ( inst, name )\n\t// {\n\t// \t// Find src object in the structure from the name\n\t// \tvar parts = name.split('.');\n\t\n\t// \t_Api.extend( inst, obj );\n\t// };\n\t\n\t\n\t//     [\n\t//       {\n\t//         name:      'data'                -- string   - Property name\n\t//         val:       function () {},       -- function - Api method (or undefined if just an object\n\t//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t//       },\n\t//       {\n\t//         name:     'row'\n\t//         val:       {},\n\t//         methodExt: [ ... ],\n\t//         propExt:   [\n\t//           {\n\t//             name:      'data'\n\t//             val:       function () {},\n\t//             methodExt: [ ... ],\n\t//             propExt:   [ ... ]\n\t//           },\n\t//           ...\n\t//         ]\n\t//       }\n\t//     ]\n\t\n\t_Api.register = _api_register = function ( name, val )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\tfor ( var j=0, jen=name.length ; j<jen ; j++ ) {\n\t\t\t\t_Api.register( name[j], val );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\their = name.split('.'),\n\t\t\tstruct = __apiStruct,\n\t\t\tkey, method;\n\t\n\t\tvar find = function ( src, name ) {\n\t\t\tfor ( var i=0, ien=src.length ; i<ien ; i++ ) {\n\t\t\t\tif ( src[i].name === name ) {\n\t\t\t\t\treturn src[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\n\t\tfor ( i=0, ien=heir.length ; i<ien ; i++ ) {\n\t\t\tmethod = heir[i].indexOf('()') !== -1;\n\t\t\tkey = method ?\n\t\t\t\their[i].replace('()', '') :\n\t\t\t\their[i];\n\t\n\t\t\tvar src = find( struct, key );\n\t\t\tif ( ! src ) {\n\t\t\t\tsrc = {\n\t\t\t\t\tname:      key,\n\t\t\t\t\tval:       {},\n\t\t\t\t\tmethodExt: [],\n\t\t\t\t\tpropExt:   []\n\t\t\t\t};\n\t\t\t\tstruct.push( src );\n\t\t\t}\n\t\n\t\t\tif ( i === ien-1 ) {\n\t\t\t\tsrc.val = val;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstruct = method ?\n\t\t\t\t\tsrc.methodExt :\n\t\t\t\t\tsrc.propExt;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\t_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {\n\t\t_Api.register( pluralName, val );\n\t\n\t\t_Api.register( singularName, function () {\n\t\t\tvar ret = val.apply( this, arguments );\n\t\n\t\t\tif ( ret === this ) {\n\t\t\t\t// Returned item is the API instance that was passed in, return it\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\telse if ( ret instanceof _Api ) {\n\t\t\t\t// New API instance returned, want the value from the first item\n\t\t\t\t// in the returned array for the singular result.\n\t\t\t\treturn ret.length ?\n\t\t\t\t\t$.isArray( ret[0] ) ?\n\t\t\t\t\t\tnew _Api( ret.context, ret[0] ) : // Array results are 'enhanced'\n\t\t\t\t\t\tret[0] :\n\t\t\t\t\tundefined;\n\t\t\t}\n\t\n\t\t\t// Non-API return - just fire it back\n\t\t\treturn ret;\n\t\t} );\n\t};\n\t\n\t\n\t/**\n\t * Selector for HTML tables. Apply the given selector to the give array of\n\t * DataTables settings objects.\n\t *\n\t * @param {string|integer} [selector] jQuery selector string or integer\n\t * @param  {array} Array of DataTables settings objects to be filtered\n\t * @return {array}\n\t * @ignore\n\t */\n\tvar __table_selector = function ( selector, a )\n\t{\n\t\t// Integer is used to pick out a table by index\n\t\tif ( typeof selector === 'number' ) {\n\t\t\treturn [ a[ selector ] ];\n\t\t}\n\t\n\t\t// Perform a jQuery selector on the table nodes\n\t\tvar nodes = $.map( a, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\treturn $(nodes)\n\t\t\t.filter( selector )\n\t\t\t.map( function (i) {\n\t\t\t\t// Need to translate back from the table node to the settings\n\t\t\t\tvar idx = $.inArray( this, nodes );\n\t\t\t\treturn a[ idx ];\n\t\t\t} )\n\t\t\t.toArray();\n\t};\n\t\n\t\n\t\n\t/**\n\t * Context selector for the API's context (i.e. the tables the API instance\n\t * refers to.\n\t *\n\t * @name    DataTable.Api#tables\n\t * @param {string|integer} [selector] Selector to pick which tables the iterator\n\t *   should operate on. If not given, all tables in the current context are\n\t *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to\n\t *   select multiple tables or as an integer to select a single table.\n\t * @returns {DataTable.Api} Returns a new API instance if a selector is given.\n\t */\n\t_api_register( 'tables()', function ( selector ) {\n\t\t// A new instance is created if there was a selector specified\n\t\treturn selector ?\n\t\t\tnew _Api( __table_selector( selector, this.context ) ) :\n\t\t\tthis;\n\t} );\n\t\n\t\n\t_api_register( 'table()', function ( selector ) {\n\t\tvar tables = this.tables( selector );\n\t\tvar ctx = tables.context;\n\t\n\t\t// Truncate to the first matched table\n\t\treturn ctx.length ?\n\t\t\tnew _Api( ctx[0] ) :\n\t\t\ttables;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTable;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().body()', 'table().body()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTBody;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().header()', 'table().header()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTHead;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTFoot;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().containers()', 'table().container()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTableWrapper;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Redraw the tables in the current context.\n\t */\n\t_api_register( 'draw()', function ( paging ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( paging === 'page' ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ( typeof paging === 'string' ) {\n\t\t\t\t\tpaging = paging === 'full-hold' ?\n\t\t\t\t\t\tfalse :\n\t\t\t\t\t\ttrue;\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, paging===false );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get the current page index.\n\t *\n\t * @return {integer} Current page index (zero based)\n\t *//**\n\t * Set the current page.\n\t *\n\t * Note that if you attempt to show a page which does not exist, DataTables will\n\t * not throw an error, but rather reset the paging.\n\t *\n\t * @param {integer|string} action The paging action to take. This can be one of:\n\t *  * `integer` - The page index to jump to\n\t *  * `string` - An action to take:\n\t *    * `first` - Jump to first page.\n\t *    * `next` - Jump to the next page\n\t *    * `previous` - Jump to previous page\n\t *    * `last` - Jump to the last page.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page()', function ( action ) {\n\t\tif ( action === undefined ) {\n\t\t\treturn this.page.info().page; // not an expensive call\n\t\t}\n\t\n\t\t// else, have an action to take on all tables\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnPageChange( settings, action );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Paging information for the first table in the current context.\n\t *\n\t * If you require paging information for another table, use the `table()` method\n\t * with a suitable selector.\n\t *\n\t * @return {object} Object with the following properties set:\n\t *  * `page` - Current page index (zero based - i.e. the first page is `0`)\n\t *  * `pages` - Total number of pages\n\t *  * `start` - Display index for the first record shown on the current page\n\t *  * `end` - Display index for the last record shown on the current page\n\t *  * `length` - Display length (number of records). Note that generally `start\n\t *    + length = end`, but this is not always true, for example if there are\n\t *    only 2 records to show on the final page, with a length of 10.\n\t *  * `recordsTotal` - Full data set length\n\t *  * `recordsDisplay` - Data set length once the current filtering criterion\n\t *    are applied.\n\t */\n\t_api_register( 'page.info()', function ( action ) {\n\t\tif ( this.context.length === 0 ) {\n\t\t\treturn undefined;\n\t\t}\n\t\n\t\tvar\n\t\t\tsettings   = this.context[0],\n\t\t\tstart      = settings._iDisplayStart,\n\t\t\tlen        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,\n\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn {\n\t\t\t\"page\":           all ? 0 : Math.floor( start / len ),\n\t\t\t\"pages\":          all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\"start\":          start,\n\t\t\t\"end\":            settings.fnDisplayEnd(),\n\t\t\t\"length\":         len,\n\t\t\t\"recordsTotal\":   settings.fnRecordsTotal(),\n\t\t\t\"recordsDisplay\": visRecords,\n\t\t\t\"serverSide\":     _fnDataSource( settings ) === 'ssp'\n\t\t};\n\t} );\n\t\n\t\n\t/**\n\t * Get the current page length.\n\t *\n\t * @return {integer} Current page length. Note `-1` indicates that all records\n\t *   are to be shown.\n\t *//**\n\t * Set the current page length.\n\t *\n\t * @param {integer} Page length to set. Use `-1` to show all records.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page.len()', function ( len ) {\n\t\t// Note that we can't call this function 'length()' because `length`\n\t\t// is a Javascript property of functions which defines how many arguments\n\t\t// the function expects.\n\t\tif ( len === undefined ) {\n\t\t\treturn this.context.length !== 0 ?\n\t\t\t\tthis.context[0]._iDisplayLength :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// else, set the page length\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnLengthChange( settings, len );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\tvar __reload = function ( settings, holdPosition, callback ) {\n\t\t// Use the draw event to trigger a callback\n\t\tif ( callback ) {\n\t\t\tvar api = new _Api( settings );\n\t\n\t\t\tapi.one( 'draw', function () {\n\t\t\t\tcallback( api.ajax.json() );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t_fnReDraw( settings, holdPosition );\n\t\t}\n\t\telse {\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t// Cancel an existing request\n\t\t\tvar xhr = settings.jqXHR;\n\t\t\tif ( xhr && xhr.readyState !== 4 ) {\n\t\t\t\txhr.abort();\n\t\t\t}\n\t\n\t\t\t// Trigger xhr\n\t\t\t_fnBuildAjax( settings, [], function( json ) {\n\t\t\t\t_fnClearTable( settings );\n\t\n\t\t\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\t_fnAddData( settings, data[i] );\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, holdPosition );\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Get the JSON response from the last Ajax request that DataTables made to the\n\t * server. Note that this returns the JSON from the first table in the current\n\t * context.\n\t *\n\t * @return {object} JSON received from the server.\n\t */\n\t_api_register( 'ajax.json()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].json;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Get the data submitted in the last Ajax request\n\t */\n\t_api_register( 'ajax.params()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].oAjaxData;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Reload tables from the Ajax data source. Note that this function will\n\t * automatically re-draw the table when the remote data has been loaded.\n\t *\n\t * @param {boolean} [reset=true] Reset (default) or hold the current paging\n\t *   position. A full re-sort and re-filter is performed when this method is\n\t *   called, which is why the pagination reset is the default action.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.reload()', function ( callback, resetPaging ) {\n\t\treturn this.iterator( 'table', function (settings) {\n\t\t\t__reload( settings, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Get the current Ajax URL. Note that this returns the URL from the first\n\t * table in the current context.\n\t *\n\t * @return {string} Current Ajax source URL\n\t *//**\n\t * Set the Ajax URL. Note that this will set the URL for all tables in the\n\t * current context.\n\t *\n\t * @param {string} url URL to set.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url()', function ( url ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( url === undefined ) {\n\t\t\t// get\n\t\t\tif ( ctx.length === 0 ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tctx = ctx[0];\n\t\n\t\t\treturn ctx.ajax ?\n\t\t\t\t$.isPlainObject( ctx.ajax ) ?\n\t\t\t\t\tctx.ajax.url :\n\t\t\t\t\tctx.ajax :\n\t\t\t\tctx.sAjaxSource;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( $.isPlainObject( settings.ajax ) ) {\n\t\t\t\tsettings.ajax.url = url;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsettings.ajax = url;\n\t\t\t}\n\t\t\t// No need to consider sAjaxSource here since DataTables gives priority\n\t\t\t// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any\n\t\t\t// value of `sAjaxSource` redundant.\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Load data from the newly set Ajax URL. Note that this method is only\n\t * available when `ajax.url()` is used to set a URL. Additionally, this method\n\t * has the same effect as calling `ajax.reload()` but is provided for\n\t * convenience when setting a new URL. Like `ajax.reload()` it will\n\t * automatically redraw the table once the remote data has been loaded.\n\t *\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {\n\t\t// Same as a reload, but makes sense to present it for easy access after a\n\t\t// url change\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\t__reload( ctx, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t\n\tvar _selector_run = function ( type, selector, selectFn, settings, opts )\n\t{\n\t\tvar\n\t\t\tout = [], res,\n\t\t\ta, i, ien, j, jen,\n\t\t\tselectorType = typeof selector;\n\t\n\t\t// Can't just check for isArray here, as an API or jQuery instance might be\n\t\t// given with their array like look\n\t\tif ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {\n\t\t\tselector = [ selector ];\n\t\t}\n\t\n\t\tfor ( i=0, ien=selector.length ; i<ien ; i++ ) {\n\t\t\t// Only split on simple strings - complex expressions will be jQuery selectors\n\t\t\ta = selector[i] && selector[i].split && ! selector[i].match(/[\\[\\(:]/) ?\n\t\t\t\tselector[i].split(',') :\n\t\t\t\t[ selector[i] ];\n\t\n\t\t\tfor ( j=0, jen=a.length ; j<jen ; j++ ) {\n\t\t\t\tres = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );\n\t\n\t\t\t\tif ( res && res.length ) {\n\t\t\t\t\tout = out.concat( res );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// selector extensions\n\t\tvar ext = _ext.selector[ type ];\n\t\tif ( ext.length ) {\n\t\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\t\tout = ext[i]( settings, opts, out );\n\t\t\t}\n\t\t}\n\t\n\t\treturn _unique( out );\n\t};\n\t\n\t\n\tvar _selector_opts = function ( opts )\n\t{\n\t\tif ( ! opts ) {\n\t\t\topts = {};\n\t\t}\n\t\n\t\t// Backwards compatibility for 1.9- which used the terminology filter rather\n\t\t// than search\n\t\tif ( opts.filter && opts.search === undefined ) {\n\t\t\topts.search = opts.filter;\n\t\t}\n\t\n\t\treturn $.extend( {\n\t\t\tsearch: 'none',\n\t\t\torder: 'current',\n\t\t\tpage: 'all'\n\t\t}, opts );\n\t};\n\t\n\t\n\tvar _selector_first = function ( inst )\n\t{\n\t\t// Reduce the API instance to the first item found\n\t\tfor ( var i=0, ien=inst.length ; i<ien ; i++ ) {\n\t\t\tif ( inst[i].length > 0 ) {\n\t\t\t\t// Assign the first element to the first item in the instance\n\t\t\t\t// and truncate the instance and context\n\t\t\t\tinst[0] = inst[i];\n\t\t\t\tinst[0].length = 1;\n\t\t\t\tinst.length = 1;\n\t\t\t\tinst.context = [ inst.context[i] ];\n\t\n\t\t\t\treturn inst;\n\t\t\t}\n\t\t}\n\t\n\t\t// Not found - return an empty instance\n\t\tinst.length = 0;\n\t\treturn inst;\n\t};\n\t\n\t\n\tvar _selector_row_indexes = function ( settings, opts )\n\t{\n\t\tvar\n\t\t\ti, ien, tmp, a=[],\n\t\t\tdisplayFiltered = settings.aiDisplay,\n\t\t\tdisplayMaster = settings.aiDisplayMaster;\n\t\n\t\tvar\n\t\t\tsearch = opts.search,  // none, applied, removed\n\t\t\torder  = opts.order,   // applied, current, index (original - compatibility with 1.9)\n\t\t\tpage   = opts.page;    // all, current\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t// In server-side processing mode, most options are irrelevant since\n\t\t\t// rows not shown don't exist and the index order is the applied order\n\t\t\t// Removed is a special case - for consistency just return an empty\n\t\t\t// array\n\t\t\treturn search === 'removed' ?\n\t\t\t\t[] :\n\t\t\t\t_range( 0, displayMaster.length );\n\t\t}\n\t\telse if ( page == 'current' ) {\n\t\t\t// Current page implies that order=current and fitler=applied, since it is\n\t\t\t// fairly senseless otherwise, regardless of what order and search actually\n\t\t\t// are\n\t\t\tfor ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {\n\t\t\t\ta.push( displayFiltered[i] );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'current' || order == 'applied' ) {\n\t\t\ta = search == 'none' ?\n\t\t\t\tdisplayMaster.slice() :                      // no search\n\t\t\t\tsearch == 'applied' ?\n\t\t\t\t\tdisplayFiltered.slice() :                // applied search\n\t\t\t\t\t$.map( displayMaster, function (el, i) { // removed search\n\t\t\t\t\t\treturn $.inArray( el, displayFiltered ) === -1 ? el : null;\n\t\t\t\t\t} );\n\t\t}\n\t\telse if ( order == 'index' || order == 'original' ) {\n\t\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tif ( search == 'none' ) {\n\t\t\t\t\ta.push( i );\n\t\t\t\t}\n\t\t\t\telse { // applied | removed\n\t\t\t\t\ttmp = $.inArray( i, displayFiltered );\n\t\n\t\t\t\t\tif ((tmp === -1 && search == 'removed') ||\n\t\t\t\t\t\t(tmp >= 0   && search == 'applied') )\n\t\t\t\t\t{\n\t\t\t\t\t\ta.push( i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn a;\n\t};\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Rows\n\t *\n\t * {}          - no selector - use all available rows\n\t * {integer}   - row aoData index\n\t * {node}      - TR node\n\t * {string}    - jQuery selector to apply to the TR elements\n\t * {array}     - jQuery array of nodes, or simply an array of TR nodes\n\t *\n\t */\n\t\n\t\n\tvar __row_selector = function ( settings, selector, opts )\n\t{\n\t\tvar rows;\n\t\tvar run = function ( sel ) {\n\t\t\tvar selInt = _intVal( sel );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Short cut - selector is a number and no options provided (default is\n\t\t\t// all records, so no need to check if the index is in there, since it\n\t\t\t// must be - dev error if the index doesn't exist).\n\t\t\tif ( selInt !== null && ! opts ) {\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\n\t\t\tif ( ! rows ) {\n\t\t\t\trows = _selector_row_indexes( settings, opts );\n\t\t\t}\n\t\n\t\t\tif ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {\n\t\t\t\t// Selector - integer\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\t\telse if ( sel === null || sel === undefined || sel === '' ) {\n\t\t\t\t// Selector - none\n\t\t\t\treturn rows;\n\t\t\t}\n\t\n\t\t\t// Selector - function\n\t\t\tif ( typeof sel === 'function' ) {\n\t\t\t\treturn $.map( rows, function (idx) {\n\t\t\t\t\tvar row = settings.aoData[ idx ];\n\t\t\t\t\treturn sel( idx, row._aData, row.nTr ) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Get nodes in the order from the `rows` array with null values removed\n\t\t\tvar nodes = _removeEmpty(\n\t\t\t\t_pluck_order( settings.aoData, rows, 'nTr' )\n\t\t\t);\n\t\n\t\t\t// Selector - node\n\t\t\tif ( sel.nodeName ) {\n\t\t\t\tif ( sel._DT_RowIndex !== undefined ) {\n\t\t\t\t\treturn [ sel._DT_RowIndex ]; // Property added by DT for fast lookup\n\t\t\t\t}\n\t\t\t\telse if ( sel._DT_CellIndex ) {\n\t\t\t\t\treturn [ sel._DT_CellIndex.row ];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tvar host = $(sel).closest('*[data-dt-row]');\n\t\t\t\t\treturn host.length ?\n\t\t\t\t\t\t[ host.data('dt-row') ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// ID selector. Want to always be able to select rows by id, regardless\n\t\t\t// of if the tr element has been created or not, so can't rely upon\n\t\t\t// jQuery here - hence a custom implementation. This does not match\n\t\t\t// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,\n\t\t\t// but to select it using a CSS selector engine (like Sizzle or\n\t\t\t// querySelect) it would need to need to be escaped for some characters.\n\t\t\t// DataTables simplifies this for row selectors since you can select\n\t\t\t// only a row. A # indicates an id any anything that follows is the id -\n\t\t\t// unescaped.\n\t\t\tif ( typeof sel === 'string' && sel.charAt(0) === '#' ) {\n\t\t\t\t// get row index from id\n\t\t\t\tvar rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];\n\t\t\t\tif ( rowObj !== undefined ) {\n\t\t\t\t\treturn [ rowObj.idx ];\n\t\t\t\t}\n\t\n\t\t\t\t// need to fall through to jQuery in case there is DOM id that\n\t\t\t\t// matches\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery selector string, array of nodes or jQuery object/\n\t\t\t// As jQuery's .filter() allows jQuery objects to be passed in filter,\n\t\t\t// it also allows arrays, so this will cope with all three options\n\t\t\treturn $(nodes)\n\t\t\t\t.filter( sel )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn this._DT_RowIndex;\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\t};\n\t\n\t\treturn _selector_run( 'row', selector, run, settings, opts );\n\t};\n\t\n\t\n\t_api_register( 'rows()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __row_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in __row_selector?\n\t\tinst.selector.rows = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_register( 'rows().nodes()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn settings.aoData[ row ].nTr || undefined;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'rows().data()', function () {\n\t\treturn this.iterator( true, 'rows', function ( settings, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, '_aData' );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\tvar r = settings.aoData[ row ];\n\t\t\treturn type === 'search' ? r._aFilterData : r._aSortData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\t_fnInvalidate( settings, row, src );\n\t\t} );\n\t} );\n\t\n\t_api_registerPlural( 'rows().indexes()', 'row().index()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn row;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {\n\t\tvar a = [];\n\t\tvar context = this.context;\n\t\n\t\t// `iterator` will drop undefined values, but in this case we want them\n\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\tfor ( var j=0, jen=this[i].length ; j<jen ; j++ ) {\n\t\t\t\tvar id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );\n\t\t\t\ta.push( (hash === true ? '#' : '' )+ id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn new _Api( context, a );\n\t} );\n\t\n\t_api_registerPlural( 'rows().remove()', 'row().remove()', function () {\n\t\tvar that = this;\n\t\n\t\tthis.iterator( 'row', function ( settings, row, thatIdx ) {\n\t\t\tvar data = settings.aoData;\n\t\t\tvar rowData = data[ row ];\n\t\t\tvar i, ien, j, jen;\n\t\t\tvar loopRow, loopCells;\n\t\n\t\t\tdata.splice( row, 1 );\n\t\n\t\t\t// Update the cached indexes\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\tloopRow = data[i];\n\t\t\t\tloopCells = loopRow.anCells;\n\t\n\t\t\t\t// Rows\n\t\t\t\tif ( loopRow.nTr !== null ) {\n\t\t\t\t\tloopRow.nTr._DT_RowIndex = i;\n\t\t\t\t}\n\t\n\t\t\t\t// Cells\n\t\t\t\tif ( loopCells !== null ) {\n\t\t\t\t\tfor ( j=0, jen=loopCells.length ; j<jen ; j++ ) {\n\t\t\t\t\t\tloopCells[j]._DT_CellIndex.row = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Delete from the display arrays\n\t\t\t_fnDeleteIndex( settings.aiDisplayMaster, row );\n\t\t\t_fnDeleteIndex( settings.aiDisplay, row );\n\t\t\t_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes\n\t\n\t\t\t// Check for an 'overflow' they case for displaying the table\n\t\t\t_fnLengthOverflow( settings );\n\t\n\t\t\t// Remove the row's ID reference if there is one\n\t\t\tvar id = settings.rowIdFn( rowData._aData );\n\t\t\tif ( id !== undefined ) {\n\t\t\t\tdelete settings.aIds[ id ];\n\t\t\t}\n\t\t} );\n\t\n\t\tthis.iterator( 'table', function ( settings ) {\n\t\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tsettings.aoData[i].idx = i;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'rows.add()', function ( rows ) {\n\t\tvar newRows = this.iterator( 'table', function ( settings ) {\n\t\t\t\tvar row, i, ien;\n\t\t\t\tvar out = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\t\t\tout.push( _fnAddTr( settings, row )[0] );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tout.push( _fnAddData( settings, row ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn out;\n\t\t\t}, 1 );\n\t\n\t\t// Return an Api.rows() extended instance, so rows().nodes() etc can be used\n\t\tvar modRows = this.rows( -1 );\n\t\tmodRows.pop();\n\t\t$.merge( modRows, newRows );\n\t\n\t\treturn modRows;\n\t} );\n\t\n\t\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( 'row()', function ( selector, opts ) {\n\t\treturn _selector_first( this.rows( selector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'row().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._aData :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\tctx[0].aoData[ this[0] ]._aData = data;\n\t\n\t\t// Automatically invalidate\n\t\t_fnInvalidate( ctx[0], this[0], 'data' );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'row().node()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\treturn ctx.length && this.length ?\n\t\t\tctx[0].aoData[ this[0] ].nTr || null :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'row.add()', function ( row ) {\n\t\t// Allow a jQuery object to be passed in - only a single row is added from\n\t\t// it though - the first element in the set\n\t\tif ( row instanceof $ && row.length ) {\n\t\t\trow = row[0];\n\t\t}\n\t\n\t\tvar rows = this.iterator( 'table', function ( settings ) {\n\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\treturn _fnAddTr( settings, row )[0];\n\t\t\t}\n\t\t\treturn _fnAddData( settings, row );\n\t\t} );\n\t\n\t\t// Return an Api.rows() extended instance, with the newly added row selected\n\t\treturn this.row( rows[0] );\n\t} );\n\t\n\t\n\t\n\tvar __details_add = function ( ctx, row, data, klass )\n\t{\n\t\t// Convert to array of TR elements\n\t\tvar rows = [];\n\t\tvar addRow = function ( r, k ) {\n\t\t\t// Recursion to allow for arrays of jQuery objects\n\t\t\tif ( $.isArray( r ) || r instanceof $ ) {\n\t\t\t\tfor ( var i=0, ien=r.length ; i<ien ; i++ ) {\n\t\t\t\t\taddRow( r[i], k );\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If we get a TR element, then just add it directly - up to the dev\n\t\t\t// to add the correct number of columns etc\n\t\t\tif ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {\n\t\t\t\trows.push( r );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Otherwise create a row with a wrapper\n\t\t\t\tvar created = $('<tr><td/></tr>').addClass( k );\n\t\t\t\t$('td', created)\n\t\t\t\t\t.addClass( k )\n\t\t\t\t\t.html( r )\n\t\t\t\t\t[0].colSpan = _fnVisbleColumns( ctx );\n\t\n\t\t\t\trows.push( created[0] );\n\t\t\t}\n\t\t};\n\t\n\t\taddRow( data, klass );\n\t\n\t\tif ( row._details ) {\n\t\t\trow._details.detach();\n\t\t}\n\t\n\t\trow._details = $(rows);\n\t\n\t\t// If the children were already shown, that state should be retained\n\t\tif ( row._detailsShow ) {\n\t\t\trow._details.insertAfter( row.nTr );\n\t\t}\n\t};\n\t\n\t\n\tvar __details_remove = function ( api, idx )\n\t{\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length ) {\n\t\t\tvar row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];\n\t\n\t\t\tif ( row && row._details ) {\n\t\t\t\trow._details.remove();\n\t\n\t\t\t\trow._detailsShow = undefined;\n\t\t\t\trow._details = undefined;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_display = function ( api, show ) {\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length && api.length ) {\n\t\t\tvar row = ctx[0].aoData[ api[0] ];\n\t\n\t\t\tif ( row._details ) {\n\t\t\t\trow._detailsShow = show;\n\t\n\t\t\t\tif ( show ) {\n\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\trow._details.detach();\n\t\t\t\t}\n\t\n\t\t\t\t__details_events( ctx[0] );\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_events = function ( settings )\n\t{\n\t\tvar api = new _Api( settings );\n\t\tvar namespace = '.dt.DT_details';\n\t\tvar drawEvent = 'draw'+namespace;\n\t\tvar colvisEvent = 'column-visibility'+namespace;\n\t\tvar destroyEvent = 'destroy'+namespace;\n\t\tvar data = settings.aoData;\n\t\n\t\tapi.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );\n\t\n\t\tif ( _pluck( data, '_details' ).length > 0 ) {\n\t\t\t// On each draw, insert the required elements into the document\n\t\t\tapi.on( drawEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tapi.rows( {page:'current'} ).eq(0).each( function (idx) {\n\t\t\t\t\t// Internal data grab\n\t\t\t\t\tvar row = data[ idx ];\n\t\n\t\t\t\t\tif ( row._detailsShow ) {\n\t\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\n\t\t\t// Column visibility change - update the colspan\n\t\t\tapi.on( colvisEvent, function ( e, ctx, idx, vis ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t// Update the colspan for the details rows (note, only if it already has\n\t\t\t\t// a colspan)\n\t\t\t\tvar row, visible = _fnVisbleColumns( ctx );\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = data[i];\n\t\n\t\t\t\t\tif ( row._details ) {\n\t\t\t\t\t\trow._details.children('td[colspan]').attr('colspan', visible );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\t// Table destroyed - nuke any child rows\n\t\t\tapi.on( destroyEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( data[i]._details ) {\n\t\t\t\t\t\t__details_remove( api, i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t// Strings for the method names to help minification\n\tvar _emp = '';\n\tvar _child_obj = _emp+'row().child';\n\tvar _child_mth = _child_obj+'()';\n\t\n\t// data can be:\n\t//  tr\n\t//  string\n\t//  jQuery or array of any of the above\n\t_api_register( _child_mth, function ( data, klass ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._details :\n\t\t\t\tundefined;\n\t\t}\n\t\telse if ( data === true ) {\n\t\t\t// show\n\t\t\tthis.child.show();\n\t\t}\n\t\telse if ( data === false ) {\n\t\t\t// remove\n\t\t\t__details_remove( this );\n\t\t}\n\t\telse if ( ctx.length && this.length ) {\n\t\t\t// set\n\t\t\t__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );\n\t\t}\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.show()',\n\t\t_child_mth+'.show()' // only when `child()` was called with parameters (without\n\t], function ( show ) {   // it returns an object and this method is not executed)\n\t\t__details_display( this, true );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.hide()',\n\t\t_child_mth+'.hide()' // only when `child()` was called with parameters (without\n\t], function () {         // it returns an object and this method is not executed)\n\t\t__details_display( this, false );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.remove()',\n\t\t_child_mth+'.remove()' // only when `child()` was called with parameters (without\n\t], function () {           // it returns an object and this method is not executed)\n\t\t__details_remove( this );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( _child_obj+'.isShown()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length && this.length ) {\n\t\t\t// _detailsShown as false or undefined will fall through to return false\n\t\t\treturn ctx[0].aoData[ this[0] ]._detailsShow || false;\n\t\t}\n\t\treturn false;\n\t} );\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Columns\n\t *\n\t * {integer}           - column index (>=0 count from left, <0 count from right)\n\t * \"{integer}:visIdx\"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)\n\t * \"{integer}:visible\" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)\n\t * \"{string}:name\"     - column name\n\t * \"{string}\"          - jQuery selector on column header nodes\n\t *\n\t */\n\t\n\t// can be an array of these items, comma separated list, or an array of comma\n\t// separated lists\n\t\n\tvar __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;\n\t\n\t\n\t// r1 and r2 are redundant - but it means that the parameters match for the\n\t// iterator callback in columns().data()\n\tvar __columnData = function ( settings, column, r1, r2, rows ) {\n\t\tvar a = [];\n\t\tfor ( var row=0, ien=rows.length ; row<ien ; row++ ) {\n\t\t\ta.push( _fnGetCellData( settings, rows[row], column ) );\n\t\t}\n\t\treturn a;\n\t};\n\t\n\t\n\tvar __column_selector = function ( settings, selector, opts )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tnames = _pluck( columns, 'sName' ),\n\t\t\tnodes = _pluck( columns, 'nTh' );\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar selInt = _intVal( s );\n\t\n\t\t\t// Selector - all\n\t\t\tif ( s === '' ) {\n\t\t\t\treturn _range( columns.length );\n\t\t\t}\n\t\n\t\t\t// Selector - index\n\t\t\tif ( selInt !== null ) {\n\t\t\t\treturn [ selInt >= 0 ?\n\t\t\t\t\tselInt : // Count from left\n\t\t\t\t\tcolumns.length + selInt // Count from right (+ because its a negative value)\n\t\t\t\t];\n\t\t\t}\n\t\n\t\t\t// Selector = function\n\t\t\tif ( typeof s === 'function' ) {\n\t\t\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\n\t\t\t\treturn $.map( columns, function (col, idx) {\n\t\t\t\t\treturn s(\n\t\t\t\t\t\t\tidx,\n\t\t\t\t\t\t\t__columnData( settings, idx, 0, 0, rows ),\n\t\t\t\t\t\t\tnodes[ idx ]\n\t\t\t\t\t\t) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// jQuery or string selector\n\t\t\tvar match = typeof s === 'string' ?\n\t\t\t\ts.match( __re_column_selector ) :\n\t\t\t\t'';\n\t\n\t\t\tif ( match ) {\n\t\t\t\tswitch( match[2] ) {\n\t\t\t\t\tcase 'visIdx':\n\t\t\t\t\tcase 'visible':\n\t\t\t\t\t\tvar idx = parseInt( match[1], 10 );\n\t\t\t\t\t\t// Visible index given, convert to column index\n\t\t\t\t\t\tif ( idx < 0 ) {\n\t\t\t\t\t\t\t// Counting from the right\n\t\t\t\t\t\t\tvar visColumns = $.map( columns, function (col,i) {\n\t\t\t\t\t\t\t\treturn col.bVisible ? i : null;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\treturn [ visColumns[ visColumns.length + idx ] ];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Counting from the left\n\t\t\t\t\t\treturn [ _fnVisibleToColumnIndex( settings, idx ) ];\n\t\n\t\t\t\t\tcase 'name':\n\t\t\t\t\t\t// match by name. `names` is column index complete and in order\n\t\t\t\t\t\treturn $.map( names, function (name, i) {\n\t\t\t\t\t\t\treturn name === match[1] ? i : null;\n\t\t\t\t\t\t} );\n\t\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Cell in the table body\n\t\t\tif ( s.nodeName && s._DT_CellIndex ) {\n\t\t\t\treturn [ s._DT_CellIndex.column ];\n\t\t\t}\n\t\n\t\t\t// jQuery selector on the TH elements for the columns\n\t\t\tvar jqResult = $( nodes )\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn $.inArray( this, nodes ); // `nodes` is column index complete and in order\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise a node which might have a `dt-column` data attribute, or be\n\t\t\t// a child or such an element\n\t\t\tvar host = $(s).closest('*[data-dt-column]');\n\t\t\treturn host.length ?\n\t\t\t\t[ host.data('dt-column') ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'column', selector, run, settings, opts );\n\t};\n\t\n\t\n\tvar __setColumnVis = function ( settings, column, vis ) {\n\t\tvar\n\t\t\tcols = settings.aoColumns,\n\t\t\tcol  = cols[ column ],\n\t\t\tdata = settings.aoData,\n\t\t\trow, cells, i, ien, tr;\n\t\n\t\t// Get\n\t\tif ( vis === undefined ) {\n\t\t\treturn col.bVisible;\n\t\t}\n\t\n\t\t// Set\n\t\t// No change\n\t\tif ( col.bVisible === vis ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( vis ) {\n\t\t\t// Insert column\n\t\t\t// Need to decide if we should use appendChild or insertBefore\n\t\t\tvar insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );\n\t\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\ttr = data[i].nTr;\n\t\t\t\tcells = data[i].anCells;\n\t\n\t\t\t\tif ( tr ) {\n\t\t\t\t\t// insertBefore can act like appendChild if 2nd arg is null\n\t\t\t\t\ttr.insertBefore( cells[ column ], cells[ insertBefore ] || null );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Remove column\n\t\t\t$( _pluck( settings.aoData, 'anCells', column ) ).detach();\n\t\t}\n\t\n\t\t// Common actions\n\t\tcol.bVisible = vis;\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t_fnSaveState( settings );\n\t};\n\t\n\t\n\t_api_register( 'columns()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __column_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in _row_selector?\n\t\tinst.selector.cols = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTh;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTf;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().data()', 'column().data()', function () {\n\t\treturn this.iterator( 'column-rows', __columnData, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].mData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows,\n\t\t\t\ttype === 'search' ? '_aFilterData' : '_aSortData', column\n\t\t\t);\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, 'anCells', column ) ;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {\n\t\tvar ret = this.iterator( 'column', function ( settings, column ) {\n\t\t\tif ( vis === undefined ) {\n\t\t\t\treturn settings.aoColumns[ column ].bVisible;\n\t\t\t} // else\n\t\t\t__setColumnVis( settings, column, vis );\n\t\t} );\n\t\n\t\t// Group the column visibility changes\n\t\tif ( vis !== undefined ) {\n\t\t\t// Second loop once the first is done for events\n\t\t\tthis.iterator( 'column', function ( settings, column ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );\n\t\t\t} );\n\t\n\t\t\tif ( calc === undefined || calc ) {\n\t\t\t\tthis.columns.adjust();\n\t\t\t}\n\t\t}\n\t\n\t\treturn ret;\n\t} );\n\t\n\t_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn type === 'visible' ?\n\t\t\t\t_fnColumnIndexToVisible( settings, column ) :\n\t\t\t\tcolumn;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'columns.adjust()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'column.index()', function ( type, idx ) {\n\t\tif ( this.context.length !== 0 ) {\n\t\t\tvar ctx = this.context[0];\n\t\n\t\t\tif ( type === 'fromVisible' || type === 'toData' ) {\n\t\t\t\treturn _fnVisibleToColumnIndex( ctx, idx );\n\t\t\t}\n\t\t\telse if ( type === 'fromData' || type === 'toVisible' ) {\n\t\t\t\treturn _fnColumnIndexToVisible( ctx, idx );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t_api_register( 'column()', function ( selector, opts ) {\n\t\treturn _selector_first( this.columns( selector, opts ) );\n\t} );\n\t\n\t\n\t\n\tvar __cell_selector = function ( settings, selector, opts )\n\t{\n\t\tvar data = settings.aoData;\n\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\tvar cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );\n\t\tvar allCells = $( [].concat.apply([], cells) );\n\t\tvar row;\n\t\tvar columns = settings.aoColumns.length;\n\t\tvar a, i, ien, j, o, host;\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar fnSelector = typeof s === 'function';\n\t\n\t\t\tif ( s === null || s === undefined || fnSelector ) {\n\t\t\t\t// All cells and function selectors\n\t\t\t\ta = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tfor ( j=0 ; j<columns ; j++ ) {\n\t\t\t\t\t\to = {\n\t\t\t\t\t\t\trow: row,\n\t\t\t\t\t\t\tcolumn: j\n\t\t\t\t\t\t};\n\t\n\t\t\t\t\t\tif ( fnSelector ) {\n\t\t\t\t\t\t\t// Selector - function\n\t\t\t\t\t\t\thost = data[ row ];\n\t\n\t\t\t\t\t\t\tif ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {\n\t\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Selector - all\n\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn a;\n\t\t\t}\n\t\t\t\n\t\t\t// Selector - index\n\t\t\tif ( $.isPlainObject( s ) ) {\n\t\t\t\treturn [s];\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery filtered cells\n\t\t\tvar jqResult = allCells\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function (i, el) {\n\t\t\t\t\treturn { // use a new object, in case someone changes the values\n\t\t\t\t\t\trow:    el._DT_CellIndex.row,\n\t\t\t\t\t\tcolumn: el._DT_CellIndex.column\n\t \t\t\t\t};\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise the selector is a node, and there is one last option - the\n\t\t\t// element might be a child of an element which has dt-row and dt-column\n\t\t\t// data attributes\n\t\t\thost = $(s).closest('*[data-dt-row]');\n\t\t\treturn host.length ?\n\t\t\t\t[ {\n\t\t\t\t\trow: host.data('dt-row'),\n\t\t\t\t\tcolumn: host.data('dt-column')\n\t\t\t\t} ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'cell', selector, run, settings, opts );\n\t};\n\t\n\t\n\t\n\t\n\t_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {\n\t\t// Argument shifting\n\t\tif ( $.isPlainObject( rowSelector ) ) {\n\t\t\t// Indexes\n\t\t\tif ( rowSelector.row === undefined ) {\n\t\t\t\t// Selector options in first parameter\n\t\t\t\topts = rowSelector;\n\t\t\t\trowSelector = null;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Cell index objects in first parameter\n\t\t\t\topts = columnSelector;\n\t\t\t\tcolumnSelector = null;\n\t\t\t}\n\t\t}\n\t\tif ( $.isPlainObject( columnSelector ) ) {\n\t\t\topts = columnSelector;\n\t\t\tcolumnSelector = null;\n\t\t}\n\t\n\t\t// Cell selector\n\t\tif ( columnSelector === null || columnSelector === undefined ) {\n\t\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t\treturn __cell_selector( settings, rowSelector, _selector_opts( opts ) );\n\t\t\t} );\n\t\t}\n\t\n\t\t// Row + column selector\n\t\tvar columns = this.columns( columnSelector, opts );\n\t\tvar rows = this.rows( rowSelector, opts );\n\t\tvar a, i, ien, j, jen;\n\t\n\t\tvar cells = this.iterator( 'table', function ( settings, idx ) {\n\t\t\ta = [];\n\t\n\t\t\tfor ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {\n\t\t\t\tfor ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {\n\t\t\t\t\ta.push( {\n\t\t\t\t\t\trow:    rows[idx][i],\n\t\t\t\t\t\tcolumn: columns[idx][j]\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn a;\n\t\t}, 1 );\n\t\n\t\t$.extend( cells.selector, {\n\t\t\tcols: columnSelector,\n\t\t\trows: rowSelector,\n\t\t\topts: opts\n\t\t} );\n\t\n\t\treturn cells;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\tvar data = settings.aoData[ row ];\n\t\n\t\t\treturn data && data.anCells ?\n\t\t\t\tdata.anCells[ column ] :\n\t\t\t\tundefined;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_register( 'cells().data()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {\n\t\ttype = type === 'search' ? '_aFilterData' : '_aSortData';\n\t\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn settings.aoData[ row ][ type ][ column ];\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column, type );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn {\n\t\t\t\trow: row,\n\t\t\t\tcolumn: column,\n\t\t\t\tcolumnVisible: _fnColumnIndexToVisible( settings, column )\n\t\t\t};\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\t_fnInvalidate( settings, row, src, column );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {\n\t\treturn _selector_first( this.cells( rowSelector, columnSelector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'cell().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\tvar cell = this[0];\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && cell.length ?\n\t\t\t\t_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\t_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );\n\t\t_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get current ordering (sorting) that has been applied to the table.\n\t *\n\t * @returns {array} 2D array containing the sorting information for the first\n\t *   table in the current context. Each element in the parent array represents\n\t *   a column being sorted upon (i.e. multi-sorting with two columns would have\n\t *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is\n\t *   the column index that the sorting condition applies to, the second is the\n\t *   direction of the sort (`desc` or `asc`) and, optionally, the third is the\n\t *   index of the sorting order from the `column.sorting` initialisation array.\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {integer} order Column index to sort upon.\n\t * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 1D array of sorting information to be applied.\n\t * @param {array} [...] Optional additional sorting conditions\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 2D array of sorting information to be applied.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order()', function ( order, dir ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( order === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].aaSorting :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\tif ( typeof order === 'number' ) {\n\t\t\t// Simple column / direction passed in\n\t\t\torder = [ [ order, dir ] ];\n\t\t}\n\t\telse if ( order.length && ! $.isArray( order[0] ) ) {\n\t\t\t// Arguments passed in (list of 1D arrays)\n\t\t\torder = Array.prototype.slice.call( arguments );\n\t\t}\n\t\t// otherwise a 2D array was passed in\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSorting = order.slice();\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Attach a sort listener to an element for a given column\n\t *\n\t * @param {node|jQuery|string} node Identifier for the element(s) to attach the\n\t *   listener to. This can take the form of a single DOM node, a jQuery\n\t *   collection of nodes or a jQuery selector which will identify the node(s).\n\t * @param {integer} column the column that a click on this node will sort on\n\t * @param {function} [callback] callback function when sort is run\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order.listener()', function ( node, column, callback ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSortAttachListener( settings, node, column, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'order.fixed()', function ( set ) {\n\t\tif ( ! set ) {\n\t\t\tvar ctx = this.context;\n\t\t\tvar fixed = ctx.length ?\n\t\t\t\tctx[0].aaSortingFixed :\n\t\t\t\tundefined;\n\t\n\t\t\treturn $.isArray( fixed ) ?\n\t\t\t\t{ pre: fixed } :\n\t\t\t\tfixed;\n\t\t}\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSortingFixed = $.extend( true, {}, set );\n\t\t} );\n\t} );\n\t\n\t\n\t// Order by the selected column(s)\n\t_api_register( [\n\t\t'columns().order()',\n\t\t'column().order()'\n\t], function ( dir ) {\n\t\tvar that = this;\n\t\n\t\treturn this.iterator( 'table', function ( settings, i ) {\n\t\t\tvar sort = [];\n\t\n\t\t\t$.each( that[i], function (j, col) {\n\t\t\t\tsort.push( [ col, dir ] );\n\t\t\t} );\n\t\n\t\t\tsettings.aaSorting = sort;\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'search()', function ( input, regex, smart, caseInsen ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( input === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].oPreviousSearch.sSearch :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {\n\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t} ), 1 );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural(\n\t\t'columns().search()',\n\t\t'column().search()',\n\t\tfunction ( input, regex, smart, caseInsen ) {\n\t\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\t\tvar preSearch = settings.aoPreSearchCols;\n\t\n\t\t\t\tif ( input === undefined ) {\n\t\t\t\t\t// get\n\t\t\t\t\treturn preSearch[ column ].sSearch;\n\t\t\t\t}\n\t\n\t\t\t\t// set\n\t\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t$.extend( preSearch[ column ], {\n\t\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t\t} );\n\t\n\t\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch, 1 );\n\t\t\t} );\n\t\t}\n\t);\n\t\n\t/*\n\t * State API methods\n\t */\n\t\n\t_api_register( 'state()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oSavedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t// Save an empty object\n\t\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, {} );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'state.loaded()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oLoadedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.save()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSaveState( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Provide a common method for plug-ins to check the version of DataTables being\n\t * used, in order to ensure compatibility.\n\t *\n\t *  @param {string} version Version string to check for, in the format \"X.Y.Z\".\n\t *    Note that the formats \"X\" and \"X.Y\" are also acceptable.\n\t *  @returns {boolean} true if this version of DataTables is greater or equal to\n\t *    the required version, or false if this version of DataTales is not\n\t *    suitable\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );\n\t */\n\tDataTable.versionCheck = DataTable.fnVersionCheck = function( version )\n\t{\n\t\tvar aThis = DataTable.version.split('.');\n\t\tvar aThat = version.split('.');\n\t\tvar iThis, iThat;\n\t\n\t\tfor ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {\n\t\t\tiThis = parseInt( aThis[i], 10 ) || 0;\n\t\t\tiThat = parseInt( aThat[i], 10 ) || 0;\n\t\n\t\t\t// Parts are the same, keep comparing\n\t\t\tif (iThis === iThat) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\t// Parts are different, return immediately\n\t\t\treturn iThis > iThat;\n\t\t}\n\t\n\t\treturn true;\n\t};\n\t\n\t\n\t/**\n\t * Check if a `<table>` node is a DataTable table already or not.\n\t *\n\t *  @param {node|jquery|string} table Table node, jQuery object or jQuery\n\t *      selector for the table to test. Note that if more than more than one\n\t *      table is passed on, only the first will be checked\n\t *  @returns {boolean} true the table given is a DataTable, or false otherwise\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {\n\t *      $('#example').dataTable();\n\t *    }\n\t */\n\tDataTable.isDataTable = DataTable.fnIsDataTable = function ( table )\n\t{\n\t\tvar t = $(table).get(0);\n\t\tvar is = false;\n\t\n\t\tif ( table instanceof DataTable.Api ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\t$.each( DataTable.settings, function (i, o) {\n\t\t\tvar head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;\n\t\t\tvar foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;\n\t\n\t\t\tif ( o.nTable === t || head === t || foot === t ) {\n\t\t\t\tis = true;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn is;\n\t};\n\t\n\t\n\t/**\n\t * Get all DataTable tables that have been initialised - optionally you can\n\t * select to get only currently visible tables.\n\t *\n\t *  @param {boolean} [visible=false] Flag to indicate if you want all (default)\n\t *    or visible tables only.\n\t *  @returns {array} Array of `table` nodes (not DataTable instances) which are\n\t *    DataTables\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    $.each( $.fn.dataTable.tables(true), function () {\n\t *      $(table).DataTable().columns.adjust();\n\t *    } );\n\t */\n\tDataTable.tables = DataTable.fnTables = function ( visible )\n\t{\n\t\tvar api = false;\n\t\n\t\tif ( $.isPlainObject( visible ) ) {\n\t\t\tapi = visible.api;\n\t\t\tvisible = visible.visible;\n\t\t}\n\t\n\t\tvar a = $.map( DataTable.settings, function (o) {\n\t\t\tif ( !visible || (visible && $(o.nTable).is(':visible')) ) {\n\t\t\t\treturn o.nTable;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn api ?\n\t\t\tnew _Api( a ) :\n\t\t\ta;\n\t};\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian notation. This is made public\n\t * for the extensions to provide the same ability as DataTables core to accept\n\t * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase\n\t * parameters.\n\t *\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t */\n\tDataTable.camelToHungarian = _fnCamelToHungarian;\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( '$()', function ( selector, opts ) {\n\t\tvar\n\t\t\trows   = this.rows( opts ).nodes(), // Get all rows\n\t\t\tjqRows = $(rows);\n\t\n\t\treturn $( [].concat(\n\t\t\tjqRows.filter( selector ).toArray(),\n\t\t\tjqRows.find( selector ).toArray()\n\t\t) );\n\t} );\n\t\n\t\n\t// jQuery functions to operate on the tables\n\t$.each( [ 'on', 'one', 'off' ], function (i, key) {\n\t\t_api_register( key+'()', function ( /* event, handler */ ) {\n\t\t\tvar args = Array.prototype.slice.call(arguments);\n\t\n\t\t\t// Add the `dt` namespace automatically if it isn't already present\n\t\t\targs[0] = $.map( args[0].split( /\\s/ ), function ( e ) {\n\t\t\t\treturn ! e.match(/\\.dt\\b/) ?\n\t\t\t\t\te+'.dt' :\n\t\t\t\t\te;\n\t\t\t\t} ).join( ' ' );\n\t\n\t\t\tvar inst = $( this.tables().nodes() );\n\t\t\tinst[key].apply( inst, args );\n\t\t\treturn this;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnClearTable( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'settings()', function () {\n\t\treturn new _Api( this.context, this.context );\n\t} );\n\t\n\t\n\t_api_register( 'init()', function () {\n\t\tvar ctx = this.context;\n\t\treturn ctx.length ? ctx[0].oInit : null;\n\t} );\n\t\n\t\n\t_api_register( 'data()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\treturn _pluck( settings.aoData, '_aData' );\n\t\t} ).flatten();\n\t} );\n\t\n\t\n\t_api_register( 'destroy()', function ( remove ) {\n\t\tremove = remove || false;\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tvar orig      = settings.nTableWrapper.parentNode;\n\t\t\tvar classes   = settings.oClasses;\n\t\t\tvar table     = settings.nTable;\n\t\t\tvar tbody     = settings.nTBody;\n\t\t\tvar thead     = settings.nTHead;\n\t\t\tvar tfoot     = settings.nTFoot;\n\t\t\tvar jqTable   = $(table);\n\t\t\tvar jqTbody   = $(tbody);\n\t\t\tvar jqWrapper = $(settings.nTableWrapper);\n\t\t\tvar rows      = $.map( settings.aoData, function (r) { return r.nTr; } );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Flag to note that the table is currently being destroyed - no action\n\t\t\t// should be taken\n\t\t\tsettings.bDestroying = true;\n\t\n\t\t\t// Fire off the destroy callbacks for plug-ins etc\n\t\t\t_fnCallbackFire( settings, \"aoDestroyCallback\", \"destroy\", [settings] );\n\t\n\t\t\t// If not being removed from the document, make all columns visible\n\t\t\tif ( ! remove ) {\n\t\t\t\tnew _Api( settings ).columns().visible( true );\n\t\t\t}\n\t\n\t\t\t// Blitz all `DT` namespaced events (these are internal events, the\n\t\t\t// lowercase, `dt` events are user subscribed and they are responsible\n\t\t\t// for removing them\n\t\t\tjqWrapper.off('.DT').find(':not(tbody *)').off('.DT');\n\t\t\t$(window).off('.DT-'+settings.sInstance);\n\t\n\t\t\t// When scrolling we had to break the table up - restore it\n\t\t\tif ( table != thead.parentNode ) {\n\t\t\t\tjqTable.children('thead').detach();\n\t\t\t\tjqTable.append( thead );\n\t\t\t}\n\t\n\t\t\tif ( tfoot && table != tfoot.parentNode ) {\n\t\t\t\tjqTable.children('tfoot').detach();\n\t\t\t\tjqTable.append( tfoot );\n\t\t\t}\n\t\n\t\t\tsettings.aaSorting = [];\n\t\t\tsettings.aaSortingFixed = [];\n\t\t\t_fnSortingClasses( settings );\n\t\n\t\t\t$( rows ).removeClass( settings.asStripeClasses.join(' ') );\n\t\n\t\t\t$('th, td', thead).removeClass( classes.sSortable+' '+\n\t\t\t\tclasses.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone\n\t\t\t);\n\t\n\t\t\tif ( settings.bJUI ) {\n\t\t\t\t$('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();\n\t\t\t\t$('th, td', thead).each( function () {\n\t\t\t\t\tvar wrapper = $('div.'+classes.sSortJUIWrapper, this);\n\t\t\t\t\t$(this).append( wrapper.contents() );\n\t\t\t\t\twrapper.detach();\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Add the TR elements back into the table in their original order\n\t\t\tjqTbody.children().detach();\n\t\t\tjqTbody.append( rows );\n\t\n\t\t\t// Remove the DataTables generated nodes, events and classes\n\t\t\tvar removedMethod = remove ? 'remove' : 'detach';\n\t\t\tjqTable[ removedMethod ]();\n\t\t\tjqWrapper[ removedMethod ]();\n\t\n\t\t\t// If we need to reattach the table to the document\n\t\t\tif ( ! remove && orig ) {\n\t\t\t\t// insertBefore acts like appendChild if !arg[1]\n\t\t\t\torig.insertBefore( table, settings.nTableReinsertBefore );\n\t\n\t\t\t\t// Restore the width of the original table - was read from the style property,\n\t\t\t\t// so we can restore directly to that\n\t\t\t\tjqTable\n\t\t\t\t\t.css( 'width', settings.sDestroyWidth )\n\t\t\t\t\t.removeClass( classes.sTable );\n\t\n\t\t\t\t// If the were originally stripe classes - then we add them back here.\n\t\t\t\t// Note this is not fool proof (for example if not all rows had stripe\n\t\t\t\t// classes - but it's a good effort without getting carried away\n\t\t\t\tien = settings.asDestroyStripes.length;\n\t\n\t\t\t\tif ( ien ) {\n\t\t\t\t\tjqTbody.children().each( function (i) {\n\t\t\t\t\t\t$(this).addClass( settings.asDestroyStripes[i % ien] );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Remove the settings object from the settings array */\n\t\t\tvar idx = $.inArray( settings, DataTable.settings );\n\t\t\tif ( idx !== -1 ) {\n\t\t\t\tDataTable.settings.splice( idx, 1 );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t// Add the `every()` method for rows, columns and cells in a compact form\n\t$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {\n\t\t_api_register( type+'s().every()', function ( fn ) {\n\t\t\tvar opts = this.selector.opts;\n\t\t\tvar api = this;\n\t\n\t\t\treturn this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {\n\t\t\t\t// Rows and columns:\n\t\t\t\t//  arg1 - index\n\t\t\t\t//  arg2 - table counter\n\t\t\t\t//  arg3 - loop counter\n\t\t\t\t//  arg4 - undefined\n\t\t\t\t// Cells:\n\t\t\t\t//  arg1 - row index\n\t\t\t\t//  arg2 - column index\n\t\t\t\t//  arg3 - table counter\n\t\t\t\t//  arg4 - loop counter\n\t\t\t\tfn.call(\n\t\t\t\t\tapi[ type ](\n\t\t\t\t\t\targ1,\n\t\t\t\t\t\ttype==='cell' ? arg2 : opts,\n\t\t\t\t\t\ttype==='cell' ? opts : undefined\n\t\t\t\t\t),\n\t\t\t\t\targ1, arg2, arg3, arg4\n\t\t\t\t);\n\t\t\t} );\n\t\t} );\n\t} );\n\t\n\t\n\t// i18n method for extensions to be able to use the language object from the\n\t// DataTable\n\t_api_register( 'i18n()', function ( token, def, plural ) {\n\t\tvar ctx = this.context[0];\n\t\tvar resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );\n\t\n\t\tif ( resolved === undefined ) {\n\t\t\tresolved = def;\n\t\t}\n\t\n\t\tif ( plural !== undefined && $.isPlainObject( resolved ) ) {\n\t\t\tresolved = resolved[ plural ] !== undefined ?\n\t\t\t\tresolved[ plural ] :\n\t\t\t\tresolved._;\n\t\t}\n\t\n\t\treturn resolved.replace( '%d', plural ); // nb: plural might be undefined,\n\t} );\n\n\t/**\n\t * Version string for plug-ins to check compatibility. Allowed format is\n\t * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used\n\t * only for non-release builds. See http://semver.org/ for more information.\n\t *  @member\n\t *  @type string\n\t *  @default Version number\n\t */\n\tDataTable.version = \"1.10.13\";\n\n\t/**\n\t * Private data store, containing all of the settings objects that are\n\t * created for the tables on a given page.\n\t *\n\t * Note that the `DataTable.settings` object is aliased to\n\t * `jQuery.fn.dataTableExt` through which it may be accessed and\n\t * manipulated, or `jQuery.fn.dataTable.settings`.\n\t *  @member\n\t *  @type array\n\t *  @default []\n\t *  @private\n\t */\n\tDataTable.settings = [];\n\n\t/**\n\t * Object models container, for the various models that DataTables has\n\t * available to it. These models define the objects that are used to hold\n\t * the active state and configuration of the table.\n\t *  @namespace\n\t */\n\tDataTable.models = {};\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * search information for the global filter and individual column filters.\n\t *  @namespace\n\t */\n\tDataTable.models.oSearch = {\n\t\t/**\n\t\t * Flag to indicate if the filtering should be case insensitive or not\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bCaseInsensitive\": true,\n\t\n\t\t/**\n\t\t * Applied search term\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sSearch\": \"\",\n\t\n\t\t/**\n\t\t * Flag to indicate if the search term should be interpreted as a\n\t\t * regular expression (true) or not (false) and therefore and special\n\t\t * regex characters escaped.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bRegex\": false,\n\t\n\t\t/**\n\t\t * Flag to indicate if DataTables is to use its smart filtering or not.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bSmart\": true\n\t};\n\t\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * each individual row. This is the object format used for the settings\n\t * aoData array.\n\t *  @namespace\n\t */\n\tDataTable.models.oRow = {\n\t\t/**\n\t\t * TR element for the row\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTr\": null,\n\t\n\t\t/**\n\t\t * Array of TD elements for each row. This is null until the row has been\n\t\t * created.\n\t\t *  @type array nodes\n\t\t *  @default []\n\t\t */\n\t\t\"anCells\": null,\n\t\n\t\t/**\n\t\t * Data object from the original data source for the row. This is either\n\t\t * an array if using the traditional form of DataTables, or an object if\n\t\t * using mData options. The exact type will depend on the passed in\n\t\t * data from the data source, or will be an array if using DOM a data\n\t\t * source.\n\t\t *  @type array|object\n\t\t *  @default []\n\t\t */\n\t\t\"_aData\": [],\n\t\n\t\t/**\n\t\t * Sorting data cache - this array is ostensibly the same length as the\n\t\t * number of columns (although each index is generated only as it is\n\t\t * needed), and holds the data that is used for sorting each column in the\n\t\t * row. We do this cache generation at the start of the sort in order that\n\t\t * the formatting of the sort data need be done only once for each cell\n\t\t * per sort. This array should not be read from or written to by anything\n\t\t * other than the master sorting methods.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aSortData\": null,\n\t\n\t\t/**\n\t\t * Per cell filtering data cache. As per the sort data cache, used to\n\t\t * increase the performance of the filtering in DataTables\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aFilterData\": null,\n\t\n\t\t/**\n\t\t * Filtering data cache. This is the same as the cell filtering cache, but\n\t\t * in this case a string rather than an array. This is easily computed with\n\t\t * a join on `_aFilterData`, but is provided as a cache so the join isn't\n\t\t * needed on every search (memory traded for performance)\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sFilterRow\": null,\n\t\n\t\t/**\n\t\t * Cache of the class name that DataTables has applied to the row, so we\n\t\t * can quickly look at this variable rather than needing to do a DOM check\n\t\t * on className for the nTr property.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *  @private\n\t\t */\n\t\t\"_sRowStripe\": \"\",\n\t\n\t\t/**\n\t\t * Denote if the original data source was from the DOM, or the data source\n\t\t * object. This is used for invalidating data, so DataTables can\n\t\t * automatically read data from the original source, unless uninstructed\n\t\t * otherwise.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"src\": null,\n\t\n\t\t/**\n\t\t * Index in the aoData array. This saves an indexOf lookup when we have the\n\t\t * object, but want to know the index\n\t\t *  @type integer\n\t\t *  @default -1\n\t\t *  @private\n\t\t */\n\t\t\"idx\": -1\n\t};\n\t\n\t\n\t/**\n\t * Template object for the column information object in DataTables. This object\n\t * is held in the settings aoColumns array and contains all the information that\n\t * DataTables needs about each individual column.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults.column}\n\t * but this one is the internal data store for DataTables's cache of columns.\n\t * It should NOT be manipulated outside of DataTables. Any configuration should\n\t * be done through the initialisation options.\n\t *  @namespace\n\t */\n\tDataTable.models.oColumn = {\n\t\t/**\n\t\t * Column index. This could be worked out on-the-fly with $.inArray, but it\n\t\t * is faster to just hold it as a variable\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"idx\": null,\n\t\n\t\t/**\n\t\t * A list of the columns that sorting should occur on when this column\n\t\t * is sorted. That this property is an array allows multi-column sorting\n\t\t * to be defined for a column (for example first name / last name columns\n\t\t * would benefit from this). The values are integers pointing to the\n\t\t * columns to be sorted on (typically it will be a single integer pointing\n\t\t * at itself, but that doesn't need to be the case).\n\t\t *  @type array\n\t\t */\n\t\t\"aDataSort\": null,\n\t\n\t\t/**\n\t\t * Define the sorting directions that are applied to the column, in sequence\n\t\t * as the column is repeatedly sorted upon - i.e. the first value is used\n\t\t * as the sorting direction when the column if first sorted (clicked on).\n\t\t * Sort it again (click again) and it will move on to the next index.\n\t\t * Repeat until loop.\n\t\t *  @type array\n\t\t */\n\t\t\"asSorting\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is searchable, and thus should be included\n\t\t * in the filtering or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSearchable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is sortable or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is currently visible in the table or not\n\t\t *  @type boolean\n\t\t */\n\t\t\"bVisible\": null,\n\t\n\t\t/**\n\t\t * Store for manual type assignment using the `column.type` option. This\n\t\t * is held in store so we can manipulate the column's `sType` property.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sManualType\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if HTML5 data attributes should be used as the data\n\t\t * source for filtering or sorting. True is either are.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @private\n\t\t */\n\t\t\"_bAttrSrc\": false,\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} nTd The TD node that has been created\n\t\t *  @param {*} sData The Data for the cell\n\t\t *  @param {array|object} oData The data for the whole row\n\t\t *  @param {int} iRow The row index for the aoData data store\n\t\t *  @default null\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\t/**\n\t\t * Function to get data from a cell in a column. You should <b>never</b>\n\t\t * access data directly through _aData internally in DataTables - always use\n\t\t * the method attached to this property. It allows mData to function as\n\t\t * required. This function is automatically assigned by the column\n\t\t * initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {string} sSpecific The specific data type you want to get -\n\t\t *    'display', 'type' 'filter' 'sort'\n\t\t *  @returns {*} The data for the cell from the given row's data\n\t\t *  @default null\n\t\t */\n\t\t\"fnGetData\": null,\n\t\n\t\t/**\n\t\t * Function to set data for a cell in the column. You should <b>never</b>\n\t\t * set the data directly to _aData internally in DataTables - always use\n\t\t * this method. It allows mData to function as required. This function\n\t\t * is automatically assigned by the column initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {*} sValue Value to set\n\t\t *  @default null\n\t\t */\n\t\t\"fnSetData\": null,\n\t\n\t\t/**\n\t\t * Property to read the value for the cells in the column from the data\n\t\t * source array / object. If null, then the default content is used, if a\n\t\t * function is given then the return from the function is used.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\t/**\n\t\t * Partner property to mData which is used (only when defined) to get\n\t\t * the data - i.e. it is basically the same as mData, but without the\n\t\t * 'set' option, and also the data fed to it is the result from mData.\n\t\t * This is the rendering method to match the data method of mData.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\t/**\n\t\t * Unique header TH/TD element for this column - this is what the sorting\n\t\t * listener is attached to (if sorting is enabled.)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTh\": null,\n\t\n\t\t/**\n\t\t * Unique footer TH/TD element for this column (if there is one). Not used\n\t\t * in DataTables as such, but can be used for plug-ins to reference the\n\t\t * footer for each column.\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTf\": null,\n\t\n\t\t/**\n\t\t * The class to apply to all TD elements in the table's TBODY for the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sClass\": null,\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t *  @type string\n\t\t */\n\t\t\"sContentPadding\": null,\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because mData\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\t/**\n\t\t * Name for the column, allowing reference to the column by name as well as\n\t\t * by index (needs a lookup to work by name).\n\t\t *  @type string\n\t\t */\n\t\t\"sName\": null,\n\t\n\t\t/**\n\t\t * Custom sorting data type - defines which of the available plug-ins in\n\t\t * afnSortData the custom sorting will use - if any is defined.\n\t\t *  @type string\n\t\t *  @default std\n\t\t */\n\t\t\"sSortDataType\": 'std',\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClass\": null,\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column -\n\t\t * when jQuery UI theming is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClassJUI\": null,\n\t\n\t\t/**\n\t\t * Title of the column - what is seen in the TH element (nTh).\n\t\t *  @type string\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\t/**\n\t\t * Column sorting and filtering type\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\t/**\n\t\t * Width of the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidth\": null,\n\t\n\t\t/**\n\t\t * Width of the column when it was first \"encountered\"\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidthOrig\": null\n\t};\n\t\n\t\n\t/*\n\t * Developer note: The properties of the object below are given in Hungarian\n\t * notation, that was used as the interface for DataTables prior to v1.10, however\n\t * from v1.10 onwards the primary interface is camel case. In order to avoid\n\t * breaking backwards compatibility utterly with this change, the Hungarian\n\t * version is still, internally the primary interface, but is is not documented\n\t * - hence the @name tags in each doc comment. This allows a Javascript function\n\t * to create a map from Hungarian notation to camel case (going the other direction\n\t * would require each property to be listed, which would at around 3K to the size\n\t * of DataTables, while this method is about a 0.5K hit.\n\t *\n\t * Ultimately this does pave the way for Hungarian notation to be dropped\n\t * completely, but that is a massive amount of work and will break current\n\t * installs (therefore is on-hold until v2).\n\t */\n\t\n\t/**\n\t * Initialisation options that can be given to DataTables at initialisation\n\t * time.\n\t *  @namespace\n\t */\n\tDataTable.defaults = {\n\t\t/**\n\t\t * An array of data to use for the table, passed in at initialisation which\n\t\t * will be used in preference to any data which is already in the DOM. This is\n\t\t * particularly useful for constructing tables purely in Javascript, for\n\t\t * example with a custom Ajax call.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.data\n\t\t *\n\t\t *  @example\n\t\t *    // Using a 2D array data source\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],\n\t\t *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\" },\n\t\t *          { \"title\": \"Browser\" },\n\t\t *          { \"title\": \"Platform\" },\n\t\t *          { \"title\": \"Version\" },\n\t\t *          { \"title\": \"Grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using an array of objects as a data source (`data`)\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 4.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  4,\n\t\t *            \"grade\":    \"X\"\n\t\t *          },\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 5.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  5,\n\t\t *            \"grade\":    \"C\"\n\t\t *          }\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\",   \"data\": \"engine\" },\n\t\t *          { \"title\": \"Browser\",  \"data\": \"browser\" },\n\t\t *          { \"title\": \"Platform\", \"data\": \"platform\" },\n\t\t *          { \"title\": \"Version\",  \"data\": \"version\" },\n\t\t *          { \"title\": \"Grade\",    \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaData\": null,\n\t\n\t\n\t\t/**\n\t\t * If ordering is enabled, then DataTables will perform a first pass sort on\n\t\t * initialisation. You can define which column(s) the sort is performed\n\t\t * upon, and the sorting direction, with this variable. The `sorting` array\n\t\t * should contain an array for each column to be sorted initially containing\n\t\t * the column's index and a direction string ('asc' or 'desc').\n\t\t *  @type array\n\t\t *  @default [[0,'asc']]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.order\n\t\t *\n\t\t *  @example\n\t\t *    // Sort by 3rd column first, and then 4th column\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": [[2,'asc'], [3,'desc']]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *    // No initial sorting\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": []\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaSorting\": [[0,'asc']],\n\t\n\t\n\t\t/**\n\t\t * This parameter is basically identical to the `sorting` parameter, but\n\t\t * cannot be overridden by user interaction with the table. What this means\n\t\t * is that you could have a column (visible or hidden) which the sorting\n\t\t * will always be forced on first - any sorting after that (from the user)\n\t\t * will then be performed as required. This can be useful for grouping rows\n\t\t * together.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.orderFixed\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderFixed\": [[0,'asc']]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\n\t\t/**\n\t\t * DataTables can be instructed to load data to display in the table from a\n\t\t * Ajax source. This option defines how that Ajax call is made and where to.\n\t\t *\n\t\t * The `ajax` property has three different modes of operation, depending on\n\t\t * how it is defined. These are:\n\t\t *\n\t\t * * `string` - Set the URL from where the data should be loaded from.\n\t\t * * `object` - Define properties for `jQuery.ajax`.\n\t\t * * `function` - Custom data get function\n\t\t *\n\t\t * `string`\n\t\t * --------\n\t\t *\n\t\t * As a string, the `ajax` property simply defines the URL from which\n\t\t * DataTables will load data.\n\t\t *\n\t\t * `object`\n\t\t * --------\n\t\t *\n\t\t * As an object, the parameters in the object are passed to\n\t\t * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control\n\t\t * of the Ajax request. DataTables has a number of default parameters which\n\t\t * you can override using this option. Please refer to the jQuery\n\t\t * documentation for a full description of the options available, although\n\t\t * the following parameters provide additional options in DataTables or\n\t\t * require special consideration:\n\t\t *\n\t\t * * `data` - As with jQuery, `data` can be provided as an object, but it\n\t\t *   can also be used as a function to manipulate the data DataTables sends\n\t\t *   to the server. The function takes a single parameter, an object of\n\t\t *   parameters with the values that DataTables has readied for sending. An\n\t\t *   object may be returned which will be merged into the DataTables\n\t\t *   defaults, or you can add the items to the object that was passed in and\n\t\t *   not return anything from the function. This supersedes `fnServerParams`\n\t\t *   from DataTables 1.9-.\n\t\t *\n\t\t * * `dataSrc` - By default DataTables will look for the property `data` (or\n\t\t *   `aaData` for compatibility with DataTables 1.9-) when obtaining data\n\t\t *   from an Ajax source or for server-side processing - this parameter\n\t\t *   allows that property to be changed. You can use Javascript dotted\n\t\t *   object notation to get a data source for multiple levels of nesting, or\n\t\t *   it my be used as a function. As a function it takes a single parameter,\n\t\t *   the JSON returned from the server, which can be manipulated as\n\t\t *   required, with the returned value being that used by DataTables as the\n\t\t *   data source for the table. This supersedes `sAjaxDataProp` from\n\t\t *   DataTables 1.9-.\n\t\t *\n\t\t * * `success` - Should not be overridden it is used internally in\n\t\t *   DataTables. To manipulate / transform the data returned by the server\n\t\t *   use `ajax.dataSrc`, or use `ajax` as a function (see below).\n\t\t *\n\t\t * `function`\n\t\t * ----------\n\t\t *\n\t\t * As a function, making the Ajax call is left up to yourself allowing\n\t\t * complete control of the Ajax request. Indeed, if desired, a method other\n\t\t * than Ajax could be used to obtain the required data, such as Web storage\n\t\t * or an AIR database.\n\t\t *\n\t\t * The function is given four parameters and no return is required. The\n\t\t * parameters are:\n\t\t *\n\t\t * 1. _object_ - Data to send to the server\n\t\t * 2. _function_ - Callback function that must be executed when the required\n\t\t *    data has been obtained. That data should be passed into the callback\n\t\t *    as the only parameter\n\t\t * 3. _object_ - DataTables settings object for the table\n\t\t *\n\t\t * Note that this supersedes `fnServerData` from DataTables 1.9-.\n\t\t *\n\t\t *  @type string|object|function\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.ajax\n\t\t *  @since 1.10.0\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax.\n\t\t *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": \"data.json\"\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to change\n\t\t *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"tableData\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to read data\n\t\t *   // from a plain array rather than an array in an object\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Manipulate the data returned from the server - add a link to data\n\t\t *   // (note this can, should, be done using `render` for the column - this\n\t\t *   // is just a simple example of how the data can be manipulated).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": function ( json ) {\n\t\t *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {\n\t\t *           json[i][0] = '<a href=\"/message/'+json[i][0]+'>View message</a>';\n\t\t *         }\n\t\t *         return json;\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Add data to the request\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"data\": function ( d ) {\n\t\t *         return {\n\t\t *           \"extra_search\": $('#extra').val()\n\t\t *         };\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Send request as POST\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"type\": \"POST\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get the data from localStorage (could interface with a form for\n\t\t *   // adding, editing and removing rows).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": function (data, callback, settings) {\n\t\t *       callback(\n\t\t *         JSON.parse( localStorage.getItem('dataTablesData') )\n\t\t *       );\n\t\t *     }\n\t\t *   } );\n\t\t */\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to readily specify the entries in the length drop\n\t\t * down menu that DataTables shows when pagination is enabled. It can be\n\t\t * either a 1D array of options which will be used for both the displayed\n\t\t * option and the value, or a 2D array which will use the array in the first\n\t\t * position as the value, and the array in the second position as the\n\t\t * displayed options (useful for language strings such as 'All').\n\t\t *\n\t\t * Note that the `pageLength` property will be automatically set to the\n\t\t * first value given in this array, unless `pageLength` is also provided.\n\t\t *  @type array\n\t\t *  @default [ 10, 25, 50, 100 ]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.lengthMenu\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthMenu\": [[10, 25, 50, -1], [10, 25, 50, \"All\"]]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aLengthMenu\": [ 10, 25, 50, 100 ],\n\t\n\t\n\t\t/**\n\t\t * The `columns` option in the initialisation parameter allows you to define\n\t\t * details about the way individual columns behave. For a full list of\n\t\t * column options that can be set, please see\n\t\t * {@link DataTable.defaults.column}. Note that if you use `columns` to\n\t\t * define your columns, you must have an entry in the array for every single\n\t\t * column that you have in your table (these can be null if you don't which\n\t\t * to specify any options).\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.column\n\t\t */\n\t\t\"aoColumns\": null,\n\t\n\t\t/**\n\t\t * Very similar to `columns`, `columnDefs` allows you to target a specific\n\t\t * column, multiple columns, or all columns, using the `targets` property of\n\t\t * each object in the array. This allows great flexibility when creating\n\t\t * tables, as the `columnDefs` arrays can be of any length, targeting the\n\t\t * columns you specifically want. `columnDefs` may use any of the column\n\t\t * options available: {@link DataTable.defaults.column}, but it _must_\n\t\t * have `targets` defined in each object in the array. Values in the `targets`\n\t\t * array may be:\n\t\t *   <ul>\n\t\t *     <li>a string - class name will be matched on the TH for the column</li>\n\t\t *     <li>0 or a positive integer - column index counting from the left</li>\n\t\t *     <li>a negative integer - column index counting from the right</li>\n\t\t *     <li>the string \"_all\" - all columns (i.e. assign a default)</li>\n\t\t *   </ul>\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.columnDefs\n\t\t */\n\t\t\"aoColumnDefs\": null,\n\t\n\t\n\t\t/**\n\t\t * Basically the same as `search`, this parameter defines the individual column\n\t\t * filtering state at initialisation time. The array must be of the same size\n\t\t * as the number of columns, and each element be an object with the parameters\n\t\t * `search` and `escapeRegex` (the latter is optional). 'null' is also\n\t\t * accepted and the default will be used.\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.searchCols\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchCols\": [\n\t\t *          null,\n\t\t *          { \"search\": \"My filter\" },\n\t\t *          null,\n\t\t *          { \"search\": \"^[0-9]\", \"escapeRegex\": false }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aoSearchCols\": [],\n\t\n\t\n\t\t/**\n\t\t * An array of CSS classes that should be applied to displayed rows. This\n\t\t * array may be of any length, and DataTables will apply each class\n\t\t * sequentially, looping when required.\n\t\t *  @type array\n\t\t *  @default null <i>Will take the values determined by the `oClasses.stripe*`\n\t\t *    options</i>\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.stripeClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stripeClasses\": [ 'strip1', 'strip2', 'strip3' ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable automatic column width calculation. This can be disabled\n\t\t * as an optimisation (it takes some time to calculate the widths) if the\n\t\t * tables widths are passed in using `columns`.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.autoWidth\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"autoWidth\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bAutoWidth\": true,\n\t\n\t\n\t\t/**\n\t\t * Deferred rendering can provide DataTables with a huge speed boost when you\n\t\t * are using an Ajax or JS data source for the table. This option, when set to\n\t\t * true, will cause DataTables to defer the creation of the table elements for\n\t\t * each row until they are needed for a draw - saving a significant amount of\n\t\t * time.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.deferRender\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajax\": \"sources/arrays.txt\",\n\t\t *        \"deferRender\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDeferRender\": false,\n\t\n\t\n\t\t/**\n\t\t * Replace a DataTable which matches the given selector and replace it with\n\t\t * one which has the properties of the new initialisation object passed. If no\n\t\t * table matches the selector, then the new DataTable will be constructed as\n\t\t * per normal.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.destroy\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"srollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      // Some time later....\n\t\t *      $('#example').dataTable( {\n\t\t *        \"filter\": false,\n\t\t *        \"destroy\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDestroy\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering of data. Filtering in DataTables is \"smart\" in\n\t\t * that it allows the end user to input multiple words (space separated) and\n\t\t * will match a row containing those words, even if not in the order that was\n\t\t * specified (this allow matching across multiple columns). Note that if you\n\t\t * wish to use filtering in DataTables this must remain 'true' - to remove the\n\t\t * default filtering input box and retain filtering abilities, please use\n\t\t * {@link DataTable.defaults.dom}.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.searching\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searching\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bFilter\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the table information display. This shows information\n\t\t * about the data that is currently visible on the page, including information\n\t\t * about filtered data if that action is being performed.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.info\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"info\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bInfo\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some\n\t\t * slightly different and additional mark-up from what DataTables has\n\t\t * traditionally used).\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.jQueryUI\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"jQueryUI\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bJQueryUI\": false,\n\t\n\t\n\t\t/**\n\t\t * Allows the end user to select the size of a formatted page from a select\n\t\t * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.lengthChange\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthChange\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bLengthChange\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable pagination.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.paging\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"paging\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bPaginate\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of a 'processing' indicator when the table is\n\t\t * being processed (e.g. a sort). This is particularly useful for tables with\n\t\t * large amounts of data where it can take a noticeable amount of time to sort\n\t\t * the entries.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.processing\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"processing\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bProcessing\": false,\n\t\n\t\n\t\t/**\n\t\t * Retrieve the DataTables object for the given selector. Note that if the\n\t\t * table has already been initialised, this parameter will cause DataTables\n\t\t * to simply return the object that has already been set up - it will not take\n\t\t * account of any changes you might have made to the initialisation object\n\t\t * passed to DataTables (setting this parameter to true is an acknowledgement\n\t\t * that you understand this). `destroy` can be used to reinitialise a table if\n\t\t * you need.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.retrieve\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      initTable();\n\t\t *      tableActions();\n\t\t *    } );\n\t\t *\n\t\t *    function initTable ()\n\t\t *    {\n\t\t *      return $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false,\n\t\t *        \"retrieve\": true\n\t\t *      } );\n\t\t *    }\n\t\t *\n\t\t *    function tableActions ()\n\t\t *    {\n\t\t *      var table = initTable();\n\t\t *      // perform API operations with oTable\n\t\t *    }\n\t\t */\n\t\t\"bRetrieve\": false,\n\t\n\t\n\t\t/**\n\t\t * When vertical (y) scrolling is enabled, DataTables will force the height of\n\t\t * the table's viewport to the given height at all times (useful for layout).\n\t\t * However, this can look odd when filtering data down to a small data set,\n\t\t * and the footer is left \"floating\" further down. This parameter (when\n\t\t * enabled) will cause DataTables to collapse the table's viewport down when\n\t\t * the result set will fit within the given Y height.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollCollapse\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200\",\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bScrollCollapse\": false,\n\t\n\t\n\t\t/**\n\t\t * Configure DataTables to use server-side processing. Note that the\n\t\t * `ajax` parameter must also be given in order to give DataTables a\n\t\t * source to obtain the required data for each draw.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverSide\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"xhr.php\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bServerSide\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable sorting of columns. Sorting of individual columns can be\n\t\t * disabled by the `sortable` option for each column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.ordering\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ordering\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSort\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or display DataTables' ability to sort multiple columns at the\n\t\t * same time (activated by shift-click by the user).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderMulti\n\t\t *\n\t\t *  @example\n\t\t *    // Disable multiple column sorting ability\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderMulti\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortMulti\": true,\n\t\n\t\n\t\t/**\n\t\t * Allows control over whether DataTables should use the top (true) unique\n\t\t * cell that is found for a single column, or the bottom (false - default).\n\t\t * This is useful when using complex headers.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderCellsTop\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderCellsTop\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortCellsTop\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the addition of the classes `sorting\\_1`, `sorting\\_2` and\n\t\t * `sorting\\_3` to the columns which are currently being sorted on. This is\n\t\t * presented as a feature switch as it can increase processing time (while\n\t\t * classes are removed and added) so for large data sets you might want to\n\t\t * turn this off.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.orderClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderClasses\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortClasses\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable state saving. When enabled HTML5 `localStorage` will be\n\t\t * used to save table display information such as pagination information,\n\t\t * display length, filtering and sorting. As such when the end user reloads\n\t\t * the page the display display will match what thy had previously set up.\n\t\t *\n\t\t * Due to the use of `localStorage` the default state saving is not supported\n\t\t * in IE6 or 7. If state saving is required in those browsers, use\n\t\t * `stateSaveCallback` to provide a storage solution such as cookies.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.stateSave\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bStateSave\": false,\n\t\n\t\n\t\t/**\n\t\t * This function is called when a TR element is created (and all TD child\n\t\t * elements have been inserted), or registered if using a DOM source, allowing\n\t\t * manipulation of the TR element (adding classes etc).\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} dataIndex The index of this row in the internal aoData array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.createdRow\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"createdRow\": function( row, data, dataIndex ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" )\n\t\t *          {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedRow\": null,\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify any aspect you want about the created DOM.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.drawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"drawCallback\": function( settings ) {\n\t\t *          alert( 'DataTables has redrawn the table' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Identical to fnHeaderCallback() but for the table footer this function\n\t\t * allows you to modify the table footer on every 'draw' event.\n\t\t *  @type function\n\t\t *  @param {node} foot \"TR\" element for the footer\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.footerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"footerCallback\": function( tfoot, data, start, end, display ) {\n\t\t *          tfoot.getElementsByTagName('th')[0].innerHTML = \"Starting index is \"+start;\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnFooterCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * When rendering large numbers in the information element for the table\n\t\t * (i.e. \"Showing 1 to 10 of 57 entries\") DataTables will render large numbers\n\t\t * to have a comma separator for the 'thousands' units (e.g. 1 million is\n\t\t * rendered as \"1,000,000\") to help readability for the end user. This\n\t\t * function will override the default method DataTables uses.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {int} toFormat number to be formatted\n\t\t *  @returns {string} formatted string for DataTables to show the number\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.formatNumber\n\t\t *\n\t\t *  @example\n\t\t *    // Format a number using a single quote for the separator (note that\n\t\t *    // this can also be done with the language.thousands option)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"formatNumber\": function ( toFormat ) {\n\t\t *          return toFormat.toString().replace(\n\t\t *            /\\B(?=(\\d{3})+(?!\\d))/g, \"'\"\n\t\t *          );\n\t\t *        };\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnFormatNumber\": function ( toFormat ) {\n\t\t\treturn toFormat.toString().replace(\n\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g,\n\t\t\t\tthis.oLanguage.sThousands\n\t\t\t);\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify the header row. This can be used to calculate and\n\t\t * display useful information about the table.\n\t\t *  @type function\n\t\t *  @param {node} head \"TR\" element for the header\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.headerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"fheaderCallback\": function( head, data, start, end, display ) {\n\t\t *          head.getElementsByTagName('th')[0].innerHTML = \"Displaying \"+(end-start)+\" records\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnHeaderCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * The information element can be used to convey information about the current\n\t\t * state of the table. Although the internationalisation options presented by\n\t\t * DataTables are quite capable of dealing with most customisations, there may\n\t\t * be times where you wish to customise the string further. This callback\n\t\t * allows you to do exactly that.\n\t\t *  @type function\n\t\t *  @param {object} oSettings DataTables settings object\n\t\t *  @param {int} start Starting position in data for the draw\n\t\t *  @param {int} end End position in data for the draw\n\t\t *  @param {int} max Total number of rows in the table (regardless of\n\t\t *    filtering)\n\t\t *  @param {int} total Total number of rows in the data set, after filtering\n\t\t *  @param {string} pre The string that DataTables has formatted using it's\n\t\t *    own rules\n\t\t *  @returns {string} The string to be displayed in the information element.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.infoCallback\n\t\t *\n\t\t *  @example\n\t\t *    $('#example').dataTable( {\n\t\t *      \"infoCallback\": function( settings, start, end, max, total, pre ) {\n\t\t *        return start +\" to \"+ end;\n\t\t *      }\n\t\t *    } );\n\t\t */\n\t\t\"fnInfoCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Called when the table has been initialised. Normally DataTables will\n\t\t * initialise sequentially and there will be no need for this function,\n\t\t * however, this does not hold true when using external language information\n\t\t * since that is obtained using an async XHR call.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} json The JSON object request from the server - only\n\t\t *    present if client-side Ajax sourced data is used\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.initComplete\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"initComplete\": function(settings, json) {\n\t\t *          alert( 'DataTables has finished its initialisation.' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnInitComplete\": null,\n\t\n\t\n\t\t/**\n\t\t * Called at the very start of each table draw and can be used to cancel the\n\t\t * draw by returning false, any other return (including undefined) results in\n\t\t * the full draw occurring).\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @returns {boolean} False will cancel the draw, anything else (including no\n\t\t *    return) will allow it to complete.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.preDrawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"preDrawCallback\": function( settings ) {\n\t\t *          if ( $('#test').val() == 1 ) {\n\t\t *            return false;\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnPreDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * This function allows you to 'post process' each row after it have been\n\t\t * generated for each table draw, but before it is rendered on screen. This\n\t\t * function might be used for setting the row class name etc.\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} displayIndex The display index for the current table draw\n\t\t *  @param {int} displayIndexFull The index of the data in the full list of\n\t\t *    rows (after filtering)\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.rowCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"rowCallback\": function( row, data, displayIndex, displayIndexFull ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" ) {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnRowCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * This parameter allows you to override the default function which obtains\n\t\t * the data from the server so something more suitable for your application.\n\t\t * For example you could use POST data, or pull information from a Gears or\n\t\t * AIR database.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {string} source HTTP source to obtain the data from (`ajax`)\n\t\t *  @param {array} data A key/value pair object containing the data to send\n\t\t *    to the server\n\t\t *  @param {function} callback to be called on completion of the data get\n\t\t *    process that will draw the data on the page.\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverData\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t *  It is often useful to send extra data to the server when making an Ajax\n\t\t * request - for example custom filtering information, and this callback\n\t\t * function makes it trivial to send extra information to the server. The\n\t\t * passed in parameter is the data set that has been constructed by\n\t\t * DataTables, and you can add to this or modify it as you require.\n\t\t *  @type function\n\t\t *  @param {array} data Data array (array of objects which are name/value\n\t\t *    pairs) that has been constructed by DataTables and will be sent to the\n\t\t *    server. In the case of Ajax sourced data with server-side processing\n\t\t *    this will be an empty array, for server-side processing there will be a\n\t\t *    significant number of parameters!\n\t\t *  @returns {undefined} Ensure that you modify the data array passed in,\n\t\t *    as this is passed by reference.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverParams\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Load the table state. With this function you can define from where, and how, the\n\t\t * state of a table is loaded. By default DataTables will load from `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} callback Callback that can be executed when done. It\n\t\t *    should be passed the loaded state object.\n\t\t *  @return {object} The DataTables state object to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadCallback\": function (settings, callback) {\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_load\",\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"success\": function (json) {\n\t\t *              callback( json );\n\t\t *            }\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadCallback\": function ( settings ) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(\n\t\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(\n\t\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the saved state prior to loading that state.\n\t\t * This callback is called when the table is loading state from the stored data, but\n\t\t * prior to the settings object being modified by the saved state. Note that for\n\t\t * plug-in authors, you should use the `stateLoadParams` event to load parameters for\n\t\t * a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that is to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never loaded\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Disallow state loading by returning false\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          return false;\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Callback that is called when the state has been loaded from the state saving method\n\t\t * and the DataTables settings object has been modified as a result of the loaded state.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that was loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoaded\n\t\t *\n\t\t *  @example\n\t\t *    // Show an alert with the filtering value that was saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoaded\": function (settings, data) {\n\t\t *          alert( 'Saved filter was: '+data.oSearch.sSearch );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoaded\": null,\n\t\n\t\n\t\t/**\n\t\t * Save the table state. This function allows you to define where and how the state\n\t\t * information for the table is stored By default DataTables will use `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveCallback\": function (settings, data) {\n\t\t *          // Send an Ajax request to the server with the state object\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_save\",\n\t\t *            \"data\": data,\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"method\": \"POST\"\n\t\t *            \"success\": function () {}\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveCallback\": function ( settings, data ) {\n\t\t\ttry {\n\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(\n\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname,\n\t\t\t\t\tJSON.stringify( data )\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the state to be saved. Called when the table\n\t\t * has changed state a new state save is required. This method allows modification of\n\t\t * the state saving object prior to actually doing the save, including addition or\n\t\t * other state properties or modification. Note that for plug-in authors, you should\n\t\t * use the `stateSaveParams` event to save parameters for a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Duration for which the saved state information is considered valid. After this period\n\t\t * has elapsed the state will be returned to the default.\n\t\t * Value is given in seconds.\n\t\t *  @type int\n\t\t *  @default 7200 <i>(2 hours)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.stateDuration\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateDuration\": 60*60*24; // 1 day\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iStateDuration\": 7200,\n\t\n\t\n\t\t/**\n\t\t * When enabled DataTables will not make a request to the server for the first\n\t\t * page draw - rather it will use the data already on the page (no sorting etc\n\t\t * will be applied to it), thus saving on an XHR at load time. `deferLoading`\n\t\t * is used to indicate that deferred loading is required, but it is also used\n\t\t * to tell DataTables how many records there are in the full table (allowing\n\t\t * the information element and pagination to be displayed correctly). In the case\n\t\t * where a filtering is applied to the table on initial load, this can be\n\t\t * indicated by giving the parameter as an array, where the first element is\n\t\t * the number of records available after filtering and the second element is the\n\t\t * number of records without filtering (allowing the table information element\n\t\t * to be shown correctly).\n\t\t *  @type int | array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.deferLoading\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records available in the table, no filtering applied\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": 57\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records after filtering, 100 without filtering (an initial filter applied)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": [ 57, 100 ],\n\t\t *        \"search\": {\n\t\t *          \"search\": \"my_filter\"\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iDeferLoading\": null,\n\t\n\t\n\t\t/**\n\t\t * Number of rows to display on a single page when using pagination. If\n\t\t * feature enabled (`lengthChange`) then the end user will be able to override\n\t\t * this to a custom setting using a pop-up menu.\n\t\t *  @type int\n\t\t *  @default 10\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pageLength\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pageLength\": 50\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayLength\": 10,\n\t\n\t\n\t\t/**\n\t\t * Define the starting point for data display when using DataTables with\n\t\t * pagination. Note that this parameter is the number of records, rather than\n\t\t * the page number, so if you have 10 records per page and want to start on\n\t\t * the third page, it should be \"20\".\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.displayStart\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"displayStart\": 20\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayStart\": 0,\n\t\n\t\n\t\t/**\n\t\t * By default DataTables allows keyboard navigation of the table (sorting, paging,\n\t\t * and filtering) by adding a `tabindex` attribute to the required elements. This\n\t\t * allows you to tab through the controls and press the enter key to activate them.\n\t\t * The tabindex is default 0, meaning that the tab follows the flow of the document.\n\t\t * You can overrule this using this parameter if you wish. Use a value of -1 to\n\t\t * disable built-in keyboard navigation.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.tabIndex\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"tabIndex\": 1\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\n\t\t/**\n\t\t * Classes that DataTables assigns to the various components and features\n\t\t * that it adds to the HTML table. This allows classes to be configured\n\t\t * during initialisation in addition to through the static\n\t\t * {@link DataTable.ext.oStdClasses} object).\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.classes\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\n\t\t/**\n\t\t * All strings that DataTables uses in the user interface that it creates\n\t\t * are defined in this object, allowing you to modified them individually or\n\t\t * completely replace them all as required.\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.language\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Strings that are used for WAI-ARIA labels and controls only (these are not\n\t\t\t * actually visible on the page, but will be read by screenreaders, and thus\n\t\t\t * must be internationalised as well).\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.aria\n\t\t\t */\n\t\t\t\"oAria\": {\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted ascending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortAscending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortAscending\": \" - click/return to sort ascending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortAscending\": \": activate to sort column ascending\",\n\t\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted descending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortDescending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortDescending\": \" - click/return to sort descending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortDescending\": \": activate to sort column descending\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * Pagination string used by DataTables for the built-in pagination\n\t\t\t * control types.\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.paginate\n\t\t\t */\n\t\t\t\"oPaginate\": {\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the first page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default First\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.first\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"first\": \"First page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sFirst\": \"First\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the last page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Last\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.last\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"last\": \"Last page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sLast\": \"Last\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'next' pagination button (to take the user to the\n\t\t\t\t * next page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Next\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.next\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"next\": \"Next page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sNext\": \"Next\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'previous' pagination button (to take the user to\n\t\t\t\t * the previous page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Previous\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.previous\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"previous\": \"Previous page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sPrevious\": \"Previous\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * This string is shown in preference to `zeroRecords` when the table is\n\t\t\t * empty of data (regardless of filtering). Note that this is an optional\n\t\t\t * parameter - if it is not given, the value of `zeroRecords` will be used\n\t\t\t * instead (either the default or given value).\n\t\t\t *  @type string\n\t\t\t *  @default No data available in table\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.emptyTable\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"emptyTable\": \"No data available in table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sEmptyTable\": \"No data available in table\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This string gives information to the end user about the information\n\t\t\t * that is current on display on the page. The following tokens can be\n\t\t\t * used in the string and will be dynamically replaced as the table\n\t\t\t * display updates. This tokens can be placed anywhere in the string, or\n\t\t\t * removed as needed by the language requires:\n\t\t\t *\n\t\t\t * * `\\_START\\_` - Display index of the first record on the current page\n\t\t\t * * `\\_END\\_` - Display index of the last record on the current page\n\t\t\t * * `\\_TOTAL\\_` - Number of records in the table after filtering\n\t\t\t * * `\\_MAX\\_` - Number of records in the table without filtering\n\t\t\t * * `\\_PAGE\\_` - Current page number\n\t\t\t * * `\\_PAGES\\_` - Total number of pages of data in the table\n\t\t\t *\n\t\t\t *  @type string\n\t\t\t *  @default Showing _START_ to _END_ of _TOTAL_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.info\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"info\": \"Showing page _PAGE_ of _PAGES_\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfo\": \"Showing _START_ to _END_ of _TOTAL_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Display information string for when the table is empty. Typically the\n\t\t\t * format of this string should match `info`.\n\t\t\t *  @type string\n\t\t\t *  @default Showing 0 to 0 of 0 entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoEmpty\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoEmpty\": \"No entries to show\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoEmpty\": \"Showing 0 to 0 of 0 entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When a user filters the information in a table, this string is appended\n\t\t\t * to the information (`info`) to give an idea of how strong the filtering\n\t\t\t * is. The variable _MAX_ is dynamically updated.\n\t\t\t *  @type string\n\t\t\t *  @default (filtered from _MAX_ total entries)\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoFiltered\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoFiltered\": \" - filtering from _MAX_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoFiltered\": \"(filtered from _MAX_ total entries)\",\n\t\n\t\n\t\t\t/**\n\t\t\t * If can be useful to append extra information to the info string at times,\n\t\t\t * and this variable does exactly that. This information will be appended to\n\t\t\t * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are\n\t\t\t * being used) at all times.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoPostFix\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoPostFix\": \"All records shown are derived from real information.\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoPostFix\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This decimal place operator is a little different from the other\n\t\t\t * language options since DataTables doesn't output floating point\n\t\t\t * numbers, so it won't ever use this for display of a number. Rather,\n\t\t\t * what this parameter does is modify the sort methods of the table so\n\t\t\t * that numbers which are in a format which has a character other than\n\t\t\t * a period (`.`) as a decimal place will be sorted numerically.\n\t\t\t *\n\t\t\t * Note that numbers with different decimal places cannot be shown in\n\t\t\t * the same table and still be sortable, the table must be consistent.\n\t\t\t * However, multiple different tables on the page can use different\n\t\t\t * decimal place characters.\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.decimal\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"decimal\": \",\"\n\t\t\t *          \"thousands\": \".\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sDecimal\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * DataTables has a build in number formatter (`formatNumber`) which is\n\t\t\t * used to format large numbers that are used in the table information.\n\t\t\t * By default a comma is used, but this can be trivially changed to any\n\t\t\t * character you wish with this parameter.\n\t\t\t *  @type string\n\t\t\t *  @default ,\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.thousands\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"thousands\": \"'\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sThousands\": \",\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Detail the action that will be taken when the drop down menu for the\n\t\t\t * pagination length option is changed. The '_MENU_' variable is replaced\n\t\t\t * with a default select list of 10, 25, 50 and 100, and can be replaced\n\t\t\t * with a custom select box if required.\n\t\t\t *  @type string\n\t\t\t *  @default Show _MENU_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.lengthMenu\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language change only\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": \"Display _MENU_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language and options change\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": 'Display <select>'+\n\t\t\t *            '<option value=\"10\">10</option>'+\n\t\t\t *            '<option value=\"20\">20</option>'+\n\t\t\t *            '<option value=\"30\">30</option>'+\n\t\t\t *            '<option value=\"40\">40</option>'+\n\t\t\t *            '<option value=\"50\">50</option>'+\n\t\t\t *            '<option value=\"-1\">All</option>'+\n\t\t\t *            '</select> records'\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLengthMenu\": \"Show _MENU_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When using Ajax sourced data and during the first draw when DataTables is\n\t\t\t * gathering the data, this message is shown in an empty row in the table to\n\t\t\t * indicate to the end user the the data is being loaded. Note that this\n\t\t\t * parameter is not used when loading data by server-side processing, just\n\t\t\t * Ajax sourced data with client-side processing.\n\t\t\t *  @type string\n\t\t\t *  @default Loading...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.loadingRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"loadingRecords\": \"Please wait - loading...\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLoadingRecords\": \"Loading...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text which is displayed when the table is processing a user action\n\t\t\t * (usually a sort command or similar).\n\t\t\t *  @type string\n\t\t\t *  @default Processing...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.processing\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"processing\": \"DataTables is currently busy\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sProcessing\": \"Processing...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Details the actions that will be taken when the user types into the\n\t\t\t * filtering input text box. The variable \"_INPUT_\", if used in the string,\n\t\t\t * is replaced with the HTML text box for the filtering input allowing\n\t\t\t * control over where it appears in the string. If \"_INPUT_\" is not given\n\t\t\t * then the input box is appended to the string automatically.\n\t\t\t *  @type string\n\t\t\t *  @default Search:\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.search\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Input text box will be appended at the end automatically\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Filter records:\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Specify where the filter should appear\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Apply filter _INPUT_ to table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sSearch\": \"Search:\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Assign a `placeholder` attribute to the search `input` element\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.searchPlaceholder\n\t\t\t */\n\t\t\t\"sSearchPlaceholder\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * All of the language information can be stored in a file on the\n\t\t\t * server-side, which DataTables will look up if this parameter is passed.\n\t\t\t * It must store the URL of the language file, which is in a JSON format,\n\t\t\t * and the object has the same properties as the oLanguage object in the\n\t\t\t * initialiser object (i.e. the above parameters). Please refer to one of\n\t\t\t * the example language files to see how this works in action.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string - i.e. disabled</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.url\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"url\": \"http://www.sprymedia.co.uk/dataTables/lang.txt\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sUrl\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text shown inside the table records when the is no information to be\n\t\t\t * displayed after filtering. `emptyTable` is shown when there is simply no\n\t\t\t * information in the table at all (regardless of filtering).\n\t\t\t *  @type string\n\t\t\t *  @default No matching records found\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.zeroRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"zeroRecords\": \"No records to display\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sZeroRecords\": \"No matching records found\"\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to have define the global filtering state at\n\t\t * initialisation time. As an object the `search` parameter must be\n\t\t * defined, but all other parameters are optional. When `regex` is true,\n\t\t * the search string will be treated as a regular expression, when false\n\t\t * (default) it will be treated as a straight string. When `smart`\n\t\t * DataTables will use it's smart filtering methods (to word match at\n\t\t * any point in the data), when false this will not be done.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.search\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"search\": {\"search\": \"Initial search\"}\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"oSearch\": $.extend( {}, DataTable.models.oSearch ),\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * By default DataTables will look for the property `data` (or `aaData` for\n\t\t * compatibility with DataTables 1.9-) when obtaining data from an Ajax\n\t\t * source or for server-side processing - this parameter allows that\n\t\t * property to be changed. You can use Javascript dotted object notation to\n\t\t * get a data source for multiple levels of nesting.\n\t\t *  @type string\n\t\t *  @default data\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxDataProp\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxDataProp\": \"data\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * You can instruct DataTables to load data from an external\n\t\t * source using this parameter (use aData if you want to pass data in you\n\t\t * already have). Simply provide a url a JSON object can be obtained from.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxSource\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\n\t\t/**\n\t\t * This initialisation variable allows you to specify exactly where in the\n\t\t * DOM you want DataTables to inject the various controls it adds to the page\n\t\t * (for example you might want the pagination controls at the top of the\n\t\t * table). DIV elements (with or without a custom class) can also be added to\n\t\t * aid styling. The follow syntax is used:\n\t\t *   <ul>\n\t\t *     <li>The following options are allowed:\n\t\t *       <ul>\n\t\t *         <li>'l' - Length changing</li>\n\t\t *         <li>'f' - Filtering input</li>\n\t\t *         <li>'t' - The table!</li>\n\t\t *         <li>'i' - Information</li>\n\t\t *         <li>'p' - Pagination</li>\n\t\t *         <li>'r' - pRocessing</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following constants are allowed:\n\t\t *       <ul>\n\t\t *         <li>'H' - jQueryUI theme \"header\" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>\n\t\t *         <li>'F' - jQueryUI theme \"footer\" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following syntax is expected:\n\t\t *       <ul>\n\t\t *         <li>'&lt;' and '&gt;' - div elements</li>\n\t\t *         <li>'&lt;\"class\" and '&gt;' - div with a class</li>\n\t\t *         <li>'&lt;\"#id\" and '&gt;' - div with an ID</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>Examples:\n\t\t *       <ul>\n\t\t *         <li>'&lt;\"wrapper\"flipt&gt;'</li>\n\t\t *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *   </ul>\n\t\t *  @type string\n\t\t *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>\n\t\t *    <\"H\"lfr>t<\"F\"ip> <i>(when `jQueryUI` is true)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.dom\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"dom\": '&lt;\"top\"i&gt;rt&lt;\"bottom\"flp&gt;&lt;\"clear\"&gt;'\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDom\": \"lfrtip\",\n\t\n\t\n\t\t/**\n\t\t * Search delay option. This will throttle full table searches that use the\n\t\t * DataTables provided search input element (it does not effect calls to\n\t\t * `dt-api search()`, providing a delay before the search is made.\n\t\t *  @type integer\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.searchDelay\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchDelay\": 200\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\n\t\t/**\n\t\t * DataTables features six different built-in options for the buttons to\n\t\t * display for pagination control:\n\t\t *\n\t\t * * `numbers` - Page number buttons only\n\t\t * * `simple` - 'Previous' and 'Next' buttons only\n\t\t * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers\n\t\t * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons\n\t\t * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers\n\t\t * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers\n\t\t *  \n\t\t * Further methods can be added using {@link DataTable.ext.oPagination}.\n\t\t *  @type string\n\t\t *  @default simple_numbers\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pagingType\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pagingType\": \"full_numbers\"\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"sPaginationType\": \"simple_numbers\",\n\t\n\t\n\t\t/**\n\t\t * Enable horizontal scrolling. When a table is too wide to fit into a\n\t\t * certain layout, or you have a large number of columns in the table, you\n\t\t * can enable x-scrolling to show the table in a viewport, which can be\n\t\t * scrolled. This property can be `true` which will allow the table to\n\t\t * scroll horizontally when needed, or any CSS unit, or a number (in which\n\t\t * case it will be treated as a pixel measurement). Setting as simply `true`\n\t\t * is recommended.\n\t\t *  @type boolean|string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollX\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": true,\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollX\": \"\",\n\t\n\t\n\t\t/**\n\t\t * This property can be used to force a DataTable to use more width than it\n\t\t * might otherwise do when x-scrolling is enabled. For example if you have a\n\t\t * table which requires to be well spaced, this parameter is useful for\n\t\t * \"over-sizing\" the table, and thus forcing scrolling. This property can by\n\t\t * any CSS unit, or a number (in which case it will be treated as a pixel\n\t\t * measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollXInner\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": \"100%\",\n\t\t *        \"scrollXInner\": \"110%\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollXInner\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Enable vertical scrolling. Vertical scrolling will constrain the DataTable\n\t\t * to the given height, and enable scrolling for any data which overflows the\n\t\t * current viewport. This can be used as an alternative to paging to display\n\t\t * a lot of data in a small area (although paging and scrolling can both be\n\t\t * enabled at the same time). This property can be any CSS unit, or a number\n\t\t * (in which case it will be treated as a pixel measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollY\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollY\": \"\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * Set the HTTP method that is used to make the Ajax call for server-side\n\t\t * processing or Ajax sourced data.\n\t\t *  @type string\n\t\t *  @default GET\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverMethod\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sServerMethod\": \"GET\",\n\t\n\t\n\t\t/**\n\t\t * DataTables makes use of renderers when displaying HTML elements for\n\t\t * a table. These renderers can be added or modified by plug-ins to\n\t\t * generate suitable mark-up for a site. For example the Bootstrap\n\t\t * integration plug-in for DataTables uses a paging button renderer to\n\t\t * display pagination buttons in the mark-up required by Bootstrap.\n\t\t *\n\t\t * For further information about the renderers available see\n\t\t * DataTable.ext.renderer\n\t\t *  @type string|object\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.renderer\n\t\t *\n\t\t */\n\t\t\"renderer\": null,\n\t\n\t\n\t\t/**\n\t\t * Set the data property name that DataTables should use to get a row's id\n\t\t * to set as the `id` property in the node.\n\t\t *  @type string\n\t\t *  @default DT_RowId\n\t\t *\n\t\t *  @name DataTable.defaults.rowId\n\t\t */\n\t\t\"rowId\": \"DT_RowId\"\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults );\n\t\n\t\n\t\n\t/*\n\t * Developer note - See note in model.defaults.js about the use of Hungarian\n\t * notation and camel case.\n\t */\n\t\n\t/**\n\t * Column options that can be given to DataTables at initialisation time.\n\t *  @namespace\n\t */\n\tDataTable.defaults.column = {\n\t\t/**\n\t\t * Define which column(s) an order will occur on for this column. This\n\t\t * allows a column's ordering to take multiple columns into account when\n\t\t * doing a sort or use the data from a different column. For example first\n\t\t * name / last name columns make sense to do a multi-column sort over the\n\t\t * two columns.\n\t\t *  @type array|int\n\t\t *  @default null <i>Takes the value of the column index automatically</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderData\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderData\": [ 0, 1 ], \"targets\": [ 0 ] },\n\t\t *          { \"orderData\": [ 1, 0 ], \"targets\": [ 1 ] },\n\t\t *          { \"orderData\": 2, \"targets\": [ 2 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderData\": [ 0, 1 ] },\n\t\t *          { \"orderData\": [ 1, 0 ] },\n\t\t *          { \"orderData\": 2 },\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aDataSort\": null,\n\t\t\"iDataSort\": -1,\n\t\n\t\n\t\t/**\n\t\t * You can control the default ordering direction, and even alter the\n\t\t * behaviour of the sort handler (i.e. only allow ascending ordering etc)\n\t\t * using this parameter.\n\t\t *  @type array\n\t\t *  @default [ 'asc', 'desc' ]\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderSequence\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderSequence\": [ \"asc\" ], \"targets\": [ 1 ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ], \"targets\": [ 2 ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ], \"targets\": [ 3 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          { \"orderSequence\": [ \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ] },\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"asSorting\": [ 'asc', 'desc' ],\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering on the data in this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.searchable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"searchable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"searchable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSearchable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable ordering on this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.visible\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"visible\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"visible\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bVisible\": true,\n\t\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} td The TD node that has been created\n\t\t *  @param {*} cellData The Data for the cell\n\t\t *  @param {array|object} rowData The data for the whole row\n\t\t *  @param {int} row The row index for the aoData data store\n\t\t *  @param {int} col The column index for aoColumns\n\t\t *\n\t\t *  @name DataTable.defaults.column.createdCell\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [3],\n\t\t *          \"createdCell\": function (td, cellData, rowData, row, col) {\n\t\t *            if ( cellData == \"1.7\" ) {\n\t\t *              $(td).css('color', 'blue')\n\t\t *            }\n\t\t *          }\n\t\t *        } ]\n\t\t *      });\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter has been replaced by `data` in DataTables to ensure naming\n\t\t * consistency. `dataProp` can still be used, as there is backwards\n\t\t * compatibility in DataTables for this option, but it is strongly\n\t\t * recommended that you use `data` in preference to `dataProp`.\n\t\t *  @name DataTable.defaults.column.dataProp\n\t\t */\n\t\n\t\n\t\t/**\n\t\t * This property can be used to read data from any data source property,\n\t\t * including deeply nested objects / properties. `data` can be given in a\n\t\t * number of different ways which effect its behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object. Note that\n\t\t *      function notation is recommended for use in `render` rather than\n\t\t *      `data` as it is much simpler to use as a renderer.\n\t\t * * `null` - use the original data source for the row rather than plucking\n\t\t *   data directly from it. This action has effects on two other\n\t\t *   initialisation options:\n\t\t *    * `defaultContent` - When null is given as the `data` option and\n\t\t *      `defaultContent` is specified for the column, the value defined by\n\t\t *      `defaultContent` will be used for the cell.\n\t\t *    * `render` - When null is used for the `data` option and the `render`\n\t\t *      option is specified for the column, the whole data source for the\n\t\t *      row is used for the renderer.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * `{array|object}` The data source for the row\n\t\t *      * `{string}` The type call data requested - this will be 'set' when\n\t\t *        setting data or 'filter', 'display', 'type', 'sort' or undefined\n\t\t *        when gathering data. Note that when `undefined` is given for the\n\t\t *        type DataTables expects to get the raw data for the object back<\n\t\t *      * `{*}` Data to set when the second parameter is 'set'.\n\t\t *    * Return:\n\t\t *      * The return value from the function is not required when 'set' is\n\t\t *        the type of call, but otherwise the return is what will be used\n\t\t *        for the data requested.\n\t\t *\n\t\t * Note that `data` is a getter and setter option. If you just require\n\t\t * formatting of data for output, you will likely want to use `render` which\n\t\t * is simply a getter and thus simpler to use.\n\t\t *\n\t\t * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The\n\t\t * name change reflects the flexibility of this property and is consistent\n\t\t * with the naming of mRender. If 'mDataProp' is given, then it will still\n\t\t * be used by DataTables, as it automatically maps the old name to the new\n\t\t * if required.\n\t\t *\n\t\t *  @type string|int|function|null\n\t\t *  @default null <i>Use automatically calculated column index</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.data\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Read table data from objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {value},\n\t\t *    //      \"version\": {value},\n\t\t *    //      \"grade\": {value}\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/objects.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform\" },\n\t\t *          { \"data\": \"version\" },\n\t\t *          { \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Read information from deeply nested objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {\n\t\t *    //         \"inner\": {value}\n\t\t *    //      },\n\t\t *    //      \"details\": [\n\t\t *    //         {value}, {value}\n\t\t *    //      ]\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform.inner\" },\n\t\t *          { \"data\": \"platform.details.0\" },\n\t\t *          { \"data\": \"platform.details.1\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `data` as a function to provide different information for\n\t\t *    // sorting, filtering and display. In this case, currency (price)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": function ( source, type, val ) {\n\t\t *            if (type === 'set') {\n\t\t *              source.price = val;\n\t\t *              // Store the computed dislay and filter values for efficiency\n\t\t *              source.price_display = val==\"\" ? \"\" : \"$\"+numberFormat(val);\n\t\t *              source.price_filter  = val==\"\" ? \"\" : \"$\"+numberFormat(val)+\" \"+val;\n\t\t *              return;\n\t\t *            }\n\t\t *            else if (type === 'display') {\n\t\t *              return source.price_display;\n\t\t *            }\n\t\t *            else if (type === 'filter') {\n\t\t *              return source.price_filter;\n\t\t *            }\n\t\t *            // 'sort', 'type' and undefined all just use the integer\n\t\t *            return source.price;\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using default content\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null,\n\t\t *          \"defaultContent\": \"Click to edit\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using array notation - outputting a list from an array\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"name[, ]\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\n\t\t/**\n\t\t * This property is the rendering partner to `data` and it is suggested that\n\t\t * when you want to manipulate data for display (including filtering,\n\t\t * sorting etc) without altering the underlying data for the table, use this\n\t\t * property. `render` can be considered to be the the read only companion to\n\t\t * `data` which is read / write (then as such more complex). Like `data`\n\t\t * this option can be given in a number of different ways to effect its\n\t\t * behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object.\n\t\t * * `object` - use different data for the different data types requested by\n\t\t *   DataTables ('filter', 'display', 'type' or 'sort'). The property names\n\t\t *   of the object is the data type the property refers to and the value can\n\t\t *   defined using an integer, string or function using the same rules as\n\t\t *   `render` normally does. Note that an `_` option _must_ be specified.\n\t\t *   This is the default value to use if you haven't specified a value for\n\t\t *   the data type requested by DataTables.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * {array|object} The data source for the row (based on `data`)\n\t\t *      * {string} The type call data requested - this will be 'filter',\n\t\t *        'display', 'type' or 'sort'.\n\t\t *      * {array|object} The full data source for the row (not based on\n\t\t *        `data`)\n\t\t *    * Return:\n\t\t *      * The return value from the function is what will be used for the\n\t\t *        data requested.\n\t\t *\n\t\t *  @type string|int|function|object|null\n\t\t *  @default null Use the data source value.\n\t\t *\n\t\t *  @name DataTable.defaults.column.render\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Create a comma separated list from an array of objects\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          {\n\t\t *            \"data\": \"platform\",\n\t\t *            \"render\": \"[, ].name\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Execute a function to obtain data\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": \"browserName()\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // As an object, extracting different data for the different types\n\t\t *    // This would be used with a data source such as:\n\t\t *    //   { \"phone\": 5552368, \"phone_filter\": \"5552368 555-2368\", \"phone_display\": \"555-2368\" }\n\t\t *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`\n\t\t *    // (which has both forms) is used for filtering for if a user inputs either format, while\n\t\t *    // the formatted phone number is the one that is shown in the table.\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": {\n\t\t *            \"_\": \"phone\",\n\t\t *            \"filter\": \"phone_filter\",\n\t\t *            \"display\": \"phone_display\"\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Use as a function to create a link from the data source\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"download_link\",\n\t\t *          \"render\": function ( data, type, full ) {\n\t\t *            return '<a href=\"'+data+'\">Download</a>';\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\n\t\t/**\n\t\t * Change the cell type created for the column - either TD cells or TH cells. This\n\t\t * can be useful as TH cells have semantic meaning in the table body, allowing them\n\t\t * to act as a header for a row (you may wish to add scope='row' to the TH elements).\n\t\t *  @type string\n\t\t *  @default td\n\t\t *\n\t\t *  @name DataTable.defaults.column.cellType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Make the first column use TH cells\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"cellType\": \"th\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sCellType\": \"td\",\n\t\n\t\n\t\t/**\n\t\t * Class to give to each cell in this column.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.class\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"class\": \"my_class\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"class\": \"my_class\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sClass\": \"\",\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t * Generally you shouldn't need this!\n\t\t *  @type string\n\t\t *  @default <i>Empty string<i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.contentPadding\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"contentPadding\": \"mmm\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sContentPadding\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because `data`\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.column.defaultContent\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\",\n\t\t *            \"targets\": [ -1 ]\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter is only used in DataTables' server-side processing. It can\n\t\t * be exceptionally useful to know what columns are being displayed on the\n\t\t * client side, and to map these to database fields. When defined, the names\n\t\t * also allow DataTables to reorder information from the server if it comes\n\t\t * back in an unexpected order (i.e. if you switch your columns around on the\n\t\t * client-side, your server-side code does not also need updating).\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.name\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"name\": \"engine\", \"targets\": [ 0 ] },\n\t\t *          { \"name\": \"browser\", \"targets\": [ 1 ] },\n\t\t *          { \"name\": \"platform\", \"targets\": [ 2 ] },\n\t\t *          { \"name\": \"version\", \"targets\": [ 3 ] },\n\t\t *          { \"name\": \"grade\", \"targets\": [ 4 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"name\": \"engine\" },\n\t\t *          { \"name\": \"browser\" },\n\t\t *          { \"name\": \"platform\" },\n\t\t *          { \"name\": \"version\" },\n\t\t *          { \"name\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sName\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Defines a data source type for the ordering which can be used to read\n\t\t * real-time information from the table (updating the internally cached\n\t\t * version) prior to ordering. This allows ordering to occur on user\n\t\t * editable elements such as form inputs.\n\t\t *  @type string\n\t\t *  @default std\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderDataType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderDataType\": \"dom-text\", \"targets\": [ 2, 3 ] },\n\t\t *          { \"type\": \"numeric\", \"targets\": [ 3 ] },\n\t\t *          { \"orderDataType\": \"dom-select\", \"targets\": [ 4 ] },\n\t\t *          { \"orderDataType\": \"dom-checkbox\", \"targets\": [ 5 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          { \"orderDataType\": \"dom-text\" },\n\t\t *          { \"orderDataType\": \"dom-text\", \"type\": \"numeric\" },\n\t\t *          { \"orderDataType\": \"dom-select\" },\n\t\t *          { \"orderDataType\": \"dom-checkbox\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sSortDataType\": \"std\",\n\t\n\t\n\t\t/**\n\t\t * The title of this column.\n\t\t *  @type string\n\t\t *  @default null <i>Derived from the 'TH' value for this column in the\n\t\t *    original HTML table.</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.title\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"title\": \"My column title\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"My column title\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\n\t\t/**\n\t\t * The type allows you to specify how the data for this column will be\n\t\t * ordered. Four types (string, numeric, date and html (which will strip\n\t\t * HTML tags before ordering)) are currently available. Note that only date\n\t\t * formats understood by Javascript's Date() object will be accepted as type\n\t\t * date. For example: \"Mar 26, 2008 5:03 PM\". May take the values: 'string',\n\t\t * 'numeric', 'date' or 'html' (by default). Further types can be adding\n\t\t * through plug-ins.\n\t\t *  @type string\n\t\t *  @default null <i>Auto-detected from raw data</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.type\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"type\": \"html\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"type\": \"html\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\n\t\t/**\n\t\t * Defining the width of the column, this parameter may take any CSS value\n\t\t * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not\n\t\t * been given a specific width through this interface ensuring that the table\n\t\t * remains readable.\n\t\t *  @type string\n\t\t *  @default null <i>Automatic</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.width\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"width\": \"20%\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"width\": \"20%\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sWidth\": null\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults.column );\n\t\n\t\n\t\n\t/**\n\t * DataTables settings object - this holds all the information needed for a\n\t * given table, including configuration, data and current application of the\n\t * table options. DataTables does not have a single instance for each DataTable\n\t * with the settings attached to that instance, but rather instances of the\n\t * DataTable \"class\" are created on-the-fly as needed (typically by a\n\t * $().dataTable() call) and the settings object is then applied to that\n\t * instance.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults} but this\n\t * one is the internal data store for DataTables's cache of columns. It should\n\t * NOT be manipulated outside of DataTables. Any configuration should be done\n\t * through the initialisation options.\n\t *  @namespace\n\t *  @todo Really should attach the settings object to individual instances so we\n\t *    don't need to create new instances on each $().dataTable() call (if the\n\t *    table already exists). It would also save passing oSettings around and\n\t *    into every single function. However, this is a very significant\n\t *    architecture change for DataTables and will almost certainly break\n\t *    backwards compatibility with older installations. This is something that\n\t *    will be done in 2.0.\n\t */\n\tDataTable.models.oSettings = {\n\t\t/**\n\t\t * Primary features of DataTables and their enablement state.\n\t\t *  @namespace\n\t\t */\n\t\t\"oFeatures\": {\n\t\n\t\t\t/**\n\t\t\t * Flag to say if DataTables should automatically try to calculate the\n\t\t\t * optimum table and columns widths (true) or not (false).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bAutoWidth\": null,\n\t\n\t\t\t/**\n\t\t\t * Delay the creation of TR and TD elements until they are actually\n\t\t\t * needed by a driven page draw. This can give a significant speed\n\t\t\t * increase for Ajax source and Javascript source data, but makes no\n\t\t\t * difference at all fro DOM and server-side processing tables.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bDeferRender\": null,\n\t\n\t\t\t/**\n\t\t\t * Enable filtering on the table or not. Note that if this is disabled\n\t\t\t * then there is no filtering at all on the table, including fnFilter.\n\t\t\t * To just remove the filtering input use sDom and remove the 'f' option.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bFilter\": null,\n\t\n\t\t\t/**\n\t\t\t * Table information element (the 'Showing x of y records' div) enable\n\t\t\t * flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bInfo\": null,\n\t\n\t\t\t/**\n\t\t\t * Present a user control allowing the end user to change the page size\n\t\t\t * when pagination is enabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bLengthChange\": null,\n\t\n\t\t\t/**\n\t\t\t * Pagination enabled or not. Note that if this is disabled then length\n\t\t\t * changing must also be disabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bPaginate\": null,\n\t\n\t\t\t/**\n\t\t\t * Processing indicator enable flag whenever DataTables is enacting a\n\t\t\t * user request - typically an Ajax request for server-side processing.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bProcessing\": null,\n\t\n\t\t\t/**\n\t\t\t * Server-side processing enabled flag - when enabled DataTables will\n\t\t\t * get all data from the server for every draw - there is no filtering,\n\t\t\t * sorting or paging done on the client-side.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bServerSide\": null,\n\t\n\t\t\t/**\n\t\t\t * Sorting enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSort\": null,\n\t\n\t\t\t/**\n\t\t\t * Multi-column sorting\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortMulti\": null,\n\t\n\t\t\t/**\n\t\t\t * Apply a class to the columns which are being sorted to provide a\n\t\t\t * visual highlight or not. This can slow things down when enabled since\n\t\t\t * there is a lot of DOM interaction.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortClasses\": null,\n\t\n\t\t\t/**\n\t\t\t * State saving enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bStateSave\": null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Scrolling settings for a table.\n\t\t *  @namespace\n\t\t */\n\t\t\"oScroll\": {\n\t\t\t/**\n\t\t\t * When the table is shorter in height than sScrollY, collapse the\n\t\t\t * table container down to the height of the table (when true).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bCollapse\": null,\n\t\n\t\t\t/**\n\t\t\t * Width of the scrollbar for the web-browser's platform. Calculated\n\t\t\t * during table initialisation.\n\t\t\t *  @type int\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"iBarWidth\": 0,\n\t\n\t\t\t/**\n\t\t\t * Viewport width for horizontal scrolling. Horizontal scrolling is\n\t\t\t * disabled if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sX\": null,\n\t\n\t\t\t/**\n\t\t\t * Width to expand the table to when using x-scrolling. Typically you\n\t\t\t * should not need to use this.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t *  @deprecated\n\t\t\t */\n\t\t\t\"sXInner\": null,\n\t\n\t\t\t/**\n\t\t\t * Viewport height for vertical scrolling. Vertical scrolling is disabled\n\t\t\t * if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sY\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Language information for the table.\n\t\t *  @namespace\n\t\t *  @extends DataTable.defaults.oLanguage\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Information callback function. See\n\t\t\t * {@link DataTable.defaults.fnInfoCallback}\n\t\t\t *  @type function\n\t\t\t *  @default null\n\t\t\t */\n\t\t\t\"fnInfoCallback\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Browser support parameters\n\t\t *  @namespace\n\t\t */\n\t\t\"oBrowser\": {\n\t\t\t/**\n\t\t\t * Indicate if the browser incorrectly calculates width:100% inside a\n\t\t\t * scrolling element (IE6/7)\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollOversize\": false,\n\t\n\t\t\t/**\n\t\t\t * Determine if the vertical scrollbar is on the right or left of the\n\t\t\t * scrolling container - needed for rtl language layout, although not\n\t\t\t * all browsers move the scrollbar (Safari).\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollbarLeft\": false,\n\t\n\t\t\t/**\n\t\t\t * Flag for if `getBoundingClientRect` is fully supported or not\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bBounding\": false,\n\t\n\t\t\t/**\n\t\t\t * Browser scrollbar width\n\t\t\t *  @type integer\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"barWidth\": 0\n\t\t},\n\t\n\t\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * Array referencing the nodes which are used for the features. The\n\t\t * parameters of this object match what is allowed by sDom - i.e.\n\t\t *   <ul>\n\t\t *     <li>'l' - Length changing</li>\n\t\t *     <li>'f' - Filtering input</li>\n\t\t *     <li>'t' - The table!</li>\n\t\t *     <li>'i' - Information</li>\n\t\t *     <li>'p' - Pagination</li>\n\t\t *     <li>'r' - pRocessing</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aanFeatures\": [],\n\t\n\t\t/**\n\t\t * Store data information - see {@link DataTable.models.oRow} for detailed\n\t\t * information.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoData\": [],\n\t\n\t\t/**\n\t\t * Array of indexes which are in the current display (after filtering etc)\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplay\": [],\n\t\n\t\t/**\n\t\t * Array of indexes for display - no filtering\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplayMaster\": [],\n\t\n\t\t/**\n\t\t * Map of row ids to data indexes\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"aIds\": {},\n\t\n\t\t/**\n\t\t * Store information about each column that is in use\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoColumns\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's header\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeader\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's footer\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooter\": [],\n\t\n\t\t/**\n\t\t * Store the applied global search information in case we want to force a\n\t\t * research or compare the old search to a new one.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t */\n\t\t\"oPreviousSearch\": {},\n\t\n\t\t/**\n\t\t * Store the applied search for each column - see\n\t\t * {@link DataTable.models.oSearch} for the format that is used for the\n\t\t * filtering information for each column.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreSearchCols\": [],\n\t\n\t\t/**\n\t\t * Sorting that is applied to the table. Note that the inner arrays are\n\t\t * used in the following manner:\n\t\t * <ul>\n\t\t *   <li>Index 0 - column number</li>\n\t\t *   <li>Index 1 - current sorting direction</li>\n\t\t * </ul>\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @todo These inner arrays should really be objects\n\t\t */\n\t\t\"aaSorting\": null,\n\t\n\t\t/**\n\t\t * Sorting that is always applied to the table (i.e. prefixed in front of\n\t\t * aaSorting).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\t/**\n\t\t * Classes to use for the striping of a table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its striping classes as well\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asDestroyStripes\": [],\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its width\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"sDestroyWidth\": 0,\n\t\n\t\t/**\n\t\t * Callback functions array for every time a row is inserted (i.e. on a draw).\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for the header on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeaderCallback\": [],\n\t\n\t\t/**\n\t\t * Callback function for the footer on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooterCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for draw callback functions\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for row created function\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCreatedCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for just before the table is redrawn. A return of\n\t\t * false will be used to cancel the draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for when the table has been initialised.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoInitComplete\": [],\n\t\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings to be stored for state saving, prior to\n\t\t * saving state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSaveParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings that have been stored for state saving\n\t\t * prior to using the stored values to restore the state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoadParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for operating on the settings object once the saved state has been\n\t\t * loaded\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoaded\": [],\n\t\n\t\t/**\n\t\t * Cache the table ID for quick access\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sTableId\": \"\",\n\t\n\t\t/**\n\t\t * The TABLE node for the main table\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTable\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the thead element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTHead\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tfoot element - if it exists\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTFoot\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tbody element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTBody\": null,\n\t\n\t\t/**\n\t\t * Cache the wrapper node (contains all DataTables controlled elements)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTableWrapper\": null,\n\t\n\t\t/**\n\t\t * Indicate if when using server-side processing the loading of data\n\t\t * should be deferred until the second draw.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDeferLoading\": false,\n\t\n\t\t/**\n\t\t * Indicate if all required information has been read in\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bInitialised\": false,\n\t\n\t\t/**\n\t\t * Information about open rows. Each object in the array has the parameters\n\t\t * 'nTr' and 'nParent'\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoOpenRows\": [],\n\t\n\t\t/**\n\t\t * Dictate the positioning of DataTables' control elements - see\n\t\t * {@link DataTable.model.oInit.sDom}.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDom\": null,\n\t\n\t\t/**\n\t\t * Search delay (in mS)\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\t/**\n\t\t * Which type of pagination should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default two_button\n\t\t */\n\t\t\"sPaginationType\": \"two_button\",\n\t\n\t\t/**\n\t\t * The state duration (for `stateSave`) in seconds.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iStateDuration\": 0,\n\t\n\t\t/**\n\t\t * Array of callback functions for state saving. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the JSON string to save that has been thus far created. Returns\n\t\t *       a JSON string to be inserted into a json object\n\t\t *       (i.e. '\"param\": [ 0, 1, 2]')</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSave\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for state loading. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the object stored. May return false to cancel state loading</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoad\": [],\n\t\n\t\t/**\n\t\t * State that was saved. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oSavedState\": null,\n\t\n\t\t/**\n\t\t * State that was loaded. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oLoadedState\": null,\n\t\n\t\t/**\n\t\t * Source url for AJAX data for the table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\t/**\n\t\t * Property from a given object from which to read the table data from. This\n\t\t * can be an empty string (when not server-side processing), in which case\n\t\t * it is  assumed an an array is given directly.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sAjaxDataProp\": null,\n\t\n\t\t/**\n\t\t * Note if draw should be blocked while getting data\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bAjaxDataGet\": true,\n\t\n\t\t/**\n\t\t * The last jQuery XHR object that was used for server-side data gathering.\n\t\t * This can be used for working with the XHR information in one of the\n\t\t * callbacks\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"jqXHR\": null,\n\t\n\t\t/**\n\t\t * JSON returned from the server in the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"json\": undefined,\n\t\n\t\t/**\n\t\t * Data submitted as part of the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"oAjaxData\": undefined,\n\t\n\t\t/**\n\t\t * Function to get the server-side data.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\t/**\n\t\t * Functions which are called prior to sending an Ajax request so extra\n\t\t * parameters can easily be sent to the server\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoServerParams\": [],\n\t\n\t\t/**\n\t\t * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if\n\t\t * required).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sServerMethod\": null,\n\t\n\t\t/**\n\t\t * Format numbers for display.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnFormatNumber\": null,\n\t\n\t\t/**\n\t\t * List of options that can be used for the user selectable length menu.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLengthMenu\": null,\n\t\n\t\t/**\n\t\t * Counter for the draws that the table does. Also used as a tracker for\n\t\t * server-side processing\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iDraw\": 0,\n\t\n\t\t/**\n\t\t * Indicate if a redraw is being done - useful for Ajax\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDrawing\": false,\n\t\n\t\t/**\n\t\t * Draw index (iDraw) of the last error when parsing the returned data\n\t\t *  @type int\n\t\t *  @default -1\n\t\t */\n\t\t\"iDrawError\": -1,\n\t\n\t\t/**\n\t\t * Paging display length\n\t\t *  @type int\n\t\t *  @default 10\n\t\t */\n\t\t\"_iDisplayLength\": 10,\n\t\n\t\t/**\n\t\t * Paging start point - aiDisplay index\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"_iDisplayStart\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the result set\n\t\t * (i.e. before filtering), Use fnRecordsTotal rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsTotal\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the current display set\n\t\t * (i.e. after filtering). Use fnRecordsDisplay rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type boolean\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsDisplay\": 0,\n\t\n\t\t/**\n\t\t * Flag to indicate if jQuery UI marking and classes should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bJUI\": null,\n\t\n\t\t/**\n\t\t * The classes to use for the table\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if filtering has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bFiltered\": false,\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if sorting has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bSorted\": false,\n\t\n\t\t/**\n\t\t * Indicate that if multiple rows are in the header and there is more than\n\t\t * one unique cell per column, if the top one (true) or bottom one (false)\n\t\t * should be used for sorting / title by DataTables.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortCellsTop\": null,\n\t\n\t\t/**\n\t\t * Initialisation object that is used for the table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInit\": null,\n\t\n\t\t/**\n\t\t * Destroy callback functions - for plug-ins to attach themselves to the\n\t\t * destroy so they can clean up markup and events.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDestroyCallback\": [],\n\t\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, before filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsTotal\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsTotal * 1 :\n\t\t\t\tthis.aiDisplayMaster.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, after filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsDisplay\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsDisplay * 1 :\n\t\t\t\tthis.aiDisplay.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the display end point - aiDisplay index\n\t\t *  @type function\n\t\t */\n\t\t\"fnDisplayEnd\": function ()\n\t\t{\n\t\t\tvar\n\t\t\t\tlen      = this._iDisplayLength,\n\t\t\t\tstart    = this._iDisplayStart,\n\t\t\t\tcalc     = start + len,\n\t\t\t\trecords  = this.aiDisplay.length,\n\t\t\t\tfeatures = this.oFeatures,\n\t\t\t\tpaginate = features.bPaginate;\n\t\n\t\t\tif ( features.bServerSide ) {\n\t\t\t\treturn paginate === false || len === -1 ?\n\t\t\t\t\tstart + records :\n\t\t\t\t\tMath.min( start+len, this._iRecordsDisplay );\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn ! paginate || calc>records || len===-1 ?\n\t\t\t\t\trecords :\n\t\t\t\t\tcalc;\n\t\t\t}\n\t\t},\n\t\n\t\t/**\n\t\t * The DataTables object for this table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInstance\": null,\n\t\n\t\t/**\n\t\t * Unique identifier for each instance of the DataTables object. If there\n\t\t * is an ID on the table node, then it takes that value, otherwise an\n\t\t * incrementing internal counter is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sInstance\": null,\n\t\n\t\t/**\n\t\t * tabindex attribute value that is added to DataTables control elements, allowing\n\t\t * keyboard navigation of the table and its controls.\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollHead\": null,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollFoot\": null,\n\t\n\t\t/**\n\t\t * Last applied sort\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLastSort\": [],\n\t\n\t\t/**\n\t\t * Stored plug-in instances\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oPlugins\": {},\n\t\n\t\t/**\n\t\t * Function used to get a row's id from the row's data\n\t\t *  @type function\n\t\t *  @default null\n\t\t */\n\t\t\"rowIdFn\": null,\n\t\n\t\t/**\n\t\t * Data location where to store a row's id\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"rowId\": null\n\t};\n\n\t/**\n\t * Extension object for DataTables that is used to provide all extension\n\t * options.\n\t *\n\t * Note that the `DataTable.ext` object is available through\n\t * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is\n\t * also aliased to `jQuery.fn.dataTableExt` for historic reasons.\n\t *  @namespace\n\t *  @extends DataTable.models.ext\n\t */\n\t\n\t\n\t/**\n\t * DataTables extensions\n\t * \n\t * This namespace acts as a collection area for plug-ins that can be used to\n\t * extend DataTables capabilities. Indeed many of the build in methods\n\t * use this method to provide their own capabilities (sorting methods for\n\t * example).\n\t *\n\t * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy\n\t * reasons\n\t *\n\t *  @namespace\n\t */\n\tDataTable.ext = _ext = {\n\t\t/**\n\t\t * Buttons. For use with the Buttons extension for DataTables. This is\n\t\t * defined here so other extensions can define buttons regardless of load\n\t\t * order. It is _not_ used by DataTables core.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tbuttons: {},\n\t\n\t\n\t\t/**\n\t\t * Element class names\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tclasses: {},\n\t\n\t\n\t\t/**\n\t\t * DataTables build type (expanded by the download builder)\n\t\t *\n\t\t *  @type string\n\t\t */\n\t\tbuild:\"dt/dt-1.10.13\",\n\t\n\t\n\t\t/**\n\t\t * Error reporting.\n\t\t * \n\t\t * How should DataTables report an error. Can take the value 'alert',\n\t\t * 'throw', 'none' or a function.\n\t\t *\n\t\t *  @type string|function\n\t\t *  @default alert\n\t\t */\n\t\terrMode: \"alert\",\n\t\n\t\n\t\t/**\n\t\t * Feature plug-ins.\n\t\t * \n\t\t * This is an array of objects which describe the feature plug-ins that are\n\t\t * available to DataTables. These feature plug-ins are then available for\n\t\t * use through the `dom` initialisation option.\n\t\t * \n\t\t * Each feature plug-in is described by an object which must have the\n\t\t * following properties:\n\t\t * \n\t\t * * `fnInit` - function that is used to initialise the plug-in,\n\t\t * * `cFeature` - a character so the feature can be enabled by the `dom`\n\t\t *   instillation option. This is case sensitive.\n\t\t *\n\t\t * The `fnInit` function has the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *\n\t\t * And the following return is expected:\n\t\t * \n\t\t * * {node|null} The element which contains your feature. Note that the\n\t\t *   return may also be void if your plug-in does not require to inject any\n\t\t *   DOM elements into DataTables control (`dom`) - for example this might\n\t\t *   be useful when developing a plug-in which allows table control via\n\t\t *   keyboard entry\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    $.fn.dataTable.ext.features.push( {\n\t\t *      \"fnInit\": function( oSettings ) {\n\t\t *        return new TableTools( { \"oDTSettings\": oSettings } );\n\t\t *      },\n\t\t *      \"cFeature\": \"T\"\n\t\t *    } );\n\t\t */\n\t\tfeature: [],\n\t\n\t\n\t\t/**\n\t\t * Row searching.\n\t\t * \n\t\t * This method of searching is complimentary to the default type based\n\t\t * searching, and a lot more comprehensive as it allows you complete control\n\t\t * over the searching logic. Each element in this array is a function\n\t\t * (parameters described below) that is called for every row in the table,\n\t\t * and your logic decides if it should be included in the searching data set\n\t\t * or not.\n\t\t *\n\t\t * Searching functions have the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{array|object}` Data for the row to be processed (same as the\n\t\t *    original format that was passed in as the data source, or an array\n\t\t *    from a DOM data source\n\t\t * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which\n\t\t *    can be useful to retrieve the `TR` element if you need DOM interaction.\n\t\t *\n\t\t * And the following return is expected:\n\t\t *\n\t\t * * {boolean} Include the row in the searched result set (true) or not\n\t\t *   (false)\n\t\t *\n\t\t * Note that as with the main search ability in DataTables, technically this\n\t\t * is \"filtering\", since it is subtractive. However, for consistency in\n\t\t * naming we call it searching here.\n\t\t *\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @example\n\t\t *    // The following example shows custom search being applied to the\n\t\t *    // fourth column (i.e. the data[3] index) based on two input values\n\t\t *    // from the end-user, matching the data in a certain range.\n\t\t *    $.fn.dataTable.ext.search.push(\n\t\t *      function( settings, data, dataIndex ) {\n\t\t *        var min = document.getElementById('min').value * 1;\n\t\t *        var max = document.getElementById('max').value * 1;\n\t\t *        var version = data[3] == \"-\" ? 0 : data[3]*1;\n\t\t *\n\t\t *        if ( min == \"\" && max == \"\" ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min == \"\" && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && \"\" == max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        return false;\n\t\t *      }\n\t\t *    );\n\t\t */\n\t\tsearch: [],\n\t\n\t\n\t\t/**\n\t\t * Selector extensions\n\t\t *\n\t\t * The `selector` option can be used to extend the options available for the\n\t\t * selector modifier options (`selector-modifier` object data type) that\n\t\t * each of the three built in selector types offer (row, column and cell +\n\t\t * their plural counterparts). For example the Select extension uses this\n\t\t * mechanism to provide an option to select only rows, columns and cells\n\t\t * that have been marked as selected by the end user (`{selected: true}`),\n\t\t * which can be used in conjunction with the existing built in selector\n\t\t * options.\n\t\t *\n\t\t * Each property is an array to which functions can be pushed. The functions\n\t\t * take three attributes:\n\t\t *\n\t\t * * Settings object for the host table\n\t\t * * Options object (`selector-modifier` object type)\n\t\t * * Array of selected item indexes\n\t\t *\n\t\t * The return is an array of the resulting item indexes after the custom\n\t\t * selector has been applied.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tselector: {\n\t\t\tcell: [],\n\t\t\tcolumn: [],\n\t\t\trow: []\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Internal functions, exposed for used in plug-ins.\n\t\t * \n\t\t * Please note that you should not need to use the internal methods for\n\t\t * anything other than a plug-in (and even then, try to avoid if possible).\n\t\t * The internal function may change between releases.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tinternal: {},\n\t\n\t\n\t\t/**\n\t\t * Legacy configuration options. Enable and disable legacy options that\n\t\t * are available in DataTables.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tlegacy: {\n\t\t\t/**\n\t\t\t * Enable / disable DataTables 1.9 compatible server-side processing\n\t\t\t * requests\n\t\t\t *\n\t\t\t *  @type boolean\n\t\t\t *  @default null\n\t\t\t */\n\t\t\tajax: null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Pagination plug-in methods.\n\t\t * \n\t\t * Each entry in this object is a function and defines which buttons should\n\t\t * be shown by the pagination rendering method that is used for the table:\n\t\t * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the\n\t\t * buttons are displayed in the document, while the functions here tell it\n\t\t * what buttons to display. This is done by returning an array of button\n\t\t * descriptions (what each button will do).\n\t\t *\n\t\t * Pagination types (the four built in options and any additional plug-in\n\t\t * options defined here) can be used through the `paginationType`\n\t\t * initialisation parameter.\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{int} page` The current page index\n\t\t * 2. `{int} pages` The number of pages in the table\n\t\t *\n\t\t * Each function is expected to return an array where each element of the\n\t\t * array can be one of:\n\t\t *\n\t\t * * `first` - Jump to first page when activated\n\t\t * * `last` - Jump to last page when activated\n\t\t * * `previous` - Show previous page when activated\n\t\t * * `next` - Show next page when activated\n\t\t * * `{int}` - Show page of the index given\n\t\t * * `{array}` - A nested array containing the above elements to add a\n\t\t *   containing 'DIV' element (might be useful for styling).\n\t\t *\n\t\t * Note that DataTables v1.9- used this object slightly differently whereby\n\t\t * an object with two functions would be defined for each plug-in. That\n\t\t * ability is still supported by DataTables 1.10+ to provide backwards\n\t\t * compatibility, but this option of use is now decremented and no longer\n\t\t * documented in DataTables 1.10+.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t *\n\t\t *  @example\n\t\t *    // Show previous, next and current page buttons only\n\t\t *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {\n\t\t *      return [ 'previous', page, 'next' ];\n\t\t *    };\n\t\t */\n\t\tpager: {},\n\t\n\t\n\t\trenderer: {\n\t\t\tpageButton: {},\n\t\t\theader: {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Ordering plug-ins - custom data source\n\t\t * \n\t\t * The extension options for ordering of data available here is complimentary\n\t\t * to the default type based ordering that DataTables typically uses. It\n\t\t * allows much greater control over the the data that is being used to\n\t\t * order a column, but is necessarily therefore more complex.\n\t\t * \n\t\t * This type of ordering is useful if you want to do ordering based on data\n\t\t * live from the DOM (for example the contents of an 'input' element) rather\n\t\t * than just the static string that DataTables knows of.\n\t\t * \n\t\t * The way these plug-ins work is that you create an array of the values you\n\t\t * wish to be ordering for the column in question and then return that\n\t\t * array. The data in the array much be in the index order of the rows in\n\t\t * the table (not the currently ordering order!). Which order data gathering\n\t\t * function is run here depends on the `dt-init columns.orderDataType`\n\t\t * parameter that is used for the column (if any).\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{int}` Target column index\n\t\t *\n\t\t * Each function is expected to return an array:\n\t\t *\n\t\t * * `{array}` Data for the column to be ordering upon\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    // Ordering using `input` node values\n\t\t *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )\n\t\t *    {\n\t\t *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {\n\t\t *        return $('input', td).val();\n\t\t *      } );\n\t\t *    }\n\t\t */\n\t\torder: {},\n\t\n\t\n\t\t/**\n\t\t * Type based plug-ins.\n\t\t *\n\t\t * Each column in DataTables has a type assigned to it, either by automatic\n\t\t * detection or by direct assignment using the `type` option for the column.\n\t\t * The type of a column will effect how it is ordering and search (plug-ins\n\t\t * can also make use of the column type if required).\n\t\t *\n\t\t * @namespace\n\t\t */\n\t\ttype: {\n\t\t\t/**\n\t\t\t * Type detection functions.\n\t\t\t *\n\t\t\t * The functions defined in this object are used to automatically detect\n\t\t\t * a column's type, making initialisation of DataTables super easy, even\n\t\t\t * when complex data is in the table.\n\t\t\t *\n\t\t\t * The functions defined take two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be analysed\n\t\t     *  2. `{settings}` DataTables settings object. This can be used to\n\t\t     *     perform context specific type detection - for example detection\n\t\t     *     based on language settings such as using a comma for a decimal\n\t\t     *     place. Generally speaking the options from the settings will not\n\t\t     *     be required\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Data type detected, or null if unknown (and thus\n\t\t\t *   pass it on to the other type detection functions.\n\t\t\t *\n\t\t\t *  @type array\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Currency type detection plug-in:\n\t\t\t *    $.fn.dataTable.ext.type.detect.push(\n\t\t\t *      function ( data, settings ) {\n\t\t\t *        // Check the numeric part\n\t\t\t *        if ( ! $.isNumeric( data.substring(1) ) ) {\n\t\t\t *          return null;\n\t\t\t *        }\n\t\t\t *\n\t\t\t *        // Check prefixed by currency\n\t\t\t *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {\n\t\t\t *          return 'currency';\n\t\t\t *        }\n\t\t\t *        return null;\n\t\t\t *      }\n\t\t\t *    );\n\t\t\t */\n\t\t\tdetect: [],\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based search formatting.\n\t\t\t *\n\t\t\t * The type based searching functions can be used to pre-format the\n\t\t\t * data to be search on. For example, it can be used to strip HTML\n\t\t\t * tags or to de-format telephone numbers for numeric only searching.\n\t\t\t *\n\t\t\t * Note that is a search is not defined for a column of a given type,\n\t\t\t * no search formatting will be performed.\n\t\t\t * \n\t\t\t * Pre-processing of searching data plug-ins - When you assign the sType\n\t\t\t * for a column (or have it automatically detected for you by DataTables\n\t\t\t * or a type detection plug-in), you will typically be using this for\n\t\t\t * custom sorting, but it can also be used to provide custom searching\n\t\t\t * by allowing you to pre-processing the data and returning the data in\n\t\t\t * the format that should be searched upon. This is done by adding\n\t\t\t * functions this object with a parameter name which matches the sType\n\t\t\t * for that target column. This is the corollary of <i>afnSortData</i>\n\t\t\t * for searching data.\n\t\t\t *\n\t\t\t * The functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for searching\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Formatted string that will be used for the searching.\n\t\t\t *\n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {\n\t\t\t *      return d.replace(/\\n/g,\" \").replace( /<.*?>/g, \"\" );\n\t\t\t *    }\n\t\t\t */\n\t\t\tsearch: {},\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based ordering.\n\t\t\t *\n\t\t\t * The column type tells DataTables what ordering to apply to the table\n\t\t\t * when a column is sorted upon. The order for each type that is defined,\n\t\t\t * is defined by the functions available in this object.\n\t\t\t *\n\t\t\t * Each ordering option can be described by three properties added to\n\t\t\t * this object:\n\t\t\t *\n\t\t\t * * `{type}-pre` - Pre-formatting function\n\t\t\t * * `{type}-asc` - Ascending order function\n\t\t\t * * `{type}-desc` - Descending order function\n\t\t\t *\n\t\t\t * All three can be used together, only `{type}-pre` or only\n\t\t\t * `{type}-asc` and `{type}-desc` together. It is generally recommended\n\t\t\t * that only `{type}-pre` is used, as this provides the optimal\n\t\t\t * implementation in terms of speed, although the others are provided\n\t\t\t * for compatibility with existing Javascript sort functions.\n\t\t\t *\n\t\t\t * `{type}-pre`: Functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for ordering\n\t\t\t *\n\t\t\t * And return:\n\t\t\t *\n\t\t\t * * `{*}` Data to be sorted upon\n\t\t\t *\n\t\t\t * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort\n\t\t\t * functions, taking two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data to compare to the second parameter\n\t\t     *  2. `{*}` Data to compare to the first parameter\n\t\t\t *\n\t\t\t * And returning:\n\t\t\t *\n\t\t\t * * `{*}` Ordering match: <0 if first parameter should be sorted lower\n\t\t\t *   than the second parameter, ===0 if the two parameters are equal and\n\t\t\t *   >0 if the first parameter should be sorted height than the second\n\t\t\t *   parameter.\n\t\t\t * \n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Numeric ordering of formatted numbers with a pre-formatter\n\t\t\t *    $.extend( $.fn.dataTable.ext.type.order, {\n\t\t\t *      \"string-pre\": function(x) {\n\t\t\t *        a = (a === \"-\" || a === \"\") ? 0 : a.replace( /[^\\d\\-\\.]/g, \"\" );\n\t\t\t *        return parseFloat( a );\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Case-sensitive string ordering, with no pre-formatting method\n\t\t\t *    $.extend( $.fn.dataTable.ext.order, {\n\t\t\t *      \"string-case-asc\": function(x,y) {\n\t\t\t *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t\t *      },\n\t\t\t *      \"string-case-desc\": function(x,y) {\n\t\t\t *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t */\n\t\t\torder: {}\n\t\t},\n\t\n\t\t/**\n\t\t * Unique DataTables instance counter\n\t\t *\n\t\t * @type int\n\t\t * @private\n\t\t */\n\t\t_unique: 0,\n\t\n\t\n\t\t//\n\t\t// Depreciated\n\t\t// The following properties are retained for backwards compatiblity only.\n\t\t// The should not be used in new projects and will be removed in a future\n\t\t// version\n\t\t//\n\t\n\t\t/**\n\t\t * Version check function.\n\t\t *  @type function\n\t\t *  @depreciated Since 1.10\n\t\t */\n\t\tfnVersionCheck: DataTable.fnVersionCheck,\n\t\n\t\n\t\t/**\n\t\t * Index for what 'this' index API functions should use\n\t\t *  @type int\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tiApiIndex: 0,\n\t\n\t\n\t\t/**\n\t\t * jQuery UI class container\n\t\t *  @type object\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\toJUIClasses: {},\n\t\n\t\n\t\t/**\n\t\t * Software version\n\t\t *  @type string\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tsVersion: DataTable.version\n\t};\n\t\n\t\n\t//\n\t// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts\n\t//\n\t$.extend( _ext, {\n\t\tafnFiltering: _ext.search,\n\t\taTypes:       _ext.type.detect,\n\t\tofnSearch:    _ext.type.search,\n\t\toSort:        _ext.type.order,\n\t\tafnSortData:  _ext.order,\n\t\taoFeatures:   _ext.feature,\n\t\toApi:         _ext.internal,\n\t\toStdClasses:  _ext.classes,\n\t\toPagination:  _ext.pager\n\t} );\n\t\n\t\n\t$.extend( DataTable.ext.classes, {\n\t\t\"sTable\": \"dataTable\",\n\t\t\"sNoFooter\": \"no-footer\",\n\t\n\t\t/* Paging buttons */\n\t\t\"sPageButton\": \"paginate_button\",\n\t\t\"sPageButtonActive\": \"current\",\n\t\t\"sPageButtonDisabled\": \"disabled\",\n\t\n\t\t/* Striping classes */\n\t\t\"sStripeOdd\": \"odd\",\n\t\t\"sStripeEven\": \"even\",\n\t\n\t\t/* Empty row */\n\t\t\"sRowEmpty\": \"dataTables_empty\",\n\t\n\t\t/* Features */\n\t\t\"sWrapper\": \"dataTables_wrapper\",\n\t\t\"sFilter\": \"dataTables_filter\",\n\t\t\"sInfo\": \"dataTables_info\",\n\t\t\"sPaging\": \"dataTables_paginate paging_\", /* Note that the type is postfixed */\n\t\t\"sLength\": \"dataTables_length\",\n\t\t\"sProcessing\": \"dataTables_processing\",\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\": \"sorting_asc\",\n\t\t\"sSortDesc\": \"sorting_desc\",\n\t\t\"sSortable\": \"sorting\", /* Sortable in both directions */\n\t\t\"sSortableAsc\": \"sorting_asc_disabled\",\n\t\t\"sSortableDesc\": \"sorting_desc_disabled\",\n\t\t\"sSortableNone\": \"sorting_disabled\",\n\t\t\"sSortColumn\": \"sorting_\", /* Note that an int is postfixed for the sorting order */\n\t\n\t\t/* Filtering */\n\t\t\"sFilterInput\": \"\",\n\t\n\t\t/* Page length */\n\t\t\"sLengthSelect\": \"\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollWrapper\": \"dataTables_scroll\",\n\t\t\"sScrollHead\": \"dataTables_scrollHead\",\n\t\t\"sScrollHeadInner\": \"dataTables_scrollHeadInner\",\n\t\t\"sScrollBody\": \"dataTables_scrollBody\",\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot\",\n\t\t\"sScrollFootInner\": \"dataTables_scrollFootInner\",\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\": \"\",\n\t\t\"sFooterTH\": \"\",\n\t\n\t\t// Deprecated\n\t\t\"sSortJUIAsc\": \"\",\n\t\t\"sSortJUIDesc\": \"\",\n\t\t\"sSortJUI\": \"\",\n\t\t\"sSortJUIAscAllowed\": \"\",\n\t\t\"sSortJUIDescAllowed\": \"\",\n\t\t\"sSortJUIWrapper\": \"\",\n\t\t\"sSortIcon\": \"\",\n\t\t\"sJUIHeader\": \"\",\n\t\t\"sJUIFooter\": \"\"\n\t} );\n\t\n\t\n\t(function() {\n\t\n\t// Reused strings for better compression. Closure compiler appears to have a\n\t// weird edge case where it is trying to expand strings rather than use the\n\t// variable version. This results in about 200 bytes being added, for very\n\t// little preference benefit since it this run on script load only.\n\tvar _empty = '';\n\t_empty = '';\n\t\n\tvar _stateDefault = _empty + 'ui-state-default';\n\tvar _sortIcon     = _empty + 'css_right ui-icon ui-icon-';\n\tvar _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';\n\t\n\t$.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {\n\t\t/* Full numbers paging buttons */\n\t\t\"sPageButton\":         \"fg-button ui-button \"+_stateDefault,\n\t\t\"sPageButtonActive\":   \"ui-state-disabled\",\n\t\t\"sPageButtonDisabled\": \"ui-state-disabled\",\n\t\n\t\t/* Features */\n\t\t\"sPaging\": \"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi \"+\n\t\t\t\"ui-buttonset-multi paging_\", /* Note that the type is postfixed */\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\":            _stateDefault+\" sorting_asc\",\n\t\t\"sSortDesc\":           _stateDefault+\" sorting_desc\",\n\t\t\"sSortable\":           _stateDefault+\" sorting\",\n\t\t\"sSortableAsc\":        _stateDefault+\" sorting_asc_disabled\",\n\t\t\"sSortableDesc\":       _stateDefault+\" sorting_desc_disabled\",\n\t\t\"sSortableNone\":       _stateDefault+\" sorting_disabled\",\n\t\t\"sSortJUIAsc\":         _sortIcon+\"triangle-1-n\",\n\t\t\"sSortJUIDesc\":        _sortIcon+\"triangle-1-s\",\n\t\t\"sSortJUI\":            _sortIcon+\"carat-2-n-s\",\n\t\t\"sSortJUIAscAllowed\":  _sortIcon+\"carat-1-n\",\n\t\t\"sSortJUIDescAllowed\": _sortIcon+\"carat-1-s\",\n\t\t\"sSortJUIWrapper\":     \"DataTables_sort_wrapper\",\n\t\t\"sSortIcon\":           \"DataTables_sort_icon\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollHead\": \"dataTables_scrollHead \"+_stateDefault,\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot \"+_stateDefault,\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\":  _stateDefault,\n\t\t\"sFooterTH\":  _stateDefault,\n\t\t\"sJUIHeader\": _headerFooter+\" ui-corner-tl ui-corner-tr\",\n\t\t\"sJUIFooter\": _headerFooter+\" ui-corner-bl ui-corner-br\"\n\t} );\n\t\n\t}());\n\t\n\t\n\t\n\tvar extPagination = DataTable.ext.pager;\n\t\n\tfunction _numbers ( page, pages ) {\n\t\tvar\n\t\t\tnumbers = [],\n\t\t\tbuttons = extPagination.numbers_length,\n\t\t\thalf = Math.floor( buttons / 2 ),\n\t\t\ti = 1;\n\t\n\t\tif ( pages <= buttons ) {\n\t\t\tnumbers = _range( 0, pages );\n\t\t}\n\t\telse if ( page <= half ) {\n\t\t\tnumbers = _range( 0, buttons-2 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t}\n\t\telse if ( page >= pages - 1 - half ) {\n\t\t\tnumbers = _range( pages-(buttons-2), pages );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\telse {\n\t\t\tnumbers = _range( page-half+2, page+half-1 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' );\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\n\t\tnumbers.DT_el = 'span';\n\t\treturn numbers;\n\t}\n\t\n\t\n\t$.extend( extPagination, {\n\t\tsimple: function ( page, pages ) {\n\t\t\treturn [ 'previous', 'next' ];\n\t\t},\n\t\n\t\tfull: function ( page, pages ) {\n\t\t\treturn [  'first', 'previous', 'next', 'last' ];\n\t\t},\n\t\n\t\tnumbers: function ( page, pages ) {\n\t\t\treturn [ _numbers(page, pages) ];\n\t\t},\n\t\n\t\tsimple_numbers: function ( page, pages ) {\n\t\t\treturn [ 'previous', _numbers(page, pages), 'next' ];\n\t\t},\n\t\n\t\tfull_numbers: function ( page, pages ) {\n\t\t\treturn [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];\n\t\t},\n\t\t\n\t\tfirst_last_numbers: function (page, pages) {\n\t \t\treturn ['first', _numbers(page, pages), 'last'];\n\t \t},\n\t\n\t\t// For testing and plug-ins to use\n\t\t_numbers: _numbers,\n\t\n\t\t// Number of number buttons (including ellipsis) to show. _Must be odd!_\n\t\tnumbers_length: 7\n\t} );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\tpageButton: {\n\t\t\t_: function ( settings, host, idx, buttons, page, pages ) {\n\t\t\t\tvar classes = settings.oClasses;\n\t\t\t\tvar lang = settings.oLanguage.oPaginate;\n\t\t\t\tvar aria = settings.oLanguage.oAria.paginate || {};\n\t\t\t\tvar btnDisplay, btnClass, counter=0;\n\t\n\t\t\t\tvar attach = function( container, buttons ) {\n\t\t\t\t\tvar i, ien, node, button;\n\t\t\t\t\tvar clickHandler = function ( e ) {\n\t\t\t\t\t\t_fnPageChange( settings, e.data.action, true );\n\t\t\t\t\t};\n\t\n\t\t\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tbutton = buttons[i];\n\t\n\t\t\t\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\t\t\t\tvar inner = $( '<'+(button.DT_el || 'div')+'/>' )\n\t\t\t\t\t\t\t\t.appendTo( container );\n\t\t\t\t\t\t\tattach( inner, button );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tbtnDisplay = null;\n\t\t\t\t\t\t\tbtnClass = '';\n\t\n\t\t\t\t\t\t\tswitch ( button ) {\n\t\t\t\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\t\t\t\tcontainer.append('<span class=\"ellipsis\">&#x2026;</span>');\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'first':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'next':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'last':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t\t\t\tclasses.sPageButtonActive : '';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\tif ( btnDisplay !== null ) {\n\t\t\t\t\t\t\t\tnode = $('<a>', {\n\t\t\t\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t\t\t\t.appendTo( container );\n\t\n\t\t\t\t\t\t\t\t_fnBindAction(\n\t\t\t\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t\t\t\t);\n\t\n\t\t\t\t\t\t\t\tcounter++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame. Try / catch the error. Not good for\n\t\t\t\t// accessibility, but neither are frames.\n\t\t\t\tvar activeEl;\n\t\n\t\t\t\ttry {\n\t\t\t\t\t// Because this approach is destroying and recreating the paging\n\t\t\t\t\t// elements, focus is lost on the select button which is bad for\n\t\t\t\t\t// accessibility. So we want to restore focus once the draw has\n\t\t\t\t\t// completed\n\t\t\t\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t\t\t\t}\n\t\t\t\tcatch (e) {}\n\t\n\t\t\t\tattach( $(host).empty(), buttons );\n\t\n\t\t\t\tif ( activeEl !== undefined ) {\n\t\t\t\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t\n\t\n\t// Built in type detection. See model.ext.aTypes for information about\n\t// what is required from this methods.\n\t$.extend( DataTable.ext.type.detect, [\n\t\t// Plain numbers - first since V8 detects some plain numbers as dates\n\t\t// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal ) ? 'num'+decimal : null;\n\t\t},\n\t\n\t\t// Dates (only those recognised by the browser's Date.parse)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\t// V8 tries _very_ hard to make a string passed into `Date.parse()`\n\t\t\t// valid, so we need to use a regex to restrict date formats. Use a\n\t\t\t// plug-in for anything other than ISO8601 style strings\n\t\t\tif ( d && !(d instanceof Date) && ! _re_date.test(d) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tvar parsed = Date.parse(d);\n\t\t\treturn (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;\n\t\t},\n\t\n\t\t// Formatted numbers\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric, formatted\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML (this is strict checking - there must be html)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\treturn _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?\n\t\t\t\t'html' : null;\n\t\t}\n\t] );\n\t\n\t\n\t\n\t// Filter formatting functions. See model.ext.ofnSearch for information about\n\t// what is required from these methods.\n\t// \n\t// Note that additional search methods are added for the html numbers and\n\t// html formatted numbers by `_addNumericSort()` when we know what the decimal\n\t// place is\n\t\n\t\n\t$.extend( DataTable.ext.type.search, {\n\t\thtml: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata\n\t\t\t\t\t\t.replace( _re_new_lines, \" \" )\n\t\t\t\t\t\t.replace( _re_html, \"\" ) :\n\t\t\t\t\t'';\n\t\t},\n\t\n\t\tstring: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata.replace( _re_new_lines, \" \" ) :\n\t\t\t\t\tdata;\n\t\t}\n\t} );\n\t\n\t\n\t\n\tvar __numericReplace = function ( d, decimalPlace, re1, re2 ) {\n\t\tif ( d !== 0 && (!d || d === '-') ) {\n\t\t\treturn -Infinity;\n\t\t}\n\t\n\t\t// If a decimal place other than `.` is used, it needs to be given to the\n\t\t// function so we can detect it and replace with a `.` which is the only\n\t\t// decimal place Javascript recognises - it is not locale aware.\n\t\tif ( decimalPlace ) {\n\t\t\td = _numToDecimal( d, decimalPlace );\n\t\t}\n\t\n\t\tif ( d.replace ) {\n\t\t\tif ( re1 ) {\n\t\t\t\td = d.replace( re1, '' );\n\t\t\t}\n\t\n\t\t\tif ( re2 ) {\n\t\t\t\td = d.replace( re2, '' );\n\t\t\t}\n\t\t}\n\t\n\t\treturn d * 1;\n\t};\n\t\n\t\n\t// Add the numeric 'deformatting' functions for sorting and search. This is done\n\t// in a function to provide an easy ability for the language options to add\n\t// additional methods if a non-period decimal place is used.\n\tfunction _addNumericSort ( decimalPlace ) {\n\t\t$.each(\n\t\t\t{\n\t\t\t\t// Plain numbers\n\t\t\t\t\"num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace );\n\t\t\t\t},\n\t\n\t\t\t\t// Formatted numbers\n\t\t\t\t\"num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_formatted_numeric );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric\n\t\t\t\t\"html-num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric, formatted\n\t\t\t\t\"html-num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );\n\t\t\t\t}\n\t\t\t},\n\t\t\tfunction ( key, fn ) {\n\t\t\t\t// Add the ordering method\n\t\t\t\t_ext.type.order[ key+decimalPlace+'-pre' ] = fn;\n\t\n\t\t\t\t// For HTML types add a search formatter that will strip the HTML\n\t\t\t\tif ( key.match(/^html\\-/) ) {\n\t\t\t\t\t_ext.type.search[ key+decimalPlace ] = _ext.type.search.html;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\t\n\t\n\t// Default sort methods\n\t$.extend( _ext.type.order, {\n\t\t// Dates\n\t\t\"date-pre\": function ( d ) {\n\t\t\treturn Date.parse( d ) || -Infinity;\n\t\t},\n\t\n\t\t// html\n\t\t\"html-pre\": function ( a ) {\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ta.replace ?\n\t\t\t\t\ta.replace( /<.*?>/g, \"\" ).toLowerCase() :\n\t\t\t\t\ta+'';\n\t\t},\n\t\n\t\t// string\n\t\t\"string-pre\": function ( a ) {\n\t\t\t// This is a little complex, but faster than always calling toString,\n\t\t\t// http://jsperf.com/tostring-v-check\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ttypeof a === 'string' ?\n\t\t\t\t\ta.toLowerCase() :\n\t\t\t\t\t! a.toString ?\n\t\t\t\t\t\t'' :\n\t\t\t\t\t\ta.toString();\n\t\t},\n\t\n\t\t// string-asc and -desc are retained only for compatibility with the old\n\t\t// sort methods\n\t\t\"string-asc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t},\n\t\n\t\t\"string-desc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t}\n\t} );\n\t\n\t\n\t// Numeric sorting types - order doesn't matter here\n\t_addNumericSort( '' );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\theader: {\n\t\t\t_: function ( settings, cell, column, classes ) {\n\t\t\t\t// No additional mark-up required\n\t\t\t\t// Attach a sort listener to update on sort - note that using the\n\t\t\t\t// `DT` namespace will allow the event to be removed automatically\n\t\t\t\t// on destroy, while the `dt` namespaced event is the one we are\n\t\t\t\t// listening for\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) { // need to check this this is the host\n\t\t\t\t\t\treturn;               // table, not a nested one\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tcolumn.sSortingClass +' '+\n\t\t\t\t\t\t\tclasses.sSortAsc +' '+\n\t\t\t\t\t\t\tclasses.sSortDesc\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t},\n\t\n\t\t\tjqueryui: function ( settings, cell, column, classes ) {\n\t\t\t\t$('<div/>')\n\t\t\t\t\t.addClass( classes.sSortJUIWrapper )\n\t\t\t\t\t.append( cell.contents() )\n\t\t\t\t\t.append( $('<span/>')\n\t\t\t\t\t\t.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo( cell );\n\t\n\t\t\t\t// Attach a sort listener to update on sort\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.find( 'span.'+classes.sSortIcon )\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tclasses.sSortJUIAsc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDesc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUI +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIAscAllowed +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDescAllowed\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortJUIAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortJUIDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClassJUI\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t/*\n\t * Public helper functions. These aren't used internally by DataTables, or\n\t * called by any of the options passed into DataTables, but they can be used\n\t * externally by developers working with DataTables. They are helper functions\n\t * to make working with DataTables a little bit easier.\n\t */\n\t\n\tvar __htmlEscapeEntities = function ( d ) {\n\t\treturn typeof d === 'string' ?\n\t\t\td.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;') :\n\t\t\td;\n\t};\n\t\n\t/**\n\t * Helpers for `columns.render`.\n\t *\n\t * The options defined here can be used with the `columns.render` initialisation\n\t * option to provide a display renderer. The following functions are defined:\n\t *\n\t * * `number` - Will format numeric data (defined by `columns.data`) for\n\t *   display, retaining the original unformatted data for sorting and filtering.\n\t *   It takes 5 parameters:\n\t *   * `string` - Thousands grouping separator\n\t *   * `string` - Decimal point indicator\n\t *   * `integer` - Number of decimal points to show\n\t *   * `string` (optional) - Prefix.\n\t *   * `string` (optional) - Postfix (/suffix).\n\t * * `text` - Escape HTML to help prevent XSS attacks. It has no optional\n\t *   parameters.\n\t *\n\t * @example\n\t *   // Column definition using the number renderer\n\t *   {\n\t *     data: \"salary\",\n\t *     render: $.fn.dataTable.render.number( '\\'', '.', 0, '$' )\n\t *   }\n\t *\n\t * @namespace\n\t */\n\tDataTable.render = {\n\t\tnumber: function ( thousands, decimal, precision, prefix, postfix ) {\n\t\t\treturn {\n\t\t\t\tdisplay: function ( d ) {\n\t\t\t\t\tif ( typeof d !== 'number' && typeof d !== 'string' ) {\n\t\t\t\t\t\treturn d;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar negative = d < 0 ? '-' : '';\n\t\t\t\t\tvar flo = parseFloat( d );\n\t\n\t\t\t\t\t// If NaN then there isn't much formatting that we can do - just\n\t\t\t\t\t// return immediately, escaping any HTML (this was supposed to\n\t\t\t\t\t// be a number after all)\n\t\t\t\t\tif ( isNaN( flo ) ) {\n\t\t\t\t\t\treturn __htmlEscapeEntities( d );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tflo = flo.toFixed( precision );\n\t\t\t\t\td = Math.abs( flo );\n\t\n\t\t\t\t\tvar intPart = parseInt( d, 10 );\n\t\t\t\t\tvar floatPart = precision ?\n\t\t\t\t\t\tdecimal+(d - intPart).toFixed( precision ).substring( 2 ):\n\t\t\t\t\t\t'';\n\t\n\t\t\t\t\treturn negative + (prefix||'') +\n\t\t\t\t\t\tintPart.toString().replace(\n\t\t\t\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g, thousands\n\t\t\t\t\t\t) +\n\t\t\t\t\t\tfloatPart +\n\t\t\t\t\t\t(postfix||'');\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\ttext: function () {\n\t\t\treturn {\n\t\t\t\tdisplay: __htmlEscapeEntities\n\t\t\t};\n\t\t}\n\t};\n\t\n\t\n\t/*\n\t * This is really a good bit rubbish this method of exposing the internal methods\n\t * publicly... - To be fixed in 2.0 using methods on the prototype\n\t */\n\t\n\t\n\t/**\n\t * Create a wrapper function for exporting an internal functions to an external API.\n\t *  @param {string} fn API function name\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#internal\n\t */\n\tfunction _fnExternApiFunc (fn)\n\t{\n\t\treturn function() {\n\t\t\tvar args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(\n\t\t\t\tArray.prototype.slice.call(arguments)\n\t\t\t);\n\t\t\treturn DataTable.ext.internal[fn].apply( this, args );\n\t\t};\n\t}\n\t\n\t\n\t/**\n\t * Reference to internal functions for use by plug-in developers. Note that\n\t * these methods are references to internal functions and are considered to be\n\t * private. If you use these methods, be aware that they are liable to change\n\t * between versions.\n\t *  @namespace\n\t */\n\t$.extend( DataTable.ext.internal, {\n\t\t_fnExternApiFunc: _fnExternApiFunc,\n\t\t_fnBuildAjax: _fnBuildAjax,\n\t\t_fnAjaxUpdate: _fnAjaxUpdate,\n\t\t_fnAjaxParameters: _fnAjaxParameters,\n\t\t_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,\n\t\t_fnAjaxDataSrc: _fnAjaxDataSrc,\n\t\t_fnAddColumn: _fnAddColumn,\n\t\t_fnColumnOptions: _fnColumnOptions,\n\t\t_fnAdjustColumnSizing: _fnAdjustColumnSizing,\n\t\t_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,\n\t\t_fnColumnIndexToVisible: _fnColumnIndexToVisible,\n\t\t_fnVisbleColumns: _fnVisbleColumns,\n\t\t_fnGetColumns: _fnGetColumns,\n\t\t_fnColumnTypes: _fnColumnTypes,\n\t\t_fnApplyColumnDefs: _fnApplyColumnDefs,\n\t\t_fnHungarianMap: _fnHungarianMap,\n\t\t_fnCamelToHungarian: _fnCamelToHungarian,\n\t\t_fnLanguageCompat: _fnLanguageCompat,\n\t\t_fnBrowserDetect: _fnBrowserDetect,\n\t\t_fnAddData: _fnAddData,\n\t\t_fnAddTr: _fnAddTr,\n\t\t_fnNodeToDataIndex: _fnNodeToDataIndex,\n\t\t_fnNodeToColumnIndex: _fnNodeToColumnIndex,\n\t\t_fnGetCellData: _fnGetCellData,\n\t\t_fnSetCellData: _fnSetCellData,\n\t\t_fnSplitObjNotation: _fnSplitObjNotation,\n\t\t_fnGetObjectDataFn: _fnGetObjectDataFn,\n\t\t_fnSetObjectDataFn: _fnSetObjectDataFn,\n\t\t_fnGetDataMaster: _fnGetDataMaster,\n\t\t_fnClearTable: _fnClearTable,\n\t\t_fnDeleteIndex: _fnDeleteIndex,\n\t\t_fnInvalidate: _fnInvalidate,\n\t\t_fnGetRowElements: _fnGetRowElements,\n\t\t_fnCreateTr: _fnCreateTr,\n\t\t_fnBuildHead: _fnBuildHead,\n\t\t_fnDrawHead: _fnDrawHead,\n\t\t_fnDraw: _fnDraw,\n\t\t_fnReDraw: _fnReDraw,\n\t\t_fnAddOptionsHtml: _fnAddOptionsHtml,\n\t\t_fnDetectHeader: _fnDetectHeader,\n\t\t_fnGetUniqueThs: _fnGetUniqueThs,\n\t\t_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,\n\t\t_fnFilterComplete: _fnFilterComplete,\n\t\t_fnFilterCustom: _fnFilterCustom,\n\t\t_fnFilterColumn: _fnFilterColumn,\n\t\t_fnFilter: _fnFilter,\n\t\t_fnFilterCreateSearch: _fnFilterCreateSearch,\n\t\t_fnEscapeRegex: _fnEscapeRegex,\n\t\t_fnFilterData: _fnFilterData,\n\t\t_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,\n\t\t_fnUpdateInfo: _fnUpdateInfo,\n\t\t_fnInfoMacros: _fnInfoMacros,\n\t\t_fnInitialise: _fnInitialise,\n\t\t_fnInitComplete: _fnInitComplete,\n\t\t_fnLengthChange: _fnLengthChange,\n\t\t_fnFeatureHtmlLength: _fnFeatureHtmlLength,\n\t\t_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,\n\t\t_fnPageChange: _fnPageChange,\n\t\t_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,\n\t\t_fnProcessingDisplay: _fnProcessingDisplay,\n\t\t_fnFeatureHtmlTable: _fnFeatureHtmlTable,\n\t\t_fnScrollDraw: _fnScrollDraw,\n\t\t_fnApplyToChildren: _fnApplyToChildren,\n\t\t_fnCalculateColumnWidths: _fnCalculateColumnWidths,\n\t\t_fnThrottle: _fnThrottle,\n\t\t_fnConvertToWidth: _fnConvertToWidth,\n\t\t_fnGetWidestNode: _fnGetWidestNode,\n\t\t_fnGetMaxLenString: _fnGetMaxLenString,\n\t\t_fnStringToCss: _fnStringToCss,\n\t\t_fnSortFlatten: _fnSortFlatten,\n\t\t_fnSort: _fnSort,\n\t\t_fnSortAria: _fnSortAria,\n\t\t_fnSortListener: _fnSortListener,\n\t\t_fnSortAttachListener: _fnSortAttachListener,\n\t\t_fnSortingClasses: _fnSortingClasses,\n\t\t_fnSortData: _fnSortData,\n\t\t_fnSaveState: _fnSaveState,\n\t\t_fnLoadState: _fnLoadState,\n\t\t_fnSettingsFromNode: _fnSettingsFromNode,\n\t\t_fnLog: _fnLog,\n\t\t_fnMap: _fnMap,\n\t\t_fnBindAction: _fnBindAction,\n\t\t_fnCallbackReg: _fnCallbackReg,\n\t\t_fnCallbackFire: _fnCallbackFire,\n\t\t_fnLengthOverflow: _fnLengthOverflow,\n\t\t_fnRenderer: _fnRenderer,\n\t\t_fnDataSource: _fnDataSource,\n\t\t_fnRowAttributes: _fnRowAttributes,\n\t\t_fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant\n\t\t                                // in 1.10, so this dead-end function is\n\t\t                                // added to prevent errors\n\t} );\n\t\n\n\t// jQuery access\n\t$.fn.dataTable = DataTable;\n\n\t// Provide access to the host jQuery object (circular reference)\n\tDataTable.$ = $;\n\n\t// Legacy aliases\n\t$.fn.dataTableSettings = DataTable.settings;\n\t$.fn.dataTableExt = DataTable.ext;\n\n\t// With a capital `D` we return a DataTables API instance rather than a\n\t// jQuery object\n\t$.fn.DataTable = function ( opts ) {\n\t\treturn $(this).dataTable( opts ).api();\n\t};\n\n\t// All properties that are available to $.fn.dataTable should also be\n\t// available on $.fn.DataTable\n\t$.each( DataTable, function ( prop, val ) {\n\t\t$.fn.DataTable[ prop ] = val;\n\t} );\n\n\n\t// Information about events fired by DataTables - for documentation.\n\t/**\n\t * Draw event, fired whenever the table is redrawn on the page, at the same\n\t * point as fnDrawCallback. This may be useful for binding events or\n\t * performing calculations when the table is altered at all.\n\t *  @name DataTable#draw.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Search event, fired when the searching applied to the table (using the\n\t * built-in global search, or column filters) is altered.\n\t *  @name DataTable#search.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page change event, fired when the paging of the table is altered.\n\t *  @name DataTable#page.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Order event, fired when the ordering applied to the table is altered.\n\t *  @name DataTable#order.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * DataTables initialisation complete event, fired when the table is fully\n\t * drawn, including Ajax data loaded, if Ajax data is required.\n\t *  @name DataTable#init.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The JSON object request from the server - only\n\t *    present if client-side Ajax sourced data is used</li></ol>\n\t */\n\n\t/**\n\t * State save event, fired when the table has changed state a new state save\n\t * is required. This event allows modification of the state saving object\n\t * prior to actually doing the save, including addition or other state\n\t * properties (for plug-ins) or modification of a DataTables core property.\n\t *  @name DataTable#stateSaveParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The state information to be saved\n\t */\n\n\t/**\n\t * State load event, fired when the table is loading state from the stored\n\t * data, but prior to the settings object being modified by the saved state\n\t * - allowing modification of the saved state is required or loading of\n\t * state for a plug-in.\n\t *  @name DataTable#stateLoadParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * State loaded event, fired when state has been loaded from stored data and\n\t * the settings object has been modified by the loaded data.\n\t *  @name DataTable#stateLoaded.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * Processing event, fired when DataTables is doing some kind of processing\n\t * (be it, order, searcg or anything else). It can be used to indicate to\n\t * the end user that there is something happening, or that something has\n\t * finished.\n\t *  @name DataTable#processing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {boolean} bShow Flag for if DataTables is doing processing or not\n\t */\n\n\t/**\n\t * Ajax (XHR) event, fired whenever an Ajax request is completed from a\n\t * request to made to the server for new data. This event is called before\n\t * DataTables processed the returned data, so it can also be used to pre-\n\t * process the data returned from the server, if needed.\n\t *\n\t * Note that this trigger is called in `fnServerData`, if you override\n\t * `fnServerData` and which to use this event, you need to trigger it in you\n\t * success function.\n\t *  @name DataTable#xhr.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {object} json JSON returned from the server\n\t *\n\t *  @example\n\t *     // Use a custom property returned from the server in another DOM element\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       $('#status').html( json.status );\n\t *     } );\n\t *\n\t *  @example\n\t *     // Pre-process the data returned from the server\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {\n\t *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;\n\t *       }\n\t *       // Note no return - manipulate the data directly in the JSON object.\n\t *     } );\n\t */\n\n\t/**\n\t * Destroy event, fired when the DataTable is destroyed by calling fnDestroy\n\t * or passing the bDestroy:true parameter in the initialisation object. This\n\t * can be used to remove bound events, added DOM nodes, etc.\n\t *  @name DataTable#destroy.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page length change event, fired when number of records to show on each\n\t * page (the length) is changed.\n\t *  @name DataTable#length.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {integer} len New length\n\t */\n\n\t/**\n\t * Column sizing has changed.\n\t *  @name DataTable#column-sizing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Column visibility has changed.\n\t *  @name DataTable#column-visibility.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {int} column Column index\n\t *  @param {bool} vis `false` if column now hidden, or `true` if visible\n\t */\n\n\treturn $.fn.dataTable;\n}));\n\n\n"
  },
  {
    "path": "platforms/android/assets/www/partial/about-help.html",
    "content": "<div class=\"mdl-cell mdl-cell--12-col mdl-card mdl-shadow--4dp\">\n    <div class=\"mdl-card__title\">\n        <h2 class=\"mdl-card__title-text\">About & Help</h2>\n    </div>\n\n    <div class=\"mdl-card__supporting-text\">\n        <h5><i class=\"material-icons\">bug_report</i> Bugs? Feedback?</h5>\n        <p>Please, fell free to write me an issue on the <a href=\"https://github.com/friimaind?tab=repositories\">Github project page</a>.</p>\n        \n        <hr />\n        \n        <h5><i class=\"material-icons\">help_outline</i> Help</h5>        \n        <p>If you get here you need help to find the credential for your Pi-hole. It's very easy!</p>\n        <p>On the App setting page you need to insert the <strong>IP of your Pi-hole</strong> (for example http://192.168.1.2) or the <strong>hostname</strong> (for example http://mypyhole.local). Note that you can also specify a <strong>custom port</strong> with this format http://192.168.1.2:99 and obviously you can use <strong>https</strong>.</p>\n        <p>The <strong>token string</strong> is required for access the Pi-hole's API and extract charts, table etc.<br />These credentials are <strong>saved locally</strong> on your smartphone.</p>\n        <p>To obtain the token string you can access to the admin web page of your Pi-hole and <strong>scan the QR code</strong> with your smartphone:</p>\n        <ul>\n            <li>Connect to your Pi-hole with a computer: http://RASPBERRY_IP/admin</li>\n            <li>Login and go to Settings</li>\n            <li>On the API tab click on \"Show API token\". It will open a new page with the QR code</li>\n            <li>On your smartphone click on the QR code scan icon near the token field</li>\n        </ul>\n        <p><em>Please note:</em> \"Show API token\" function is present on Pi-hole >= 2.5 Web Interface Version.</p>\n        <p>You can even obtain the token string with a manual operation: the token string is inside your Raspberry, I suggest you to use a PC and paste it inside Google Keep or any other shared app with your smartphone.</p>\n        <ul>\n            <li>Connect to your Pi-hole with SSH.<br /><pre class=\"language-markup\"><code>ssh pi@RASPBERRY_IP</code></pre></li>\n            <li>Look at the configuration file<br /><pre class=\"language-markup\"><code>less /etc/pihole/setupVars.conf</code></pre></li>\n            <li>The token is the long string after the <strong>WEBPASSWORD=</strong></li>\n        </ul>\n        \n        <hr />\n        \n        <h5><i class=\"material-icons\">android</i> About this app</h5>\n        <p>First of all: <strong>thank you</strong> for trying this app!</p>\n        <p>I'm <a href=\"https://blog.friimaind.it\">Massimiliano Monaro</a> and I developed this app as a playground to learn Apache Cordova.</p>\n        <p>I am not affiliated to Pi-hole team, this is an unofficial app.</p>\n        <p>It would not have been possible to develop it without the help of some great tools:</p>\n        <ul>\n            <li><a href=\"https://pi-hole.net\">Pi-hole</a>: the main protagonist, it saves my daily web browsing.</li>\n            <li><a href=\"https://cordova.apache.org\">Apache Cordova</a>: this great framework gave me the opportunity to use my favorite languages to develop this native app.</li>\n            <li><a href=\"https://jquery.com\">jQuery</a>: 90% of the app is made with this library.</li>\n            <li><a href=\"https://gionkunz.github.io/chartist-js\">Chartist JS</a>: all charts is made with this wonderful library.</li>\n            <li><a href=\"https://getmdl.io\">MDL</a>: this library helped me to create the graphic interface of the app.</li>\n            <li><a href=\"https://datatables.net\">DataTables</a>: the Query Log page is handled by this jQuery plugin.</li>\n            <li><a href=\"http://hammerjs.github.io\">Hammer.js</a>: the library to recognize touch gestures.</li>\n        </ul>\n        <p>Lastly, I would like to thank my <strong>girlfriend Elisa</strong> who pushes me to accomplish things I love and my former colleague and friend <a href=\"https://melodycode.com/\">Daniele Simonin</a> for his technical help.</p>\n        <p>On Github you can find the <a href=\"https://github.com/friimaind/pi-hole-droid/blob/master/PRIVACY.MD\">Privacy Policy</a>.</p>\n    </div>   \n</div>"
  },
  {
    "path": "platforms/android/assets/www/partial/app-settings.html",
    "content": "<div class=\"mdl-cell mdl-cell--12-col mdl-card mdl-shadow--4dp\">\n    <div class=\"mdl-card__title\">\n        <h2 class=\"mdl-card__title-text\">Settings</h2>\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">vpn_key</i>\n    </div>\n\n    <div class=\"mdl-card__supporting-text\">\n        <p>Please insert here your Pi-hole settings.</p>\n        <p>To obtain the token you can <strong>scan your Pi-hole's QR code</strong> from the admin web page. Click on the icon near the token field.</p>\n        <p>Need help? <a href=\"#/\" id=\"go_to_help\">Go to the Help page</a></p>\n        <form id=\"form_settings\" class=\"fullwidth\" method=\"POST\">\n            <div class=\"mdl-textfield mdl-js-textfield mdl-textfield--floating-label\">\n                <input class=\"mdl-textfield__input\" type=\"url\" id=\"pihole_host\">\n                <label class=\"mdl-textfield__label\" for=\"pihole_host\">Pi-hole's IP or hostname</label>                \n            </div>\n            <div class=\"mdl-textfield mdl-js-textfield mdl-textfield--floating-label\">\n                <input class=\"mdl-textfield__input\" type=\"text\" id=\"pihole_token\">\n                <label class=\"mdl-textfield__label\" for=\"pihole_token\">Pi-hole's token string</label>\n                <img id=\"qrcode_scan\" src=\"img/qrcode-scan.svg\" />\n            </div>\n            \n            <button type=\"submit\" class=\"mdl-button mdl-js-button mdl-button--raised mdl-button--accent\">                                \n                Save                \n            </button>\n        </form>\n    </div>\n\n    <dialog class=\"mdl-dialog\">\n        <h4 class=\"mdl-dialog__title\"><i class=\"material-icons mdl-color-text--red\">warning</i> Uhm...</h4>\n        <div class=\"mdl-dialog__content\">\n            <p>I'm sorry but I <strong>cannot connect</strong> to your Pi-hole.</p>\n            <p>Please insert a valid url (http://IP_OR_HOSTNAME) and the correct token.</p>\n        </div>\n        <div class=\"mdl-dialog__actions\">\n            <button type=\"button\" class=\"mdl-button close\">OK</button>\n        </div>\n    </dialog>\n</div>"
  },
  {
    "path": "platforms/android/assets/www/partial/dashboard.html",
    "content": "<div class=\"centered-element\">\n    <div id=\"ads_blocked_today\" class=\"pihole-card pihole-card-floating mdl-card mdl-shadow--2dp bg-aqua\">\n        <div class=\"mdl-card__title mdl-card--expand\">\n            <h2><i class=\"material-icons loading\">refresh</i></h2>\n        </div>    \n        <div class=\"mdl-card__actions mdl-card--border\">\n            DNS Queries Blocked Today\n\n            <div class=\"mdl-layout-spacer\"></div>\n            <i class=\"material-icons\">today</i>\n        </div>\n    </div>\n\n    <div id=\"dns_queries_today\" class=\"pihole-card pihole-card-floating mdl-card mdl-shadow--2dp bg-green\">\n        <div class=\"mdl-card__title mdl-card--expand\">\n            <h2><i class=\"material-icons loading\">refresh</i></h2>\n        </div>\n        <div class=\"mdl-card__actions mdl-card--border\">\n            DNS Queries Today\n\n            <div class=\"mdl-layout-spacer\"></div>\n            <i class=\"material-icons\">public</i>\n        </div>\n    </div>\n\n    <div id=\"ads_percentage_today\" class=\"pihole-card pihole-card-floating mdl-card mdl-shadow--2dp bg-yellow\">\n        <div class=\"mdl-card__title mdl-card--expand\">\n            <h2><i class=\"material-icons loading\">refresh</i></h2>\n        </div>\n        <div class=\"mdl-card__actions mdl-card--border\">\n            Of Today's Queries Were Blocked\n\n            <div class=\"mdl-layout-spacer\"></div>\n            <i class=\"material-icons\">block</i>\n        </div>\n    </div>\n\n    <div id=\"domains_being_blocked\" class=\"pihole-card pihole-card-floating mdl-card mdl-shadow--2dp bg-red\">\n        <div class=\"mdl-card__title mdl-card--expand\">\n            <h2><i class=\"material-icons loading\">refresh</i></h2>\n        </div>\n        <div class=\"mdl-card__actions mdl-card--border\">\n            Domains Being Blocked\n\n            <div class=\"mdl-layout-spacer\"></div>\n            <i class=\"material-icons\">list</i>\n        </div>\n    </div>\n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Query types\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card__title mdl-card--expand\">        \n        <div class=\"ct-chart ct-chart-query-types\"><i class=\"material-icons loading\">refresh</i></div>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Forward destinations\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">forward</i>\n    </div>\n    <div class=\"mdl-card__title mdl-card--expand\">\n        <div class=\"ct-chart ct-chart-forward-destinations\"><i class=\"material-icons loading\">refresh</i></div>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Top domains\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card--expand\">        \n        <table class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth\">\n            <thead>\n                <tr>\n                    <th class=\"mdl-data-table__cell--non-numeric fullwidth\">Domain</th>\n                    <th class=\"fullwidth\">Hit</th>\n                </tr>\n            </thead>\n            <tbody id=\"tbody-table-top-queries\">\n                <tr>\n                    <td colspan=\"2\">\n                        <p class=\"mdl-typography--text-center\">\n                            <i class=\"material-icons loading\">refresh</i>\n                        </p>\n                    </td>\n                </tr>\n            </tbody>\n        </table>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Top advertisers\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card--expand\">\n        <table class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth\">\n            <thead>\n                <tr>\n                    <th class=\"mdl-data-table__cell--non-numeric fullwidth\">Domain</th>\n                    <th class=\"fullwidth\">Hit</th>\n                </tr>\n            </thead>\n            <tbody id=\"tbody-table-top-ads\">\n                <tr>\n                    <td colspan=\"2\">\n                        <p class=\"mdl-typography--text-center\">\n                            <i class=\"material-icons loading\">refresh</i>\n                        </p>\n                    </td>\n                </tr>\n            </tbody>\n        </table>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Top clients\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card--expand\">\n        <table class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth\">\n            <thead>\n                <tr>\n                    <th class=\"mdl-data-table__cell--non-numeric fullwidth\">Client</th>\n                    <th class=\"fullwidth\">Hit</th>\n                </tr>\n            </thead>\n            <tbody id=\"tbody-table-top-clients\">\n                <tr>\n                    <td colspan=\"2\">\n                        <p class=\"mdl-typography--text-center\">\n                            <i class=\"material-icons loading\">refresh</i>\n                        </p>\n                    </td>\n                </tr>\n            </tbody>\n            </tbody>\n        </table>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Recent items\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card--expand\">\n        <p class=\"please-rotate mdl-typography--text-center\">\n            <span class=\"mdl-chip mdl-chip--contact\">\n                <span class=\"mdl-chip__contact mdl-color--indigo mdl-color-text--white material-icons\">rotate_left</span>\n                <span class=\"mdl-chip__text\">Please rotate your device</span>\n            </span>\n        </p>\n        <table class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth force-landscape\">            \n            <thead>\n                <tr>\n                    <th class=\"mdl-data-table__cell--non-numeric fullwidth\">Time</th>\n                    <th>Domain</th>\n                    <th>IP</th>\n                </tr>\n            </thead>\n            <tbody id=\"tbody-table-recent-items\">\n                <tr>\n                    <td colspan=\"3\">\n                        <p class=\"mdl-typography--text-center\">\n                            <i class=\"material-icons loading\">refresh</i>\n                        </p>\n                    </td>\n                </tr>\n            </tbody>            \n        </table>\n    </div>    \n</div>"
  },
  {
    "path": "platforms/android/assets/www/partial/query-log.html",
    "content": "<p class=\"please-rotate mdl-typography--text-center\">\n    <span class=\"mdl-chip mdl-chip--contact\">\n        <span class=\"mdl-chip__contact mdl-color--indigo mdl-color-text--white material-icons\">rotate_left</span>\n        <span class=\"mdl-chip__text\">Please rotate your device</span>\n    </span>\n</p>\n\n<div class=\"force-landscape\">\n    <p class=\"mdl-typography--text-center\">\n        <span class=\"mdl-chip mdl-chip--contact mdl-please-wait\">\n            <span class=\"mdl-chip__contact mdl-color--indigo mdl-color-text--white\"><i class=\"material-icons loading\">refresh</i></span>\n            <span class=\"mdl-chip__text\">Please wait, there are a lot of data to be processed.</span>\n        </span>\n    </p>\n    \n    <table id=\"query-log-table\" class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth\" cellspacing=\"0\" width=\"100%\"></table>\n</div>"
  },
  {
    "path": "platforms/android/assets/www/plugins/cordova-plugin-splashscreen/www/splashscreen.js",
    "content": "cordova.define(\"cordova-plugin-splashscreen.SplashScreen\", function(require, exports, module) {\n/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nvar exec = require('cordova/exec');\n\nvar splashscreen = {\n    show:function() {\n        exec(null, null, \"SplashScreen\", \"show\", []);\n    },\n    hide:function() {\n        exec(null, null, \"SplashScreen\", \"hide\", []);\n    }\n};\n\nmodule.exports = splashscreen;\n\n});\n"
  },
  {
    "path": "platforms/android/assets/www/plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js",
    "content": "cordova.define(\"phonegap-plugin-barcodescanner.BarcodeScanner\", function(require, exports, module) {\n/**\n * cordova is available under *either* the terms of the modified BSD license *or* the\n * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.\n *\n * Copyright (c) Matt Kane 2010\n * Copyright (c) 2011, IBM Corporation\n */\n\n\n        var exec = cordova.require(\"cordova/exec\");\n\n        var scanInProgress = false;\n\n        /**\n         * Constructor.\n         *\n         * @returns {BarcodeScanner}\n         */\n        function BarcodeScanner() {\n\n            /**\n             * Encoding constants.\n             *\n             * @type Object\n             */\n            this.Encode = {\n                TEXT_TYPE: \"TEXT_TYPE\",\n                EMAIL_TYPE: \"EMAIL_TYPE\",\n                PHONE_TYPE: \"PHONE_TYPE\",\n                SMS_TYPE: \"SMS_TYPE\"\n                //  CONTACT_TYPE: \"CONTACT_TYPE\",  // TODO:  not implemented, requires passing a Bundle class from Javascript to Java\n                //  LOCATION_TYPE: \"LOCATION_TYPE\" // TODO:  not implemented, requires passing a Bundle class from Javascript to Java\n            };\n\n    /**\n     * Barcode format constants, defined in ZXing library.\n     *\n     * @type Object\n     */\n    this.format = {\n        \"all_1D\": 61918,\n        \"aztec\": 1,\n        \"codabar\": 2,\n        \"code_128\": 16,\n        \"code_39\": 4,\n        \"code_93\": 8,\n        \"data_MATRIX\": 32,\n        \"ean_13\": 128,\n        \"ean_8\": 64,\n        \"itf\": 256,\n        \"maxicode\": 512,\n        \"msi\": 131072,\n        \"pdf_417\": 1024,\n        \"plessey\": 262144,\n        \"qr_CODE\": 2048,\n        \"rss_14\": 4096,\n        \"rss_EXPANDED\": 8192,\n        \"upc_A\": 16384,\n        \"upc_E\": 32768,\n        \"upc_EAN_EXTENSION\": 65536\n        };\n  }\n\n/**\n * Read code from scanner.\n *\n * @param {Function} successCallback This function will recieve a result object: {\n         *        text : '12345-mock',    // The code that was scanned.\n         *        format : 'FORMAT_NAME', // Code format.\n         *        cancelled : true/false, // Was canceled.\n         *    }\n * @param {Function} errorCallback\n * @param config\n */\nBarcodeScanner.prototype.scan = function (successCallback, errorCallback, config) {\n\n            if (config instanceof Array) {\n                // do nothing\n            } else {\n                if (typeof(config) === 'object') {\n                    config = [ config ];\n                } else {\n                    config = [];\n                }\n            }\n\n            if (errorCallback == null) {\n                errorCallback = function () {\n                };\n            }\n\n            if (typeof errorCallback != \"function\") {\n                console.log(\"BarcodeScanner.scan failure: failure parameter not a function\");\n                return;\n            }\n\n            if (typeof successCallback != \"function\") {\n                console.log(\"BarcodeScanner.scan failure: success callback parameter must be a function\");\n                return;\n            }\n\n            if (scanInProgress) {\n                errorCallback('Scan is already in progress');\n                return;\n            }\n\n            scanInProgress = true;\n\n            exec(\n                function(result) {\n                    scanInProgress = false;\n                    successCallback(result);\n                },\n                function(error) {\n                    scanInProgress = false;\n                    errorCallback(error);\n                },\n                'BarcodeScanner',\n                'scan',\n                config\n            );\n        };\n\n        //-------------------------------------------------------------------\n        BarcodeScanner.prototype.encode = function (type, data, successCallback, errorCallback, options) {\n            if (errorCallback == null) {\n                errorCallback = function () {\n                };\n            }\n\n            if (typeof errorCallback != \"function\") {\n                console.log(\"BarcodeScanner.encode failure: failure parameter not a function\");\n                return;\n            }\n\n            if (typeof successCallback != \"function\") {\n                console.log(\"BarcodeScanner.encode failure: success callback parameter must be a function\");\n                return;\n            }\n\n            exec(successCallback, errorCallback, 'BarcodeScanner', 'encode', [\n                {\"type\": type, \"data\": data, \"options\": options}\n            ]);\n        };\n\n        var barcodeScanner = new BarcodeScanner();\n        module.exports = barcodeScanner;\n\n});\n"
  },
  {
    "path": "platforms/android/build.gradle",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\napply plugin: 'com.android.application'\n\nbuildscript {\n    repositories {\n        mavenCentral()\n        jcenter()\n    }\n\n    // Switch the Android Gradle plugin version requirement depending on the\n    // installed version of Gradle. This dependency is documented at\n    // http://tools.android.com/tech-docs/new-build-system/version-compatibility\n    // and https://issues.apache.org/jira/browse/CB-8143\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.2.3'\n    }\n}\n\n// Allow plugins to declare Maven dependencies via build-extras.gradle.\nallprojects {\n    repositories {\n        mavenCentral();\n        jcenter()\n    }\n}\n\ntask wrapper(type: Wrapper) {\n    gradleVersion = '2.14.1'\n}\n\n// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties.\n// Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html\next {\n    apply from: 'CordovaLib/cordova.gradle'\n    // The value for android.compileSdkVersion.\n    if (!project.hasProperty('cdvCompileSdkVersion')) {\n        cdvCompileSdkVersion = null;\n    }\n    // The value for android.buildToolsVersion.\n    if (!project.hasProperty('cdvBuildToolsVersion')) {\n        cdvBuildToolsVersion = null;\n    }\n    // Sets the versionCode to the given value.\n    if (!project.hasProperty('cdvVersionCode')) {\n        cdvVersionCode = null\n    }\n    // Sets the minSdkVersion to the given value.\n    if (!project.hasProperty('cdvMinSdkVersion')) {\n        cdvMinSdkVersion = null\n    }\n    // Whether to build architecture-specific APKs.\n    if (!project.hasProperty('cdvBuildMultipleApks')) {\n        cdvBuildMultipleApks = null\n    }\n    // .properties files to use for release signing.\n    if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) {\n        cdvReleaseSigningPropertiesFile = null\n    }\n    // .properties files to use for debug signing.\n    if (!project.hasProperty('cdvDebugSigningPropertiesFile')) {\n        cdvDebugSigningPropertiesFile = null\n    }\n    // Set by build.js script.\n    if (!project.hasProperty('cdvBuildArch')) {\n        cdvBuildArch = null\n    }\n\n    // Plugin gradle extensions can append to this to have code run at the end.\n    cdvPluginPostBuildExtras = []\n}\n\n// PLUGIN GRADLE EXTENSIONS START\napply from: \"phonegap-plugin-barcodescanner/piholedroid-barcodescanner.gradle\"\n// PLUGIN GRADLE EXTENSIONS END\n\ndef hasBuildExtras = file('build-extras.gradle').exists()\nif (hasBuildExtras) {\n    apply from: 'build-extras.gradle'\n}\n\n// Set property defaults after extension .gradle files.\nif (ext.cdvCompileSdkVersion == null) {\n    ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget()\n}\nif (ext.cdvBuildToolsVersion == null) {\n    ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()\n}\nif (ext.cdvDebugSigningPropertiesFile == null && file('debug-signing.properties').exists()) {\n    ext.cdvDebugSigningPropertiesFile = 'debug-signing.properties'\n}\nif (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.properties').exists()) {\n    ext.cdvReleaseSigningPropertiesFile = 'release-signing.properties'\n}\n\n// Cast to appropriate types.\next.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean();\next.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : Integer.parseInt('' + cdvMinSdkVersion)\next.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode)\n\ndef computeBuildTargetName(debugBuild) {\n    def ret = 'assemble'\n    if (cdvBuildMultipleApks && cdvBuildArch) {\n        def arch = cdvBuildArch == 'arm' ? 'armv7' : cdvBuildArch\n        ret += '' + arch.toUpperCase().charAt(0) + arch.substring(1);\n    }\n    return ret + (debugBuild ? 'Debug' : 'Release')\n}\n\n// Make cdvBuild a task that depends on the debug/arch-sepecific task.\ntask cdvBuildDebug\ncdvBuildDebug.dependsOn {\n    return computeBuildTargetName(true)\n}\n\ntask cdvBuildRelease\ncdvBuildRelease.dependsOn {\n    return computeBuildTargetName(false)\n}\n\ntask cdvPrintProps << {\n    println('cdvCompileSdkVersion=' + cdvCompileSdkVersion)\n    println('cdvBuildToolsVersion=' + cdvBuildToolsVersion)\n    println('cdvVersionCode=' + cdvVersionCode)\n    println('cdvMinSdkVersion=' + cdvMinSdkVersion)\n    println('cdvBuildMultipleApks=' + cdvBuildMultipleApks)\n    println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile)\n    println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile)\n    println('cdvBuildArch=' + cdvBuildArch)\n    println('computedVersionCode=' + android.defaultConfig.versionCode)\n    android.productFlavors.each { flavor ->\n        println('computed' + flavor.name.capitalize() + 'VersionCode=' + flavor.versionCode)\n    }\n}\n\nandroid {\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['src']\n            aidl.srcDirs = ['src']\n            renderscript.srcDirs = ['src']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n            jniLibs.srcDirs = ['libs']\n        }\n    }\n\n    defaultConfig {\n        versionCode 10005\n        versionName '1.0.5'\n        applicationId privateHelpers.extractStringFromManifest(\"package\")\n\n        if (cdvMinSdkVersion != null) {\n            minSdkVersion cdvMinSdkVersion\n        }\n    }\n\n    lintOptions {\n      abortOnError false;\n    }\n\n    compileSdkVersion cdvCompileSdkVersion\n    buildToolsVersion cdvBuildToolsVersion\n\n    if (Boolean.valueOf(cdvBuildMultipleApks)) {\n        productFlavors {\n            armv7 {\n                versionCode defaultConfig.versionCode*10 + 2\n                ndk {\n                    abiFilters \"armeabi-v7a\", \"\"\n                }\n            }\n            x86 {\n                versionCode defaultConfig.versionCode*10 + 4\n                ndk {\n                    abiFilters \"x86\", \"\"\n                }\n            }\n            all {\n                ndk {\n                    abiFilters \"all\", \"\"\n                }\n            }\n        }\n    }\n    /*\n\n    ELSE NOTHING! DON'T MESS WITH THE VERSION CODE IF YOU DON'T HAVE TO!\n\n    else if (!cdvVersionCode) {\n      def minSdkVersion = cdvMinSdkVersion ?: privateHelpers.extractIntFromManifest(\"minSdkVersion\")\n      // Vary versionCode by the two most common API levels:\n      // 14 is ICS, which is the lowest API level for many apps.\n      // 20 is Lollipop, which is the lowest API level for the updatable system webview.\n      if (minSdkVersion >= 20) {\n        defaultConfig.versionCode += 9\n      } else if (minSdkVersion >= 14) {\n        defaultConfig.versionCode += 8\n      }\n    }\n    */\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_6\n        targetCompatibility JavaVersion.VERSION_1_6\n    }\n\n    if (cdvReleaseSigningPropertiesFile) {\n        signingConfigs {\n            release {\n                // These must be set or Gradle will complain (even if they are overridden).\n                keyAlias = \"\"\n                keyPassword = \"__unset\" // And these must be set to non-empty in order to have the signing step added to the task graph.\n                storeFile = null\n                storePassword = \"__unset\"\n            }\n        }\n        buildTypes {\n            release {\n                signingConfig signingConfigs.release\n            }\n        }\n        addSigningProps(cdvReleaseSigningPropertiesFile, signingConfigs.release)\n    }\n    if (cdvDebugSigningPropertiesFile) {\n        addSigningProps(cdvDebugSigningPropertiesFile, signingConfigs.debug)\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: '*.jar')\n    // SUB-PROJECT DEPENDENCIES START\n    debugCompile(project(path: \"CordovaLib\", configuration: \"debug\"))\n    releaseCompile(project(path: \"CordovaLib\", configuration: \"release\"))\n    // SUB-PROJECT DEPENDENCIES END\n}\n\ndef promptForReleaseKeyPassword() {\n    if (!cdvReleaseSigningPropertiesFile) {\n        return;\n    }\n    if ('__unset'.equals(android.signingConfigs.release.storePassword)) {\n        android.signingConfigs.release.storePassword = privateHelpers.promptForPassword('Enter key store password: ')\n    }\n    if ('__unset'.equals(android.signingConfigs.release.keyPassword)) {\n        android.signingConfigs.release.keyPassword = privateHelpers.promptForPassword('Enter key password: ');\n    }\n}\n\ngradle.taskGraph.whenReady { taskGraph ->\n    taskGraph.getAllTasks().each() { task ->\n        if (task.name == 'validateReleaseSigning' || task.name == 'validateSigningRelease') {\n            promptForReleaseKeyPassword()\n        }\n    }\n}\n\ndef addSigningProps(propsFilePath, signingConfig) {\n    def propsFile = file(propsFilePath)\n    def props = new Properties()\n    propsFile.withReader { reader ->\n        props.load(reader)\n    }\n\n    def storeFile = new File(props.get('key.store') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile'))\n    if (!storeFile.isAbsolute()) {\n        storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile())\n    }\n    if (!storeFile.exists()) {\n        throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath())\n    }\n    signingConfig.keyAlias = props.get('key.alias') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias')\n    signingConfig.keyPassword = props.get('keyPassword', props.get('key.alias.password', signingConfig.keyPassword))\n    signingConfig.storeFile = storeFile\n    signingConfig.storePassword = props.get('storePassword', props.get('key.store.password', signingConfig.storePassword))\n    def storeType = props.get('storeType', props.get('key.store.type', ''))\n    if (!storeType) {\n        def filename = storeFile.getName().toLowerCase();\n        if (filename.endsWith('.p12') || filename.endsWith('.pfx')) {\n            storeType = 'pkcs12'\n        } else {\n            storeType = signingConfig.storeType // \"jks\"\n        }\n    }\n    signingConfig.storeType = storeType\n}\n\nfor (def func : cdvPluginPostBuildExtras) {\n    func()\n}\n\n// This can be defined within build-extras.gradle as:\n//     ext.postBuildExtras = { ... code here ... }\nif (hasProperty('postBuildExtras')) {\n    postBuildExtras()\n}\n"
  },
  {
    "path": "platforms/android/cordova/.jshintrc",
    "content": "{\n    \"node\": true\n  , \"bitwise\": true\n  , \"undef\": true\n  , \"trailing\": true\n  , \"quotmark\": true\n  , \"indent\": 4\n  , \"unused\": \"vars\"\n  , \"latedef\": \"nofunc\"\n}\n"
  },
  {
    "path": "platforms/android/cordova/Api.js",
    "content": "/**\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n*/\n\nvar path = require('path');\nvar Q = require('q');\n\nvar AndroidProject = require('./lib/AndroidProject');\nvar AndroidStudio = require('./lib/AndroidStudio');\nvar PluginManager = require('cordova-common').PluginManager;\n\nvar CordovaLogger = require('cordova-common').CordovaLogger;\nvar selfEvents = require('cordova-common').events;\n\nvar PLATFORM = 'android';\n\n\nfunction setupEvents(externalEventEmitter) {\n    if (externalEventEmitter) {\n        // This will make the platform internal events visible outside\n        selfEvents.forwardEventsTo(externalEventEmitter);\n        return externalEventEmitter;\n    }\n\n    // There is no logger if external emitter is not present,\n    // so attach a console logger\n    CordovaLogger.get().subscribe(selfEvents);\n    return selfEvents;\n}\n\n\n/**\n * Class, that acts as abstraction over particular platform. Encapsulates the\n *   platform's properties and methods.\n *\n * Platform that implements own PlatformApi instance _should implement all\n *   prototype methods_ of this class to be fully compatible with cordova-lib.\n *\n * The PlatformApi instance also should define the following field:\n *\n * * platform: String that defines a platform name.\n */\nfunction Api(platform, platformRootDir, events) {\n    this.platform = PLATFORM;\n    this.root = path.resolve(__dirname, '..');\n\n    setupEvents(events);\n\n    var self = this;\n\n    this.locations = {\n        root: self.root,\n        www: path.join(self.root, 'assets/www'),\n        res: path.join(self.root, 'res'),\n        platformWww: path.join(self.root, 'platform_www'),\n        configXml: path.join(self.root, 'res/xml/config.xml'),\n        defaultConfigXml: path.join(self.root, 'cordova/defaults.xml'),\n        strings: path.join(self.root, 'res/values/strings.xml'),\n        manifest: path.join(self.root, 'AndroidManifest.xml'),\n        build: path.join(self.root, 'build'),\n        // NOTE: Due to platformApi spec we need to return relative paths here\n        cordovaJs: 'bin/templates/project/assets/www/cordova.js',\n        cordovaJsSrc: 'cordova-js-src'\n    };\n\n    // XXX Override some locations for Android Studio projects\n    if(AndroidStudio.isAndroidStudioProject(self.root) === true) {\n      selfEvents.emit('log', 'Android Studio project detected');\n      this.android_studio = true;\n      this.locations.configXml = path.join(self.root, 'app/src/main/res/xml/config.xml');\n      this.locations.strings = path.join(self.root, 'app/src/main/res/xml/strings.xml');\n      this.locations.manifest = path.join(self.root, 'app/src/main/AndroidManifest.xml');\n      this.locations.www = path.join(self.root, 'app/src/main/assets/www');\n      this.locations.res = path.join(self.root, 'app/src/main/res');\n    }\n}\n\n/**\n * Installs platform to specified directory and creates a platform project.\n *\n * @param  {String}  destination Destination directory, where insatll platform to\n * @param  {ConfigParser}  [config] ConfgiParser instance, used to retrieve\n *   project creation options, such as package id and project name.\n * @param  {Object}  [options]  An options object. The most common options are:\n * @param  {String}  [options.customTemplate]  A path to custom template, that\n *   should override the default one from platform.\n * @param  {Boolean}  [options.link]  Flag that indicates that platform's\n *   sources will be linked to installed platform instead of copying.\n * @param {EventEmitter} [events] An EventEmitter instance that will be used for\n *   logging purposes. If no EventEmitter provided, all events will be logged to\n *   console\n *\n * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi\n *   instance or rejected with CordovaError.\n */\nApi.createPlatform = function (destination, config, options, events) {\n    events = setupEvents(events);\n    var result;\n    try {\n        result = require('../../lib/create')\n        .create(destination, config, options, events)\n        .then(function (destination) {\n            var PlatformApi = require(path.resolve(destination, 'cordova/Api'));\n            return new PlatformApi(PLATFORM, destination, events);\n        });\n    }\n    catch (e) {\n        events.emit('error','createPlatform is not callable from the android project API.');\n        throw(e);\n    }\n    return result;\n};\n\n/**\n * Updates already installed platform.\n *\n * @param  {String}  destination Destination directory, where platform installed\n * @param  {Object}  [options]  An options object. The most common options are:\n * @param  {String}  [options.customTemplate]  A path to custom template, that\n *   should override the default one from platform.\n * @param  {Boolean}  [options.link]  Flag that indicates that platform's\n *   sources will be linked to installed platform instead of copying.\n * @param {EventEmitter} [events] An EventEmitter instance that will be used for\n *   logging purposes. If no EventEmitter provided, all events will be logged to\n *   console\n *\n * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi\n *   instance or rejected with CordovaError.\n */\nApi.updatePlatform = function (destination, options, events) {\n    events = setupEvents(events);\n    var result;\n    try {\n        result = require('../../lib/create')\n        .update(destination, options, events)\n        .then(function (destination) {\n            var PlatformApi = require(path.resolve(destination, 'cordova/Api'));\n            return new PlatformApi('android', destination, events);\n        });\n    }\n    catch (e) {\n        events.emit('error','updatePlatform is not callable from the android project API, you will need to do this manually.');\n        throw(e);\n    }\n    return result;\n};\n\n/**\n * Gets a CordovaPlatform object, that represents the platform structure.\n *\n * @return  {CordovaPlatform}  A structure that contains the description of\n *   platform's file structure and other properties of platform.\n */\nApi.prototype.getPlatformInfo = function () {\n    var result = {};\n    result.locations = this.locations;\n    result.root = this.root;\n    result.name = this.platform;\n    result.version = require('./version');\n    result.projectConfig = this._config;\n\n    return result;\n};\n\n/**\n * Updates installed platform with provided www assets and new app\n *   configuration. This method is required for CLI workflow and will be called\n *   each time before build, so the changes, made to app configuration and www\n *   code, will be applied to platform.\n *\n * @param {CordovaProject} cordovaProject A CordovaProject instance, that defines a\n *   project structure and configuration, that should be applied to platform\n *   (contains project's www location and ConfigParser instance for project's\n *   config).\n *\n * @return  {Promise}  Return a promise either fulfilled, or rejected with\n *   CordovaError instance.\n */\nApi.prototype.prepare = function (cordovaProject, prepareOptions) {\n    return require('./lib/prepare').prepare.call(this, cordovaProject, prepareOptions);\n};\n\n/**\n * Installs a new plugin into platform. This method only copies non-www files\n *   (sources, libs, etc.) to platform. It also doesn't resolves the\n *   dependencies of plugin. Both of handling of www files, such as assets and\n *   js-files and resolving dependencies are the responsibility of caller.\n *\n * @param  {PluginInfo}  plugin  A PluginInfo instance that represents plugin\n *   that will be installed.\n * @param  {Object}  installOptions  An options object. Possible options below:\n * @param  {Boolean}  installOptions.link: Flag that specifies that plugin\n *   sources will be symlinked to app's directory instead of copying (if\n *   possible).\n * @param  {Object}  installOptions.variables  An object that represents\n *   variables that will be used to install plugin. See more details on plugin\n *   variables in documentation:\n *   https://cordova.apache.org/docs/en/4.0.0/plugin_ref_spec.md.html\n *\n * @return  {Promise}  Return a promise either fulfilled, or rejected with\n *   CordovaError instance.\n */\nApi.prototype.addPlugin = function (plugin, installOptions) {\n    var project = AndroidProject.getProjectFile(this.root);\n    var self = this;\n\n    installOptions = installOptions || {};\n    installOptions.variables = installOptions.variables || {};\n    // Add PACKAGE_NAME variable into vars\n    if (!installOptions.variables.PACKAGE_NAME) {\n        installOptions.variables.PACKAGE_NAME = project.getPackageName();\n    }\n\n    if(this.android_studio === true) {\n      installOptions.android_studio = true;\n    }\n\n    return Q()\n       .then(function () {\n            //CB-11964: Do a clean when installing the plugin code to get around\n            //the Gradle bug introduced by the Android Gradle Plugin Version 2.2\n            //TODO: Delete when the next version of Android Gradle plugin comes out\n\n           // Since clean doesn't just clean the build, it also wipes out www, we need\n           // to pass additional options.\n\n           // Do some basic argument parsing\n            var opts = {};\n\n             // Skip cleaning prepared files when not invoking via cordova CLI.\n            opts.noPrepare = true;\n\n            if(!AndroidStudio.isAndroidStudioProject(self.root) && !project.isClean()) {\n              return self.clean(opts);\n            }\n        })\n       .then(function () {\n            return PluginManager.get(self.platform, self.locations, project)\n                .addPlugin(plugin, installOptions);\n        })\n      .then(function () {\n            if (plugin.getFrameworks(this.platform).length === 0) return;\n\n            selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');\n            require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles();\n        }.bind(this))\n       // CB-11022 Return truthy value to prevent running prepare after\n        .thenResolve(true);\n};\n\n/**\n * Removes an installed plugin from platform.\n *\n * Since method accepts PluginInfo instance as input parameter instead of plugin\n *   id, caller shoud take care of managing/storing PluginInfo instances for\n *   future uninstalls.\n *\n * @param  {PluginInfo}  plugin  A PluginInfo instance that represents plugin\n *   that will be installed.\n *\n * @return  {Promise}  Return a promise either fulfilled, or rejected with\n *   CordovaError instance.\n */\nApi.prototype.removePlugin = function (plugin, uninstallOptions) {\n    var project = AndroidProject.getProjectFile(this.root);\n\n    if(uninstallOptions && uninstallOptions.usePlatformWww === true && this.android_studio === true) {\n      uninstallOptions.usePlatformWww = false;\n      uninstallOptions.android_studio = true;\n    }\n\n    return PluginManager.get(this.platform, this.locations, project)\n        .removePlugin(plugin, uninstallOptions)\n        .then(function () {\n            if (plugin.getFrameworks(this.platform).length === 0) return;\n\n            selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');\n            require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles();\n        }.bind(this))\n        // CB-11022 Return truthy value to prevent running prepare after\n        .thenResolve(true);\n};\n\n/**\n * Builds an application package for current platform.\n *\n * @param  {Object}  buildOptions  A build options. This object's structure is\n *   highly depends on platform's specific. The most common options are:\n * @param  {Boolean}  buildOptions.debug  Indicates that packages should be\n *   built with debug configuration. This is set to true by default unless the\n *   'release' option is not specified.\n * @param  {Boolean}  buildOptions.release  Indicates that packages should be\n *   built with release configuration. If not set to true, debug configuration\n *   will be used.\n * @param   {Boolean}  buildOptions.device  Specifies that built app is intended\n *   to run on device\n * @param   {Boolean}  buildOptions.emulator: Specifies that built app is\n *   intended to run on emulator\n * @param   {String}  buildOptions.target  Specifies the device id that will be\n *   used to run built application.\n * @param   {Boolean}  buildOptions.nobuild  Indicates that this should be a\n *   dry-run call, so no build artifacts will be produced.\n * @param   {String[]}  buildOptions.archs  Specifies chip architectures which\n *   app packages should be built for. List of valid architectures is depends on\n *   platform.\n * @param   {String}  buildOptions.buildConfig  The path to build configuration\n *   file. The format of this file is depends on platform.\n * @param   {String[]} buildOptions.argv Raw array of command-line arguments,\n *   passed to `build` command. The purpose of this property is to pass a\n *   platform-specific arguments, and eventually let platform define own\n *   arguments processing logic.\n *\n * @return {Promise<Object[]>} A promise either fulfilled with an array of build\n *   artifacts (application packages) if package was built successfully,\n *   or rejected with CordovaError. The resultant build artifact objects is not\n *   strictly typed and may conatin arbitrary set of fields as in sample below.\n *\n *     {\n *         architecture: 'x86',\n *         buildType: 'debug',\n *         path: '/path/to/build',\n *         type: 'app'\n *     }\n *\n * The return value in most cases will contain only one item but in some cases\n *   there could be multiple items in output array, e.g. when multiple\n *   arhcitectures is specified.\n */\nApi.prototype.build = function (buildOptions) {\n    var self = this;\n    return require('./lib/check_reqs').run()\n    .then(function () {\n        return require('./lib/build').run.call(self, buildOptions);\n    })\n    .then(function (buildResults) {\n        // Cast build result to array of build artifacts\n        return buildResults.apkPaths.map(function (apkPath) {\n            return {\n                buildType: buildResults.buildType,\n                buildMethod: buildResults.buildMethod,\n                path: apkPath,\n                type: 'apk'\n            };\n        });\n    });\n};\n\n/**\n * Builds an application package for current platform and runs it on\n *   specified/default device. If no 'device'/'emulator'/'target' options are\n *   specified, then tries to run app on default device if connected, otherwise\n *   runs the app on emulator.\n *\n * @param   {Object}  runOptions  An options object. The structure is the same\n *   as for build options.\n *\n * @return {Promise} A promise either fulfilled if package was built and ran\n *   successfully, or rejected with CordovaError.\n */\nApi.prototype.run = function(runOptions) {\n    var self = this;\n    return require('./lib/check_reqs').run()\n    .then(function () {\n        return require('./lib/run').run.call(self, runOptions);\n    });\n};\n\n/**\n * Cleans out the build artifacts from platform's directory, and also\n * cleans out the platform www directory if called without options specified.\n *\n * @return  {Promise}  Return a promise either fulfilled, or rejected with\n *   CordovaError.\n */\nApi.prototype.clean = function(cleanOptions) {\n    var self = this;\n    return require('./lib/check_reqs').run()\n      .then(function () {\n          return require('./lib/build').runClean.call(self, cleanOptions);\n      })\n      .then(function () {\n          return require('./lib/prepare').clean.call(self, cleanOptions);\n      });\n};\n\n\n\n/**\n * Performs a requirements check for current platform. Each platform defines its\n *   own set of requirements, which should be resolved before platform can be\n *   built successfully.\n *\n * @return  {Promise<Requirement[]>}  Promise, resolved with set of Requirement\n *   objects for current platform.\n */\nApi.prototype.requirements = function() {\n    return require('./lib/check_reqs').check_all();\n};\n\nmodule.exports = Api;\n"
  },
  {
    "path": "platforms/android/cordova/android_sdk_version",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar android_sdk = require('./lib/android_sdk');\n\nandroid_sdk.print_newest_available_sdk_target().done(null, function(err) {\n    console.error(err);\n    process.exit(2);\n});\n\n\n"
  },
  {
    "path": "platforms/android/cordova/android_sdk_version.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n:: \n:: http://www.apache.org/licenses/LICENSE-2.0\n:: \n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0android_sdk_version\"\nIF EXIST %script_path% (\n        node \"%script_path%\" %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'android_sdk_version' script in 'bin' folder, aborting...>&2\n    EXIT /B 1\n)\n"
  },
  {
    "path": "platforms/android/cordova/build",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar args  = process.argv;\nvar Api = require('./Api');\nvar nopt = require('nopt');\nvar path = require('path');\n\n// Support basic help commands\nif(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0)\n    require('./lib/build').help();\n\n// Do some basic argument parsing\nvar buildOpts = nopt({\n    'verbose' : Boolean,\n    'silent' : Boolean,\n    'debug' : Boolean,\n    'release' : Boolean,\n    'nobuild': Boolean,\n    'buildConfig' : path\n}, { 'd' : '--verbose' });\n\n// Make buildOptions compatible with PlatformApi build method spec\nbuildOpts.argv = buildOpts.argv.original;\n\nrequire('./loggingHelper').adjustLoggerLevel(buildOpts);\n\nnew Api().build(buildOpts)\n.catch(function(err) {\n    console.error(err.stack);\n    process.exit(2);\n});\n"
  },
  {
    "path": "platforms/android/cordova/build.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n::\n:: http://www.apache.org/licenses/LICENSE-2.0\n::\n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0build\"\nIF EXIST %script_path% (\n        node %script_path% %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'build' script in 'cordova' folder, aborting...>&2\n    EXIT /B 1\n)"
  },
  {
    "path": "platforms/android/cordova/check_reqs",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar check_reqs = require('./lib/check_reqs');\n\ncheck_reqs.run().done(\n    function success() {\n        console.log('Looks like your environment fully supports cordova-android development!');\n    }, function fail(err) {\n        console.log(err);\n        process.exit(2);\n    }\n);\n"
  },
  {
    "path": "platforms/android/cordova/check_reqs.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n:: \n:: http://www.apache.org/licenses/LICENSE-2.0\n:: \n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0check_reqs\"\nIF EXIST %script_path% (\n        node \"%script_path%\" %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'check_reqs' script in 'bin' folder, aborting...>&2\n    EXIT /B 1\n)\n"
  },
  {
    "path": "platforms/android/cordova/clean",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar Api = require('./Api');\nvar path  = require('path');\nvar nopt = require('nopt');\n\n// Support basic help commands\nif(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) {\n    console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]));\n    console.log('Cleans the project directory.');\n    process.exit(0);\n}\n\n// Do some basic argument parsing\nvar opts = nopt({\n    'verbose' : Boolean,\n    'silent' : Boolean\n}, { 'd' : '--verbose' });\n\n// Make buildOptions compatible with PlatformApi clean method spec\nopts.argv = opts.argv.original;\n\n// Skip cleaning prepared files when not invoking via cordova CLI.\nopts.noPrepare = true;\n\nrequire('./loggingHelper').adjustLoggerLevel(opts);\n\nnew Api().clean(opts)\n.catch(function(err) {\n    console.error(err.stack);\n    process.exit(2);\n});\n"
  },
  {
    "path": "platforms/android/cordova/clean.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n::\n:: http://www.apache.org/licenses/LICENSE-2.0\n::\n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0clean\"\nIF EXIST %script_path% (\n        node %script_path% %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'clean' script in 'cordova' folder, aborting...>&2\n    EXIT /B 1\n)"
  },
  {
    "path": "platforms/android/cordova/defaults.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n Licensed to the Apache Software Foundation (ASF) under one\n or more contributor license agreements.  See the NOTICE file\n distributed with this work for additional information\n regarding copyright ownership.  The ASF licenses this file\n to you under the Apache License, Version 2.0 (the\n \"License\"); you may not use this file except in compliance\n with the License.  You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing,\n software distributed under the License is distributed on an\n \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n KIND, either express or implied.  See the License for the\n specific language governing permissions and limitations\n under the License.\n-->\n<widget xmlns     = \"http://www.w3.org/ns/widgets\"\n        id        = \"io.cordova.helloCordova\"\n        version   = \"2.0.0\">\n\n    <!-- Preferences for Android -->\n    <preference name=\"loglevel\" value=\"DEBUG\" />\n</widget>\n"
  },
  {
    "path": "platforms/android/cordova/lib/Adb.js",
    "content": "/**\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n*/\n\nvar Q = require('q');\nvar os = require('os');\nvar events = require('cordova-common').events;\nvar spawn = require('cordova-common').superspawn.spawn;\nvar CordovaError = require('cordova-common').CordovaError;\n\nvar Adb = {};\n\nfunction isDevice(line) {\n    return line.match(/\\w+\\tdevice/) && !line.match(/emulator/);\n}\n\nfunction isEmulator(line) {\n    return line.match(/device/) && line.match(/emulator/);\n}\n\n/**\n * Lists available/connected devices and emulators\n *\n * @param   {Object}   opts            Various options\n * @param   {Boolean}  opts.emulators  Specifies whether this method returns\n *   emulators only\n *\n * @return  {Promise<String[]>}        list of available/connected\n *   devices/emulators\n */\nAdb.devices = function (opts) {\n    return spawn('adb', ['devices'], {cwd: os.tmpdir()})\n    .then(function(output) {\n        return output.split('\\n').filter(function (line) {\n            // Filter out either real devices or emulators, depending on options\n            return (line && opts && opts.emulators) ? isEmulator(line) : isDevice(line);\n        }).map(function (line) {\n            return line.replace(/\\tdevice/, '').replace('\\r', '');\n        });\n    });\n};\n\nAdb.install = function (target, packagePath, opts) {\n    events.emit('verbose', 'Installing apk ' + packagePath + ' on target ' + target + '...');\n    var args = ['-s', target, 'install'];\n    if (opts && opts.replace) args.push('-r');\n    return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()})\n    .then(function(output) {\n        // 'adb install' seems to always returns no error, even if installation fails\n        // so we catching output to detect installation failure\n        if (output.match(/Failure/)) {\n            if (output.match(/INSTALL_PARSE_FAILED_NO_CERTIFICATES/)) {\n                output += '\\n\\n' + 'Sign the build using \\'-- --keystore\\' or \\'--buildConfig\\'' +\n                    ' or sign and deploy the unsigned apk manually using Android tools.';\n            } else if (output.match(/INSTALL_FAILED_VERSION_DOWNGRADE/)) {\n                output += '\\n\\n' + 'You\\'re trying to install apk with a lower versionCode that is already installed.' +\n                    '\\nEither uninstall an app or increment the versionCode.';\n            }\n\n            return Q.reject(new CordovaError('Failed to install apk to device: ' + output));\n        }\n    });\n};\n\nAdb.uninstall = function (target, packageId) {\n    events.emit('verbose', 'Uninstalling package ' + packageId + ' from target ' + target + '...');\n    return spawn('adb', ['-s', target, 'uninstall', packageId], {cwd: os.tmpdir()});\n};\n\nAdb.shell = function (target, shellCommand) {\n    events.emit('verbose', 'Running adb shell command \"' + shellCommand + '\" on target ' + target + '...');\n    var args = ['-s', target, 'shell'];\n    shellCommand = shellCommand.split(/\\s+/);\n    return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()})\n    .catch(function (output) {\n        return Q.reject(new CordovaError('Failed to execute shell command \"' +\n            shellCommand + '\"\" on device: ' + output));\n    });\n};\n\nAdb.start = function (target, activityName) {\n    events.emit('verbose', 'Starting application \"' + activityName + '\" on target ' + target + '...');\n    return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName)\n    .catch(function (output) {\n        return Q.reject(new CordovaError('Failed to start application \"' +\n            activityName + '\"\" on device: ' + output));\n    });\n};\n\nmodule.exports = Adb;\n"
  },
  {
    "path": "platforms/android/cordova/lib/AndroidManifest.js",
    "content": "/**\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n*/\n\nvar fs = require('fs');\nvar et = require('elementtree');\nvar xml= require('cordova-common').xmlHelpers;\n\nvar DEFAULT_ORIENTATION = 'default';\n\n/** Wraps an AndroidManifest file */\nfunction AndroidManifest(path) {\n    this.path = path;\n    this.doc = xml.parseElementtreeSync(path);\n    if (this.doc.getroot().tag !== 'manifest') {\n        throw new Error('AndroidManifest at ' + path + ' has incorrect root node name (expected \"manifest\")');\n    }\n}\n\nAndroidManifest.prototype.getVersionName = function() {\n    return this.doc.getroot().attrib['android:versionName'];\n};\n\nAndroidManifest.prototype.setVersionName = function(versionName) {\n    this.doc.getroot().attrib['android:versionName'] = versionName;\n    return this;\n};\n\nAndroidManifest.prototype.getVersionCode = function() {\n    return this.doc.getroot().attrib['android:versionCode'];\n};\n\nAndroidManifest.prototype.setVersionCode = function(versionCode) {\n    this.doc.getroot().attrib['android:versionCode'] = versionCode;\n    return this;\n};\n\nAndroidManifest.prototype.getPackageId = function() {\n    /*jshint -W069 */\n    return this.doc.getroot().attrib['package'];\n    /*jshint +W069 */\n};\n\nAndroidManifest.prototype.setPackageId = function(pkgId) {\n    /*jshint -W069 */\n    this.doc.getroot().attrib['package'] = pkgId;\n    /*jshint +W069 */\n    return this;\n};\n\nAndroidManifest.prototype.getActivity = function() {\n    var activity = this.doc.getroot().find('./application/activity');\n    return {\n        getName: function () {\n            return activity.attrib['android:name'];\n        },\n        setName: function (name) {\n            if (!name) {\n                delete activity.attrib['android:name'];\n            } else {\n                activity.attrib['android:name'] = name;\n            }\n            return this;\n        },\n        getOrientation: function () {\n            return activity.attrib['android:screenOrientation'];\n        },\n        setOrientation: function (orientation) {\n            if (!orientation || orientation.toLowerCase() === DEFAULT_ORIENTATION) {\n                delete activity.attrib['android:screenOrientation'];\n            } else {\n                activity.attrib['android:screenOrientation'] = orientation;\n            }\n            return this;\n        },\n        getLaunchMode: function () {\n            return activity.attrib['android:launchMode'];\n        },\n        setLaunchMode: function (launchMode) {\n            if (!launchMode) {\n                delete activity.attrib['android:launchMode'];\n            } else {\n                activity.attrib['android:launchMode'] = launchMode;\n            }\n            return this;\n        }\n    };\n};\n\n['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion']\n.forEach(function(sdkPrefName) {\n    // Copy variable reference to avoid closure issues\n    var prefName = sdkPrefName;\n\n    AndroidManifest.prototype['get' + capitalize(prefName)] = function() {\n        var usesSdk = this.doc.getroot().find('./uses-sdk');\n        return usesSdk && usesSdk.attrib['android:' + prefName];\n    };\n\n    AndroidManifest.prototype['set' + capitalize(prefName)] = function(prefValue) {\n        var usesSdk = this.doc.getroot().find('./uses-sdk');\n\n        if (!usesSdk && prefValue) { // if there is no required uses-sdk element, we should create it first\n            usesSdk = new et.Element('uses-sdk');\n            this.doc.getroot().append(usesSdk);\n        }\n\n        if (prefValue) {\n            usesSdk.attrib['android:' + prefName] = prefValue;\n        }\n\n        return this;\n    };\n});\n\nAndroidManifest.prototype.getDebuggable = function() {\n    return this.doc.getroot().find('./application').attrib['android:debuggable'] === 'true';\n};\n\nAndroidManifest.prototype.setDebuggable = function(value) {\n    var application = this.doc.getroot().find('./application');\n    if (value) {\n        application.attrib['android:debuggable'] = 'true';\n    } else {\n        // The default value is \"false\", so we can remove attribute at all.\n        delete application.attrib['android:debuggable'];\n    }\n    return this;\n};\n\n/**\n * Writes manifest to disk syncronously. If filename is specified, then manifest\n *   will be written to that file\n *\n * @param   {String}  [destPath]  File to write manifest to. If omitted,\n *   manifest will be written to file it has been read from.\n */\nAndroidManifest.prototype.write = function(destPath) {\n    fs.writeFileSync(destPath || this.path, this.doc.write({indent: 4}), 'utf-8');\n};\n\nmodule.exports = AndroidManifest;\n\nfunction capitalize (str) {\n    return str.charAt(0).toUpperCase() + str.slice(1);\n}\n"
  },
  {
    "path": "platforms/android/cordova/lib/AndroidProject.js",
    "content": "/**\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n*/\n\nvar fs = require('fs');\nvar path = require('path');\nvar properties_parser = require('properties-parser');\nvar AndroidManifest = require('./AndroidManifest');\nvar AndroidStudio = require('./AndroidStudio');\nvar pluginHandlers = require('./pluginHandlers');\n\nvar projectFileCache = {};\n\nfunction addToPropertyList(projectProperties, key, value) {\n    var i = 1;\n    while (projectProperties.get(key + '.' + i))\n        i++;\n\n    projectProperties.set(key + '.' + i, value);\n    projectProperties.dirty = true;\n}\n\nfunction removeFromPropertyList(projectProperties, key, value) {\n    var i = 1;\n    var currentValue;\n    while ((currentValue = projectProperties.get(key + '.' + i))) {\n        if (currentValue === value) {\n            while ((currentValue = projectProperties.get(key + '.' + (i + 1)))) {\n                projectProperties.set(key + '.' + i, currentValue);\n                i++;\n            }\n            projectProperties.set(key + '.' + i);\n            break;\n        }\n        i++;\n    }\n    projectProperties.dirty = true;\n}\n\nfunction getRelativeLibraryPath (parentDir, subDir) {\n    var libraryPath = path.relative(parentDir, subDir);\n    return (path.sep == '\\\\') ? libraryPath.replace(/\\\\/g, '/') : libraryPath;\n}\n\nfunction AndroidProject(projectDir) {\n    this._propertiesEditors = {};\n    this._subProjectDirs = {};\n    this._dirty = false;\n    this.projectDir = projectDir;\n    this.platformWww = path.join(this.projectDir, 'platform_www');\n    this.www = path.join(this.projectDir, 'assets/www');\n    if(AndroidStudio.isAndroidStudioProject(projectDir) === true) {\n      this.www = path.join(this.projectDir, 'app/src/main/assets/www');\n    }\n}\n\nAndroidProject.getProjectFile = function (projectDir) {\n    if (!projectFileCache[projectDir]) {\n        projectFileCache[projectDir] = new AndroidProject(projectDir);\n    }\n\n    return projectFileCache[projectDir];\n};\n\nAndroidProject.purgeCache = function (projectDir) {\n    if (projectDir) {\n        delete projectFileCache[projectDir];\n    } else {\n        projectFileCache = {};\n    }\n};\n\n/**\n * Reads the package name out of the Android Manifest file\n *\n * @param   {String}  projectDir  The absolute path to the directory containing the project\n *\n * @return  {String}              The name of the package\n */\nAndroidProject.prototype.getPackageName = function() {\n    var manifestPath = path.join(this.projectDir, 'AndroidManifest.xml');\n    if(AndroidStudio.isAndroidStudioProject(this.projectDir) === true) {\n      manifestPath = path.join(this.projectDir, 'app/src/main/AndroidManifest.xml');\n    }\n    return new AndroidManifest(manifestPath).getPackageId();\n};\n\nAndroidProject.prototype.getCustomSubprojectRelativeDir = function(plugin_id, src) {\n    // All custom subprojects are prefixed with the last portion of the package id.\n    // This is to avoid collisions when opening multiple projects in Eclipse that have subprojects with the same name.\n    var packageName = this.getPackageName();\n    var lastDotIndex = packageName.lastIndexOf('.');\n    var prefix = packageName.substring(lastDotIndex + 1);\n    var subRelativeDir = path.join(plugin_id, prefix + '-' + path.basename(src));\n    return subRelativeDir;\n};\n\nAndroidProject.prototype.addSubProject = function(parentDir, subDir) {\n    var parentProjectFile = path.resolve(parentDir, 'project.properties');\n    var subProjectFile = path.resolve(subDir, 'project.properties');\n    var parentProperties = this._getPropertiesFile(parentProjectFile);\n    // TODO: Setting the target needs to happen only for pre-3.7.0 projects\n    if (fs.existsSync(subProjectFile)) {\n        var subProperties = this._getPropertiesFile(subProjectFile);\n        subProperties.set('target', parentProperties.get('target'));\n        subProperties.dirty = true;\n        this._subProjectDirs[subDir] = true;\n    }\n    addToPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));\n\n    this._dirty = true;\n};\n\nAndroidProject.prototype.removeSubProject = function(parentDir, subDir) {\n    var parentProjectFile = path.resolve(parentDir, 'project.properties');\n    var parentProperties = this._getPropertiesFile(parentProjectFile);\n    removeFromPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));\n    delete this._subProjectDirs[subDir];\n    this._dirty = true;\n};\n\nAndroidProject.prototype.addGradleReference = function(parentDir, subDir) {\n    var parentProjectFile = path.resolve(parentDir, 'project.properties');\n    var parentProperties = this._getPropertiesFile(parentProjectFile);\n    addToPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));\n    this._dirty = true;\n};\n\nAndroidProject.prototype.removeGradleReference = function(parentDir, subDir) {\n    var parentProjectFile = path.resolve(parentDir, 'project.properties');\n    var parentProperties = this._getPropertiesFile(parentProjectFile);\n    removeFromPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));\n    this._dirty = true;\n};\n\nAndroidProject.prototype.addSystemLibrary = function(parentDir, value) {\n    var parentProjectFile = path.resolve(parentDir, 'project.properties');\n    var parentProperties = this._getPropertiesFile(parentProjectFile);\n    addToPropertyList(parentProperties, 'cordova.system.library', value);\n    this._dirty = true;\n};\n\nAndroidProject.prototype.removeSystemLibrary = function(parentDir, value) {\n    var parentProjectFile = path.resolve(parentDir, 'project.properties');\n    var parentProperties = this._getPropertiesFile(parentProjectFile);\n    removeFromPropertyList(parentProperties, 'cordova.system.library', value);\n    this._dirty = true;\n};\n\nAndroidProject.prototype.write = function() {\n    if (!this._dirty) {\n        return;\n    }\n    this._dirty = false;\n\n    for (var filename in this._propertiesEditors) {\n        var editor = this._propertiesEditors[filename];\n        if (editor.dirty) {\n            fs.writeFileSync(filename, editor.toString());\n            editor.dirty = false;\n        }\n    }\n};\n\nAndroidProject.prototype._getPropertiesFile = function (filename) {\n    if (!this._propertiesEditors[filename]) {\n        if (fs.existsSync(filename)) {\n            this._propertiesEditors[filename] = properties_parser.createEditor(filename);\n        } else {\n            this._propertiesEditors[filename] = properties_parser.createEditor();\n        }\n    }\n\n    return this._propertiesEditors[filename];\n};\n\nAndroidProject.prototype.getInstaller = function (type) {\n    return pluginHandlers.getInstaller(type);\n};\n\nAndroidProject.prototype.getUninstaller = function (type) {\n    return pluginHandlers.getUninstaller(type);\n};\n\n/*\n * This checks if an Android project is clean or has old build artifacts\n */\n\nAndroidProject.prototype.isClean = function() {\n    var build_path = path.join(this.projectDir, 'build');\n    //If the build directory doesn't exist, it's clean\n    return !(fs.existsSync(build_path));\n};\n\nmodule.exports = AndroidProject;\n"
  },
  {
    "path": "platforms/android/cordova/lib/AndroidStudio.js",
    "content": "/*\n *  This is a simple routine that checks if project is an Android Studio Project\n *\n *  @param {String} root Root folder of the project\n */\n\n/*jshint esnext: false */\n\nvar path = require('path');\nvar fs = require('fs');\nvar CordovaError = require('cordova-common').CordovaError;\n\nmodule.exports.isAndroidStudioProject = function isAndroidStudioProject(root) {\n    var eclipseFiles = ['AndroidManifest.xml', 'libs', 'res', 'project.properties', 'platform_www'];\n    var androidStudioFiles = ['app', 'gradle', 'app/src/main/res'];\n\n    // assume it is an AS project and not an Eclipse project\n    var isEclipse = false;\n    var isAS = true;\n\n    if(!fs.existsSync(root)) {\n        throw new CordovaError('AndroidStudio.js:inAndroidStudioProject root does not exist: ' + root);\n    }\n\n    // if any of the following exists, then we are not an ASProj\n    eclipseFiles.forEach(function(file) {\n        if(fs.existsSync(path.join(root, file))) {\n            isEclipse = true;\n        }\n    });\n\n    // if it is NOT an eclipse project, check that all required files exist\n    if(!isEclipse) {\n        androidStudioFiles.forEach(function(file){\n            if(!fs.existsSync(path.join(root, file))) {\n                console.log('missing file :: ' + file);\n                isAS = false;\n            }\n        });\n    }\n    return (!isEclipse && isAS);\n};\n"
  },
  {
    "path": "platforms/android/cordova/lib/android_sdk.js",
    "content": "\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar Q = require('q'),\n    superspawn = require('cordova-common').superspawn;\n\nvar suffix_number_regex = /(\\d+)$/;\n// Used for sorting Android targets, example strings to sort:\n//   android-19\n//   android-L\n//   Google Inc.:Google APIs:20\n//   Google Inc.:Glass Development Kit Preview:20\n// The idea is to sort based on largest \"suffix\" number - meaning the bigger\n// the number at the end, the more recent the target, the closer to the\n// start of the array.\nfunction sort_by_largest_numerical_suffix(a, b) {\n    var suffix_a = a.match(suffix_number_regex);\n    var suffix_b = b.match(suffix_number_regex);\n    if (suffix_a && suffix_b) {\n        // If the two targets being compared have suffixes, return less than\n        // zero, or greater than zero, based on which suffix is larger.\n        return (parseInt(suffix_a[1]) > parseInt(suffix_b[1]) ? -1 : 1);\n    } else {\n        // If no suffix numbers were detected, leave the order as-is between\n        // elements a and b.\n        return 0;\n    }\n}\n\nmodule.exports.print_newest_available_sdk_target = function() {\n    return module.exports.list_targets()\n    .then(function(targets) {\n        targets.sort(sort_by_largest_numerical_suffix);\n        console.log(targets[0]);\n    });\n};\n\nmodule.exports.version_string_to_api_level = {\n    '4.0': 14,\n    '4.0.3': 15,\n    '4.1': 16,\n    '4.2': 17,\n    '4.3': 18,\n    '4.4': 19,\n    '4.4W': 20,\n    '5.0': 21,\n    '5.1': 22,\n    '6.0': 23,\n    '7.0': 24,\n    '7.1.1': 25\n};\n\nmodule.exports.list_targets_with_android = function() {\n    return superspawn.spawn('android', ['list', 'targets'])\n    .then(function(stdout) {\n        var target_out = stdout.split('\\n');\n        var targets = [];\n        for (var i = target_out.length - 1; i >= 0; i--) {\n            if(target_out[i].match(/id:/)) {\n                targets.push(target_out[i].match(/\"(.+)\"/)[1]);\n            }\n        }\n        return targets;\n    });\n};\n\nmodule.exports.list_targets_with_sdkmanager = function() {\n    return superspawn.spawn('sdkmanager', ['--list'])\n    .then(function(stdout) {\n        var parsing_installed_packages = false;\n        var lines = stdout.split('\\n');\n        var targets = [];\n        for (var i = 0, l = lines.length; i < l; i++) {\n            var line = lines[i];\n            if (line.match(/Installed packages/)) {\n                parsing_installed_packages = true;\n            } else if (line.match(/Available Packages/) || line.match(/Available Updates/)) {\n                // we are done working through installed packages, exit\n                break;\n            }\n            if (parsing_installed_packages) {\n                // Match stock android platform\n                if (line.match(/platforms;android-\\d+/)) {\n                    targets.push(line.match(/(android-\\d+)/)[1]);\n                }\n                // Match Google APIs\n                if (line.match(/addon-google_apis-google-\\d+/)) {\n                    var description = lines[i + 1];\n                    // munge description to match output from old android sdk tooling\n                    var api_level = description.match(/Android (\\d+)/); //[1];\n                    if (api_level) {\n                        targets.push('Google Inc.:Google APIs:' + api_level[1]);\n                    }\n                }\n                // TODO: match anything else?\n            }\n        }\n        return targets;\n    });\n};\n\nmodule.exports.list_targets = function() {\n    return module.exports.list_targets_with_android()\n    .catch(function(err) {\n        // there's a chance `android` no longer works.\n        // lets see if `sdkmanager` is available and we can figure it out\n        var avail_regex = /\"?android\"? command is no longer available/;\n        if (err.code && ((err.stdout && err.stdout.match(avail_regex)) || (err.stderr && err.stderr.match(avail_regex)))) {\n            return module.exports.list_targets_with_sdkmanager();\n        } else throw err;\n    }).then(function(targets) {\n        if (targets.length === 0) {\n            return Q.reject(new Error('No android targets (SDKs) installed!'));\n        }\n        return targets;\n    });\n};\n"
  },
  {
    "path": "platforms/android/cordova/lib/build.js",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar Q       = require('q'),\n    path    = require('path'),\n    fs      = require('fs'),\n    nopt = require('nopt');\n\nvar Adb = require('./Adb');\n\nvar builders = require('./builders/builders');\nvar events = require('cordova-common').events;\nvar spawn = require('cordova-common').superspawn.spawn;\nvar CordovaError = require('cordova-common').CordovaError;\n\nfunction parseOpts(options, resolvedTarget, projectRoot) {\n    options = options || {};\n    options.argv = nopt({\n        gradle: Boolean,\n        ant: Boolean,\n        prepenv: Boolean,\n        versionCode: String,\n        minSdkVersion: String,\n        gradleArg: [String, Array],\n        keystore: path,\n        alias: String,\n        storePassword: String,\n        password: String,\n        keystoreType: String\n    }, {}, options.argv, 0);\n\n    var ret = {\n        buildType: options.release ? 'release' : 'debug',\n        buildMethod: process.env.ANDROID_BUILD || 'gradle',\n        prepEnv: options.argv.prepenv,\n        arch: resolvedTarget && resolvedTarget.arch,\n        extraArgs: []\n    };\n\n    if (options.argv.ant || options.argv.gradle)\n        ret.buildMethod = options.argv.ant ? 'ant' : 'gradle';\n\n    if (options.nobuild) ret.buildMethod = 'none';\n\n    if (options.argv.versionCode)\n        ret.extraArgs.push('-PcdvVersionCode=' + options.argv.versionCode);\n\n    if (options.argv.minSdkVersion)\n        ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion);\n\n    if (options.argv.gradleArg) {\n        ret.extraArgs = ret.extraArgs.concat(options.argv.gradleArg);\n    }\n\n    var packageArgs = {};\n\n    if (options.argv.keystore)\n        packageArgs.keystore = path.relative(projectRoot, path.resolve(options.argv.keystore));\n\n    ['alias','storePassword','password','keystoreType'].forEach(function (flagName) {\n        if (options.argv[flagName])\n            packageArgs[flagName] = options.argv[flagName];\n    });\n\n    var buildConfig = options.buildConfig;\n\n    // If some values are not specified as command line arguments - use build config to supplement them.\n    // Command line arguemnts have precedence over build config.\n    if (buildConfig) {\n        if (!fs.existsSync(buildConfig)) {\n            throw new Error('Specified build config file does not exist: ' + buildConfig);\n        }\n        events.emit('log', 'Reading build config file: '+ path.resolve(buildConfig));\n        var buildjson = fs.readFileSync(buildConfig, 'utf8');\n        var config = JSON.parse(buildjson.replace(/^\\ufeff/, '')); // Remove BOM\n        if (config.android && config.android[ret.buildType]) {\n            var androidInfo = config.android[ret.buildType];\n            if(androidInfo.keystore && !packageArgs.keystore) {\n                if(androidInfo.keystore.substr(0,1) === '~') {\n                    androidInfo.keystore = process.env.HOME + androidInfo.keystore.substr(1);\n                }\n                packageArgs.keystore = path.resolve(path.dirname(buildConfig), androidInfo.keystore);\n                events.emit('log', 'Reading the keystore from: ' + packageArgs.keystore);\n            }\n\n            ['alias', 'storePassword', 'password','keystoreType'].forEach(function (key){\n                packageArgs[key] = packageArgs[key] || androidInfo[key];\n            });\n        }\n    }\n\n    if (packageArgs.keystore && packageArgs.alias) {\n        ret.packageInfo = new PackageInfo(packageArgs.keystore, packageArgs.alias, packageArgs.storePassword,\n            packageArgs.password, packageArgs.keystoreType);\n    }\n\n    if(!ret.packageInfo) {\n        if(Object.keys(packageArgs).length > 0) {\n            events.emit('warn', '\\'keystore\\' and \\'alias\\' need to be specified to generate a signed archive.');\n        }\n    }\n\n    return ret;\n}\n\n/*\n * Builds the project with the specifed options\n * Returns a promise.\n */\nmodule.exports.runClean = function(options) {\n    var opts = parseOpts(options, null, this.root);\n    var builder = builders.getBuilder(opts.buildMethod);\n    return builder.prepEnv(opts)\n    .then(function() {\n        return builder.clean(opts);\n    });\n};\n\n/**\n * Builds the project with the specifed options.\n *\n * @param   {BuildOptions}  options      A set of options. See PlatformApi.build\n *   method documentation for reference.\n * @param   {Object}  optResolvedTarget  A deployment target. Used to pass\n *   target architecture from upstream 'run' call. TODO: remove this option in\n *   favor of setting buildOptions.archs field.\n *\n * @return  {Promise<Object>}            Promise, resolved with built packages\n *   information.\n */\nmodule.exports.run = function(options, optResolvedTarget) {\n    var opts = parseOpts(options, optResolvedTarget, this.root);\n    var builder = builders.getBuilder(opts.buildMethod);\n    return builder.prepEnv(opts)\n    .then(function() {\n        if (opts.prepEnv) {\n            events.emit('verbose', 'Build file successfully prepared.');\n            return;\n        }\n        return builder.build(opts)\n        .then(function() {\n            var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);\n            events.emit('log', 'Built the following apk(s): \\n\\t' + apkPaths.join('\\n\\t'));\n            return {\n                apkPaths: apkPaths,\n                buildType: opts.buildType,\n                buildMethod: opts.buildMethod\n            };\n        });\n    });\n};\n\n/*\n * Detects the architecture of a device/emulator\n * Returns \"arm\" or \"x86\".\n */\nmodule.exports.detectArchitecture = function(target) {\n    function helper() {\n        return Adb.shell(target, 'cat /proc/cpuinfo')\n        .then(function(output) {\n            return /intel/i.exec(output) ? 'x86' : 'arm';\n        });\n    }\n    // It sometimes happens (at least on OS X), that this command will hang forever.\n    // To fix it, either unplug & replug device, or restart adb server.\n    return helper()\n    .timeout(1000, new CordovaError('Device communication timed out. Try unplugging & replugging the device.'))\n    .then(null, function(err) {\n        if (/timed out/.exec('' + err)) {\n            // adb kill-server doesn't seem to do the trick.\n            // Could probably find a x-platform version of killall, but I'm not actually\n            // sure that this scenario even happens on non-OSX machines.\n            events.emit('verbose', 'adb timed out while detecting device/emulator architecture. Killing adb and trying again.');\n            return spawn('killall', ['adb'])\n            .then(function() {\n                return helper()\n                .then(null, function() {\n                    // The double kill is sadly often necessary, at least on mac.\n                    events.emit('warn', 'adb timed out a second time while detecting device/emulator architecture. Killing adb and trying again.');\n                    return spawn('killall', ['adb'])\n                    .then(function() {\n                        return helper()\n                        .then(null, function() {\n                            return Q.reject(new CordovaError('adb timed out a third time while detecting device/emulator architecture. Try unplugging & replugging the device.'));\n                        });\n                    });\n                });\n            }, function() {\n                // For non-killall OS's.\n                return Q.reject(err);\n            });\n        }\n        throw err;\n    });\n};\n\nmodule.exports.findBestApkForArchitecture = function(buildResults, arch) {\n    var paths = buildResults.apkPaths.filter(function(p) {\n        var apkName = path.basename(p);\n        if (buildResults.buildType == 'debug') {\n            return /-debug/.exec(apkName);\n        }\n        return !/-debug/.exec(apkName);\n    });\n    var archPattern = new RegExp('-' + arch);\n    var hasArchPattern = /-x86|-arm/;\n    for (var i = 0; i < paths.length; ++i) {\n        var apkName = path.basename(paths[i]);\n        if (hasArchPattern.exec(apkName)) {\n            if (archPattern.exec(apkName)) {\n                return paths[i];\n            }\n        } else {\n            return paths[i];\n        }\n    }\n    throw new Error('Could not find apk architecture: ' + arch + ' build-type: ' + buildResults.buildType);\n};\n\nfunction PackageInfo(keystore, alias, storePassword, password, keystoreType) {\n    this.keystore = {\n        'name': 'key.store',\n        'value': keystore\n    };\n    this.alias = {\n        'name': 'key.alias',\n        'value': alias\n    };\n    if (storePassword) {\n        this.storePassword = {\n            'name': 'key.store.password',\n            'value': storePassword\n        };\n    }\n    if (password) {\n        this.password = {\n            'name': 'key.alias.password',\n            'value': password\n        };\n    }\n    if (keystoreType) {\n        this.keystoreType = {\n            'name': 'key.store.type',\n            'value': keystoreType\n        };\n    }\n}\n\nPackageInfo.prototype = {\n    toProperties: function() {\n        var self = this;\n        var result = '';\n        Object.keys(self).forEach(function(key) {\n            result += self[key].name;\n            result += '=';\n            result += self[key].value.replace(/\\\\/g, '\\\\\\\\');\n            result += '\\n';\n        });\n        return result;\n    }\n};\n\nmodule.exports.help = function() {\n    console.log('Usage: ' + path.relative(process.cwd(), path.join('../build')) + ' [flags] [Signed APK flags]');\n    console.log('Flags:');\n    console.log('    \\'--debug\\': will build project in debug mode (default)');\n    console.log('    \\'--release\\': will build project for release');\n    console.log('    \\'--ant\\': will build project with ant');\n    console.log('    \\'--gradle\\': will build project with gradle (default)');\n    console.log('    \\'--nobuild\\': will skip build process (useful when using run command)');\n    console.log('    \\'--prepenv\\': don\\'t build, but copy in build scripts where necessary');\n    console.log('    \\'--versionCode=#\\': Override versionCode for this build. Useful for uploading multiple APKs. Requires --gradle.');\n    console.log('    \\'--minSdkVersion=#\\': Override minSdkVersion for this build. Useful for uploading multiple APKs. Requires --gradle.');\n    console.log('    \\'--gradleArg=<gradle command line arg>\\': Extra args to pass to the gradle command. Use one flag per arg. Ex. --gradleArg=-PcdvBuildMultipleApks=true');\n    console.log('');\n    console.log('Signed APK flags (overwrites debug/release-signing.proprties) :');\n    console.log('    \\'--keystore=<path to keystore>\\': Key store used to build a signed archive. (Required)');\n    console.log('    \\'--alias=\\': Alias for the key store. (Required)');\n    console.log('    \\'--storePassword=\\': Password for the key store. (Optional - prompted)');\n    console.log('    \\'--password=\\': Password for the key. (Optional - prompted)');\n    console.log('    \\'--keystoreType\\': Type of the keystore. (Optional)');\n    process.exit(0);\n};\n"
  },
  {
    "path": "platforms/android/cordova/lib/builders/AntBuilder.js",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar Q = require('q');\nvar fs = require('fs');\nvar path = require('path');\nvar util = require('util');\nvar shell = require('shelljs');\nvar spawn = require('cordova-common').superspawn.spawn;\nvar CordovaError = require('cordova-common').CordovaError;\nvar check_reqs = require('../check_reqs');\n\nvar SIGNING_PROPERTIES = '-signing.properties';\nvar MARKER = 'YOUR CHANGES WILL BE ERASED!';\nvar TEMPLATE =\n    '# This file is automatically generated.\\n' +\n    '# Do not modify this file -- ' + MARKER + '\\n';\n\nvar GenericBuilder = require('./GenericBuilder');\n\nfunction AntBuilder (projectRoot) {\n    GenericBuilder.call(this, projectRoot);\n\n    this.binDirs = {ant: this.binDirs.ant};\n}\n\nutil.inherits(AntBuilder, GenericBuilder);\n\nAntBuilder.prototype.getArgs = function(cmd, opts) {\n    var args = [cmd, '-f', path.join(this.root, 'build.xml')];\n    // custom_rules.xml is required for incremental builds.\n    if (hasCustomRules(this.root)) {\n        args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen');\n    }\n    if(opts.packageInfo) {\n        args.push('-propertyfile=' + path.join(this.root, opts.buildType + SIGNING_PROPERTIES));\n    }\n    return args;\n};\n\nAntBuilder.prototype.prepEnv = function(opts) {\n    var self = this;\n    return check_reqs.check_ant()\n    .then(function() {\n        // Copy in build.xml on each build so that:\n        // A) we don't require the Android SDK at project creation time, and\n        // B) we always use the SDK's latest version of it.\n        /*jshint -W069 */\n        var sdkDir = process.env['ANDROID_HOME'];\n        /*jshint +W069 */\n        var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');\n        function writeBuildXml(projectPath) {\n            var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest());\n            fs.writeFileSync(path.join(projectPath, 'build.xml'), newData);\n            if (!fs.existsSync(path.join(projectPath, 'local.properties'))) {\n                fs.writeFileSync(path.join(projectPath, 'local.properties'), TEMPLATE);\n            }\n        }\n        writeBuildXml(self.root);\n        var propertiesObj = self.readProjectProperties();\n        var subProjects = propertiesObj.libs;\n        for (var i = 0; i < subProjects.length; ++i) {\n            writeBuildXml(path.join(self.root, subProjects[i]));\n        }\n        if (propertiesObj.systemLibs.length > 0) {\n            throw new CordovaError('Project contains at least one plugin that requires a system library. This is not supported with ANT. Use gradle instead.');\n        }\n\n        var propertiesFile = opts.buildType + SIGNING_PROPERTIES;\n        var propertiesFilePath = path.join(self.root, propertiesFile);\n        if (opts.packageInfo) {\n            fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());\n        } else if(isAutoGenerated(propertiesFilePath)) {\n            shell.rm('-f', propertiesFilePath);\n        }\n    });\n};\n\n/*\n * Builds the project with ant.\n * Returns a promise.\n */\nAntBuilder.prototype.build = function(opts) {\n    // Without our custom_rules.xml, we need to clean before building.\n    var ret = Q();\n    if (!hasCustomRules(this.root)) {\n        // clean will call check_ant() for us.\n        ret = this.clean(opts);\n    }\n\n    var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);\n    return check_reqs.check_ant()\n    .then(function() {\n        return spawn('ant', args, {stdio: 'pipe'});\n    }).progress(function (stdio){\n        if (stdio.stderr) {\n            process.stderr.write(stdio.stderr);\n        } else {\n            process.stdout.write(stdio.stdout);\n        }\n    }).catch(function (error) {\n        if (error.toString().indexOf('Unable to resolve project target') >= 0) {\n            return check_reqs.check_android_target(error).then(function() {\n                // If due to some odd reason - check_android_target succeeds\n                // we should still fail here.\n                return Q.reject(error);\n            });\n        }\n        return Q.reject(error);\n    });\n};\n\nAntBuilder.prototype.clean = function(opts) {\n    var args = this.getArgs('clean', opts);\n    var self = this;\n    return check_reqs.check_ant()\n    .then(function() {\n        return spawn('ant', args, {stdio: 'inherit'});\n    })\n    .then(function () {\n        shell.rm('-rf', path.join(self.root, 'out'));\n\n        ['debug', 'release'].forEach(function(config) {\n            var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES);\n            if(isAutoGenerated(propertiesFilePath)){\n                shell.rm('-f', propertiesFilePath);\n            }\n        });\n    });\n};\n\nmodule.exports = AntBuilder;\n\nfunction hasCustomRules(projectRoot) {\n    return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));\n}\n\nfunction isAutoGenerated(file) {\n    return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;\n}\n"
  },
  {
    "path": "platforms/android/cordova/lib/builders/GenericBuilder.js",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar Q = require('q');\nvar fs = require('fs');\nvar path = require('path');\nvar shell = require('shelljs');\nvar events = require('cordova-common').events;\nvar CordovaError = require('cordova-common').CordovaError;\n\nfunction GenericBuilder (projectDir) {\n    this.root = projectDir || path.resolve(__dirname, '../../..');\n    this.binDirs = {\n        ant: path.join(this.root, hasCustomRules(this.root) ? 'ant-build' : 'bin'),\n        gradle: path.join(this.root, 'build', 'outputs', 'apk')\n    };\n}\n\nfunction hasCustomRules(projectRoot) {\n    return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));\n}\n\nGenericBuilder.prototype.prepEnv = function() {\n    return Q();\n};\n\nGenericBuilder.prototype.build = function() {\n    events.emit('log', 'Skipping build...');\n    return Q(null);\n};\n\nGenericBuilder.prototype.clean = function() {\n    return Q();\n};\n\nGenericBuilder.prototype.findOutputApks = function(build_type, arch) {\n    var self = this;\n    return Object.keys(this.binDirs)\n    .reduce(function (result, builderName) {\n        var binDir = self.binDirs[builderName];\n        return result.concat(findOutputApksHelper(binDir, build_type, builderName === 'ant' ? null : arch));\n    }, [])\n    .sort(apkSorter);\n};\n\nGenericBuilder.prototype.readProjectProperties = function () {\n    function findAllUniq(data, r) {\n        var s = {};\n        var m;\n        while ((m = r.exec(data))) {\n            s[m[1]] = 1;\n        }\n        return Object.keys(s);\n    }\n\n    var data = fs.readFileSync(path.join(this.root, 'project.properties'), 'utf8');\n    return {\n        libs: findAllUniq(data, /^\\s*android\\.library\\.reference\\.\\d+=(.*)(?:\\s|$)/mg),\n        gradleIncludes: findAllUniq(data, /^\\s*cordova\\.gradle\\.include\\.\\d+=(.*)(?:\\s|$)/mg),\n        systemLibs: findAllUniq(data, /^\\s*cordova\\.system\\.library\\.\\d+=(.*)(?:\\s|$)/mg)\n    };\n};\n\nGenericBuilder.prototype.extractRealProjectNameFromManifest = function () {\n    var manifestPath = path.join(this.root, 'AndroidManifest.xml');\n    var manifestData = fs.readFileSync(manifestPath, 'utf8');\n    var m = /<manifest[\\s\\S]*?package\\s*=\\s*\"(.*?)\"/i.exec(manifestData);\n    if (!m) {\n        throw new CordovaError('Could not find package name in ' + manifestPath);\n    }\n\n    var packageName=m[1];\n    var lastDotIndex = packageName.lastIndexOf('.');\n    return packageName.substring(lastDotIndex + 1);\n};\n\nmodule.exports = GenericBuilder;\n\nfunction apkSorter(fileA, fileB) {\n    // De-prioritize unsigned builds\n    var unsignedRE = /-unsigned/;\n    if (unsignedRE.exec(fileA)) {\n        return 1;\n    } else if (unsignedRE.exec(fileB)) {\n        return -1;\n    }\n\n    var timeDiff = fs.statSync(fileA).mtime - fs.statSync(fileB).mtime;\n    return timeDiff === 0 ? fileA.length - fileB.length : timeDiff;\n}\n\nfunction findOutputApksHelper(dir, build_type, arch) {\n    var shellSilent = shell.config.silent;\n    shell.config.silent = true;\n\n    var ret = shell.ls(path.join(dir, '*.apk'))\n    .filter(function(candidate) {\n        var apkName = path.basename(candidate);\n        // Need to choose between release and debug .apk.\n        if (build_type === 'debug') {\n            return /-debug/.exec(apkName) && !/-unaligned|-unsigned/.exec(apkName);\n        }\n        if (build_type === 'release') {\n            return /-release/.exec(apkName) && !/-unaligned/.exec(apkName);\n        }\n        return true;\n    })\n    .sort(apkSorter);\n\n    shellSilent = shellSilent;\n\n    if (ret.length === 0) {\n        return ret;\n    }\n    // Assume arch-specific build if newest apk has -x86 or -arm.\n    var archSpecific = !!/-x86|-arm/.exec(path.basename(ret[0]));\n    // And show only arch-specific ones (or non-arch-specific)\n    ret = ret.filter(function(p) {\n        /*jshint -W018 */\n        return !!/-x86|-arm/.exec(path.basename(p)) == archSpecific;\n        /*jshint +W018 */\n    });\n\n    if (archSpecific && ret.length > 1 && arch) {\n        ret = ret.filter(function(p) {\n            return path.basename(p).indexOf('-' + arch) != -1;\n        });\n    }\n\n    return ret;\n}\n"
  },
  {
    "path": "platforms/android/cordova/lib/builders/GradleBuilder.js",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar Q = require('q');\nvar fs = require('fs');\nvar util = require('util');\nvar path = require('path');\nvar shell = require('shelljs');\nvar spawn = require('cordova-common').superspawn.spawn;\nvar CordovaError = require('cordova-common').CordovaError;\nvar check_reqs = require('../check_reqs');\n\nvar GenericBuilder = require('./GenericBuilder');\n\nvar MARKER = 'YOUR CHANGES WILL BE ERASED!';\nvar SIGNING_PROPERTIES = '-signing.properties';\nvar TEMPLATE =\n    '# This file is automatically generated.\\n' +\n    '# Do not modify this file -- ' + MARKER + '\\n';\n\nfunction GradleBuilder (projectRoot) {\n    GenericBuilder.call(this, projectRoot);\n\n    this.binDirs = {gradle: this.binDirs.gradle};\n}\n\nutil.inherits(GradleBuilder, GenericBuilder);\n\nGradleBuilder.prototype.getArgs = function(cmd, opts) {\n    if (cmd == 'release') {\n        cmd = 'cdvBuildRelease';\n    } else if (cmd == 'debug') {\n        cmd = 'cdvBuildDebug';\n    }\n    var args = [cmd, '-b', path.join(this.root, 'build.gradle')];\n    if (opts.arch) {\n        args.push('-PcdvBuildArch=' + opts.arch);\n    }\n\n    // 10 seconds -> 6 seconds\n    args.push('-Dorg.gradle.daemon=true');\n    // to allow dex in process\n    args.push('-Dorg.gradle.jvmargs=-Xmx2048m');\n    // allow NDK to be used - required by Gradle 1.5 plugin\n    args.push('-Pandroid.useDeprecatedNdk=true');\n    args.push.apply(args, opts.extraArgs);\n    // Shaves another 100ms, but produces a \"try at own risk\" warning. Not worth it (yet):\n    // args.push('-Dorg.gradle.parallel=true');\n    return args;\n};\n\n/*\n * This returns a promise\n */\n\nGradleBuilder.prototype.runGradleWrapper = function(gradle_cmd) {\n    var gradlePath = path.join(this.root, 'gradlew');\n    var wrapperGradle = path.join(this.root, 'wrapper.gradle');\n    if(fs.existsSync(gradlePath)) {\n      //Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows\n    } else {\n      return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], {stdio: 'inherit'});\n    }\n};\n\n\n// Makes the project buildable, minus the gradle wrapper.\nGradleBuilder.prototype.prepBuildFiles = function() {\n    // Update the version of build.gradle in each dependent library.\n    var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');\n    var propertiesObj = this.readProjectProperties();\n    var subProjects = propertiesObj.libs;\n    var checkAndCopy = function(subProject, root) {\n      var subProjectGradle = path.join(root, subProject, 'build.gradle');\n      // This is the future-proof way of checking if a file exists\n      // This must be synchronous to satisfy a Travis test\n      try {\n          fs.accessSync(subProjectGradle, fs.F_OK);\n      } catch (e) {\n          shell.cp('-f', pluginBuildGradle, subProjectGradle);\n      }\n    };\n    for (var i = 0; i < subProjects.length; ++i) {\n        if (subProjects[i] !== 'CordovaLib') {\n          checkAndCopy(subProjects[i], this.root);\n        }\n    }\n    var name = this.extractRealProjectNameFromManifest();\n    //Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149\n    var settingsGradlePaths =  subProjects.map(function(p){\n        var realDir=p.replace(/[/\\\\]/g, ':');\n        var libName=realDir.replace(name+'-','');\n        var str='include \":'+libName+'\"\\n';\n        if(realDir.indexOf(name+'-')!==-1)\n            str+='project(\":'+libName+'\").projectDir = new File(\"'+p+'\")\\n';\n        return str;\n    });\n\n    // Write the settings.gradle file.\n    fs.writeFileSync(path.join(this.root, 'settings.gradle'),\n        '// GENERATED FILE - DO NOT EDIT\\n' +\n        'include \":\"\\n' + settingsGradlePaths.join(''));\n    // Update dependencies within build.gradle.\n    var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8');\n    var depsList = '';\n    var root = this.root;\n    var insertExclude = function(p) {\n          var gradlePath = path.join(root, p, 'build.gradle');\n          var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8');\n          if(projectGradleFile.indexOf('CordovaLib') != -1) {\n            depsList += '{\\n        exclude module:(\"CordovaLib\")\\n    }\\n';\n          }\n          else {\n            depsList +='\\n';\n          }\n    };\n    subProjects.forEach(function(p) {\n        console.log('Subproject Path: ' + p);\n        var libName=p.replace(/[/\\\\]/g, ':').replace(name+'-','');\n        depsList += '    debugCompile(project(path: \"' + libName + '\", configuration: \"debug\"))';\n        insertExclude(p);\n        depsList += '    releaseCompile(project(path: \"' + libName + '\", configuration: \"release\"))';\n        insertExclude(p);\n    });\n    // For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390\n    var SYSTEM_LIBRARY_MAPPINGS = [\n        [/^\\/?extras\\/android\\/support\\/(.*)$/, 'com.android.support:support-$1:+'],\n        [/^\\/?google\\/google_play_services\\/libproject\\/google-play-services_lib\\/?$/, 'com.google.android.gms:play-services:+']\n    ];\n    propertiesObj.systemLibs.forEach(function(p) {\n        var mavenRef;\n        // It's already in gradle form if it has two ':'s\n        if (/:.*:/.exec(p)) {\n            mavenRef = p;\n        } else {\n            for (var i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) {\n                var pair = SYSTEM_LIBRARY_MAPPINGS[i];\n                if (pair[0].exec(p)) {\n                    mavenRef = p.replace(pair[0], pair[1]);\n                    break;\n                }\n            }\n            if (!mavenRef) {\n                throw new CordovaError('Unsupported system library (does not work with gradle): ' + p);\n            }\n        }\n        depsList += '    compile \"' + mavenRef + '\"\\n';\n    });\n    buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\\s\\S]*(\\/\\/ SUB-PROJECT DEPENDENCIES END)/, '$1\\n' + depsList + '    $2');\n    var includeList = '';\n    propertiesObj.gradleIncludes.forEach(function(includePath) {\n        includeList += 'apply from: \"' + includePath + '\"\\n';\n    });\n    buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\\s\\S]*(\\/\\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\\n' + includeList + '$2');\n    fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle);\n};\n\nGradleBuilder.prototype.prepEnv = function(opts) {\n    var self = this;\n    return check_reqs.check_gradle()\n      .then(function(gradlePath) {\n        return self.runGradleWrapper(gradlePath);\n      }).then(function() {\n          return self.prepBuildFiles();\n      }).then(function() {\n        // We now copy the gradle out of the framework\n        // This is a dirty patch to get the build working\n        /*\n        var wrapperDir = path.join(self.root, 'CordovaLib');\n        if (process.platform == 'win32') {\n            shell.rm('-f', path.join(self.root, 'gradlew.bat'));\n            shell.cp(path.join(wrapperDir, 'gradlew.bat'), self.root);\n        } else {\n            shell.rm('-f', path.join(self.root, 'gradlew'));\n            shell.cp(path.join(wrapperDir, 'gradlew'), self.root);\n        }\n        shell.rm('-rf', path.join(self.root, 'gradle', 'wrapper'));\n        shell.mkdir('-p', path.join(self.root, 'gradle'));\n        shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(self.root, 'gradle'));\n*/\n        // If the gradle distribution URL is set, make sure it points to version we want.\n        // If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.\n        // For some reason, using ^ and $ don't work.  This does the job, though.\n        var distributionUrlRegex = /distributionUrl.*zip/;\n        /*jshint -W069 */\n        var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\\\://services.gradle.org/distributions/gradle-3.3-all.zip';\n        /*jshint +W069 */\n        var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');\n        shell.chmod('u+w', gradleWrapperPropertiesPath);\n        shell.sed('-i', distributionUrlRegex, 'distributionUrl='+distributionUrl, gradleWrapperPropertiesPath);\n\n        var propertiesFile = opts.buildType + SIGNING_PROPERTIES;\n        var propertiesFilePath = path.join(self.root, propertiesFile);\n        if (opts.packageInfo) {\n            fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());\n        } else if (isAutoGenerated(propertiesFilePath)) {\n            shell.rm('-f', propertiesFilePath);\n        }\n    });\n};\n\n/*\n * Builds the project with gradle.\n * Returns a promise.\n */\nGradleBuilder.prototype.build = function(opts) {\n    var wrapper = path.join(this.root, 'gradlew');\n    var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);\n\n    return spawn(wrapper, args, {stdio: 'pipe'})\n    .progress(function (stdio){\n        if (stdio.stderr) {\n            /*\n             * Workaround for the issue with Java printing some unwanted information to\n             * stderr instead of stdout.\n             * This function suppresses 'Picked up _JAVA_OPTIONS' message from being\n             * printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for\n             * explanation.\n             */\n            var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());\n            if (suppressThisLine) {\n                return;\n            }\n            process.stderr.write(stdio.stderr);\n        } else {\n            process.stdout.write(stdio.stdout);\n        }\n    }).catch(function (error) {\n        if (error.toString().indexOf('failed to find target with hash string') >= 0) {\n            return check_reqs.check_android_target(error).then(function() {\n                // If due to some odd reason - check_android_target succeeds\n                // we should still fail here.\n                return Q.reject(error);\n            });\n        }\n        return Q.reject(error);\n    });\n};\n\nGradleBuilder.prototype.clean = function(opts) {\n    var builder = this;\n    var wrapper = path.join(this.root, 'gradlew');\n    var args = builder.getArgs('clean', opts);\n    return Q().then(function() {\n        return spawn(wrapper, args, {stdio: 'inherit'});\n    })\n    .then(function () {\n        shell.rm('-rf', path.join(builder.root, 'out'));\n\n        ['debug', 'release'].forEach(function(config) {\n            var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES);\n            if(isAutoGenerated(propertiesFilePath)){\n                shell.rm('-f', propertiesFilePath);\n            }\n        });\n    });\n};\n\nmodule.exports = GradleBuilder;\n\nfunction isAutoGenerated(file) {\n    return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;\n}\n"
  },
  {
    "path": "platforms/android/cordova/lib/builders/builders.js",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar CordovaError = require('cordova-common').CordovaError;\n\nvar knownBuilders = {\n    ant: 'AntBuilder',\n    gradle: 'GradleBuilder',\n    none: 'GenericBuilder'\n};\n\n/**\n * Helper method that instantiates and returns a builder for specified build\n *   type.\n *\n * @param   {String}  builderType   Builder name to construct and return. Must\n *   be one of 'ant', 'gradle' or 'none'\n *\n * @return  {Builder}               A builder instance for specified build type.\n */\nmodule.exports.getBuilder = function (builderType, projectRoot) {\n    if (!knownBuilders[builderType])\n        throw new CordovaError('Builder ' + builderType + ' is not supported.');\n\n    try {\n        var Builder = require('./' + knownBuilders[builderType]);\n        return new Builder(projectRoot);\n    } catch (err) {\n        throw new CordovaError('Failed to instantiate ' + knownBuilders[builderType] + ' builder: ' + err);\n    }\n};\n"
  },
  {
    "path": "platforms/android/cordova/lib/check_reqs.js",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\n/* jshint sub:true */\n\nvar shelljs = require('shelljs'),\n    child_process = require('child_process'),\n    Q     = require('q'),\n    path  = require('path'),\n    fs    = require('fs'),\n    os    = require('os'),\n    REPO_ROOT  = path.join(__dirname, '..', '..', '..', '..'),\n    PROJECT_ROOT = path.join(__dirname, '..', '..');\nvar CordovaError = require('cordova-common').CordovaError;\nvar superspawn = require('cordova-common').superspawn;\nvar android_sdk = require('./android_sdk');\n\nfunction forgivingWhichSync(cmd) {\n    try {\n        return fs.realpathSync(shelljs.which(cmd));\n    } catch (e) {\n        return '';\n    }\n}\n\nfunction tryCommand(cmd, errMsg, catchStderr) {\n    var d = Q.defer();\n    child_process.exec(cmd, function(err, stdout, stderr) {\n        if (err) d.reject(new CordovaError(errMsg));\n        // Sometimes it is necessary to return an stderr instead of stdout in case of success, since\n        // some commands prints theirs output to stderr instead of stdout. 'javac' is the example\n        else d.resolve((catchStderr ? stderr : stdout).trim());\n    });\n    return d.promise;\n}\n\nmodule.exports.isWindows = function() {\n    return (os.platform() == 'win32');\n};\n\nmodule.exports.isDarwin = function() {\n    return (os.platform() == 'darwin');\n};\n\n// Get valid target from framework/project.properties if run from this repo\n// Otherwise get target from project.properties file within a generated cordova-android project\nmodule.exports.get_target = function() {\n    function extractFromFile(filePath) {\n        var target = shelljs.grep(/\\btarget=/, filePath);\n        if (!target) {\n            throw new Error('Could not find android target within: ' + filePath);\n        }\n        return target.split('=')[1].trim();\n    }\n    var repo_file = path.join(REPO_ROOT, 'framework', 'project.properties');\n    if (fs.existsSync(repo_file)) {\n        return extractFromFile(repo_file);\n    }\n    var project_file = path.join(PROJECT_ROOT, 'project.properties');\n    if (fs.existsSync(project_file)) {\n        // if no target found, we're probably in a project and project.properties is in PROJECT_ROOT.\n        return extractFromFile(project_file);\n    }\n    throw new Error('Could not find android target in either ' + repo_file + ' nor ' + project_file);\n};\n\n// Returns a promise. Called only by build and clean commands.\nmodule.exports.check_ant = function() {\n    return superspawn.spawn('ant', ['-version'])\n    .then(function(output) {\n        // Parse Ant version from command output\n        return /version ((?:\\d+\\.)+(?:\\d+))/i.exec(output)[1];\n    }).catch(function(err) {\n        throw new CordovaError('Failed to run `ant -version`. Make sure you have `ant` on your $PATH.');\n    });\n};\n\nmodule.exports.get_gradle_wrapper = function() {\n    var androidStudioPath;\n    var i = 0;\n    var foundStudio = false;\n    var program_dir;\n    if (module.exports.isDarwin()) {\n        program_dir = fs.readdirSync('/Applications');\n        while (i < program_dir.length && !foundStudio) {\n            if (program_dir[i].startsWith('Android Studio')) {\n                //TODO: Check for a specific Android Studio version, make sure it's not Canary\n                androidStudioPath = path.join('/Applications', program_dir[i], 'Contents', 'gradle');\n                foundStudio = true;\n            } else { ++i; }\n        }\n    } else if (module.exports.isWindows()) {\n        var androidPath = path.join(process.env['ProgramFiles'], 'Android') + '/';\n        if (fs.existsSync(androidPath)) {\n            program_dir = fs.readdirSync(androidPath);\n            while (i < program_dir.length && !foundStudio) {\n                if (program_dir[i].startsWith('Android Studio')) {\n                    foundStudio = true;\n                    androidStudioPath = path.join(process.env['ProgramFiles'], 'Android', program_dir[i], 'gradle');\n                } else { ++i; }\n            }\n        }\n    }\n\n    if (androidStudioPath !== null && fs.existsSync(androidStudioPath)) {\n        var dirs = fs.readdirSync(androidStudioPath);\n        if(dirs[0].split('-')[0] == 'gradle') {\n            return path.join(androidStudioPath, dirs[0], 'bin', 'gradle');\n        }\n    } else {\n        //OK, let's try to check for Gradle!\n        return forgivingWhichSync('gradle');\n    }\n};\n\n// Returns a promise. Called only by build and clean commands.\nmodule.exports.check_gradle = function() {\n    var sdkDir = process.env['ANDROID_HOME'];\n    var d = Q.defer();\n    if (!sdkDir)\n        return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.\\n' +\n            'Might need to install Android SDK or set up \\'ANDROID_HOME\\' env variable.'));\n\n    var gradlePath = module.exports.get_gradle_wrapper();\n    if (gradlePath.length !== 0)\n        d.resolve(gradlePath);\n    else\n        d.reject(new CordovaError('Could not find an installed version of Gradle either in Android Studio,\\n' +\n                                'or on your system to install the gradle wrapper. Please include gradle \\n' +\n                                'in your path, or install Android Studio'));\n    return d.promise;\n};\n\n// Returns a promise.\nmodule.exports.check_java = function() {\n    var javacPath = forgivingWhichSync('javac');\n    var hasJavaHome = !!process.env['JAVA_HOME'];\n    return Q().then(function() {\n        if (hasJavaHome) {\n            // Windows java installer doesn't add javac to PATH, nor set JAVA_HOME (ugh).\n            if (!javacPath) {\n                process.env['PATH'] += path.delimiter + path.join(process.env['JAVA_HOME'], 'bin');\n            }\n        } else {\n            if (javacPath) {\n                // OS X has a command for finding JAVA_HOME.\n                var find_java = '/usr/libexec/java_home';\n                var default_java_error_msg = 'Failed to find \\'JAVA_HOME\\' environment variable. Try setting setting it manually.';\n                if (fs.existsSync(find_java)) {\n                    return superspawn.spawn(find_java)\n                    .then(function(stdout) {\n                        process.env['JAVA_HOME'] = stdout.trim();\n                    }).catch(function(err) {\n                        throw new CordovaError(default_java_error_msg);\n                    });\n                } else {\n                    // See if we can derive it from javac's location.\n                    // fs.realpathSync is require on Ubuntu, which symplinks from /usr/bin -> JDK\n                    var maybeJavaHome = path.dirname(path.dirname(javacPath));\n                    if (fs.existsSync(path.join(maybeJavaHome, 'lib', 'tools.jar'))) {\n                        process.env['JAVA_HOME'] = maybeJavaHome;\n                    } else {\n                        throw new CordovaError(default_java_error_msg);\n                    }\n                }\n            } else if (module.exports.isWindows()) {\n                // Try to auto-detect java in the default install paths.\n                var oldSilent = shelljs.config.silent;\n                shelljs.config.silent = true;\n                var firstJdkDir =\n                    shelljs.ls(process.env['ProgramFiles'] + '\\\\java\\\\jdk*')[0] ||\n                    shelljs.ls('C:\\\\Program Files\\\\java\\\\jdk*')[0] ||\n                    shelljs.ls('C:\\\\Program Files (x86)\\\\java\\\\jdk*')[0];\n                shelljs.config.silent = oldSilent;\n                if (firstJdkDir) {\n                    // shelljs always uses / in paths.\n                    firstJdkDir = firstJdkDir.replace(/\\//g, path.sep);\n                    if (!javacPath) {\n                        process.env['PATH'] += path.delimiter + path.join(firstJdkDir, 'bin');\n                    }\n                    process.env['JAVA_HOME'] = firstJdkDir;\n                }\n            }\n        }\n    }).then(function() {\n        var msg =\n            'Failed to run \"javac -version\", make sure that you have a JDK installed.\\n' +\n            'You can get it from: http://www.oracle.com/technetwork/java/javase/downloads.\\n';\n        if (process.env['JAVA_HOME']) {\n            msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'] + '\\n';\n        }\n        // We use tryCommand with catchStderr = true, because\n        // javac writes version info to stderr instead of stdout\n        return tryCommand('javac -version', msg, true)\n        .then(function (output) {\n            //Let's check for at least Java 8, and keep it future proof so we can support Java 10\n            var match = /javac ((?:1\\.)(?:[8-9]\\.)(?:\\d+))|((?:1\\.)(?:[1-9]\\d+\\.)(?:\\d+))/i.exec(output);\n            return match && match[1];\n        });\n    });\n};\n\n// Returns a promise.\nmodule.exports.check_android = function() {\n    return Q().then(function() {\n        var androidCmdPath = forgivingWhichSync('android');\n        var adbInPath = forgivingWhichSync('adb');\n        var avdmanagerInPath = forgivingWhichSync('avdmanager');\n        var hasAndroidHome = !!process.env['ANDROID_HOME'] && fs.existsSync(process.env['ANDROID_HOME']);\n        function maybeSetAndroidHome(value) {\n            if (!hasAndroidHome && fs.existsSync(value)) {\n                hasAndroidHome = true;\n                process.env['ANDROID_HOME'] = value;\n            }\n        }\n        // First ensure ANDROID_HOME is set\n        // If we have no hints (nothing in PATH), try a few default locations\n        if (!hasAndroidHome && !androidCmdPath && !adbInPath && !avdmanagerInPath) {\n            if (module.exports.isWindows()) {\n                // Android Studio 1.0 installer\n                maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'sdk'));\n                maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'sdk'));\n                // Android Studio pre-1.0 installer\n                maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'android-studio', 'sdk'));\n                maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'android-studio', 'sdk'));\n                // Stand-alone installer\n                maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'android-sdk'));\n                maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'android-sdk'));\n            } else if (module.exports.isDarwin()) {\n                // Android Studio 1.0 installer\n                maybeSetAndroidHome(path.join(process.env['HOME'], 'Library', 'Android', 'sdk'));\n                // Android Studio pre-1.0 installer\n                maybeSetAndroidHome('/Applications/Android Studio.app/sdk');\n                // Stand-alone zip file that user might think to put under /Applications\n                maybeSetAndroidHome('/Applications/android-sdk-macosx');\n                maybeSetAndroidHome('/Applications/android-sdk');\n            }\n            if (process.env['HOME']) {\n                // Stand-alone zip file that user might think to put under their home directory\n                maybeSetAndroidHome(path.join(process.env['HOME'], 'android-sdk-macosx'));\n                maybeSetAndroidHome(path.join(process.env['HOME'], 'android-sdk'));\n            }\n        }\n        if (!hasAndroidHome) {\n            // If we dont have ANDROID_HOME, but we do have some tools on the PATH, try to infer from the tooling PATH.\n            var parentDir, grandParentDir;\n            if (androidCmdPath) {\n                parentDir = path.dirname(androidCmdPath);\n                grandParentDir = path.dirname(parentDir);\n                if (path.basename(parentDir) == 'tools' || fs.existsSync(path.join(grandParentDir, 'tools', 'android'))) {\n                    maybeSetAndroidHome(grandParentDir);\n                } else {\n                    throw new CordovaError('Failed to find \\'ANDROID_HOME\\' environment variable. Try setting setting it manually.\\n' +\n                        'Detected \\'android\\' command at ' + parentDir + ' but no \\'tools\\' directory found near.\\n' +\n                        'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'tools directory.');\n                }\n            }\n            if (adbInPath) {\n                parentDir = path.dirname(adbInPath);\n                grandParentDir = path.dirname(parentDir);\n                if (path.basename(parentDir) == 'platform-tools') {\n                    maybeSetAndroidHome(grandParentDir);\n                } else {\n                    throw new CordovaError('Failed to find \\'ANDROID_HOME\\' environment variable. Try setting setting it manually.\\n' +\n                        'Detected \\'adb\\' command at ' + parentDir + ' but no \\'platform-tools\\' directory found near.\\n' +\n                        'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'platform-tools directory.');\n                }\n            }\n            if (avdmanagerInPath) {\n                parentDir = path.dirname(avdmanagerInPath);\n                grandParentDir = path.dirname(parentDir);\n                if (path.basename(parentDir) == 'bin' && path.basename(grandParentDir) == 'tools') {\n                    maybeSetAndroidHome(path.dirname(grandParentDir));\n                } else {\n                    throw new CordovaError('Failed to find \\'ANDROID_HOME\\' environment variable. Try setting setting it manually.\\n' +\n                        'Detected \\'avdmanager\\' command at ' + parentDir + ' but no \\'tools' + path.sep + 'bin\\' directory found near.\\n' +\n                        'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'tools' + path.sep + 'bin directory.');\n                }\n            }\n        }\n        if (!process.env['ANDROID_HOME']) {\n            throw new CordovaError('Failed to find \\'ANDROID_HOME\\' environment variable. Try setting setting it manually.\\n' +\n                'Failed to find \\'android\\' command in your \\'PATH\\'. Try update your \\'PATH\\' to include path to valid SDK directory.');\n        }\n        if (!fs.existsSync(process.env['ANDROID_HOME'])) {\n            throw new CordovaError('\\'ANDROID_HOME\\' environment variable is set to non-existent path: ' + process.env['ANDROID_HOME'] +\n                '\\nTry update it manually to point to valid SDK directory.');\n        }\n        // Next let's make sure relevant parts of the SDK tooling is in our PATH\n        if (hasAndroidHome && !androidCmdPath) {\n            process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools');\n        }\n        if (hasAndroidHome && !adbInPath) {\n            process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'platform-tools');\n        }\n        if (hasAndroidHome && !avdmanagerInPath) {\n            process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools', 'bin');\n        }\n        return hasAndroidHome;\n    });\n};\n\n// TODO: is this actually needed?\nmodule.exports.getAbsoluteAndroidCmd = function () {\n    var cmd = forgivingWhichSync('android');\n    if (cmd.length === 0) {\n        cmd = forgivingWhichSync('sdkmanager');\n    }\n    if (module.exports.isWindows()) {\n        return '\"' + cmd + '\"';\n    }\n    return cmd.replace(/(\\s)/g, '\\\\$1');\n};\n\nmodule.exports.check_android_target = function(originalError) {\n    // valid_target can look like:\n    //   android-19\n    //   android-L\n    //   Google Inc.:Google APIs:20\n    //   Google Inc.:Glass Development Kit Preview:20\n    var desired_api_level = module.exports.get_target();\n    return android_sdk.list_targets()\n    .then(function(targets) {\n        if (targets.indexOf(desired_api_level) >= 0) {\n            return targets;\n        }\n        var androidCmd = module.exports.getAbsoluteAndroidCmd();\n        var msg = 'Please install Android target / API level: \"' + desired_api_level  + '\".\\n\\n' +\n            'Hint: Open the SDK manager by running: ' + androidCmd + '\\n' +\n            'You will require:\\n' +\n            '1. \"SDK Platform\" for API level ' + desired_api_level + '\\n' +\n            '2. \"Android SDK Platform-tools (latest)\\n' +\n            '3. \"Android SDK Build-tools\" (latest)';\n        if (originalError) {\n            msg = originalError + '\\n' + msg;\n        }\n        throw new CordovaError(msg);\n    });\n};\n\n// Returns a promise.\nmodule.exports.run = function() {\n     return Q.all([this.check_java(), this.check_android()])\n     .then(function(values) {\n         console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']);\n         console.log('JAVA_HOME=' + process.env['JAVA_HOME']);\n\n         if (!values[0]) {\n            throw new CordovaError('Requirements check failed for JDK 1.8 or greater');\n         }\n\n         if (!values[1]) {\n            throw new CordovaError('Requirements check failed for Android SDK');\n         }\n     });\n};\n\n\n/**\n * Object thar represents one of requirements for current platform.\n * @param {String} id         The unique identifier for this requirements.\n * @param {String} name       The name of requirements. Human-readable field.\n * @param {String} version    The version of requirement installed. In some cases could be an array of strings\n *                            (for example, check_android_target returns an array of android targets installed)\n * @param {Boolean} installed Indicates whether the requirement is installed or not\n */\nvar Requirement = function (id, name, version, installed) {\n    this.id = id;\n    this.name = name;\n    this.installed = installed || false;\n    this.metadata = {\n        version: version,\n    };\n};\n\n/**\n * Methods that runs all checks one by one and returns a result of checks\n * as an array of Requirement objects. This method intended to be used by cordova-lib check_reqs method\n *\n * @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled.\n */\nmodule.exports.check_all = function() {\n\n    var requirements = [\n        new Requirement('java', 'Java JDK'),\n        new Requirement('androidSdk', 'Android SDK'),\n        new Requirement('androidTarget', 'Android target'),\n        new Requirement('gradle', 'Gradle')\n    ];\n\n    var checkFns = [\n        this.check_java,\n        this.check_android,\n        this.check_android_target,\n        this.check_gradle\n    ];\n\n    // Then execute requirement checks one-by-one\n    return checkFns.reduce(function (promise, checkFn, idx) {\n        // Update each requirement with results\n        var requirement = requirements[idx];\n        return promise.then(checkFn)\n        .then(function (version) {\n            requirement.installed = true;\n            requirement.metadata.version = version;\n        }, function (err) {\n            requirement.metadata.reason = err instanceof Error ? err.message : err;\n        });\n    }, Q())\n    .then(function () {\n        // When chain is completed, return requirements array to upstream API\n        return requirements;\n    });\n};\n"
  },
  {
    "path": "platforms/android/cordova/lib/device.js",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar Q     = require('q'),\n    build = require('./build');\nvar path = require('path');\nvar Adb = require('./Adb');\nvar AndroidManifest = require('./AndroidManifest');\nvar spawn = require('cordova-common').superspawn.spawn;\nvar CordovaError = require('cordova-common').CordovaError;\nvar events = require('cordova-common').events;\n\n/**\n * Returns a promise for the list of the device ID's found\n * @param lookHarder When true, try restarting adb if no devices are found.\n */\nmodule.exports.list = function(lookHarder) {\n    return Adb.devices()\n    .then(function(list) {\n        if (list.length === 0 && lookHarder) {\n            // adb kill-server doesn't seem to do the trick.\n            // Could probably find a x-platform version of killall, but I'm not actually\n            // sure that this scenario even happens on non-OSX machines.\n            return spawn('killall', ['adb'])\n            .then(function() {\n                events.emit('verbose', 'Restarting adb to see if more devices are detected.');\n                return Adb.devices();\n            }, function() {\n                // For non-killall OS's.\n                return list;\n            });\n        }\n        return list;\n    });\n};\n\nmodule.exports.resolveTarget = function(target) {\n    return this.list(true)\n    .then(function(device_list) {\n        if (!device_list || !device_list.length) {\n            return Q.reject(new CordovaError('Failed to deploy to device, no devices found.'));\n        }\n        // default device\n        target = target || device_list[0];\n\n        if (device_list.indexOf(target) < 0) {\n            return Q.reject('ERROR: Unable to find target \\'' + target + '\\'.');\n        }\n\n        return build.detectArchitecture(target)\n        .then(function(arch) {\n            return { target: target, arch: arch, isEmulator: false };\n        });\n    });\n};\n\n/*\n * Installs a previously built application on the device\n * and launches it.\n * Returns a promise.\n */\nmodule.exports.install = function(target, buildResults) {\n    return Q().then(function() {\n        if (target && typeof target == 'object') {\n            return target;\n        }\n        return module.exports.resolveTarget(target);\n    }).then(function(resolvedTarget) {\n        var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);\n        var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));\n        var pkgName = manifest.getPackageId();\n        var launchName = pkgName + '/.' + manifest.getActivity().getName();\n        events.emit('log', 'Using apk: ' + apk_path);\n        events.emit('log', 'Package name: ' + pkgName);\n\n        return Adb.install(resolvedTarget.target, apk_path, {replace: true})\n        .catch(function (error) {\n            // CB-9557 CB-10157 only uninstall and reinstall app if the one that\n            // is already installed on device was signed w/different certificate\n            if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString()))\n                throw error;\n\n            events.emit('warn', 'Uninstalling app from device and reinstalling it again because the ' +\n                'installed app already signed with different key');\n\n            // This promise is always resolved, even if 'adb uninstall' fails to uninstall app\n            // or the app doesn't installed at all, so no error catching needed.\n            return Adb.uninstall(resolvedTarget.target, pkgName)\n            .then(function() {\n                return Adb.install(resolvedTarget.target, apk_path, {replace: true});\n            });\n        })\n        .then(function() {\n            //unlock screen\n            return Adb.shell(resolvedTarget.target, 'input keyevent 82');\n        }).then(function() {\n            return Adb.start(resolvedTarget.target, launchName);\n        }).then(function() {\n            events.emit('log', 'LAUNCH SUCCESS');\n        });\n    });\n};\n"
  },
  {
    "path": "platforms/android/cordova/lib/emulator.js",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\n/* jshint sub:true */\n\nvar retry      = require('./retry');\nvar build      = require('./build');\nvar path = require('path');\nvar Adb = require('./Adb');\nvar AndroidManifest = require('./AndroidManifest');\nvar events = require('cordova-common').events;\nvar superspawn = require('cordova-common').superspawn;\nvar CordovaError = require('cordova-common').CordovaError;\nvar shelljs = require('shelljs');\nvar android_sdk = require('./android_sdk');\nvar check_reqs = require('./check_reqs');\n\nvar Q             = require('q');\nvar os            = require('os');\nvar fs            = require('fs');\nvar child_process = require('child_process');\n\n// constants\nvar ONE_SECOND              = 1000; // in milliseconds\nvar ONE_MINUTE              = 60 * ONE_SECOND; // in milliseconds\nvar INSTALL_COMMAND_TIMEOUT = 5 * ONE_MINUTE; // in milliseconds\nvar NUM_INSTALL_RETRIES     = 3;\nvar CHECK_BOOTED_INTERVAL   = 3 * ONE_SECOND; // in milliseconds\nvar EXEC_KILL_SIGNAL        = 'SIGKILL';\n\nfunction forgivingWhichSync(cmd) {\n    try {\n        return fs.realpathSync(shelljs.which(cmd));\n    } catch (e) {\n        return '';\n    }\n}\n\nmodule.exports.list_images_using_avdmanager = function () {\n    return superspawn.spawn('avdmanager', ['list', 'avd'])\n    .then(function(output) {\n        var response = output.split('\\n');\n        var emulator_list = [];\n        for (var i = 1; i < response.length; i++) {\n            // To return more detailed information use img_obj\n            var img_obj = {};\n            if (response[i].match(/Name:\\s/)) {\n                img_obj['name'] = response[i].split('Name: ')[1].replace('\\r', '');\n                if (response[i + 1].match(/Device:\\s/)) {\n                    i++;\n                    img_obj['device'] = response[i].split('Device: ')[1].replace('\\r', '');\n                }\n                if (response[i + 1].match(/Path:\\s/)) {\n                    i++;\n                    img_obj['path'] = response[i].split('Path: ')[1].replace('\\r', '');\n                }\n                if (response[i + 1].match(/Target:\\s/)) {\n                    i++;\n                    if (response[i + 1].match(/ABI:\\s/)) {\n                        img_obj['abi'] = response[i + 1].split('ABI: ')[1].replace('\\r', '');\n                    }\n                    // This next conditional just aims to match the old output of `android list avd`\n                    // We do so so that we don't have to change the logic when parsing for the\n                    // best emulator target to spawn (see below in `best_image`)\n                    // This allows us to transitionally support both `android` and `avdmanager` binaries,\n                    // depending on what SDK version the user has\n                    if (response[i + 1].match(/Based\\son:\\s/)) {\n                        img_obj['target'] = response[i + 1].split('Based on:')[1];\n                        if (img_obj['target'].match(/Tag\\/ABI:\\s/)) {\n                            img_obj['target'] = img_obj['target'].split('Tag/ABI:')[0].replace('\\r', '').trim();\n                            if (img_obj['target'].indexOf('(') > -1) {\n                                img_obj['target'] = img_obj['target'].substr(0, img_obj['target'].indexOf('(') - 1).trim();\n                            }\n                        }\n                        var version_string = img_obj['target'].replace(/Android\\s+/, '');\n\n                        var api_level = android_sdk.version_string_to_api_level[version_string];\n                        if (api_level) {\n                            img_obj['target'] += ' (API level ' + api_level + ')';\n                        }\n                    }\n                }\n                if (response[i + 1].match(/Skin:\\s/)) {\n                    i++;\n                    img_obj['skin'] = response[i].split('Skin: ')[1].replace('\\r', '');\n                }\n\n                emulator_list.push(img_obj);\n            }\n            /* To just return a list of names use this\n            if (response[i].match(/Name:\\s/)) {\n                emulator_list.push(response[i].split('Name: ')[1].replace('\\r', '');\n            }*/\n\n        }\n        return emulator_list;\n    });\n};\n\nmodule.exports.list_images_using_android = function() {\n    return superspawn.spawn('android', ['list', 'avds'])\n    .then(function(output) {\n        var response = output.split('\\n');\n        var emulator_list = [];\n        for (var i = 1; i < response.length; i++) {\n            // To return more detailed information use img_obj\n            var img_obj = {};\n            if (response[i].match(/Name:\\s/)) {\n                img_obj['name'] = response[i].split('Name: ')[1].replace('\\r', '');\n                if (response[i + 1].match(/Device:\\s/)) {\n                    i++;\n                    img_obj['device'] = response[i].split('Device: ')[1].replace('\\r', '');\n                }\n                if (response[i + 1].match(/Path:\\s/)) {\n                    i++;\n                    img_obj['path'] = response[i].split('Path: ')[1].replace('\\r', '');\n                }\n                if (response[i + 1].match(/\\(API\\slevel\\s/) || (response[i + 2] && response[i + 2].match(/\\(API\\slevel\\s/))) {\n                    i++;\n                    var secondLine = response[i + 1].match(/\\(API\\slevel\\s/) ? response[i + 1] : '';\n                    img_obj['target'] = (response[i] + secondLine).split('Target: ')[1].replace('\\r', '');\n                }\n                if (response[i + 1].match(/ABI:\\s/)) {\n                    i++;\n                    img_obj['abi'] = response[i].split('ABI: ')[1].replace('\\r', '');\n                }\n                if (response[i + 1].match(/Skin:\\s/)) {\n                    i++;\n                    img_obj['skin'] = response[i].split('Skin: ')[1].replace('\\r', '');\n                }\n\n                emulator_list.push(img_obj);\n            }\n            /* To just return a list of names use this\n            if (response[i].match(/Name:\\s/)) {\n                emulator_list.push(response[i].split('Name: ')[1].replace('\\r', '');\n            }*/\n\n        }\n        return emulator_list;\n    });\n};\n\n/**\n * Returns a Promise for a list of emulator images in the form of objects\n * {\n       name   : <emulator_name>,\n       device : <device>,\n       path   : <path_to_emulator_image>,\n       target : <api_target>,\n       abi    : <cpu>,\n       skin   : <skin>\n   }\n */\nmodule.exports.list_images = function() {\n    if (forgivingWhichSync('android')) {\n        return module.exports.list_images_using_android()\n        .catch(function(err) {\n            // try to use `avdmanager` in case `android` reports it is no longer available.\n            // this likely means the target machine is using a newer version of\n            // the android sdk, and possibly `avdmanager` is available.\n            if (err.code == 1 && err.stdout.indexOf('android command is no longer available')) {\n                return module.exports.list_images_using_avdmanager();\n            } else {\n                throw err;\n            }\n        });\n    } else if (forgivingWhichSync('avdmanager')) {\n        return module.exports.list_images_using_avdmanager();\n    } else {\n        return Q().then(function() {\n            throw new CordovaError('Could not find either `android` or `avdmanager` on your $PATH! Are you sure the Android SDK is installed and available?');\n        });\n    }\n};\n\n/**\n * Will return the closest avd to the projects target\n * or undefined if no avds exist.\n * Returns a promise.\n */\nmodule.exports.best_image = function() {\n    return this.list_images()\n    .then(function(images) {\n        // Just return undefined if there is no images\n        if (images.length === 0) return;\n\n        var closest = 9999;\n        var best = images[0];\n        var project_target = check_reqs.get_target().replace('android-', '');\n        for (var i in images) {\n            var target = images[i].target;\n            if(target) {\n                var num = target.split('(API level ')[1].replace(')', '');\n                if (num == project_target) {\n                    return images[i];\n                } else if (project_target - num < closest && project_target > num) {\n                    closest = project_target - num;\n                    best = images[i];\n                }\n            }\n        }\n        return best;\n    });\n};\n\n// Returns a promise.\nmodule.exports.list_started = function() {\n    return Adb.devices({emulators: true});\n};\n\n// Returns a promise.\nmodule.exports.list_targets = function() {\n    return superspawn.spawn('android', ['list', 'targets'], {cwd: os.tmpdir()})\n    .then(function(output) {\n        var target_out = output.split('\\n');\n        var targets = [];\n        for (var i = target_out.length; i >= 0; i--) {\n            if(target_out[i].match(/id:/)) {\n                targets.push(targets[i].split(' ')[1]);\n            }\n        }\n        return targets;\n    });\n};\n\n/*\n * Gets unused port for android emulator, between 5554 and 5584\n * Returns a promise.\n */\nmodule.exports.get_available_port = function () {\n    var self = this;\n\n    return self.list_started()\n    .then(function (emulators) {\n        for (var p = 5584; p >= 5554; p-=2) {\n            if (emulators.indexOf('emulator-' + p) === -1) {\n                events.emit('verbose', 'Found available port: ' + p);\n                return p;\n            }\n        }\n        throw new CordovaError('Could not find an available avd port');\n    });\n};\n\n/*\n * Starts an emulator with the given ID,\n * and returns the started ID of that emulator.\n * If no ID is given it will use the first image available,\n * if no image is available it will error out (maybe create one?).\n * If no boot timeout is given or the value is negative it will wait forever for\n * the emulator to boot\n *\n * Returns a promise.\n */\nmodule.exports.start = function(emulator_ID, boot_timeout) {\n    var self = this;\n\n    return Q().then(function() {\n        if (emulator_ID) return Q(emulator_ID);\n\n        return self.best_image()\n        .then(function(best) {\n            if (best && best.name) {\n                events.emit('warn', 'No emulator specified, defaulting to ' + best.name);\n                return best.name;\n            }\n\n            var androidCmd = check_reqs.getAbsoluteAndroidCmd();\n            return Q.reject(new CordovaError('No emulator images (avds) found.\\n' +\n                '1. Download desired System Image by running: ' + androidCmd + ' sdk\\n' +\n                '2. Create an AVD by running: ' + androidCmd + ' avd\\n' +\n                'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\\n'));\n        });\n    }).then(function(emulatorId) {\n        return self.get_available_port()\n        .then(function (port) {\n            // Figure out the directory the emulator binary runs in, and set the cwd to that directory.\n            // Workaround for https://code.google.com/p/android/issues/detail?id=235461\n            var emulator_dir = path.dirname(shelljs.which('emulator'));\n            var args = ['-avd', emulatorId, '-port', port];\n            // Don't wait for it to finish, since the emulator will probably keep running for a long time.\n            child_process\n                .spawn('emulator', args, { stdio: 'inherit', detached: true, cwd: emulator_dir })\n                .unref();\n\n            // wait for emulator to start\n            events.emit('log', 'Waiting for emulator to start...');\n            return self.wait_for_emulator(port);\n        });\n    }).then(function(emulatorId) {\n        if (!emulatorId)\n            return Q.reject(new CordovaError('Failed to start emulator'));\n\n        //wait for emulator to boot up\n        process.stdout.write('Waiting for emulator to boot (this may take a while)...');\n        return self.wait_for_boot(emulatorId, boot_timeout)\n        .then(function(success) {\n            if (success) {\n                events.emit('log','BOOT COMPLETE');\n                //unlock screen\n                return Adb.shell(emulatorId, 'input keyevent 82')\n                .then(function() {\n                    //return the new emulator id for the started emulators\n                    return emulatorId;\n                });\n            } else {\n                // We timed out waiting for the boot to happen\n                return null;\n            }\n        });\n    });\n};\n\n/*\n * Waits for an emulator to boot on a given port.\n * Returns this emulator's ID in a promise.\n */\nmodule.exports.wait_for_emulator = function(port) {\n    var self = this;\n    return Q().then(function() {\n        var emulator_id = 'emulator-' + port;\n        return Adb.shell(emulator_id, 'getprop dev.bootcomplete')\n        .then(function (output) {\n            if (output.indexOf('1') >= 0) {\n                return emulator_id;\n            }\n            return self.wait_for_emulator(port);\n        }, function (error) {\n            if (error && error.message &&\n            (error.message.indexOf('not found') > -1) ||\n            error.message.indexOf('device offline') > -1) {\n                // emulator not yet started, continue waiting\n                return self.wait_for_emulator(port);\n            } else {\n                // something unexpected has happened\n                throw error;\n            }\n        });\n     });\n};\n\n/*\n * Waits for the core android process of the emulator to start. Returns a\n * promise that resolves to a boolean indicating success. Not specifying a\n * time_remaining or passing a negative value will cause it to wait forever\n */\nmodule.exports.wait_for_boot = function(emulator_id, time_remaining) {\n    var self = this;\n    return Adb.shell(emulator_id, 'ps')\n    .then(function(output) {\n        if (output.match(/android\\.process\\.acore/)) {\n            return true;\n        } else if (time_remaining === 0) {\n            return false;\n        } else {\n            process.stdout.write('.');\n\n            // Check at regular intervals\n            return Q.delay(time_remaining < CHECK_BOOTED_INTERVAL ? time_remaining : CHECK_BOOTED_INTERVAL).then(function() {\n                var updated_time = time_remaining >= 0 ? Math.max(time_remaining - CHECK_BOOTED_INTERVAL, 0) : time_remaining;\n                return self.wait_for_boot(emulator_id, updated_time);\n            });\n        }\n    });\n};\n\n/*\n * Create avd\n * TODO : Enter the stdin input required to complete the creation of an avd.\n * Returns a promise.\n */\nmodule.exports.create_image = function(name, target) {\n    console.log('Creating new avd named ' + name);\n    if (target) {\n        return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', target])\n        .then(null, function(error) {\n            console.error('ERROR : Failed to create emulator image : ');\n            console.error(' Do you have the latest android targets including ' + target + '?');\n            console.error(error);\n        });\n    } else {\n        console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');\n        return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]])\n        .then(function() {\n            // TODO: This seems like another error case, even though it always happens.\n            console.error('ERROR : Unable to create an avd emulator, no targets found.');\n            console.error('Ensure you have targets available by running the \"android\" command');\n            return Q.reject();\n        }, function(error) {\n            console.error('ERROR : Failed to create emulator image : ');\n            console.error(error);\n        });\n    }\n};\n\nmodule.exports.resolveTarget = function(target) {\n    return this.list_started()\n    .then(function(emulator_list) {\n        if (emulator_list.length < 1) {\n            return Q.reject('No running Android emulators found, please start an emulator before deploying your project.');\n        }\n\n        // default emulator\n        target = target || emulator_list[0];\n        if (emulator_list.indexOf(target) < 0) {\n            return Q.reject('Unable to find target \\'' + target + '\\'. Failed to deploy to emulator.');\n        }\n\n        return build.detectArchitecture(target)\n        .then(function(arch) {\n            return {target:target, arch:arch, isEmulator:true};\n        });\n    });\n};\n\n/*\n * Installs a previously built application on the emulator and launches it.\n * If no target is specified, then it picks one.\n * If no started emulators are found, error out.\n * Returns a promise.\n */\nmodule.exports.install = function(givenTarget, buildResults) {\n\n    var target;\n    var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));\n    var pkgName = manifest.getPackageId();\n\n    // resolve the target emulator\n    return Q().then(function () {\n        if (givenTarget && typeof givenTarget == 'object') {\n            return givenTarget;\n        } else {\n            return module.exports.resolveTarget(givenTarget);\n        }\n\n    // set the resolved target\n    }).then(function (resolvedTarget) {\n        target = resolvedTarget;\n\n    // install the app\n    }).then(function () {\n        // This promise is always resolved, even if 'adb uninstall' fails to uninstall app\n        // or the app doesn't installed at all, so no error catching needed.\n        return Q.when()\n        .then(function() {\n\n            var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);\n            var execOptions = {\n                cwd: os.tmpdir(),\n                timeout:    INSTALL_COMMAND_TIMEOUT, // in milliseconds\n                killSignal: EXEC_KILL_SIGNAL\n            };\n\n            events.emit('log', 'Using apk: ' + apk_path);\n            events.emit('log', 'Package name: ' + pkgName);\n            events.emit('verbose', 'Installing app on emulator...');\n\n            // A special function to call adb install in specific environment w/ specific options.\n            // Introduced as a part of fix for http://issues.apache.org/jira/browse/CB-9119\n            // to workaround sporadic emulator hangs\n            function adbInstallWithOptions(target, apk, opts) {\n                events.emit('verbose', 'Installing apk ' + apk + ' on ' + target + '...');\n\n                var command = 'adb -s ' + target + ' install -r \"' + apk + '\"';\n                return Q.promise(function (resolve, reject) {\n                    child_process.exec(command, opts, function(err, stdout, stderr) {\n                        if (err) reject(new CordovaError('Error executing \"' + command + '\": ' + stderr));\n                        // adb does not return an error code even if installation fails. Instead it puts a specific\n                        // message to stdout, so we have to use RegExp matching to detect installation failure.\n                        else if (/Failure/.test(stdout)) {\n                            if (stdout.match(/INSTALL_PARSE_FAILED_NO_CERTIFICATES/)) {\n                                stdout += 'Sign the build using \\'-- --keystore\\' or \\'--buildConfig\\'' +\n                                    ' or sign and deploy the unsigned apk manually using Android tools.';\n                            } else if (stdout.match(/INSTALL_FAILED_VERSION_DOWNGRADE/)) {\n                                stdout += 'You\\'re trying to install apk with a lower versionCode that is already installed.' +\n                                    '\\nEither uninstall an app or increment the versionCode.';\n                            }\n\n                            reject(new CordovaError('Failed to install apk to emulator: ' + stdout));\n                        } else resolve(stdout);\n                    });\n                });\n            }\n\n            function installPromise () {\n                return adbInstallWithOptions(target.target, apk_path, execOptions)\n                .catch(function (error) {\n                    // CB-9557 CB-10157 only uninstall and reinstall app if the one that\n                    // is already installed on device was signed w/different certificate\n                    if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString()))\n                        throw error;\n\n                    events.emit('warn', 'Uninstalling app from device and reinstalling it because the ' +\n                        'currently installed app was signed with different key');\n\n                    // This promise is always resolved, even if 'adb uninstall' fails to uninstall app\n                    // or the app doesn't installed at all, so no error catching needed.\n                    return Adb.uninstall(target.target, pkgName)\n                    .then(function() {\n                        return adbInstallWithOptions(target.target, apk_path, execOptions);\n                    });\n                });\n            }\n\n            return retry.retryPromise(NUM_INSTALL_RETRIES, installPromise)\n            .then(function (output) {\n                events.emit('log', 'INSTALL SUCCESS');\n            });\n        });\n    // unlock screen\n    }).then(function () {\n\n        events.emit('verbose', 'Unlocking screen...');\n        return Adb.shell(target.target, 'input keyevent 82');\n    }).then(function () {\n        Adb.start(target.target, pkgName + '/.' + manifest.getActivity().getName());\n    // report success or failure\n    }).then(function (output) {\n        events.emit('log', 'LAUNCH SUCCESS');\n    });\n};\n"
  },
  {
    "path": "platforms/android/cordova/lib/install-device",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar device = require('./device'),\n    args   = process.argv;\n\nif(args.length > 2) {\n    var install_target;\n    if (args[2].substring(0, 9) == '--target=') {\n        install_target = args[2].substring(9, args[2].length);\n        device.install(install_target).done(null, function(err) {\n            console.error('ERROR: ' + err);\n            process.exit(2);\n        });\n     } else {\n        console.error('ERROR : argument \\'' + args[2] + '\\' not recognized.');\n        process.exit(2);\n     }\n} else {\n    device.install().done(null, function(err) {\n        console.error('ERROR: ' + err);\n        process.exit(2);\n    });\n}\n"
  },
  {
    "path": "platforms/android/cordova/lib/install-device.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n:: \n:: http://www.apache.org/licenses/LICENSE-2.0\n:: \n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0install-device\"\nIF EXIST %script_path% (\n        node \"%script_path%\" %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'install-device' script in 'cordova\\lib' folder, aborting...>&2\n    EXIT /B 1\n)"
  },
  {
    "path": "platforms/android/cordova/lib/install-emulator",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar emulator = require('./emulator'),\n    args     = process.argv;\n\nvar install_target;\nif(args.length > 2) {\n    if (args[2].substring(0, 9) == '--target=') {\n        install_target = args[2].substring(9, args[2].length);\n     } else {\n        console.error('ERROR : argument \\'' + args[2] + '\\' not recognized.');\n        process.exit(2);\n     }\n}\n\nemulator.install(install_target).done(null, function(err) {\n    console.error('ERROR: ' + err);\n    process.exit(2);\n});\n"
  },
  {
    "path": "platforms/android/cordova/lib/install-emulator.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n:: \n:: http://www.apache.org/licenses/LICENSE-2.0\n:: \n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0install-emulator\"\nIF EXIST %script_path% (\n        node \"%script_path%\" %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'install-emulator' script in 'cordova\\lib' folder, aborting...>&2\n    EXIT /B 1\n)"
  },
  {
    "path": "platforms/android/cordova/lib/list-devices",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar devices = require('./device');\n\n// Usage support for when args are given\nrequire('./check_reqs').check_android().then(function() {\n    devices.list().done(function(device_list) {\n        device_list && device_list.forEach(function(dev) {\n            console.log(dev);\n        });\n    }, function(err) {\n        console.error('ERROR: ' + err);\n        process.exit(2);\n    });\n});\n"
  },
  {
    "path": "platforms/android/cordova/lib/list-devices.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n:: \n:: http://www.apache.org/licenses/LICENSE-2.0\n:: \n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0list-devices\"\nIF EXIST %script_path% (\n        node \"%script_path%\" %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'list-devices' script in 'cordova\\lib' folder, aborting...>&2\n    EXIT /B 1\n)"
  },
  {
    "path": "platforms/android/cordova/lib/list-emulator-images",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar emulators = require('./emulator');\n\n// Usage support for when args are given\nrequire('./check_reqs').check_android().then(function() {\n    emulators.list_images().done(function(emulator_list) {\n        emulator_list && emulator_list.forEach(function(emu) {\n            console.log(emu.name);\n        });\n    }, function(err) {\n        console.error('ERROR: ' + err);\n        process.exit(2);\n    });\n});\n"
  },
  {
    "path": "platforms/android/cordova/lib/list-emulator-images.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n:: \n:: http://www.apache.org/licenses/LICENSE-2.0\n:: \n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0list-emulator-images\"\nIF EXIST %script_path% (\n        node \"%script_path%\" %*\n) ELSE (\n    ECHO. \n    ECHO ERROR: Could not find 'list-emulator-images' script in 'cordova\\lib' folder, aborting...>&2\n    EXIT /B 1\n)\n"
  },
  {
    "path": "platforms/android/cordova/lib/list-started-emulators",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar emulators = require('./emulator');\n\n// Usage support for when args are given\nrequire('./check_reqs').check_android().then(function() {\n    emulators.list_started().done(function(emulator_list) {\n        emulator_list && emulator_list.forEach(function(emu) {\n            console.log(emu);\n        });\n    }, function(err) {\n        console.error('ERROR: ' + err);\n        process.exit(2);\n    });\n});\n"
  },
  {
    "path": "platforms/android/cordova/lib/list-started-emulators.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n:: \n:: http://www.apache.org/licenses/LICENSE-2.0\n:: \n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0list-started-emulators\"\nIF EXIST %script_path% (\n        node \"%script_path%\" %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'list-started-emulators' script in 'cordova\\lib' folder, aborting...>&2\n    EXIT /B 1\n)"
  },
  {
    "path": "platforms/android/cordova/lib/log.js",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar path  = require('path'),\n    os  = require('os'),\n    Q     = require('q'),\n    child_process = require('child_process'),\n    ROOT  = path.join(__dirname, '..', '..');\n\n/*\n * Starts running logcat in the shell.\n * Returns a promise.\n */\nmodule.exports.run = function() {\n    var d = Q.defer();\n    var adb = child_process.spawn('adb', ['logcat'], {cwd: os.tmpdir()});\n\n    adb.stdout.on('data', function(data) {\n        var lines = data ? data.toString().split('\\n') : [];\n        var out = lines.filter(function(x) { return x.indexOf('nativeGetEnabledTags') < 0; });\n        console.log(out.join('\\n'));\n    });\n\n    adb.stderr.on('data', console.error);\n    adb.on('close', function(code) {\n        if (code > 0) {\n            d.reject('Failed to run logcat command.');\n        } else d.resolve();\n    });\n\n    return d.promise;\n};\n\nmodule.exports.help = function() {\n    console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'log')));\n    console.log('Gives the logcat output on the command line.');\n    process.exit(0);\n};\n"
  },
  {
    "path": "platforms/android/cordova/lib/plugin-build.gradle",
    "content": "/* Licensed to the Apache Software Foundation (ASF) under one\n   or more contributor license agreements.  See the NOTICE file\n   distributed with this work for additional information\n   regarding copyright ownership.  The ASF licenses this file\n   to you under the Apache License, Version 2.0 (the\n   \"License\"); you may not use this file except in compliance\n   with the License.  You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing,\n   software distributed under the License is distributed on an\n   \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n   KIND, either express or implied.  See the License for the\n   specific language governing permissions and limitations\n   under the License.\n*/\n\n// GENERATED FILE! DO NOT EDIT!\n\nbuildscript {\n    repositories {\n        mavenCentral()\n        jcenter()\n    }\n\n    // Switch the Android Gradle plugin version requirement depending on the\n    // installed version of Gradle. This dependency is documented at\n    // http://tools.android.com/tech-docs/new-build-system/version-compatibility\n    // and https://issues.apache.org/jira/browse/CB-8143\n    dependencies {\n        classpath 'com.android.tools.build:gradle:1.0.0+'\n    }\n}\n\napply plugin: 'com.android.library'\n\ndependencies {\n    compile fileTree(dir: 'libs', include: '*.jar')\n    debugCompile project(path: \":CordovaLib\", configuration: \"debug\")\n    releaseCompile project(path: \":CordovaLib\", configuration: \"release\")\n}\n\nandroid {\n    compileSdkVersion cdvCompileSdkVersion\n    buildToolsVersion cdvBuildToolsVersion\n    publishNonDefault true\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_6\n        targetCompatibility JavaVersion.VERSION_1_6\n    }\n\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['src']\n            aidl.srcDirs = ['src']\n            renderscript.srcDirs = ['src']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n            jniLibs.srcDirs = ['libs']\n        }\n    }\n}\n\nif (file('build-extras.gradle').exists()) {\n    apply from: 'build-extras.gradle'\n}\n"
  },
  {
    "path": "platforms/android/cordova/lib/pluginHandlers.js",
    "content": "/*\n *\n * Copyright 2013 Anis Kadri\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n/* jshint unused: vars */\n\nvar fs = require('fs');\nvar path = require('path');\nvar shell = require('shelljs');\nvar events = require('cordova-common').events;\nvar CordovaError = require('cordova-common').CordovaError;\n\nvar handlers = {\n    'source-file':{\n        install:function(obj, plugin, project, options) {\n            if (!obj.src) throw new CordovaError(generateAttributeError('src', 'source-file', plugin.id));\n            if (!obj.targetDir) throw new CordovaError(generateAttributeError('target-dir', 'source-file', plugin.id));\n\n            var dest = path.join(obj.targetDir, path.basename(obj.src));\n\n            if(options && options.android_studio === true) {\n              dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));\n            }\n\n            if (options && options.force) {\n                copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));\n            } else {\n                copyNewFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));\n            }\n        },\n        uninstall:function(obj, plugin, project, options) {\n            var dest = path.join(obj.targetDir, path.basename(obj.src));\n            \n            if(options && options.android_studio === true) {\n              dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));\n            }\n\n            deleteJava(project.projectDir, dest);\n        }\n    },\n    'lib-file':{\n        install:function(obj, plugin, project, options) {\n            var dest = path.join('libs', path.basename(obj.src));\n            if(options && options.android_studio === true) {\n              dest = path.join('app/libs', path.basename(obj.src));\n            }\n            copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));\n        },\n        uninstall:function(obj, plugin, project, options) {\n            var dest = path.join('libs', path.basename(obj.src));\n            if(options && options.android_studio === true) {\n              dest = path.join('app/libs', path.basename(obj.src));\n            }\n            removeFile(project.projectDir, dest);\n        }\n    },\n    'resource-file':{\n        install:function(obj, plugin, project, options) {\n            copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), !!(options && options.link));\n        },\n        uninstall:function(obj, plugin, project, options) {\n            removeFile(project.projectDir, path.normalize(obj.target));\n        }\n    },\n    'framework': {\n        install:function(obj, plugin, project, options) {\n            var src = obj.src;\n            if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));\n\n            events.emit('verbose', 'Installing Android library: ' + src);\n            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;\n            var subDir;\n\n            if (obj.custom) {\n                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);\n                copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, !!(options && options.link));\n                subDir = path.resolve(project.projectDir, subRelativeDir);\n            } else {\n                obj.type = 'sys';\n                subDir = src;\n            }\n\n            if (obj.type == 'gradleReference') {\n                project.addGradleReference(parentDir, subDir);\n            } else if (obj.type == 'sys') {\n                project.addSystemLibrary(parentDir, subDir);\n            } else {\n                project.addSubProject(parentDir, subDir);\n            }\n        },\n        uninstall:function(obj, plugin, project, options) {\n            var src = obj.src;\n            if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));\n\n            events.emit('verbose', 'Uninstalling Android library: ' + src);\n            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;\n            var subDir;\n\n            if (obj.custom) {\n                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);\n                removeFile(project.projectDir, subRelativeDir);\n                subDir = path.resolve(project.projectDir, subRelativeDir);\n                // If it's the last framework in the plugin, remove the parent directory.\n                var parDir = path.dirname(subDir);\n                if (fs.existsSync(parDir) && fs.readdirSync(parDir).length === 0) {\n                    fs.rmdirSync(parDir);\n                }\n            } else {\n                obj.type = 'sys';\n                subDir = src;\n            }\n\n            if (obj.type == 'gradleReference') {\n                project.removeGradleReference(parentDir, subDir);\n            } else if (obj.type == 'sys') {\n                project.removeSystemLibrary(parentDir, subDir);\n            } else {\n                project.removeSubProject(parentDir, subDir);\n            }\n        }\n    },\n    asset:{\n        install:function(obj, plugin, project, options) {\n            if (!obj.src) {\n                throw new CordovaError(generateAttributeError('src', 'asset', plugin.id));\n            }\n            if (!obj.target) {\n                throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));\n            }\n\n            copyFile(plugin.dir, obj.src, project.www, obj.target);\n            if (options && options.usePlatformWww) {\n                // CB-11022 copy file to both directories if usePlatformWww is specified\n                copyFile(plugin.dir, obj.src, project.platformWww, obj.target);\n            }\n        },\n        uninstall:function(obj, plugin, project, options) {\n            var target = obj.target || obj.src;\n\n            if (!target) throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));\n\n            removeFileF(path.resolve(project.www, target));\n            removeFileF(path.resolve(project.www, 'plugins', plugin.id));\n            if (options && options.usePlatformWww) {\n                // CB-11022 remove file from both directories if usePlatformWww is specified\n                removeFileF(path.resolve(project.platformWww, target));\n                removeFileF(path.resolve(project.platformWww, 'plugins', plugin.id));\n            }\n        }\n    },\n    'js-module': {\n        install: function (obj, plugin, project, options) {\n            // Copy the plugin's files into the www directory.\n            var moduleSource = path.resolve(plugin.dir, obj.src);\n            var moduleName = plugin.id + '.' + (obj.name || path.basename(obj.src, path.extname (obj.src)));\n\n            // Read in the file, prepend the cordova.define, and write it back out.\n            var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\\ufeff/, ''); // Window BOM\n            if (moduleSource.match(/.*\\.json$/)) {\n                scriptContent = 'module.exports = ' + scriptContent;\n            }\n            scriptContent = 'cordova.define(\"' + moduleName + '\", function(require, exports, module) {\\n' + scriptContent + '\\n});\\n';\n\n            var wwwDest = path.resolve(project.www, 'plugins', plugin.id, obj.src);\n            shell.mkdir('-p', path.dirname(wwwDest));\n            fs.writeFileSync(wwwDest, scriptContent, 'utf-8');\n\n            if (options && options.usePlatformWww) {\n                // CB-11022 copy file to both directories if usePlatformWww is specified\n                var platformWwwDest = path.resolve(project.platformWww, 'plugins', plugin.id, obj.src);\n                shell.mkdir('-p', path.dirname(platformWwwDest));\n                fs.writeFileSync(platformWwwDest, scriptContent, 'utf-8');\n            }\n        },\n        uninstall: function (obj, plugin, project, options) {\n            var pluginRelativePath = path.join('plugins', plugin.id, obj.src);\n            removeFileAndParents(project.www, pluginRelativePath);\n            if (options && options.usePlatformWww) {\n                // CB-11022 remove file from both directories if usePlatformWww is specified\n                removeFileAndParents(project.platformWww, pluginRelativePath);\n            }\n        }\n    }\n};\n\nmodule.exports.getInstaller = function (type) {\n    if (handlers[type] && handlers[type].install) {\n        return handlers[type].install;\n    }\n\n    events.emit('verbose', '<' + type + '> is not supported for android plugins');\n};\n\nmodule.exports.getUninstaller = function(type) {\n    if (handlers[type] && handlers[type].uninstall) {\n        return handlers[type].uninstall;\n    }\n\n    events.emit('verbose', '<' + type + '> is not supported for android plugins');\n};\n\nfunction copyFile (plugin_dir, src, project_dir, dest, link) {\n    src = path.resolve(plugin_dir, src);\n    if (!fs.existsSync(src)) throw new CordovaError('\"' + src + '\" not found!');\n\n    // check that src path is inside plugin directory\n    var real_path = fs.realpathSync(src);\n    var real_plugin_path = fs.realpathSync(plugin_dir);\n    if (real_path.indexOf(real_plugin_path) !== 0)\n        throw new CordovaError('File \"' + src + '\" is located outside the plugin directory \"' + plugin_dir + '\"');\n\n    dest = path.resolve(project_dir, dest);\n\n    // check that dest path is located in project directory\n    if (dest.indexOf(project_dir) !== 0)\n        throw new CordovaError('Destination \"' + dest + '\" for source file \"' + src + '\" is located outside the project');\n\n    shell.mkdir('-p', path.dirname(dest));\n    if (link) {\n        symlinkFileOrDirTree(src, dest);\n    } else if (fs.statSync(src).isDirectory()) {\n        // XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq\n        shell.cp('-Rf', src+'/*', dest);\n    } else {\n        shell.cp('-f', src, dest);\n    }\n}\n\n// Same as copy file but throws error if target exists\nfunction copyNewFile (plugin_dir, src, project_dir, dest, link) {\n    var target_path = path.resolve(project_dir, dest);\n    if (fs.existsSync(target_path))\n        throw new CordovaError('\"' + target_path + '\" already exists!');\n\n    copyFile(plugin_dir, src, project_dir, dest, !!link);\n}\n\nfunction symlinkFileOrDirTree(src, dest) {\n    if (fs.existsSync(dest)) {\n        shell.rm('-Rf', dest);\n    }\n\n    if (fs.statSync(src).isDirectory()) {\n        shell.mkdir('-p', dest);\n        fs.readdirSync(src).forEach(function(entry) {\n            symlinkFileOrDirTree(path.join(src, entry), path.join(dest, entry));\n        });\n    }\n    else {\n        fs.symlinkSync(path.relative(fs.realpathSync(path.dirname(dest)), src), dest);\n    }\n}\n\n// checks if file exists and then deletes. Error if doesn't exist\nfunction removeFile (project_dir, src) {\n    var file = path.resolve(project_dir, src);\n    shell.rm('-Rf', file);\n}\n\n// deletes file/directory without checking\nfunction removeFileF (file) {\n    shell.rm('-Rf', file);\n}\n\n// Sometimes we want to remove some java, and prune any unnecessary empty directories\nfunction deleteJava (project_dir, destFile) {\n    removeFileAndParents(project_dir, destFile, 'src');\n}\n\nfunction removeFileAndParents (baseDir, destFile, stopper) {\n    stopper = stopper || '.';\n    var file = path.resolve(baseDir, destFile);\n    if (!fs.existsSync(file)) return;\n\n    removeFileF(file);\n\n    // check if directory is empty\n    var curDir = path.dirname(file);\n\n    while(curDir !== path.resolve(baseDir, stopper)) {\n        if(fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {\n            fs.rmdirSync(curDir);\n            curDir = path.resolve(curDir, '..');\n        } else {\n            // directory not empty...do nothing\n            break;\n        }\n    }\n}\n\nfunction generateAttributeError(attribute, element, id) {\n    return 'Required attribute \"' + attribute + '\" not specified in <' + element + '> element from plugin: ' + id;\n}\n"
  },
  {
    "path": "platforms/android/cordova/lib/prepare.js",
    "content": "/**\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n*/\n\nvar Q = require('q');\nvar fs = require('fs');\nvar path = require('path');\nvar shell = require('shelljs');\nvar events = require('cordova-common').events;\nvar AndroidManifest = require('./AndroidManifest');\nvar xmlHelpers = require('cordova-common').xmlHelpers;\nvar CordovaError = require('cordova-common').CordovaError;\nvar ConfigParser = require('cordova-common').ConfigParser;\nvar FileUpdater = require('cordova-common').FileUpdater;\nvar PlatformJson = require('cordova-common').PlatformJson;\nvar PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;\nvar PluginInfoProvider = require('cordova-common').PluginInfoProvider;\n\nmodule.exports.prepare = function (cordovaProject, options) {\n    var self = this;\n\n    var platformJson = PlatformJson.load(this.locations.root, this.platform);\n    var munger = new PlatformMunger(this.platform, this.locations.root, platformJson, new PluginInfoProvider());\n\n    this._config = updateConfigFilesFrom(cordovaProject.projectConfig, munger, this.locations);\n\n    // Update own www dir with project's www assets and plugins' assets and js-files\n    return Q.when(updateWww(cordovaProject, this.locations))\n    .then(function () {\n        // update project according to config.xml changes.\n        return updateProjectAccordingTo(self._config, self.locations);\n    })\n    .then(function () {\n        updateIcons(cordovaProject, path.relative(cordovaProject.root, self.locations.res));\n        updateSplashes(cordovaProject, path.relative(cordovaProject.root, self.locations.res));\n        updateFileResources(cordovaProject, path.relative(cordovaProject.root, self.locations.root));\n    })\n    .then(function () {\n        events.emit('verbose', 'Prepared android project successfully');\n    });\n};\n\nmodule.exports.clean = function (options) {\n    // A cordovaProject isn't passed into the clean() function, because it might have\n    // been called from the platform shell script rather than the CLI. Check for the\n    // noPrepare option passed in by the non-CLI clean script. If that's present, or if\n    // there's no config.xml found at the project root, then don't clean prepared files.\n    var projectRoot = path.resolve(this.root, '../..');\n    if ((options && options.noPrepare) || !fs.existsSync(this.locations.configXml) ||\n            !fs.existsSync(this.locations.configXml)) {\n        return Q();\n    }\n\n    var projectConfig = new ConfigParser(this.locations.configXml);\n\n    var self = this;\n    return Q().then(function () {\n        cleanWww(projectRoot, self.locations);\n        cleanIcons(projectRoot, projectConfig, path.relative(projectRoot, self.locations.res));\n        cleanSplashes(projectRoot, projectConfig, path.relative(projectRoot, self.locations.res));\n        cleanFileResources(projectRoot, projectConfig, path.relative(projectRoot, self.locations.root));\n    });\n};\n\n/**\n * Updates config files in project based on app's config.xml and config munge,\n *   generated by plugins.\n *\n * @param   {ConfigParser}   sourceConfig  A project's configuration that will\n *   be merged into platform's config.xml\n * @param   {ConfigChanges}  configMunger  An initialized ConfigChanges instance\n *   for this platform.\n * @param   {Object}         locations     A map of locations for this platform\n *\n * @return  {ConfigParser}                 An instance of ConfigParser, that\n *   represents current project's configuration. When returned, the\n *   configuration is already dumped to appropriate config.xml file.\n */\nfunction updateConfigFilesFrom(sourceConfig, configMunger, locations) {\n    events.emit('verbose', 'Generating platform-specific config.xml from defaults for android at ' + locations.configXml);\n\n    // First cleanup current config and merge project's one into own\n    // Overwrite platform config.xml with defaults.xml.\n    shell.cp('-f', locations.defaultConfigXml, locations.configXml);\n\n    // Then apply config changes from global munge to all config files\n    // in project (including project's config)\n    configMunger.reapply_global_munge().save_all();\n\n    events.emit('verbose', 'Merging project\\'s config.xml into platform-specific android config.xml');\n    // Merge changes from app's config.xml into platform's one\n    var config = new ConfigParser(locations.configXml);\n    xmlHelpers.mergeXml(sourceConfig.doc.getroot(),\n        config.doc.getroot(), 'android', /*clobber=*/true);\n\n    config.write();\n    return config;\n}\n\n/**\n * Logs all file operations via the verbose event stream, indented.\n */\nfunction logFileOp(message) {\n    events.emit('verbose', '  ' + message);\n}\n\n/**\n * Updates platform 'www' directory by replacing it with contents of\n *   'platform_www' and app www. Also copies project's overrides' folder into\n *   the platform 'www' folder\n *\n * @param   {Object}  cordovaProject    An object which describes cordova project.\n * @param   {Object}  destinations      An object that contains destination\n *   paths for www files.\n */\nfunction updateWww(cordovaProject, destinations) {\n    var sourceDirs = [\n        path.relative(cordovaProject.root, cordovaProject.locations.www),\n        path.relative(cordovaProject.root, destinations.platformWww)\n    ];\n\n    // If project contains 'merges' for our platform, use them as another overrides\n    var merges_path = path.join(cordovaProject.root, 'merges', 'android');\n    if (fs.existsSync(merges_path)) {\n        events.emit('verbose', 'Found \"merges/android\" folder. Copying its contents into the android project.');\n        sourceDirs.push(path.join('merges', 'android'));\n    }\n\n    var targetDir = path.relative(cordovaProject.root, destinations.www);\n    events.emit(\n        'verbose', 'Merging and updating files from [' + sourceDirs.join(', ') + '] to ' + targetDir);\n    FileUpdater.mergeAndUpdateDir(\n        sourceDirs, targetDir, { rootDir: cordovaProject.root }, logFileOp);\n}\n\n/**\n * Cleans all files from the platform 'www' directory.\n */\nfunction cleanWww(projectRoot, locations) {\n    var targetDir = path.relative(projectRoot, locations.www);\n    events.emit('verbose', 'Cleaning ' + targetDir);\n\n    // No source paths are specified, so mergeAndUpdateDir() will clear the target directory.\n    FileUpdater.mergeAndUpdateDir(\n        [], targetDir, { rootDir: projectRoot, all: true }, logFileOp);\n}\n\n/**\n * Updates project structure and AndroidManifest according to project's configuration.\n *\n * @param   {ConfigParser}  platformConfig  A project's configuration that will\n *   be used to update project\n * @param   {Object}  locations       A map of locations for this platform\n */\nfunction updateProjectAccordingTo(platformConfig, locations) {\n    // Update app name by editing res/values/strings.xml\n    var name = platformConfig.name();\n    var strings = xmlHelpers.parseElementtreeSync(locations.strings);\n    strings.find('string[@name=\"app_name\"]').text = name.replace(/\\'/g, '\\\\\\'');\n    fs.writeFileSync(locations.strings, strings.write({indent: 4}), 'utf-8');\n    events.emit('verbose', 'Wrote out android application name \"' + name + '\" to ' + locations.strings);\n\n    // Java packages cannot support dashes\n    var pkg = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');\n\n    var manifest = new AndroidManifest(locations.manifest);\n    var orig_pkg = manifest.getPackageId();\n\n    manifest.getActivity()\n        .setOrientation(platformConfig.getPreference('orientation'))\n        .setLaunchMode(findAndroidLaunchModePreference(platformConfig));\n\n    manifest.setVersionName(platformConfig.version())\n        .setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))\n        .setPackageId(pkg)\n        .setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))\n        .setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))\n        .setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))\n        .write();\n\n    var javaPattern = path.join(locations.root, 'src', orig_pkg.replace(/\\./g, '/'), '*.java');\n    var java_files = shell.ls(javaPattern).filter(function(f) {\n        return shell.grep(/extends\\s+CordovaActivity/g, f);\n    });\n\n    if (java_files.length === 0) {\n        throw new CordovaError('No Java files found that extend CordovaActivity.');\n    } else if(java_files.length > 1) {\n        events.emit('log', 'Multiple candidate Java files that extend CordovaActivity found. Guessing at the first one, ' + java_files[0]);\n    }\n\n    var destFile = path.join(locations.root, 'src', pkg.replace(/\\./g, '/'), path.basename(java_files[0]));\n    shell.mkdir('-p', path.dirname(destFile));\n    shell.sed(/package [\\w\\.]*;/, 'package ' + pkg + ';', java_files[0]).to(destFile);\n    events.emit('verbose', 'Wrote out Android package name \"' + pkg + '\" to ' + destFile);\n\n    if (orig_pkg !== pkg) {\n        // If package was name changed we need to remove old java with main activity\n        shell.rm('-Rf',java_files[0]);\n        // remove any empty directories\n        var currentDir = path.dirname(java_files[0]);\n        var sourcesRoot = path.resolve(locations.root, 'src');\n        while(currentDir !== sourcesRoot) {\n            if(fs.existsSync(currentDir) && fs.readdirSync(currentDir).length === 0) {\n                fs.rmdirSync(currentDir);\n                currentDir = path.resolve(currentDir, '..');\n            } else {\n                break;\n            }\n        }\n    }\n}\n\n// Consturct the default value for versionCode as\n// PATCH + MINOR * 100 + MAJOR * 10000\n// see http://developer.android.com/tools/publishing/versioning.html\nfunction default_versionCode(version) {\n    var nums = version.split('-')[0].split('.');\n    var versionCode = 0;\n    if (+nums[0]) {\n        versionCode += +nums[0] * 10000;\n    }\n    if (+nums[1]) {\n        versionCode += +nums[1] * 100;\n    }\n    if (+nums[2]) {\n        versionCode += +nums[2];\n    }\n\n    events.emit('verbose', 'android-versionCode not found in config.xml. Generating a code based on version in config.xml (' + version + '): ' + versionCode);\n    return versionCode;\n}\n\nfunction getImageResourcePath(resourcesDir, type, density, name, sourceName) {\n    if (/\\.9\\.png$/.test(sourceName)) {\n        name = name.replace(/\\.png$/, '.9.png');\n    }\n    var resourcePath = path.join(resourcesDir, (density ? type + '-' + density : type), name);\n    return resourcePath;\n}\n\nfunction updateSplashes(cordovaProject, platformResourcesDir) {\n    var resources = cordovaProject.projectConfig.getSplashScreens('android');\n\n    // if there are \"splash\" elements in config.xml\n    if (resources.length === 0) {\n        events.emit('verbose', 'This app does not have splash screens defined');\n        return;\n    }\n\n    var resourceMap = mapImageResources(cordovaProject.root, platformResourcesDir, 'drawable', 'screen.png');\n\n    var hadMdpi = false;\n    resources.forEach(function (resource) {\n        if (!resource.density) {\n            return;\n        }\n        if (resource.density == 'mdpi') {\n            hadMdpi = true;\n        }\n        var targetPath = getImageResourcePath(\n            platformResourcesDir, 'drawable', resource.density, 'screen.png', path.basename(resource.src));\n        resourceMap[targetPath] = resource.src;\n    });\n\n    // There's no \"default\" drawable, so assume default == mdpi.\n    if (!hadMdpi && resources.defaultResource) {\n        var targetPath = getImageResourcePath(\n            platformResourcesDir, 'drawable', 'mdpi', 'screen.png', path.basename(resources.defaultResource.src));\n        resourceMap[targetPath] = resources.defaultResource.src;\n    }\n\n    events.emit('verbose', 'Updating splash screens at ' + platformResourcesDir);\n    FileUpdater.updatePaths(\n        resourceMap, { rootDir: cordovaProject.root }, logFileOp);\n}\n\nfunction cleanSplashes(projectRoot, projectConfig, platformResourcesDir) {\n    var resources = projectConfig.getSplashScreens('android');\n    if (resources.length > 0) {\n        var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'drawable', 'screen.png');\n        events.emit('verbose', 'Cleaning splash screens at ' + platformResourcesDir);\n\n        // No source paths are specified in the map, so updatePaths() will delete the target files.\n        FileUpdater.updatePaths(\n            resourceMap, { rootDir: projectRoot, all: true }, logFileOp);\n    }\n}\n\nfunction updateIcons(cordovaProject, platformResourcesDir) {\n    var icons = cordovaProject.projectConfig.getIcons('android');\n\n    // if there are icon elements in config.xml\n    if (icons.length === 0) {\n        events.emit('verbose', 'This app does not have launcher icons defined');\n        return;\n    }\n\n    var resourceMap = mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'icon.png');\n\n    var android_icons = {};\n    var default_icon;\n    // http://developer.android.com/design/style/iconography.html\n    var sizeToDensityMap = {\n        36: 'ldpi',\n        48: 'mdpi',\n        72: 'hdpi',\n        96: 'xhdpi',\n        144: 'xxhdpi',\n        192: 'xxxhdpi'\n    };\n    // find the best matching icon for a given density or size\n    // @output android_icons\n    var parseIcon = function(icon, icon_size) {\n        // do I have a platform icon for that density already\n        var density = icon.density || sizeToDensityMap[icon_size];\n        if (!density) {\n            // invalid icon defition ( or unsupported size)\n            return;\n        }\n        var previous = android_icons[density];\n        if (previous && previous.platform) {\n            return;\n        }\n        android_icons[density] = icon;\n    };\n\n    // iterate over all icon elements to find the default icon and call parseIcon\n    for (var i=0; i<icons.length; i++) {\n        var icon = icons[i];\n        var size = icon.width;\n        if (!size) {\n            size = icon.height;\n        }\n        if (!size && !icon.density) {\n            if (default_icon) {\n                events.emit('verbose', 'Found extra default icon: ' + icon.src + ' (ignoring in favor of ' + default_icon.src + ')');\n            } else {\n                default_icon = icon;\n            }\n        } else {\n            parseIcon(icon, size);\n        }\n    }\n\n    // The source paths for icons and splashes are relative to\n    // project's config.xml location, so we use it as base path.\n    for (var density in android_icons) {\n        var targetPath = getImageResourcePath(\n            platformResourcesDir, 'mipmap', density, 'icon.png', path.basename(android_icons[density].src));\n        resourceMap[targetPath] = android_icons[density].src;\n    }\n\n    // There's no \"default\" drawable, so assume default == mdpi.\n    if (default_icon && !android_icons.mdpi) {\n        var defaultTargetPath = getImageResourcePath(\n            platformResourcesDir, 'mipmap', 'mdpi', 'icon.png', path.basename(default_icon.src));\n        resourceMap[defaultTargetPath] = default_icon.src;\n    }\n\n    events.emit('verbose', 'Updating icons at ' + platformResourcesDir);\n    FileUpdater.updatePaths(\n        resourceMap, { rootDir: cordovaProject.root }, logFileOp);\n}\n\nfunction cleanIcons(projectRoot, projectConfig, platformResourcesDir) {\n    var icons = projectConfig.getIcons('android');\n    if (icons.length > 0) {\n        var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'icon.png');\n        events.emit('verbose', 'Cleaning icons at ' + platformResourcesDir);\n\n        // No source paths are specified in the map, so updatePaths() will delete the target files.\n        FileUpdater.updatePaths(\n            resourceMap, { rootDir: projectRoot, all: true }, logFileOp);\n    }\n}\n\n/**\n * Gets a map containing resources of a specified name from all drawable folders in a directory.\n */\nfunction mapImageResources(rootDir, subDir, type, resourceName) {\n    var pathMap = {};\n    shell.ls(path.join(rootDir, subDir, type + '-*'))\n    .forEach(function (drawableFolder) {\n        var imagePath = path.join(subDir, path.basename(drawableFolder), resourceName);\n        pathMap[imagePath] = null;\n    });\n    return pathMap;\n}\n\n\nfunction updateFileResources(cordovaProject, platformDir) {\n    var files = cordovaProject.projectConfig.getFileResources('android');\n\n    // if there are resource-file elements in config.xml\n    if (files.length === 0) {\n        events.emit('verbose', 'This app does not have additional resource files defined');\n        return;\n    }\n\n    var resourceMap = {};\n    files.forEach(function(res) {\n        var targetPath = path.join(platformDir, res.target);\n        resourceMap[targetPath] = res.src;\n    });\n\n    events.emit('verbose', 'Updating resource files at ' + platformDir);\n    FileUpdater.updatePaths(\n        resourceMap, { rootDir: cordovaProject.root }, logFileOp);\n}\n\n\nfunction cleanFileResources(projectRoot, projectConfig, platformDir) {\n    var files = projectConfig.getFileResources('android');\n    if (files.length > 0) {\n        events.emit('verbose', 'Cleaning resource files at ' + platformDir);\n\n        var resourceMap = {};\n        files.forEach(function(res) {\n            var filePath = path.join(platformDir, res.target);\n            resourceMap[filePath] = null;\n        });\n\n        FileUpdater.updatePaths(\n                resourceMap, { rootDir: projectRoot, all: true}, logFileOp);\n    }\n}\n\n/**\n * Gets and validates 'AndroidLaunchMode' prepference from config.xml. Returns\n *   preference value and warns if it doesn't seems to be valid\n *\n * @param   {ConfigParser}  platformConfig  A configParser instance for\n *   platform.\n *\n * @return  {String}                  Preference's value from config.xml or\n *   default value, if there is no such preference. The default value is\n *   'singleTop'\n */\nfunction findAndroidLaunchModePreference(platformConfig) {\n    var launchMode = platformConfig.getPreference('AndroidLaunchMode');\n    if (!launchMode) {\n        // Return a default value\n        return 'singleTop';\n    }\n\n    var expectedValues = ['standard', 'singleTop', 'singleTask', 'singleInstance'];\n    var valid = expectedValues.indexOf(launchMode) >= 0;\n    if (!valid) {\n        // Note: warn, but leave the launch mode as developer wanted, in case the list of options changes in the future\n        events.emit('warn', 'Unrecognized value for AndroidLaunchMode preference: ' +\n            launchMode + '. Expected values are: ' + expectedValues.join(', '));\n    }\n\n    return launchMode;\n}\n"
  },
  {
    "path": "platforms/android/cordova/lib/retry.js",
    "content": "#!/usr/bin/env node\n\n/*\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n*/\n\n/* jshint node: true */\n\n'use strict';\n\nvar events = require('cordova-common').events;\n\n/*\n * Retry a promise-returning function a number of times, propagating its\n * results on success or throwing its error on a failed final attempt.\n *\n * @arg {Number}   attemts_left    - The number of times to retry the passed call.\n * @arg {Function} promiseFunction - A function that returns a promise.\n * @arg {...}                      - Arguments to pass to promiseFunction.\n *\n * @returns {Promise}\n */\nmodule.exports.retryPromise = function (attemts_left, promiseFunction) {\n\n    // NOTE:\n    //      get all trailing arguments, by skipping the first two (attemts_left and\n    //      promiseFunction) because they shouldn't get passed to promiseFunction\n    var promiseFunctionArguments = Array.prototype.slice.call(arguments, 2);\n\n    return promiseFunction.apply(undefined, promiseFunctionArguments).then(\n\n        // on success pass results through\n        function onFulfilled(value) {\n            return value;\n        },\n\n        // on rejection either retry, or throw the error\n        function onRejected(error) {\n\n            attemts_left -= 1;\n\n            if (attemts_left < 1) {\n                throw error;\n            }\n\n            events.emit('verbose', 'A retried call failed. Retrying ' + attemts_left + ' more time(s).');\n\n            // retry call self again with the same arguments, except attemts_left is now lower\n            var fullArguments = [attemts_left, promiseFunction].concat(promiseFunctionArguments);\n            return module.exports.retryPromise.apply(undefined, fullArguments);\n        }\n    );\n};\n"
  },
  {
    "path": "platforms/android/cordova/lib/run.js",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\n/* jshint loopfunc:true */\n\nvar path  = require('path'),\n    build = require('./build'),\n    emulator = require('./emulator'),\n    device   = require('./device'),\n    Q = require('q'),\n    events = require('cordova-common').events;\n\nfunction getInstallTarget(runOptions) {\n    var install_target;\n    if (runOptions.target) {\n        install_target = runOptions.target;\n    } else if (runOptions.device) {\n        install_target = '--device';\n    } else if (runOptions.emulator) {\n        install_target = '--emulator';\n    }\n\n    return install_target;\n}\n\n/**\n * Runs the application on a device if available. If no device is found, it will\n *   use a started emulator. If no started emulators are found it will attempt\n *   to start an avd. If no avds are found it will error out.\n *\n * @param   {Object}  runOptions  various run/build options. See Api.js build/run\n *   methods for reference.\n *\n * @return  {Promise}\n */\n module.exports.run = function(runOptions) {\n\n    var self = this;\n    var install_target = getInstallTarget(runOptions);\n\n    return Q()\n    .then(function() {\n        if (!install_target) {\n            // no target given, deploy to device if available, otherwise use the emulator.\n            return device.list()\n            .then(function(device_list) {\n                if (device_list.length > 0) {\n                    events.emit('warn', 'No target specified, deploying to device \\'' + device_list[0] + '\\'.');\n                    install_target = device_list[0];\n                } else {\n                    events.emit('warn', 'No target specified and no devices found, deploying to emulator');\n                    install_target = '--emulator';\n                }\n            });\n        }\n    }).then(function() {\n        if (install_target == '--device') {\n            return device.resolveTarget(null);\n        } else if (install_target == '--emulator') {\n            // Give preference to any already started emulators. Else, start one.\n            return emulator.list_started()\n            .then(function(started) {\n                return started && started.length > 0 ? started[0] : emulator.start();\n            }).then(function(emulatorId) {\n                return emulator.resolveTarget(emulatorId);\n            });\n        }\n        // They specified a specific device/emulator ID.\n        return device.list()\n        .then(function(devices) {\n            if (devices.indexOf(install_target) > -1) {\n                return device.resolveTarget(install_target);\n            }\n            return emulator.list_started()\n            .then(function(started_emulators) {\n                if (started_emulators.indexOf(install_target) > -1) {\n                    return emulator.resolveTarget(install_target);\n                }\n                return emulator.list_images()\n                .then(function(avds) {\n                    // if target emulator isn't started, then start it.\n                    for (var avd in avds) {\n                        if (avds[avd].name == install_target) {\n                            return emulator.start(install_target)\n                            .then(function(emulatorId) {\n                                return emulator.resolveTarget(emulatorId);\n                            });\n                        }\n                    }\n                    return Q.reject('Target \\'' + install_target + '\\' not found, unable to run project');\n                });\n            });\n        });\n    }).then(function(resolvedTarget) {\n        // Better just call self.build, but we're doing some processing of\n        // build results (according to platformApi spec) so they are in different\n        // format than emulator.install expects.\n        // TODO: Update emulator/device.install to handle this change\n        return build.run.call(self, runOptions, resolvedTarget)\n        .then(function(buildResults) {\n            if (resolvedTarget.isEmulator) {\n                return emulator.wait_for_boot(resolvedTarget.target)\n                .then(function () {\n                    return emulator.install(resolvedTarget, buildResults);\n                });\n            }\n            return device.install(resolvedTarget, buildResults);\n        });\n    });\n};\n\nmodule.exports.help = function() {\n    console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]) + ' [options]');\n    console.log('Build options :');\n    console.log('    --debug : Builds project in debug mode');\n    console.log('    --release : Builds project in release mode');\n    console.log('    --nobuild : Runs the currently built project without recompiling');\n    console.log('Deploy options :');\n    console.log('    --device : Will deploy the built project to a device');\n    console.log('    --emulator : Will deploy the built project to an emulator if one exists');\n    console.log('    --target=<target_id> : Installs to the target with the specified id.');\n    process.exit(0);\n};\n"
  },
  {
    "path": "platforms/android/cordova/lib/start-emulator",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar emulator = require('./emulator'),\n      args   = process.argv;\n\nvar install_target;\nif(args.length > 2) {\n    if (args[2].substring(0, 9) == '--target=') {\n        install_target = args[2].substring(9, args[2].length);\n     } else {\n        console.error('ERROR : argument \\'' + args[2] + '\\' not recognized.');\n        process.exit(2);\n     }\n}\n\nemulator.start(install_target).done(null, function(err) {\n    console.error('ERROR: ' + err);\n    process.exit(2);\n});\n\n"
  },
  {
    "path": "platforms/android/cordova/lib/start-emulator.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n:: \n:: http://www.apache.org/licenses/LICENSE-2.0\n:: \n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0start-emulator\"\nIF EXIST %script_path% (\n        node \"%script_path%\" %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'start-emulator' script in 'cordova\\lib' folder, aborting...>&2\n    EXIT /B 1\n)"
  },
  {
    "path": "platforms/android/cordova/log",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar log  = require('./lib/log'),\n    reqs = require('./lib/check_reqs'),\n    args = process.argv;\n\n// Usage support for when args are given\nif(args.length > 2) {\n    log.help();\n} else {\n    reqs.run().done(function() {\n        return log.run();\n    }, function(err) {\n        console.error('ERROR: ' + err);\n        process.exit(2);\n    });\n}\n"
  },
  {
    "path": "platforms/android/cordova/log.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n::\n:: http://www.apache.org/licenses/LICENSE-2.0\n::\n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0log\"\nIF EXIST %script_path% (\n        node %script_path% %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'log' script in 'cordova' folder, aborting...>&2\n    EXIT /B 1\n)"
  },
  {
    "path": "platforms/android/cordova/loggingHelper.js",
    "content": "var CordovaLogger = require('cordova-common').CordovaLogger;\n\nmodule.exports = {\n    adjustLoggerLevel: function (opts) {\n        if (opts instanceof Array) {\n            opts.silent = opts.indexOf('--silent') !== -1;\n            opts.verbose = opts.indexOf('--verbose') !== -1;\n        }\n\n        if (opts.silent) {\n            CordovaLogger.get().setLevel('error');\n        }\n\n        if (opts.verbose) {\n            CordovaLogger.get().setLevel('verbose');\n        }\n    }\n};\n"
  },
  {
    "path": "platforms/android/cordova/run",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar Api = require('./Api');\nvar nopt = require('nopt');\nvar path = require('path');\n\n// Support basic help commands\nif(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0)\n    require('./lib/run').help();\n\n// Do some basic argument parsing\nvar runOpts = nopt({\n    'verbose' : Boolean,\n    'silent' : Boolean,\n    'debug' : Boolean,\n    'release' : Boolean,\n    'nobuild': Boolean,\n    'buildConfig' : path,\n    'archs' : String,\n    'device' : Boolean,\n    'emulator': Boolean,\n    'target' : String\n}, { 'd' : '--verbose' });\n\n// Make runOptions compatible with PlatformApi run method spec\nrunOpts.argv = runOpts.argv.remain;\n\nrequire('./loggingHelper').adjustLoggerLevel(runOpts);\n\nnew Api().run(runOpts)\n.catch(function(err) {\n    console.error(err, err.stack);\n    process.exit(2);\n});\n"
  },
  {
    "path": "platforms/android/cordova/run.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n::\n:: http://www.apache.org/licenses/LICENSE-2.0\n::\n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0run\"\nIF EXIST %script_path% (\n        node %script_path% %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'run' script in 'cordova' folder, aborting...>&2\n    EXIT /B 1\n)"
  },
  {
    "path": "platforms/android/cordova/version",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\n// Coho updates this line:\nvar VERSION = \"6.2.1\";\n\nmodule.exports.version = VERSION;\n\nif (!module.parent) {\n    console.log(VERSION);\n}\n"
  },
  {
    "path": "platforms/android/cordova/version.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n::\n:: http://www.apache.org/licenses/LICENSE-2.0\n::\n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0version\"\nIF EXIST %script_path% (\n        node %script_path% %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'version' script in 'cordova' folder, aborting...>&2\n    EXIT /B 1\n)\n"
  },
  {
    "path": "platforms/android/phonegap-plugin-barcodescanner/piholedroid-barcodescanner.gradle",
    "content": "def DEFAULT_MIN_SDK_VERSION = 15\ndef minSdk = Math.max(DEFAULT_MIN_SDK_VERSION, cdvHelpers.getConfigPreference('android-minSdkVersion',0) as Integer);\nif (cdvMinSdkVersion == null || Integer.parseInt(cdvMinSdkVersion) < minSdk ) {\n    ext.cdvMinSdkVersion = minSdk;\n}\n\nrepositories{\n    jcenter()\n    flatDir{\n        dirs 'libs'\n    }\n}\n\ndependencies {\n    compile 'com.android.support:support-v4:+'\n    compile(name:'barcodescanner', ext:'aar')\n}\n\nandroid {\n    packagingOptions {\n        exclude 'META-INF/NOTICE'\n        exclude 'META-INF/LICENSE'\n    }\n}"
  },
  {
    "path": "platforms/android/platform_www/cordova-js-src/android/nativeapiprovider.js",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n*/\n\n/**\n * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi.\n */\n\nvar nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi');\nvar currentApi = nativeApi;\n\nmodule.exports = {\n    get: function() { return currentApi; },\n    setPreferPrompt: function(value) {\n        currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi;\n    },\n    // Used only by tests.\n    set: function(value) {\n        currentApi = value;\n    }\n};\n"
  },
  {
    "path": "platforms/android/platform_www/cordova-js-src/android/promptbasednativeapi.js",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n*/\n\n/**\n * Implements the API of ExposedJsApi.java, but uses prompt() to communicate.\n * This is used pre-JellyBean, where addJavascriptInterface() is disabled.\n */\n\nmodule.exports = {\n    exec: function(bridgeSecret, service, action, callbackId, argsJson) {\n        return prompt(argsJson, 'gap:'+JSON.stringify([bridgeSecret, service, action, callbackId]));\n    },\n    setNativeToJsBridgeMode: function(bridgeSecret, value) {\n        prompt(value, 'gap_bridge_mode:' + bridgeSecret);\n    },\n    retrieveJsMessages: function(bridgeSecret, fromOnlineEvent) {\n        return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret);\n    }\n};\n"
  },
  {
    "path": "platforms/android/platform_www/cordova-js-src/exec.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n/**\n * Execute a cordova command.  It is up to the native side whether this action\n * is synchronous or asynchronous.  The native side can return:\n *      Synchronous: PluginResult object as a JSON string\n *      Asynchronous: Empty string \"\"\n * If async, the native side will cordova.callbackSuccess or cordova.callbackError,\n * depending upon the result of the action.\n *\n * @param {Function} success    The success callback\n * @param {Function} fail       The fail callback\n * @param {String} service      The name of the service to use\n * @param {String} action       Action to be run in cordova\n * @param {String[]} [args]     Zero or more arguments to pass to the method\n */\nvar cordova = require('cordova'),\n    nativeApiProvider = require('cordova/android/nativeapiprovider'),\n    utils = require('cordova/utils'),\n    base64 = require('cordova/base64'),\n    channel = require('cordova/channel'),\n    jsToNativeModes = {\n        PROMPT: 0,\n        JS_OBJECT: 1\n    },\n    nativeToJsModes = {\n        // Polls for messages using the JS->Native bridge.\n        POLLING: 0,\n        // For LOAD_URL to be viable, it would need to have a work-around for\n        // the bug where the soft-keyboard gets dismissed when a message is sent.\n        LOAD_URL: 1,\n        // For the ONLINE_EVENT to be viable, it would need to intercept all event\n        // listeners (both through addEventListener and window.ononline) as well\n        // as set the navigator property itself.\n        ONLINE_EVENT: 2,\n        EVAL_BRIDGE: 3\n    },\n    jsToNativeBridgeMode,  // Set lazily.\n    nativeToJsBridgeMode = nativeToJsModes.EVAL_BRIDGE,\n    pollEnabled = false,\n    bridgeSecret = -1;\n\nvar messagesFromNative = [];\nvar isProcessing = false;\nvar resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve();\nvar nextTick = resolvedPromise ? function(fn) { resolvedPromise.then(fn); } : function(fn) { setTimeout(fn); };\n\nfunction androidExec(success, fail, service, action, args) {\n    if (bridgeSecret < 0) {\n        // If we ever catch this firing, we'll need to queue up exec()s\n        // and fire them once we get a secret. For now, I don't think\n        // it's possible for exec() to be called since plugins are parsed but\n        // not run until until after onNativeReady.\n        throw new Error('exec() called without bridgeSecret');\n    }\n    // Set default bridge modes if they have not already been set.\n    // By default, we use the failsafe, since addJavascriptInterface breaks too often\n    if (jsToNativeBridgeMode === undefined) {\n        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);\n    }\n\n    // If args is not provided, default to an empty array\n    args = args || [];\n\n    // Process any ArrayBuffers in the args into a string.\n    for (var i = 0; i < args.length; i++) {\n        if (utils.typeName(args[i]) == 'ArrayBuffer') {\n            args[i] = base64.fromArrayBuffer(args[i]);\n        }\n    }\n\n    var callbackId = service + cordova.callbackId++,\n        argsJson = JSON.stringify(args);\n    if (success || fail) {\n        cordova.callbacks[callbackId] = {success:success, fail:fail};\n    }\n\n    var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);\n    // If argsJson was received by Java as null, try again with the PROMPT bridge mode.\n    // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.\n    if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && msgs === \"@Null arguments.\") {\n        androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);\n        androidExec(success, fail, service, action, args);\n        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);\n    } else if (msgs) {\n        messagesFromNative.push(msgs);\n        // Always process async to avoid exceptions messing up stack.\n        nextTick(processMessages);\n    }\n}\n\nandroidExec.init = function() {\n    //CB-11828\n    //This failsafe checks the version of Android and if it's Jellybean, it switches it to\n    //using the Online Event bridge for communicating from Native to JS\n    //\n    //It's ugly, but it's necessary.\n    var check = navigator.userAgent.toLowerCase().match(/android\\s[0-9].[0-9]/);\n    var version_code = check && check[0].match(/4.[0-3].*/);\n    if (version_code != null && nativeToJsBridgeMode == nativeToJsModes.EVAL_BRIDGE) {\n      nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT;\n    }\n\n    bridgeSecret = +prompt('', 'gap_init:' + nativeToJsBridgeMode);\n    channel.onNativeReady.fire();\n};\n\nfunction pollOnceFromOnlineEvent() {\n    pollOnce(true);\n}\n\nfunction pollOnce(opt_fromOnlineEvent) {\n    if (bridgeSecret < 0) {\n        // This can happen when the NativeToJsMessageQueue resets the online state on page transitions.\n        // We know there's nothing to retrieve, so no need to poll.\n        return;\n    }\n    var msgs = nativeApiProvider.get().retrieveJsMessages(bridgeSecret, !!opt_fromOnlineEvent);\n    if (msgs) {\n        messagesFromNative.push(msgs);\n        // Process sync since we know we're already top-of-stack.\n        processMessages();\n    }\n}\n\nfunction pollingTimerFunc() {\n    if (pollEnabled) {\n        pollOnce();\n        setTimeout(pollingTimerFunc, 50);\n    }\n}\n\nfunction hookOnlineApis() {\n    function proxyEvent(e) {\n        cordova.fireWindowEvent(e.type);\n    }\n    // The network module takes care of firing online and offline events.\n    // It currently fires them only on document though, so we bridge them\n    // to window here (while first listening for exec()-releated online/offline\n    // events).\n    window.addEventListener('online', pollOnceFromOnlineEvent, false);\n    window.addEventListener('offline', pollOnceFromOnlineEvent, false);\n    cordova.addWindowEventHandler('online');\n    cordova.addWindowEventHandler('offline');\n    document.addEventListener('online', proxyEvent, false);\n    document.addEventListener('offline', proxyEvent, false);\n}\n\nhookOnlineApis();\n\nandroidExec.jsToNativeModes = jsToNativeModes;\nandroidExec.nativeToJsModes = nativeToJsModes;\n\nandroidExec.setJsToNativeBridgeMode = function(mode) {\n    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {\n        mode = jsToNativeModes.PROMPT;\n    }\n    nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);\n    jsToNativeBridgeMode = mode;\n};\n\nandroidExec.setNativeToJsBridgeMode = function(mode) {\n    if (mode == nativeToJsBridgeMode) {\n        return;\n    }\n    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {\n        pollEnabled = false;\n    }\n\n    nativeToJsBridgeMode = mode;\n    // Tell the native side to switch modes.\n    // Otherwise, it will be set by androidExec.init()\n    if (bridgeSecret >= 0) {\n        nativeApiProvider.get().setNativeToJsBridgeMode(bridgeSecret, mode);\n    }\n\n    if (mode == nativeToJsModes.POLLING) {\n        pollEnabled = true;\n        setTimeout(pollingTimerFunc, 1);\n    }\n};\n\nfunction buildPayload(payload, message) {\n    var payloadKind = message.charAt(0);\n    if (payloadKind == 's') {\n        payload.push(message.slice(1));\n    } else if (payloadKind == 't') {\n        payload.push(true);\n    } else if (payloadKind == 'f') {\n        payload.push(false);\n    } else if (payloadKind == 'N') {\n        payload.push(null);\n    } else if (payloadKind == 'n') {\n        payload.push(+message.slice(1));\n    } else if (payloadKind == 'A') {\n        var data = message.slice(1);\n        payload.push(base64.toArrayBuffer(data));\n    } else if (payloadKind == 'S') {\n        payload.push(window.atob(message.slice(1)));\n    } else if (payloadKind == 'M') {\n        var multipartMessages = message.slice(1);\n        while (multipartMessages !== \"\") {\n            var spaceIdx = multipartMessages.indexOf(' ');\n            var msgLen = +multipartMessages.slice(0, spaceIdx);\n            var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen);\n            multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1);\n            buildPayload(payload, multipartMessage);\n        }\n    } else {\n        payload.push(JSON.parse(message));\n    }\n}\n\n// Processes a single message, as encoded by NativeToJsMessageQueue.java.\nfunction processMessage(message) {\n    var firstChar = message.charAt(0);\n    if (firstChar == 'J') {\n        // This is deprecated on the .java side. It doesn't work with CSP enabled.\n        eval(message.slice(1));\n    } else if (firstChar == 'S' || firstChar == 'F') {\n        var success = firstChar == 'S';\n        var keepCallback = message.charAt(1) == '1';\n        var spaceIdx = message.indexOf(' ', 2);\n        var status = +message.slice(2, spaceIdx);\n        var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);\n        var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);\n        var payloadMessage = message.slice(nextSpaceIdx + 1);\n        var payload = [];\n        buildPayload(payload, payloadMessage);\n        cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);\n    } else {\n        console.log(\"processMessage failed: invalid message: \" + JSON.stringify(message));\n    }\n}\n\nfunction processMessages() {\n    // Check for the reentrant case.\n    if (isProcessing) {\n        return;\n    }\n    if (messagesFromNative.length === 0) {\n        return;\n    }\n    isProcessing = true;\n    try {\n        var msg = popMessageFromQueue();\n        // The Java side can send a * message to indicate that it\n        // still has messages waiting to be retrieved.\n        if (msg == '*' && messagesFromNative.length === 0) {\n            nextTick(pollOnce);\n            return;\n        }\n        processMessage(msg);\n    } finally {\n        isProcessing = false;\n        if (messagesFromNative.length > 0) {\n            nextTick(processMessages);\n        }\n    }\n}\n\nfunction popMessageFromQueue() {\n    var messageBatch = messagesFromNative.shift();\n    if (messageBatch == '*') {\n        return '*';\n    }\n\n    var spaceIdx = messageBatch.indexOf(' ');\n    var msgLen = +messageBatch.slice(0, spaceIdx);\n    var message = messageBatch.substr(spaceIdx + 1, msgLen);\n    messageBatch = messageBatch.slice(spaceIdx + msgLen + 1);\n    if (messageBatch) {\n        messagesFromNative.unshift(messageBatch);\n    }\n    return message;\n}\n\nmodule.exports = androidExec;\n"
  },
  {
    "path": "platforms/android/platform_www/cordova-js-src/platform.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n// The last resume event that was received that had the result of a plugin call.\nvar lastResumeEvent = null;\n\nmodule.exports = {\n    id: 'android',\n    bootstrap: function() {\n        var channel = require('cordova/channel'),\n            cordova = require('cordova'),\n            exec = require('cordova/exec'),\n            modulemapper = require('cordova/modulemapper');\n\n        // Get the shared secret needed to use the bridge.\n        exec.init();\n\n        // TODO: Extract this as a proper plugin.\n        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');\n\n        var APP_PLUGIN_NAME = Number(cordova.platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';\n\n        // Inject a listener for the backbutton on the document.\n        var backButtonChannel = cordova.addDocumentEventHandler('backbutton');\n        backButtonChannel.onHasSubscribersChange = function() {\n            // If we just attached the first handler or detached the last handler,\n            // let native know we need to override the back button.\n            exec(null, null, APP_PLUGIN_NAME, \"overrideBackbutton\", [this.numHandlers == 1]);\n        };\n\n        // Add hardware MENU and SEARCH button handlers\n        cordova.addDocumentEventHandler('menubutton');\n        cordova.addDocumentEventHandler('searchbutton');\n\n        function bindButtonChannel(buttonName) {\n            // generic button bind used for volumeup/volumedown buttons\n            var volumeButtonChannel = cordova.addDocumentEventHandler(buttonName + 'button');\n            volumeButtonChannel.onHasSubscribersChange = function() {\n                exec(null, null, APP_PLUGIN_NAME, \"overrideButton\", [buttonName, this.numHandlers == 1]);\n            };\n        }\n        // Inject a listener for the volume buttons on the document.\n        bindButtonChannel('volumeup');\n        bindButtonChannel('volumedown');\n\n        // The resume event is not \"sticky\", but it is possible that the event\n        // will contain the result of a plugin call. We need to ensure that the\n        // plugin result is delivered even after the event is fired (CB-10498)\n        var cordovaAddEventListener = document.addEventListener;\n\n        document.addEventListener = function(evt, handler, capture) {\n            cordovaAddEventListener(evt, handler, capture);\n\n            if (evt === 'resume' && lastResumeEvent) {\n                handler(lastResumeEvent);\n            }\n        };\n\n        // Let native code know we are all done on the JS side.\n        // Native code will then un-hide the WebView.\n        channel.onCordovaReady.subscribe(function() {\n            exec(onMessageFromNative, null, APP_PLUGIN_NAME, 'messageChannel', []);\n            exec(null, null, APP_PLUGIN_NAME, \"show\", []);\n        });\n    }\n};\n\nfunction onMessageFromNative(msg) {\n    var cordova = require('cordova');\n    var action = msg.action;\n\n    switch (action)\n    {\n        // Button events\n        case 'backbutton':\n        case 'menubutton':\n        case 'searchbutton':\n        // App life cycle events\n        case 'pause':\n        // Volume events\n        case 'volumedownbutton':\n        case 'volumeupbutton':\n            cordova.fireDocumentEvent(action);\n            break;\n        case 'resume':\n            if(arguments.length > 1 && msg.pendingResult) {\n                if(arguments.length === 2) {\n                    msg.pendingResult.result = arguments[1];\n                } else {\n                    // The plugin returned a multipart message\n                    var res = [];\n                    for(var i = 1; i < arguments.length; i++) {\n                        res.push(arguments[i]);\n                    }\n                    msg.pendingResult.result = res;\n                }\n\n                // Save the plugin result so that it can be delivered to the js\n                // even if they miss the initial firing of the event\n                lastResumeEvent = msg;\n            }\n            cordova.fireDocumentEvent(action, msg);\n            break;\n        default:\n            throw new Error('Unknown event action ' + action);\n    }\n}\n"
  },
  {
    "path": "platforms/android/platform_www/cordova-js-src/plugin/android/app.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nvar exec = require('cordova/exec');\nvar APP_PLUGIN_NAME = Number(require('cordova').platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';\n\nmodule.exports = {\n    /**\n    * Clear the resource cache.\n    */\n    clearCache:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"clearCache\", []);\n    },\n\n    /**\n    * Load the url into the webview or into new browser instance.\n    *\n    * @param url           The URL to load\n    * @param props         Properties that can be passed in to the activity:\n    *      wait: int                           => wait msec before loading URL\n    *      loadingDialog: \"Title,Message\"      => display a native loading dialog\n    *      loadUrlTimeoutValue: int            => time in msec to wait before triggering a timeout error\n    *      clearHistory: boolean              => clear webview history (default=false)\n    *      openExternal: boolean              => open in a new browser (default=false)\n    *\n    * Example:\n    *      navigator.app.loadUrl(\"http://server/myapp/index.html\", {wait:2000, loadingDialog:\"Wait,Loading App\", loadUrlTimeoutValue: 60000});\n    */\n    loadUrl:function(url, props) {\n        exec(null, null, APP_PLUGIN_NAME, \"loadUrl\", [url, props]);\n    },\n\n    /**\n    * Cancel loadUrl that is waiting to be loaded.\n    */\n    cancelLoadUrl:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"cancelLoadUrl\", []);\n    },\n\n    /**\n    * Clear web history in this web view.\n    * Instead of BACK button loading the previous web page, it will exit the app.\n    */\n    clearHistory:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"clearHistory\", []);\n    },\n\n    /**\n    * Go to previous page displayed.\n    * This is the same as pressing the backbutton on Android device.\n    */\n    backHistory:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"backHistory\", []);\n    },\n\n    /**\n    * Override the default behavior of the Android back button.\n    * If overridden, when the back button is pressed, the \"backKeyDown\" JavaScript event will be fired.\n    *\n    * Note: The user should not have to call this method.  Instead, when the user\n    *       registers for the \"backbutton\" event, this is automatically done.\n    *\n    * @param override        T=override, F=cancel override\n    */\n    overrideBackbutton:function(override) {\n        exec(null, null, APP_PLUGIN_NAME, \"overrideBackbutton\", [override]);\n    },\n\n    /**\n    * Override the default behavior of the Android volume button.\n    * If overridden, when the volume button is pressed, the \"volume[up|down]button\"\n    * JavaScript event will be fired.\n    *\n    * Note: The user should not have to call this method.  Instead, when the user\n    *       registers for the \"volume[up|down]button\" event, this is automatically done.\n    *\n    * @param button          volumeup, volumedown\n    * @param override        T=override, F=cancel override\n    */\n    overrideButton:function(button, override) {\n        exec(null, null, APP_PLUGIN_NAME, \"overrideButton\", [button, override]);\n    },\n\n    /**\n    * Exit and terminate the application.\n    */\n    exitApp:function() {\n        return exec(null, null, APP_PLUGIN_NAME, \"exitApp\", []);\n    }\n};\n"
  },
  {
    "path": "platforms/android/platform_www/cordova.js",
    "content": "// Platform: android\n// 7c5fcc5a5adfbf3fb8ceaf36fbdd4bd970bd9c20\n/*\n Licensed to the Apache Software Foundation (ASF) under one\n or more contributor license agreements.  See the NOTICE file\n distributed with this work for additional information\n regarding copyright ownership.  The ASF licenses this file\n to you under the Apache License, Version 2.0 (the\n \"License\"); you may not use this file except in compliance\n with the License.  You may obtain a copy of the License at\n \n     http://www.apache.org/licenses/LICENSE-2.0\n \n Unless required by applicable law or agreed to in writing,\n software distributed under the License is distributed on an\n \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n KIND, either express or implied.  See the License for the\n specific language governing permissions and limitations\n under the License.\n*/\n;(function() {\nvar PLATFORM_VERSION_BUILD_LABEL = '6.2.1';\n// file: src/scripts/require.js\n\n/*jshint -W079 */\n/*jshint -W020 */\n\nvar require,\n    define;\n\n(function () {\n    var modules = {},\n    // Stack of moduleIds currently being built.\n        requireStack = [],\n    // Map of module ID -> index into requireStack of modules currently being built.\n        inProgressModules = {},\n        SEPARATOR = \".\";\n\n\n\n    function build(module) {\n        var factory = module.factory,\n            localRequire = function (id) {\n                var resultantId = id;\n                //Its a relative path, so lop off the last portion and add the id (minus \"./\")\n                if (id.charAt(0) === \".\") {\n                    resultantId = module.id.slice(0, module.id.lastIndexOf(SEPARATOR)) + SEPARATOR + id.slice(2);\n                }\n                return require(resultantId);\n            };\n        module.exports = {};\n        delete module.factory;\n        factory(localRequire, module.exports, module);\n        return module.exports;\n    }\n\n    require = function (id) {\n        if (!modules[id]) {\n            throw \"module \" + id + \" not found\";\n        } else if (id in inProgressModules) {\n            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;\n            throw \"Cycle in require graph: \" + cycle;\n        }\n        if (modules[id].factory) {\n            try {\n                inProgressModules[id] = requireStack.length;\n                requireStack.push(id);\n                return build(modules[id]);\n            } finally {\n                delete inProgressModules[id];\n                requireStack.pop();\n            }\n        }\n        return modules[id].exports;\n    };\n\n    define = function (id, factory) {\n        if (modules[id]) {\n            throw \"module \" + id + \" already defined\";\n        }\n\n        modules[id] = {\n            id: id,\n            factory: factory\n        };\n    };\n\n    define.remove = function (id) {\n        delete modules[id];\n    };\n\n    define.moduleMap = modules;\n})();\n\n//Export for use in node\nif (typeof module === \"object\" && typeof require === \"function\") {\n    module.exports.require = require;\n    module.exports.define = define;\n}\n\n// file: src/cordova.js\ndefine(\"cordova\", function(require, exports, module) {\n\n// Workaround for Windows 10 in hosted environment case\n// http://www.w3.org/html/wg/drafts/html/master/browsers.html#named-access-on-the-window-object\nif (window.cordova && !(window.cordova instanceof HTMLElement)) {\n    throw new Error(\"cordova already defined\");\n}\n\n\nvar channel = require('cordova/channel');\nvar platform = require('cordova/platform');\n\n\n/**\n * Intercept calls to addEventListener + removeEventListener and handle deviceready,\n * resume, and pause events.\n */\nvar m_document_addEventListener = document.addEventListener;\nvar m_document_removeEventListener = document.removeEventListener;\nvar m_window_addEventListener = window.addEventListener;\nvar m_window_removeEventListener = window.removeEventListener;\n\n/**\n * Houses custom event handlers to intercept on document + window event listeners.\n */\nvar documentEventHandlers = {},\n    windowEventHandlers = {};\n\ndocument.addEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    if (typeof documentEventHandlers[e] != 'undefined') {\n        documentEventHandlers[e].subscribe(handler);\n    } else {\n        m_document_addEventListener.call(document, evt, handler, capture);\n    }\n};\n\nwindow.addEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    if (typeof windowEventHandlers[e] != 'undefined') {\n        windowEventHandlers[e].subscribe(handler);\n    } else {\n        m_window_addEventListener.call(window, evt, handler, capture);\n    }\n};\n\ndocument.removeEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    // If unsubscribing from an event that is handled by a plugin\n    if (typeof documentEventHandlers[e] != \"undefined\") {\n        documentEventHandlers[e].unsubscribe(handler);\n    } else {\n        m_document_removeEventListener.call(document, evt, handler, capture);\n    }\n};\n\nwindow.removeEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    // If unsubscribing from an event that is handled by a plugin\n    if (typeof windowEventHandlers[e] != \"undefined\") {\n        windowEventHandlers[e].unsubscribe(handler);\n    } else {\n        m_window_removeEventListener.call(window, evt, handler, capture);\n    }\n};\n\nfunction createEvent(type, data) {\n    var event = document.createEvent('Events');\n    event.initEvent(type, false, false);\n    if (data) {\n        for (var i in data) {\n            if (data.hasOwnProperty(i)) {\n                event[i] = data[i];\n            }\n        }\n    }\n    return event;\n}\n\n\nvar cordova = {\n    define:define,\n    require:require,\n    version:PLATFORM_VERSION_BUILD_LABEL,\n    platformVersion:PLATFORM_VERSION_BUILD_LABEL,\n    platformId:platform.id,\n    /**\n     * Methods to add/remove your own addEventListener hijacking on document + window.\n     */\n    addWindowEventHandler:function(event) {\n        return (windowEventHandlers[event] = channel.create(event));\n    },\n    addStickyDocumentEventHandler:function(event) {\n        return (documentEventHandlers[event] = channel.createSticky(event));\n    },\n    addDocumentEventHandler:function(event) {\n        return (documentEventHandlers[event] = channel.create(event));\n    },\n    removeWindowEventHandler:function(event) {\n        delete windowEventHandlers[event];\n    },\n    removeDocumentEventHandler:function(event) {\n        delete documentEventHandlers[event];\n    },\n    /**\n     * Retrieve original event handlers that were replaced by Cordova\n     *\n     * @return object\n     */\n    getOriginalHandlers: function() {\n        return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},\n        'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};\n    },\n    /**\n     * Method to fire event from native code\n     * bNoDetach is required for events which cause an exception which needs to be caught in native code\n     */\n    fireDocumentEvent: function(type, data, bNoDetach) {\n        var evt = createEvent(type, data);\n        if (typeof documentEventHandlers[type] != 'undefined') {\n            if( bNoDetach ) {\n                documentEventHandlers[type].fire(evt);\n            }\n            else {\n                setTimeout(function() {\n                    // Fire deviceready on listeners that were registered before cordova.js was loaded.\n                    if (type == 'deviceready') {\n                        document.dispatchEvent(evt);\n                    }\n                    documentEventHandlers[type].fire(evt);\n                }, 0);\n            }\n        } else {\n            document.dispatchEvent(evt);\n        }\n    },\n    fireWindowEvent: function(type, data) {\n        var evt = createEvent(type,data);\n        if (typeof windowEventHandlers[type] != 'undefined') {\n            setTimeout(function() {\n                windowEventHandlers[type].fire(evt);\n            }, 0);\n        } else {\n            window.dispatchEvent(evt);\n        }\n    },\n\n    /**\n     * Plugin callback mechanism.\n     */\n    // Randomize the starting callbackId to avoid collisions after refreshing or navigating.\n    // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.\n    callbackId: Math.floor(Math.random() * 2000000000),\n    callbacks:  {},\n    callbackStatus: {\n        NO_RESULT: 0,\n        OK: 1,\n        CLASS_NOT_FOUND_EXCEPTION: 2,\n        ILLEGAL_ACCESS_EXCEPTION: 3,\n        INSTANTIATION_EXCEPTION: 4,\n        MALFORMED_URL_EXCEPTION: 5,\n        IO_EXCEPTION: 6,\n        INVALID_ACTION: 7,\n        JSON_EXCEPTION: 8,\n        ERROR: 9\n    },\n\n    /**\n     * Called by native code when returning successful result from an action.\n     */\n    callbackSuccess: function(callbackId, args) {\n        cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);\n    },\n\n    /**\n     * Called by native code when returning error result from an action.\n     */\n    callbackError: function(callbackId, args) {\n        // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.\n        // Derive success from status.\n        cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);\n    },\n\n    /**\n     * Called by native code when returning the result from an action.\n     */\n    callbackFromNative: function(callbackId, isSuccess, status, args, keepCallback) {\n        try {\n            var callback = cordova.callbacks[callbackId];\n            if (callback) {\n                if (isSuccess && status == cordova.callbackStatus.OK) {\n                    callback.success && callback.success.apply(null, args);\n                } else if (!isSuccess) {\n                    callback.fail && callback.fail.apply(null, args);\n                }\n                /*\n                else\n                    Note, this case is intentionally not caught.\n                    this can happen if isSuccess is true, but callbackStatus is NO_RESULT\n                    which is used to remove a callback from the list without calling the callbacks\n                    typically keepCallback is false in this case\n                */\n                // Clear callback if not expecting any more results\n                if (!keepCallback) {\n                    delete cordova.callbacks[callbackId];\n                }\n            }\n        }\n        catch (err) {\n            var msg = \"Error in \" + (isSuccess ? \"Success\" : \"Error\") + \" callbackId: \" + callbackId + \" : \" + err;\n            console && console.log && console.log(msg);\n            cordova.fireWindowEvent(\"cordovacallbackerror\", { 'message': msg });\n            throw err;\n        }\n    },\n    addConstructor: function(func) {\n        channel.onCordovaReady.subscribe(function() {\n            try {\n                func();\n            } catch(e) {\n                console.log(\"Failed to run constructor: \" + e);\n            }\n        });\n    }\n};\n\n\nmodule.exports = cordova;\n\n});\n\n// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/android/nativeapiprovider.js\ndefine(\"cordova/android/nativeapiprovider\", function(require, exports, module) {\n\n/**\n * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi.\n */\n\nvar nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi');\nvar currentApi = nativeApi;\n\nmodule.exports = {\n    get: function() { return currentApi; },\n    setPreferPrompt: function(value) {\n        currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi;\n    },\n    // Used only by tests.\n    set: function(value) {\n        currentApi = value;\n    }\n};\n\n});\n\n// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/android/promptbasednativeapi.js\ndefine(\"cordova/android/promptbasednativeapi\", function(require, exports, module) {\n\n/**\n * Implements the API of ExposedJsApi.java, but uses prompt() to communicate.\n * This is used pre-JellyBean, where addJavascriptInterface() is disabled.\n */\n\nmodule.exports = {\n    exec: function(bridgeSecret, service, action, callbackId, argsJson) {\n        return prompt(argsJson, 'gap:'+JSON.stringify([bridgeSecret, service, action, callbackId]));\n    },\n    setNativeToJsBridgeMode: function(bridgeSecret, value) {\n        prompt(value, 'gap_bridge_mode:' + bridgeSecret);\n    },\n    retrieveJsMessages: function(bridgeSecret, fromOnlineEvent) {\n        return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret);\n    }\n};\n\n});\n\n// file: src/common/argscheck.js\ndefine(\"cordova/argscheck\", function(require, exports, module) {\n\nvar utils = require('cordova/utils');\n\nvar moduleExports = module.exports;\n\nvar typeMap = {\n    'A': 'Array',\n    'D': 'Date',\n    'N': 'Number',\n    'S': 'String',\n    'F': 'Function',\n    'O': 'Object'\n};\n\nfunction extractParamName(callee, argIndex) {\n    return (/.*?\\((.*?)\\)/).exec(callee)[1].split(', ')[argIndex];\n}\n\nfunction checkArgs(spec, functionName, args, opt_callee) {\n    if (!moduleExports.enableChecks) {\n        return;\n    }\n    var errMsg = null;\n    var typeName;\n    for (var i = 0; i < spec.length; ++i) {\n        var c = spec.charAt(i),\n            cUpper = c.toUpperCase(),\n            arg = args[i];\n        // Asterix means allow anything.\n        if (c == '*') {\n            continue;\n        }\n        typeName = utils.typeName(arg);\n        if ((arg === null || arg === undefined) && c == cUpper) {\n            continue;\n        }\n        if (typeName != typeMap[cUpper]) {\n            errMsg = 'Expected ' + typeMap[cUpper];\n            break;\n        }\n    }\n    if (errMsg) {\n        errMsg += ', but got ' + typeName + '.';\n        errMsg = 'Wrong type for parameter \"' + extractParamName(opt_callee || args.callee, i) + '\" of ' + functionName + ': ' + errMsg;\n        // Don't log when running unit tests.\n        if (typeof jasmine == 'undefined') {\n            console.error(errMsg);\n        }\n        throw TypeError(errMsg);\n    }\n}\n\nfunction getValue(value, defaultValue) {\n    return value === undefined ? defaultValue : value;\n}\n\nmoduleExports.checkArgs = checkArgs;\nmoduleExports.getValue = getValue;\nmoduleExports.enableChecks = true;\n\n\n});\n\n// file: src/common/base64.js\ndefine(\"cordova/base64\", function(require, exports, module) {\n\nvar base64 = exports;\n\nbase64.fromArrayBuffer = function(arrayBuffer) {\n    var array = new Uint8Array(arrayBuffer);\n    return uint8ToBase64(array);\n};\n\nbase64.toArrayBuffer = function(str) {\n    var decodedStr = typeof atob != 'undefined' ? atob(str) : new Buffer(str,'base64').toString('binary');\n    var arrayBuffer = new ArrayBuffer(decodedStr.length);\n    var array = new Uint8Array(arrayBuffer);\n    for (var i=0, len=decodedStr.length; i < len; i++) {\n        array[i] = decodedStr.charCodeAt(i);\n    }\n    return arrayBuffer;\n};\n\n//------------------------------------------------------------------------------\n\n/* This code is based on the performance tests at http://jsperf.com/b64tests\n * This 12-bit-at-a-time algorithm was the best performing version on all\n * platforms tested.\n */\n\nvar b64_6bit = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nvar b64_12bit;\n\nvar b64_12bitTable = function() {\n    b64_12bit = [];\n    for (var i=0; i<64; i++) {\n        for (var j=0; j<64; j++) {\n            b64_12bit[i*64+j] = b64_6bit[i] + b64_6bit[j];\n        }\n    }\n    b64_12bitTable = function() { return b64_12bit; };\n    return b64_12bit;\n};\n\nfunction uint8ToBase64(rawData) {\n    var numBytes = rawData.byteLength;\n    var output=\"\";\n    var segment;\n    var table = b64_12bitTable();\n    for (var i=0;i<numBytes-2;i+=3) {\n        segment = (rawData[i] << 16) + (rawData[i+1] << 8) + rawData[i+2];\n        output += table[segment >> 12];\n        output += table[segment & 0xfff];\n    }\n    if (numBytes - i == 2) {\n        segment = (rawData[i] << 16) + (rawData[i+1] << 8);\n        output += table[segment >> 12];\n        output += b64_6bit[(segment & 0xfff) >> 6];\n        output += '=';\n    } else if (numBytes - i == 1) {\n        segment = (rawData[i] << 16);\n        output += table[segment >> 12];\n        output += '==';\n    }\n    return output;\n}\n\n});\n\n// file: src/common/builder.js\ndefine(\"cordova/builder\", function(require, exports, module) {\n\nvar utils = require('cordova/utils');\n\nfunction each(objects, func, context) {\n    for (var prop in objects) {\n        if (objects.hasOwnProperty(prop)) {\n            func.apply(context, [objects[prop], prop]);\n        }\n    }\n}\n\nfunction clobber(obj, key, value) {\n    exports.replaceHookForTesting(obj, key);\n    var needsProperty = false;\n    try {\n        obj[key] = value;\n    } catch (e) {\n        needsProperty = true;\n    }\n    // Getters can only be overridden by getters.\n    if (needsProperty || obj[key] !== value) {\n        utils.defineGetter(obj, key, function() {\n            return value;\n        });\n    }\n}\n\nfunction assignOrWrapInDeprecateGetter(obj, key, value, message) {\n    if (message) {\n        utils.defineGetter(obj, key, function() {\n            console.log(message);\n            delete obj[key];\n            clobber(obj, key, value);\n            return value;\n        });\n    } else {\n        clobber(obj, key, value);\n    }\n}\n\nfunction include(parent, objects, clobber, merge) {\n    each(objects, function (obj, key) {\n        try {\n            var result = obj.path ? require(obj.path) : {};\n\n            if (clobber) {\n                // Clobber if it doesn't exist.\n                if (typeof parent[key] === 'undefined') {\n                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);\n                } else if (typeof obj.path !== 'undefined') {\n                    // If merging, merge properties onto parent, otherwise, clobber.\n                    if (merge) {\n                        recursiveMerge(parent[key], result);\n                    } else {\n                        assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);\n                    }\n                }\n                result = parent[key];\n            } else {\n                // Overwrite if not currently defined.\n                if (typeof parent[key] == 'undefined') {\n                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);\n                } else {\n                    // Set result to what already exists, so we can build children into it if they exist.\n                    result = parent[key];\n                }\n            }\n\n            if (obj.children) {\n                include(result, obj.children, clobber, merge);\n            }\n        } catch(e) {\n            utils.alert('Exception building Cordova JS globals: ' + e + ' for key \"' + key + '\"');\n        }\n    });\n}\n\n/**\n * Merge properties from one object onto another recursively.  Properties from\n * the src object will overwrite existing target property.\n *\n * @param target Object to merge properties into.\n * @param src Object to merge properties from.\n */\nfunction recursiveMerge(target, src) {\n    for (var prop in src) {\n        if (src.hasOwnProperty(prop)) {\n            if (target.prototype && target.prototype.constructor === target) {\n                // If the target object is a constructor override off prototype.\n                clobber(target.prototype, prop, src[prop]);\n            } else {\n                if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {\n                    recursiveMerge(target[prop], src[prop]);\n                } else {\n                    clobber(target, prop, src[prop]);\n                }\n            }\n        }\n    }\n}\n\nexports.buildIntoButDoNotClobber = function(objects, target) {\n    include(target, objects, false, false);\n};\nexports.buildIntoAndClobber = function(objects, target) {\n    include(target, objects, true, false);\n};\nexports.buildIntoAndMerge = function(objects, target) {\n    include(target, objects, true, true);\n};\nexports.recursiveMerge = recursiveMerge;\nexports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;\nexports.replaceHookForTesting = function() {};\n\n});\n\n// file: src/common/channel.js\ndefine(\"cordova/channel\", function(require, exports, module) {\n\nvar utils = require('cordova/utils'),\n    nextGuid = 1;\n\n/**\n * Custom pub-sub \"channel\" that can have functions subscribed to it\n * This object is used to define and control firing of events for\n * cordova initialization, as well as for custom events thereafter.\n *\n * The order of events during page load and Cordova startup is as follows:\n *\n * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.\n * onNativeReady*              Internal event that indicates the Cordova native side is ready.\n * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.\n * onDeviceReady*              User event fired to indicate that Cordova is ready\n * onResume                    User event fired to indicate a start/resume lifecycle event\n * onPause                     User event fired to indicate a pause lifecycle event\n *\n * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.\n * All listeners that subscribe after the event is fired will be executed right away.\n *\n * The only Cordova events that user code should register for are:\n *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript\n *      pause                 App has moved to background\n *      resume                App has returned to foreground\n *\n * Listeners can be registered as:\n *      document.addEventListener(\"deviceready\", myDeviceReadyListener, false);\n *      document.addEventListener(\"resume\", myResumeListener, false);\n *      document.addEventListener(\"pause\", myPauseListener, false);\n *\n * The DOM lifecycle events should be used for saving and restoring state\n *      window.onload\n *      window.onunload\n *\n */\n\n/**\n * Channel\n * @constructor\n * @param type  String the channel name\n */\nvar Channel = function(type, sticky) {\n    this.type = type;\n    // Map of guid -> function.\n    this.handlers = {};\n    // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.\n    this.state = sticky ? 1 : 0;\n    // Used in sticky mode to remember args passed to fire().\n    this.fireArgs = null;\n    // Used by onHasSubscribersChange to know if there are any listeners.\n    this.numHandlers = 0;\n    // Function that is called when the first listener is subscribed, or when\n    // the last listener is unsubscribed.\n    this.onHasSubscribersChange = null;\n},\n    channel = {\n        /**\n         * Calls the provided function only after all of the channels specified\n         * have been fired. All channels must be sticky channels.\n         */\n        join: function(h, c) {\n            var len = c.length,\n                i = len,\n                f = function() {\n                    if (!(--i)) h();\n                };\n            for (var j=0; j<len; j++) {\n                if (c[j].state === 0) {\n                    throw Error('Can only use join with sticky channels.');\n                }\n                c[j].subscribe(f);\n            }\n            if (!len) h();\n        },\n        create: function(type) {\n            return channel[type] = new Channel(type, false);\n        },\n        createSticky: function(type) {\n            return channel[type] = new Channel(type, true);\n        },\n\n        /**\n         * cordova Channels that must fire before \"deviceready\" is fired.\n         */\n        deviceReadyChannelsArray: [],\n        deviceReadyChannelsMap: {},\n\n        /**\n         * Indicate that a feature needs to be initialized before it is ready to be used.\n         * This holds up Cordova's \"deviceready\" event until the feature has been initialized\n         * and Cordova.initComplete(feature) is called.\n         *\n         * @param feature {String}     The unique feature name\n         */\n        waitForInitialization: function(feature) {\n            if (feature) {\n                var c = channel[feature] || this.createSticky(feature);\n                this.deviceReadyChannelsMap[feature] = c;\n                this.deviceReadyChannelsArray.push(c);\n            }\n        },\n\n        /**\n         * Indicate that initialization code has completed and the feature is ready to be used.\n         *\n         * @param feature {String}     The unique feature name\n         */\n        initializationComplete: function(feature) {\n            var c = this.deviceReadyChannelsMap[feature];\n            if (c) {\n                c.fire();\n            }\n        }\n    };\n\nfunction checkSubscriptionArgument(argument) {\n    if (typeof argument !== \"function\" && typeof argument.handleEvent !== \"function\") {\n        throw new Error(\n                \"Must provide a function or an EventListener object \" +\n                \"implementing the handleEvent interface.\"\n        );\n    }\n}\n\n/**\n * Subscribes the given function to the channel. Any time that\n * Channel.fire is called so too will the function.\n * Optionally specify an execution context for the function\n * and a guid that can be used to stop subscribing to the channel.\n * Returns the guid.\n */\nChannel.prototype.subscribe = function(eventListenerOrFunction, eventListener) {\n    checkSubscriptionArgument(eventListenerOrFunction);\n    var handleEvent, guid;\n\n    if (eventListenerOrFunction && typeof eventListenerOrFunction === \"object\") {\n        // Received an EventListener object implementing the handleEvent interface\n        handleEvent = eventListenerOrFunction.handleEvent;\n        eventListener = eventListenerOrFunction;\n    } else {\n        // Received a function to handle event\n        handleEvent = eventListenerOrFunction;\n    }\n\n    if (this.state == 2) {\n        handleEvent.apply(eventListener || this, this.fireArgs);\n        return;\n    }\n\n    guid = eventListenerOrFunction.observer_guid;\n    if (typeof eventListener === \"object\") {\n        handleEvent = utils.close(eventListener, handleEvent);\n    }\n\n    if (!guid) {\n        // First time any channel has seen this subscriber\n        guid = '' + nextGuid++;\n    }\n    handleEvent.observer_guid = guid;\n    eventListenerOrFunction.observer_guid = guid;\n\n    // Don't add the same handler more than once.\n    if (!this.handlers[guid]) {\n        this.handlers[guid] = handleEvent;\n        this.numHandlers++;\n        if (this.numHandlers == 1) {\n            this.onHasSubscribersChange && this.onHasSubscribersChange();\n        }\n    }\n};\n\n/**\n * Unsubscribes the function with the given guid from the channel.\n */\nChannel.prototype.unsubscribe = function(eventListenerOrFunction) {\n    checkSubscriptionArgument(eventListenerOrFunction);\n    var handleEvent, guid, handler;\n\n    if (eventListenerOrFunction && typeof eventListenerOrFunction === \"object\") {\n        // Received an EventListener object implementing the handleEvent interface\n        handleEvent = eventListenerOrFunction.handleEvent;\n    } else {\n        // Received a function to handle event\n        handleEvent = eventListenerOrFunction;\n    }\n\n    guid = handleEvent.observer_guid;\n    handler = this.handlers[guid];\n    if (handler) {\n        delete this.handlers[guid];\n        this.numHandlers--;\n        if (this.numHandlers === 0) {\n            this.onHasSubscribersChange && this.onHasSubscribersChange();\n        }\n    }\n};\n\n/**\n * Calls all functions subscribed to this channel.\n */\nChannel.prototype.fire = function(e) {\n    var fail = false,\n        fireArgs = Array.prototype.slice.call(arguments);\n    // Apply stickiness.\n    if (this.state == 1) {\n        this.state = 2;\n        this.fireArgs = fireArgs;\n    }\n    if (this.numHandlers) {\n        // Copy the values first so that it is safe to modify it from within\n        // callbacks.\n        var toCall = [];\n        for (var item in this.handlers) {\n            toCall.push(this.handlers[item]);\n        }\n        for (var i = 0; i < toCall.length; ++i) {\n            toCall[i].apply(this, fireArgs);\n        }\n        if (this.state == 2 && this.numHandlers) {\n            this.numHandlers = 0;\n            this.handlers = {};\n            this.onHasSubscribersChange && this.onHasSubscribersChange();\n        }\n    }\n};\n\n\n// defining them here so they are ready super fast!\n// DOM event that is received when the web page is loaded and parsed.\nchannel.createSticky('onDOMContentLoaded');\n\n// Event to indicate the Cordova native side is ready.\nchannel.createSticky('onNativeReady');\n\n// Event to indicate that all Cordova JavaScript objects have been created\n// and it's time to run plugin constructors.\nchannel.createSticky('onCordovaReady');\n\n// Event to indicate that all automatically loaded JS plugins are loaded and ready.\n// FIXME remove this\nchannel.createSticky('onPluginsReady');\n\n// Event to indicate that Cordova is ready\nchannel.createSticky('onDeviceReady');\n\n// Event to indicate a resume lifecycle event\nchannel.create('onResume');\n\n// Event to indicate a pause lifecycle event\nchannel.create('onPause');\n\n// Channels that must fire before \"deviceready\" is fired.\nchannel.waitForInitialization('onCordovaReady');\nchannel.waitForInitialization('onDOMContentLoaded');\n\nmodule.exports = channel;\n\n});\n\n// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/exec.js\ndefine(\"cordova/exec\", function(require, exports, module) {\n\n/**\n * Execute a cordova command.  It is up to the native side whether this action\n * is synchronous or asynchronous.  The native side can return:\n *      Synchronous: PluginResult object as a JSON string\n *      Asynchronous: Empty string \"\"\n * If async, the native side will cordova.callbackSuccess or cordova.callbackError,\n * depending upon the result of the action.\n *\n * @param {Function} success    The success callback\n * @param {Function} fail       The fail callback\n * @param {String} service      The name of the service to use\n * @param {String} action       Action to be run in cordova\n * @param {String[]} [args]     Zero or more arguments to pass to the method\n */\nvar cordova = require('cordova'),\n    nativeApiProvider = require('cordova/android/nativeapiprovider'),\n    utils = require('cordova/utils'),\n    base64 = require('cordova/base64'),\n    channel = require('cordova/channel'),\n    jsToNativeModes = {\n        PROMPT: 0,\n        JS_OBJECT: 1\n    },\n    nativeToJsModes = {\n        // Polls for messages using the JS->Native bridge.\n        POLLING: 0,\n        // For LOAD_URL to be viable, it would need to have a work-around for\n        // the bug where the soft-keyboard gets dismissed when a message is sent.\n        LOAD_URL: 1,\n        // For the ONLINE_EVENT to be viable, it would need to intercept all event\n        // listeners (both through addEventListener and window.ononline) as well\n        // as set the navigator property itself.\n        ONLINE_EVENT: 2,\n        EVAL_BRIDGE: 3\n    },\n    jsToNativeBridgeMode,  // Set lazily.\n    nativeToJsBridgeMode = nativeToJsModes.EVAL_BRIDGE,\n    pollEnabled = false,\n    bridgeSecret = -1;\n\nvar messagesFromNative = [];\nvar isProcessing = false;\nvar resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve();\nvar nextTick = resolvedPromise ? function(fn) { resolvedPromise.then(fn); } : function(fn) { setTimeout(fn); };\n\nfunction androidExec(success, fail, service, action, args) {\n    if (bridgeSecret < 0) {\n        // If we ever catch this firing, we'll need to queue up exec()s\n        // and fire them once we get a secret. For now, I don't think\n        // it's possible for exec() to be called since plugins are parsed but\n        // not run until until after onNativeReady.\n        throw new Error('exec() called without bridgeSecret');\n    }\n    // Set default bridge modes if they have not already been set.\n    // By default, we use the failsafe, since addJavascriptInterface breaks too often\n    if (jsToNativeBridgeMode === undefined) {\n        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);\n    }\n\n    // If args is not provided, default to an empty array\n    args = args || [];\n\n    // Process any ArrayBuffers in the args into a string.\n    for (var i = 0; i < args.length; i++) {\n        if (utils.typeName(args[i]) == 'ArrayBuffer') {\n            args[i] = base64.fromArrayBuffer(args[i]);\n        }\n    }\n\n    var callbackId = service + cordova.callbackId++,\n        argsJson = JSON.stringify(args);\n    if (success || fail) {\n        cordova.callbacks[callbackId] = {success:success, fail:fail};\n    }\n\n    var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);\n    // If argsJson was received by Java as null, try again with the PROMPT bridge mode.\n    // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.\n    if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && msgs === \"@Null arguments.\") {\n        androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);\n        androidExec(success, fail, service, action, args);\n        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);\n    } else if (msgs) {\n        messagesFromNative.push(msgs);\n        // Always process async to avoid exceptions messing up stack.\n        nextTick(processMessages);\n    }\n}\n\nandroidExec.init = function() {\n    //CB-11828\n    //This failsafe checks the version of Android and if it's Jellybean, it switches it to\n    //using the Online Event bridge for communicating from Native to JS\n    //\n    //It's ugly, but it's necessary.\n    var check = navigator.userAgent.toLowerCase().match(/android\\s[0-9].[0-9]/);\n    var version_code = check && check[0].match(/4.[0-3].*/);\n    if (version_code != null && nativeToJsBridgeMode == nativeToJsModes.EVAL_BRIDGE) {\n      nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT;\n    }\n\n    bridgeSecret = +prompt('', 'gap_init:' + nativeToJsBridgeMode);\n    channel.onNativeReady.fire();\n};\n\nfunction pollOnceFromOnlineEvent() {\n    pollOnce(true);\n}\n\nfunction pollOnce(opt_fromOnlineEvent) {\n    if (bridgeSecret < 0) {\n        // This can happen when the NativeToJsMessageQueue resets the online state on page transitions.\n        // We know there's nothing to retrieve, so no need to poll.\n        return;\n    }\n    var msgs = nativeApiProvider.get().retrieveJsMessages(bridgeSecret, !!opt_fromOnlineEvent);\n    if (msgs) {\n        messagesFromNative.push(msgs);\n        // Process sync since we know we're already top-of-stack.\n        processMessages();\n    }\n}\n\nfunction pollingTimerFunc() {\n    if (pollEnabled) {\n        pollOnce();\n        setTimeout(pollingTimerFunc, 50);\n    }\n}\n\nfunction hookOnlineApis() {\n    function proxyEvent(e) {\n        cordova.fireWindowEvent(e.type);\n    }\n    // The network module takes care of firing online and offline events.\n    // It currently fires them only on document though, so we bridge them\n    // to window here (while first listening for exec()-releated online/offline\n    // events).\n    window.addEventListener('online', pollOnceFromOnlineEvent, false);\n    window.addEventListener('offline', pollOnceFromOnlineEvent, false);\n    cordova.addWindowEventHandler('online');\n    cordova.addWindowEventHandler('offline');\n    document.addEventListener('online', proxyEvent, false);\n    document.addEventListener('offline', proxyEvent, false);\n}\n\nhookOnlineApis();\n\nandroidExec.jsToNativeModes = jsToNativeModes;\nandroidExec.nativeToJsModes = nativeToJsModes;\n\nandroidExec.setJsToNativeBridgeMode = function(mode) {\n    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {\n        mode = jsToNativeModes.PROMPT;\n    }\n    nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);\n    jsToNativeBridgeMode = mode;\n};\n\nandroidExec.setNativeToJsBridgeMode = function(mode) {\n    if (mode == nativeToJsBridgeMode) {\n        return;\n    }\n    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {\n        pollEnabled = false;\n    }\n\n    nativeToJsBridgeMode = mode;\n    // Tell the native side to switch modes.\n    // Otherwise, it will be set by androidExec.init()\n    if (bridgeSecret >= 0) {\n        nativeApiProvider.get().setNativeToJsBridgeMode(bridgeSecret, mode);\n    }\n\n    if (mode == nativeToJsModes.POLLING) {\n        pollEnabled = true;\n        setTimeout(pollingTimerFunc, 1);\n    }\n};\n\nfunction buildPayload(payload, message) {\n    var payloadKind = message.charAt(0);\n    if (payloadKind == 's') {\n        payload.push(message.slice(1));\n    } else if (payloadKind == 't') {\n        payload.push(true);\n    } else if (payloadKind == 'f') {\n        payload.push(false);\n    } else if (payloadKind == 'N') {\n        payload.push(null);\n    } else if (payloadKind == 'n') {\n        payload.push(+message.slice(1));\n    } else if (payloadKind == 'A') {\n        var data = message.slice(1);\n        payload.push(base64.toArrayBuffer(data));\n    } else if (payloadKind == 'S') {\n        payload.push(window.atob(message.slice(1)));\n    } else if (payloadKind == 'M') {\n        var multipartMessages = message.slice(1);\n        while (multipartMessages !== \"\") {\n            var spaceIdx = multipartMessages.indexOf(' ');\n            var msgLen = +multipartMessages.slice(0, spaceIdx);\n            var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen);\n            multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1);\n            buildPayload(payload, multipartMessage);\n        }\n    } else {\n        payload.push(JSON.parse(message));\n    }\n}\n\n// Processes a single message, as encoded by NativeToJsMessageQueue.java.\nfunction processMessage(message) {\n    var firstChar = message.charAt(0);\n    if (firstChar == 'J') {\n        // This is deprecated on the .java side. It doesn't work with CSP enabled.\n        eval(message.slice(1));\n    } else if (firstChar == 'S' || firstChar == 'F') {\n        var success = firstChar == 'S';\n        var keepCallback = message.charAt(1) == '1';\n        var spaceIdx = message.indexOf(' ', 2);\n        var status = +message.slice(2, spaceIdx);\n        var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);\n        var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);\n        var payloadMessage = message.slice(nextSpaceIdx + 1);\n        var payload = [];\n        buildPayload(payload, payloadMessage);\n        cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);\n    } else {\n        console.log(\"processMessage failed: invalid message: \" + JSON.stringify(message));\n    }\n}\n\nfunction processMessages() {\n    // Check for the reentrant case.\n    if (isProcessing) {\n        return;\n    }\n    if (messagesFromNative.length === 0) {\n        return;\n    }\n    isProcessing = true;\n    try {\n        var msg = popMessageFromQueue();\n        // The Java side can send a * message to indicate that it\n        // still has messages waiting to be retrieved.\n        if (msg == '*' && messagesFromNative.length === 0) {\n            nextTick(pollOnce);\n            return;\n        }\n        processMessage(msg);\n    } finally {\n        isProcessing = false;\n        if (messagesFromNative.length > 0) {\n            nextTick(processMessages);\n        }\n    }\n}\n\nfunction popMessageFromQueue() {\n    var messageBatch = messagesFromNative.shift();\n    if (messageBatch == '*') {\n        return '*';\n    }\n\n    var spaceIdx = messageBatch.indexOf(' ');\n    var msgLen = +messageBatch.slice(0, spaceIdx);\n    var message = messageBatch.substr(spaceIdx + 1, msgLen);\n    messageBatch = messageBatch.slice(spaceIdx + msgLen + 1);\n    if (messageBatch) {\n        messagesFromNative.unshift(messageBatch);\n    }\n    return message;\n}\n\nmodule.exports = androidExec;\n\n});\n\n// file: src/common/exec/proxy.js\ndefine(\"cordova/exec/proxy\", function(require, exports, module) {\n\n\n// internal map of proxy function\nvar CommandProxyMap = {};\n\nmodule.exports = {\n\n    // example: cordova.commandProxy.add(\"Accelerometer\",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);\n    add:function(id,proxyObj) {\n        console.log(\"adding proxy for \" + id);\n        CommandProxyMap[id] = proxyObj;\n        return proxyObj;\n    },\n\n    // cordova.commandProxy.remove(\"Accelerometer\");\n    remove:function(id) {\n        var proxy = CommandProxyMap[id];\n        delete CommandProxyMap[id];\n        CommandProxyMap[id] = null;\n        return proxy;\n    },\n\n    get:function(service,action) {\n        return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );\n    }\n};\n});\n\n// file: src/common/init.js\ndefine(\"cordova/init\", function(require, exports, module) {\n\nvar channel = require('cordova/channel');\nvar cordova = require('cordova');\nvar modulemapper = require('cordova/modulemapper');\nvar platform = require('cordova/platform');\nvar pluginloader = require('cordova/pluginloader');\nvar utils = require('cordova/utils');\n\nvar platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];\n\nfunction logUnfiredChannels(arr) {\n    for (var i = 0; i < arr.length; ++i) {\n        if (arr[i].state != 2) {\n            console.log('Channel not fired: ' + arr[i].type);\n        }\n    }\n}\n\nwindow.setTimeout(function() {\n    if (channel.onDeviceReady.state != 2) {\n        console.log('deviceready has not fired after 5 seconds.');\n        logUnfiredChannels(platformInitChannelsArray);\n        logUnfiredChannels(channel.deviceReadyChannelsArray);\n    }\n}, 5000);\n\n// Replace navigator before any modules are required(), to ensure it happens as soon as possible.\n// We replace it so that properties that can't be clobbered can instead be overridden.\nfunction replaceNavigator(origNavigator) {\n    var CordovaNavigator = function() {};\n    CordovaNavigator.prototype = origNavigator;\n    var newNavigator = new CordovaNavigator();\n    // This work-around really only applies to new APIs that are newer than Function.bind.\n    // Without it, APIs such as getGamepads() break.\n    if (CordovaNavigator.bind) {\n        for (var key in origNavigator) {\n            if (typeof origNavigator[key] == 'function') {\n                newNavigator[key] = origNavigator[key].bind(origNavigator);\n            }\n            else {\n                (function(k) {\n                    utils.defineGetterSetter(newNavigator,key,function() {\n                        return origNavigator[k];\n                    });\n                })(key);\n            }\n        }\n    }\n    return newNavigator;\n}\n\nif (window.navigator) {\n    window.navigator = replaceNavigator(window.navigator);\n}\n\nif (!window.console) {\n    window.console = {\n        log: function(){}\n    };\n}\nif (!window.console.warn) {\n    window.console.warn = function(msg) {\n        this.log(\"warn: \" + msg);\n    };\n}\n\n// Register pause, resume and deviceready channels as events on document.\nchannel.onPause = cordova.addDocumentEventHandler('pause');\nchannel.onResume = cordova.addDocumentEventHandler('resume');\nchannel.onActivated = cordova.addDocumentEventHandler('activated');\nchannel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');\n\n// Listen for DOMContentLoaded and notify our channel subscribers.\nif (document.readyState == 'complete' || document.readyState == 'interactive') {\n    channel.onDOMContentLoaded.fire();\n} else {\n    document.addEventListener('DOMContentLoaded', function() {\n        channel.onDOMContentLoaded.fire();\n    }, false);\n}\n\n// _nativeReady is global variable that the native side can set\n// to signify that the native code is ready. It is a global since\n// it may be called before any cordova JS is ready.\nif (window._nativeReady) {\n    channel.onNativeReady.fire();\n}\n\nmodulemapper.clobbers('cordova', 'cordova');\nmodulemapper.clobbers('cordova/exec', 'cordova.exec');\nmodulemapper.clobbers('cordova/exec', 'Cordova.exec');\n\n// Call the platform-specific initialization.\nplatform.bootstrap && platform.bootstrap();\n\n// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js.\n// The delay allows the attached modules to be defined before the plugin loader looks for them.\nsetTimeout(function() {\n    pluginloader.load(function() {\n        channel.onPluginsReady.fire();\n    });\n}, 0);\n\n/**\n * Create all cordova objects once native side is ready.\n */\nchannel.join(function() {\n    modulemapper.mapModules(window);\n\n    platform.initialize && platform.initialize();\n\n    // Fire event to notify that all objects are created\n    channel.onCordovaReady.fire();\n\n    // Fire onDeviceReady event once page has fully loaded, all\n    // constructors have run and cordova info has been received from native\n    // side.\n    channel.join(function() {\n        require('cordova').fireDocumentEvent('deviceready');\n    }, channel.deviceReadyChannelsArray);\n\n}, platformInitChannelsArray);\n\n\n});\n\n// file: src/common/init_b.js\ndefine(\"cordova/init_b\", function(require, exports, module) {\n\nvar channel = require('cordova/channel');\nvar cordova = require('cordova');\nvar modulemapper = require('cordova/modulemapper');\nvar platform = require('cordova/platform');\nvar pluginloader = require('cordova/pluginloader');\nvar utils = require('cordova/utils');\n\nvar platformInitChannelsArray = [channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady];\n\n// setting exec\ncordova.exec = require('cordova/exec');\n\nfunction logUnfiredChannels(arr) {\n    for (var i = 0; i < arr.length; ++i) {\n        if (arr[i].state != 2) {\n            console.log('Channel not fired: ' + arr[i].type);\n        }\n    }\n}\n\nwindow.setTimeout(function() {\n    if (channel.onDeviceReady.state != 2) {\n        console.log('deviceready has not fired after 5 seconds.');\n        logUnfiredChannels(platformInitChannelsArray);\n        logUnfiredChannels(channel.deviceReadyChannelsArray);\n    }\n}, 5000);\n\n// Replace navigator before any modules are required(), to ensure it happens as soon as possible.\n// We replace it so that properties that can't be clobbered can instead be overridden.\nfunction replaceNavigator(origNavigator) {\n    var CordovaNavigator = function() {};\n    CordovaNavigator.prototype = origNavigator;\n    var newNavigator = new CordovaNavigator();\n    // This work-around really only applies to new APIs that are newer than Function.bind.\n    // Without it, APIs such as getGamepads() break.\n    if (CordovaNavigator.bind) {\n        for (var key in origNavigator) {\n            if (typeof origNavigator[key] == 'function') {\n                newNavigator[key] = origNavigator[key].bind(origNavigator);\n            }\n            else {\n                (function(k) {\n                    utils.defineGetterSetter(newNavigator,key,function() {\n                        return origNavigator[k];\n                    });\n                })(key);\n            }\n        }\n    }\n    return newNavigator;\n}\nif (window.navigator) {\n    window.navigator = replaceNavigator(window.navigator);\n}\n\nif (!window.console) {\n    window.console = {\n        log: function(){}\n    };\n}\nif (!window.console.warn) {\n    window.console.warn = function(msg) {\n        this.log(\"warn: \" + msg);\n    };\n}\n\n// Register pause, resume and deviceready channels as events on document.\nchannel.onPause = cordova.addDocumentEventHandler('pause');\nchannel.onResume = cordova.addDocumentEventHandler('resume');\nchannel.onActivated = cordova.addDocumentEventHandler('activated');\nchannel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');\n\n// Listen for DOMContentLoaded and notify our channel subscribers.\nif (document.readyState == 'complete' || document.readyState == 'interactive') {\n    channel.onDOMContentLoaded.fire();\n} else {\n    document.addEventListener('DOMContentLoaded', function() {\n        channel.onDOMContentLoaded.fire();\n    }, false);\n}\n\n// _nativeReady is global variable that the native side can set\n// to signify that the native code is ready. It is a global since\n// it may be called before any cordova JS is ready.\nif (window._nativeReady) {\n    channel.onNativeReady.fire();\n}\n\n// Call the platform-specific initialization.\nplatform.bootstrap && platform.bootstrap();\n\n// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js.\n// The delay allows the attached modules to be defined before the plugin loader looks for them.\nsetTimeout(function() {\n    pluginloader.load(function() {\n        channel.onPluginsReady.fire();\n    });\n}, 0);\n\n/**\n * Create all cordova objects once native side is ready.\n */\nchannel.join(function() {\n    modulemapper.mapModules(window);\n\n    platform.initialize && platform.initialize();\n\n    // Fire event to notify that all objects are created\n    channel.onCordovaReady.fire();\n\n    // Fire onDeviceReady event once page has fully loaded, all\n    // constructors have run and cordova info has been received from native\n    // side.\n    channel.join(function() {\n        require('cordova').fireDocumentEvent('deviceready');\n    }, channel.deviceReadyChannelsArray);\n\n}, platformInitChannelsArray);\n\n});\n\n// file: src/common/modulemapper.js\ndefine(\"cordova/modulemapper\", function(require, exports, module) {\n\nvar builder = require('cordova/builder'),\n    moduleMap = define.moduleMap,\n    symbolList,\n    deprecationMap;\n\nexports.reset = function() {\n    symbolList = [];\n    deprecationMap = {};\n};\n\nfunction addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {\n    if (!(moduleName in moduleMap)) {\n        throw new Error('Module ' + moduleName + ' does not exist.');\n    }\n    symbolList.push(strategy, moduleName, symbolPath);\n    if (opt_deprecationMessage) {\n        deprecationMap[symbolPath] = opt_deprecationMessage;\n    }\n}\n\n// Note: Android 2.3 does have Function.bind().\nexports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.runs = function(moduleName) {\n    addEntry('r', moduleName, null);\n};\n\nfunction prepareNamespace(symbolPath, context) {\n    if (!symbolPath) {\n        return context;\n    }\n    var parts = symbolPath.split('.');\n    var cur = context;\n    for (var i = 0, part; part = parts[i]; ++i) {\n        cur = cur[part] = cur[part] || {};\n    }\n    return cur;\n}\n\nexports.mapModules = function(context) {\n    var origSymbols = {};\n    context.CDV_origSymbols = origSymbols;\n    for (var i = 0, len = symbolList.length; i < len; i += 3) {\n        var strategy = symbolList[i];\n        var moduleName = symbolList[i + 1];\n        var module = require(moduleName);\n        // <runs/>\n        if (strategy == 'r') {\n            continue;\n        }\n        var symbolPath = symbolList[i + 2];\n        var lastDot = symbolPath.lastIndexOf('.');\n        var namespace = symbolPath.substr(0, lastDot);\n        var lastName = symbolPath.substr(lastDot + 1);\n\n        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;\n        var parentObj = prepareNamespace(namespace, context);\n        var target = parentObj[lastName];\n\n        if (strategy == 'm' && target) {\n            builder.recursiveMerge(target, module);\n        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {\n            if (!(symbolPath in origSymbols)) {\n                origSymbols[symbolPath] = target;\n            }\n            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);\n        }\n    }\n};\n\nexports.getOriginalSymbol = function(context, symbolPath) {\n    var origSymbols = context.CDV_origSymbols;\n    if (origSymbols && (symbolPath in origSymbols)) {\n        return origSymbols[symbolPath];\n    }\n    var parts = symbolPath.split('.');\n    var obj = context;\n    for (var i = 0; i < parts.length; ++i) {\n        obj = obj && obj[parts[i]];\n    }\n    return obj;\n};\n\nexports.reset();\n\n\n});\n\n// file: src/common/modulemapper_b.js\ndefine(\"cordova/modulemapper_b\", function(require, exports, module) {\n\nvar builder = require('cordova/builder'),\n    symbolList = [],\n    deprecationMap;\n\nexports.reset = function() {\n    symbolList = [];\n    deprecationMap = {};\n};\n\nfunction addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {\n    symbolList.push(strategy, moduleName, symbolPath);\n    if (opt_deprecationMessage) {\n        deprecationMap[symbolPath] = opt_deprecationMessage;\n    }\n}\n\n// Note: Android 2.3 does have Function.bind().\nexports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.runs = function(moduleName) {\n    addEntry('r', moduleName, null);\n};\n\nfunction prepareNamespace(symbolPath, context) {\n    if (!symbolPath) {\n        return context;\n    }\n    var parts = symbolPath.split('.');\n    var cur = context;\n    for (var i = 0, part; part = parts[i]; ++i) {\n        cur = cur[part] = cur[part] || {};\n    }\n    return cur;\n}\n\nexports.mapModules = function(context) {\n    var origSymbols = {};\n    context.CDV_origSymbols = origSymbols;\n    for (var i = 0, len = symbolList.length; i < len; i += 3) {\n        var strategy = symbolList[i];\n        var moduleName = symbolList[i + 1];\n        var module = require(moduleName);\n        // <runs/>\n        if (strategy == 'r') {\n            continue;\n        }\n        var symbolPath = symbolList[i + 2];\n        var lastDot = symbolPath.lastIndexOf('.');\n        var namespace = symbolPath.substr(0, lastDot);\n        var lastName = symbolPath.substr(lastDot + 1);\n\n        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;\n        var parentObj = prepareNamespace(namespace, context);\n        var target = parentObj[lastName];\n\n        if (strategy == 'm' && target) {\n            builder.recursiveMerge(target, module);\n        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {\n            if (!(symbolPath in origSymbols)) {\n                origSymbols[symbolPath] = target;\n            }\n            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);\n        }\n    }\n};\n\nexports.getOriginalSymbol = function(context, symbolPath) {\n    var origSymbols = context.CDV_origSymbols;\n    if (origSymbols && (symbolPath in origSymbols)) {\n        return origSymbols[symbolPath];\n    }\n    var parts = symbolPath.split('.');\n    var obj = context;\n    for (var i = 0; i < parts.length; ++i) {\n        obj = obj && obj[parts[i]];\n    }\n    return obj;\n};\n\nexports.reset();\n\n\n});\n\n// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/platform.js\ndefine(\"cordova/platform\", function(require, exports, module) {\n\n// The last resume event that was received that had the result of a plugin call.\nvar lastResumeEvent = null;\n\nmodule.exports = {\n    id: 'android',\n    bootstrap: function() {\n        var channel = require('cordova/channel'),\n            cordova = require('cordova'),\n            exec = require('cordova/exec'),\n            modulemapper = require('cordova/modulemapper');\n\n        // Get the shared secret needed to use the bridge.\n        exec.init();\n\n        // TODO: Extract this as a proper plugin.\n        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');\n\n        var APP_PLUGIN_NAME = Number(cordova.platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';\n\n        // Inject a listener for the backbutton on the document.\n        var backButtonChannel = cordova.addDocumentEventHandler('backbutton');\n        backButtonChannel.onHasSubscribersChange = function() {\n            // If we just attached the first handler or detached the last handler,\n            // let native know we need to override the back button.\n            exec(null, null, APP_PLUGIN_NAME, \"overrideBackbutton\", [this.numHandlers == 1]);\n        };\n\n        // Add hardware MENU and SEARCH button handlers\n        cordova.addDocumentEventHandler('menubutton');\n        cordova.addDocumentEventHandler('searchbutton');\n\n        function bindButtonChannel(buttonName) {\n            // generic button bind used for volumeup/volumedown buttons\n            var volumeButtonChannel = cordova.addDocumentEventHandler(buttonName + 'button');\n            volumeButtonChannel.onHasSubscribersChange = function() {\n                exec(null, null, APP_PLUGIN_NAME, \"overrideButton\", [buttonName, this.numHandlers == 1]);\n            };\n        }\n        // Inject a listener for the volume buttons on the document.\n        bindButtonChannel('volumeup');\n        bindButtonChannel('volumedown');\n\n        // The resume event is not \"sticky\", but it is possible that the event\n        // will contain the result of a plugin call. We need to ensure that the\n        // plugin result is delivered even after the event is fired (CB-10498)\n        var cordovaAddEventListener = document.addEventListener;\n\n        document.addEventListener = function(evt, handler, capture) {\n            cordovaAddEventListener(evt, handler, capture);\n\n            if (evt === 'resume' && lastResumeEvent) {\n                handler(lastResumeEvent);\n            }\n        };\n\n        // Let native code know we are all done on the JS side.\n        // Native code will then un-hide the WebView.\n        channel.onCordovaReady.subscribe(function() {\n            exec(onMessageFromNative, null, APP_PLUGIN_NAME, 'messageChannel', []);\n            exec(null, null, APP_PLUGIN_NAME, \"show\", []);\n        });\n    }\n};\n\nfunction onMessageFromNative(msg) {\n    var cordova = require('cordova');\n    var action = msg.action;\n\n    switch (action)\n    {\n        // Button events\n        case 'backbutton':\n        case 'menubutton':\n        case 'searchbutton':\n        // App life cycle events\n        case 'pause':\n        // Volume events\n        case 'volumedownbutton':\n        case 'volumeupbutton':\n            cordova.fireDocumentEvent(action);\n            break;\n        case 'resume':\n            if(arguments.length > 1 && msg.pendingResult) {\n                if(arguments.length === 2) {\n                    msg.pendingResult.result = arguments[1];\n                } else {\n                    // The plugin returned a multipart message\n                    var res = [];\n                    for(var i = 1; i < arguments.length; i++) {\n                        res.push(arguments[i]);\n                    }\n                    msg.pendingResult.result = res;\n                }\n\n                // Save the plugin result so that it can be delivered to the js\n                // even if they miss the initial firing of the event\n                lastResumeEvent = msg;\n            }\n            cordova.fireDocumentEvent(action, msg);\n            break;\n        default:\n            throw new Error('Unknown event action ' + action);\n    }\n}\n\n});\n\n// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/plugin/android/app.js\ndefine(\"cordova/plugin/android/app\", function(require, exports, module) {\n\nvar exec = require('cordova/exec');\nvar APP_PLUGIN_NAME = Number(require('cordova').platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';\n\nmodule.exports = {\n    /**\n    * Clear the resource cache.\n    */\n    clearCache:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"clearCache\", []);\n    },\n\n    /**\n    * Load the url into the webview or into new browser instance.\n    *\n    * @param url           The URL to load\n    * @param props         Properties that can be passed in to the activity:\n    *      wait: int                           => wait msec before loading URL\n    *      loadingDialog: \"Title,Message\"      => display a native loading dialog\n    *      loadUrlTimeoutValue: int            => time in msec to wait before triggering a timeout error\n    *      clearHistory: boolean              => clear webview history (default=false)\n    *      openExternal: boolean              => open in a new browser (default=false)\n    *\n    * Example:\n    *      navigator.app.loadUrl(\"http://server/myapp/index.html\", {wait:2000, loadingDialog:\"Wait,Loading App\", loadUrlTimeoutValue: 60000});\n    */\n    loadUrl:function(url, props) {\n        exec(null, null, APP_PLUGIN_NAME, \"loadUrl\", [url, props]);\n    },\n\n    /**\n    * Cancel loadUrl that is waiting to be loaded.\n    */\n    cancelLoadUrl:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"cancelLoadUrl\", []);\n    },\n\n    /**\n    * Clear web history in this web view.\n    * Instead of BACK button loading the previous web page, it will exit the app.\n    */\n    clearHistory:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"clearHistory\", []);\n    },\n\n    /**\n    * Go to previous page displayed.\n    * This is the same as pressing the backbutton on Android device.\n    */\n    backHistory:function() {\n        exec(null, null, APP_PLUGIN_NAME, \"backHistory\", []);\n    },\n\n    /**\n    * Override the default behavior of the Android back button.\n    * If overridden, when the back button is pressed, the \"backKeyDown\" JavaScript event will be fired.\n    *\n    * Note: The user should not have to call this method.  Instead, when the user\n    *       registers for the \"backbutton\" event, this is automatically done.\n    *\n    * @param override        T=override, F=cancel override\n    */\n    overrideBackbutton:function(override) {\n        exec(null, null, APP_PLUGIN_NAME, \"overrideBackbutton\", [override]);\n    },\n\n    /**\n    * Override the default behavior of the Android volume button.\n    * If overridden, when the volume button is pressed, the \"volume[up|down]button\"\n    * JavaScript event will be fired.\n    *\n    * Note: The user should not have to call this method.  Instead, when the user\n    *       registers for the \"volume[up|down]button\" event, this is automatically done.\n    *\n    * @param button          volumeup, volumedown\n    * @param override        T=override, F=cancel override\n    */\n    overrideButton:function(button, override) {\n        exec(null, null, APP_PLUGIN_NAME, \"overrideButton\", [button, override]);\n    },\n\n    /**\n    * Exit and terminate the application.\n    */\n    exitApp:function() {\n        return exec(null, null, APP_PLUGIN_NAME, \"exitApp\", []);\n    }\n};\n\n});\n\n// file: src/common/pluginloader.js\ndefine(\"cordova/pluginloader\", function(require, exports, module) {\n\nvar modulemapper = require('cordova/modulemapper');\nvar urlutil = require('cordova/urlutil');\n\n// Helper function to inject a <script> tag.\n// Exported for testing.\nexports.injectScript = function(url, onload, onerror) {\n    var script = document.createElement(\"script\");\n    // onload fires even when script fails loads with an error.\n    script.onload = onload;\n    // onerror fires for malformed URLs.\n    script.onerror = onerror;\n    script.src = url;\n    document.head.appendChild(script);\n};\n\nfunction injectIfNecessary(id, url, onload, onerror) {\n    onerror = onerror || onload;\n    if (id in define.moduleMap) {\n        onload();\n    } else {\n        exports.injectScript(url, function() {\n            if (id in define.moduleMap) {\n                onload();\n            } else {\n                onerror();\n            }\n        }, onerror);\n    }\n}\n\nfunction onScriptLoadingComplete(moduleList, finishPluginLoading) {\n    // Loop through all the plugins and then through their clobbers and merges.\n    for (var i = 0, module; module = moduleList[i]; i++) {\n        if (module.clobbers && module.clobbers.length) {\n            for (var j = 0; j < module.clobbers.length; j++) {\n                modulemapper.clobbers(module.id, module.clobbers[j]);\n            }\n        }\n\n        if (module.merges && module.merges.length) {\n            for (var k = 0; k < module.merges.length; k++) {\n                modulemapper.merges(module.id, module.merges[k]);\n            }\n        }\n\n        // Finally, if runs is truthy we want to simply require() the module.\n        if (module.runs) {\n            modulemapper.runs(module.id);\n        }\n    }\n\n    finishPluginLoading();\n}\n\n// Handler for the cordova_plugins.js content.\n// See plugman's plugin_loader.js for the details of this object.\n// This function is only called if the really is a plugins array that isn't empty.\n// Otherwise the onerror response handler will just call finishPluginLoading().\nfunction handlePluginsObject(path, moduleList, finishPluginLoading) {\n    // Now inject the scripts.\n    var scriptCounter = moduleList.length;\n\n    if (!scriptCounter) {\n        finishPluginLoading();\n        return;\n    }\n    function scriptLoadedCallback() {\n        if (!--scriptCounter) {\n            onScriptLoadingComplete(moduleList, finishPluginLoading);\n        }\n    }\n\n    for (var i = 0; i < moduleList.length; i++) {\n        injectIfNecessary(moduleList[i].id, path + moduleList[i].file, scriptLoadedCallback);\n    }\n}\n\nfunction findCordovaPath() {\n    var path = null;\n    var scripts = document.getElementsByTagName('script');\n    var term = '/cordova.js';\n    for (var n = scripts.length-1; n>-1; n--) {\n        var src = scripts[n].src.replace(/\\?.*$/, ''); // Strip any query param (CB-6007).\n        if (src.indexOf(term) == (src.length - term.length)) {\n            path = src.substring(0, src.length - term.length) + '/';\n            break;\n        }\n    }\n    return path;\n}\n\n// Tries to load all plugins' js-modules.\n// This is an async process, but onDeviceReady is blocked on onPluginsReady.\n// onPluginsReady is fired when there are no plugins to load, or they are all done.\nexports.load = function(callback) {\n    var pathPrefix = findCordovaPath();\n    if (pathPrefix === null) {\n        console.log('Could not find cordova.js script tag. Plugin loading may fail.');\n        pathPrefix = '';\n    }\n    injectIfNecessary('cordova/plugin_list', pathPrefix + 'cordova_plugins.js', function() {\n        var moduleList = require(\"cordova/plugin_list\");\n        handlePluginsObject(pathPrefix, moduleList, callback);\n    }, callback);\n};\n\n\n});\n\n// file: src/common/pluginloader_b.js\ndefine(\"cordova/pluginloader_b\", function(require, exports, module) {\n\nvar modulemapper = require('cordova/modulemapper');\n\n// Handler for the cordova_plugins.js content.\n// See plugman's plugin_loader.js for the details of this object.\nfunction handlePluginsObject(moduleList) {\n    // if moduleList is not defined or empty, we've nothing to do\n    if (!moduleList || !moduleList.length) {\n        return;\n    }\n\n    // Loop through all the modules and then through their clobbers and merges.\n    for (var i = 0, module; module = moduleList[i]; i++) {\n        if (module.clobbers && module.clobbers.length) {\n            for (var j = 0; j < module.clobbers.length; j++) {\n                modulemapper.clobbers(module.id, module.clobbers[j]);\n            }\n        }\n\n        if (module.merges && module.merges.length) {\n            for (var k = 0; k < module.merges.length; k++) {\n                modulemapper.merges(module.id, module.merges[k]);\n            }\n        }\n\n        // Finally, if runs is truthy we want to simply require() the module.\n        if (module.runs) {\n            modulemapper.runs(module.id);\n        }\n    }\n}\n\n// Loads all plugins' js-modules. Plugin loading is syncronous in browserified bundle\n// but the method accepts callback to be compatible with non-browserify flow.\n// onDeviceReady is blocked on onPluginsReady. onPluginsReady is fired when there are\n// no plugins to load, or they are all done.\nexports.load = function(callback) {\n    var moduleList = require(\"cordova/plugin_list\");\n    handlePluginsObject(moduleList);\n\n    callback();\n};\n\n\n});\n\n// file: src/common/urlutil.js\ndefine(\"cordova/urlutil\", function(require, exports, module) {\n\n\n/**\n * For already absolute URLs, returns what is passed in.\n * For relative URLs, converts them to absolute ones.\n */\nexports.makeAbsolute = function makeAbsolute(url) {\n    var anchorEl = document.createElement('a');\n    anchorEl.href = url;\n    return anchorEl.href;\n};\n\n\n});\n\n// file: src/common/utils.js\ndefine(\"cordova/utils\", function(require, exports, module) {\n\nvar utils = exports;\n\n/**\n * Defines a property getter / setter for obj[key].\n */\nutils.defineGetterSetter = function(obj, key, getFunc, opt_setFunc) {\n    if (Object.defineProperty) {\n        var desc = {\n            get: getFunc,\n            configurable: true\n        };\n        if (opt_setFunc) {\n            desc.set = opt_setFunc;\n        }\n        Object.defineProperty(obj, key, desc);\n    } else {\n        obj.__defineGetter__(key, getFunc);\n        if (opt_setFunc) {\n            obj.__defineSetter__(key, opt_setFunc);\n        }\n    }\n};\n\n/**\n * Defines a property getter for obj[key].\n */\nutils.defineGetter = utils.defineGetterSetter;\n\nutils.arrayIndexOf = function(a, item) {\n    if (a.indexOf) {\n        return a.indexOf(item);\n    }\n    var len = a.length;\n    for (var i = 0; i < len; ++i) {\n        if (a[i] == item) {\n            return i;\n        }\n    }\n    return -1;\n};\n\n/**\n * Returns whether the item was found in the array.\n */\nutils.arrayRemove = function(a, item) {\n    var index = utils.arrayIndexOf(a, item);\n    if (index != -1) {\n        a.splice(index, 1);\n    }\n    return index != -1;\n};\n\nutils.typeName = function(val) {\n    return Object.prototype.toString.call(val).slice(8, -1);\n};\n\n/**\n * Returns an indication of whether the argument is an array or not\n */\nutils.isArray = Array.isArray ||\n                function(a) {return utils.typeName(a) == 'Array';};\n\n/**\n * Returns an indication of whether the argument is a Date or not\n */\nutils.isDate = function(d) {\n    return (d instanceof Date);\n};\n\n/**\n * Does a deep clone of the object.\n */\nutils.clone = function(obj) {\n    if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') {\n        return obj;\n    }\n\n    var retVal, i;\n\n    if(utils.isArray(obj)){\n        retVal = [];\n        for(i = 0; i < obj.length; ++i){\n            retVal.push(utils.clone(obj[i]));\n        }\n        return retVal;\n    }\n\n    retVal = {};\n    for(i in obj){\n        // https://issues.apache.org/jira/browse/CB-11522 'unknown' type may be returned in\n        // custom protocol activation case on Windows Phone 8.1 causing \"No such interface supported\" exception\n        // on cloning.\n        if((!(i in retVal) || retVal[i] != obj[i]) && typeof obj[i] != 'undefined' && typeof obj[i] != 'unknown') {\n            retVal[i] = utils.clone(obj[i]);\n        }\n    }\n    return retVal;\n};\n\n/**\n * Returns a wrapped version of the function\n */\nutils.close = function(context, func, params) {\n    return function() {\n        var args = params || arguments;\n        return func.apply(context, args);\n    };\n};\n\n//------------------------------------------------------------------------------\nfunction UUIDcreatePart(length) {\n    var uuidpart = \"\";\n    for (var i=0; i<length; i++) {\n        var uuidchar = parseInt((Math.random() * 256), 10).toString(16);\n        if (uuidchar.length == 1) {\n            uuidchar = \"0\" + uuidchar;\n        }\n        uuidpart += uuidchar;\n    }\n    return uuidpart;\n}\n\n/**\n * Create a UUID\n */\nutils.createUUID = function() {\n    return UUIDcreatePart(4) + '-' +\n        UUIDcreatePart(2) + '-' +\n        UUIDcreatePart(2) + '-' +\n        UUIDcreatePart(2) + '-' +\n        UUIDcreatePart(6);\n};\n\n\n/**\n * Extends a child object from a parent object using classical inheritance\n * pattern.\n */\nutils.extend = (function() {\n    // proxy used to establish prototype chain\n    var F = function() {};\n    // extend Child from Parent\n    return function(Child, Parent) {\n\n        F.prototype = Parent.prototype;\n        Child.prototype = new F();\n        Child.__super__ = Parent.prototype;\n        Child.prototype.constructor = Child;\n    };\n}());\n\n/**\n * Alerts a message in any available way: alert or console.log.\n */\nutils.alert = function(msg) {\n    if (window.alert) {\n        window.alert(msg);\n    } else if (console && console.log) {\n        console.log(msg);\n    }\n};\n\n\n\n\n\n});\n\nwindow.cordova = require('cordova');\n// file: src/scripts/bootstrap.js\n\nrequire('cordova/init');\n\n})();"
  },
  {
    "path": "platforms/android/platform_www/cordova_plugins.js",
    "content": "cordova.define('cordova/plugin_list', function(require, exports, module) {\nmodule.exports = [\n    {\n        \"id\": \"cordova-plugin-splashscreen.SplashScreen\",\n        \"file\": \"plugins/cordova-plugin-splashscreen/www/splashscreen.js\",\n        \"pluginId\": \"cordova-plugin-splashscreen\",\n        \"clobbers\": [\n            \"navigator.splashscreen\"\n        ]\n    },\n    {\n        \"id\": \"phonegap-plugin-barcodescanner.BarcodeScanner\",\n        \"file\": \"plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js\",\n        \"pluginId\": \"phonegap-plugin-barcodescanner\",\n        \"clobbers\": [\n            \"cordova.plugins.barcodeScanner\"\n        ]\n    }\n];\nmodule.exports.metadata = \n// TOP OF METADATA\n{\n    \"cordova-plugin-compat\": \"1.1.0\",\n    \"cordova-plugin-splashscreen\": \"4.0.1\",\n    \"cordova-plugin-whitelist\": \"1.3.1\",\n    \"phonegap-plugin-barcodescanner\": \"6.0.6\"\n};\n// BOTTOM OF METADATA\n});"
  },
  {
    "path": "platforms/android/platform_www/plugins/cordova-plugin-splashscreen/www/splashscreen.js",
    "content": "cordova.define(\"cordova-plugin-splashscreen.SplashScreen\", function(require, exports, module) {\n/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nvar exec = require('cordova/exec');\n\nvar splashscreen = {\n    show:function() {\n        exec(null, null, \"SplashScreen\", \"show\", []);\n    },\n    hide:function() {\n        exec(null, null, \"SplashScreen\", \"hide\", []);\n    }\n};\n\nmodule.exports = splashscreen;\n\n});\n"
  },
  {
    "path": "platforms/android/platform_www/plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js",
    "content": "cordova.define(\"phonegap-plugin-barcodescanner.BarcodeScanner\", function(require, exports, module) {\n/**\n * cordova is available under *either* the terms of the modified BSD license *or* the\n * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.\n *\n * Copyright (c) Matt Kane 2010\n * Copyright (c) 2011, IBM Corporation\n */\n\n\n        var exec = cordova.require(\"cordova/exec\");\n\n        var scanInProgress = false;\n\n        /**\n         * Constructor.\n         *\n         * @returns {BarcodeScanner}\n         */\n        function BarcodeScanner() {\n\n            /**\n             * Encoding constants.\n             *\n             * @type Object\n             */\n            this.Encode = {\n                TEXT_TYPE: \"TEXT_TYPE\",\n                EMAIL_TYPE: \"EMAIL_TYPE\",\n                PHONE_TYPE: \"PHONE_TYPE\",\n                SMS_TYPE: \"SMS_TYPE\"\n                //  CONTACT_TYPE: \"CONTACT_TYPE\",  // TODO:  not implemented, requires passing a Bundle class from Javascript to Java\n                //  LOCATION_TYPE: \"LOCATION_TYPE\" // TODO:  not implemented, requires passing a Bundle class from Javascript to Java\n            };\n\n    /**\n     * Barcode format constants, defined in ZXing library.\n     *\n     * @type Object\n     */\n    this.format = {\n        \"all_1D\": 61918,\n        \"aztec\": 1,\n        \"codabar\": 2,\n        \"code_128\": 16,\n        \"code_39\": 4,\n        \"code_93\": 8,\n        \"data_MATRIX\": 32,\n        \"ean_13\": 128,\n        \"ean_8\": 64,\n        \"itf\": 256,\n        \"maxicode\": 512,\n        \"msi\": 131072,\n        \"pdf_417\": 1024,\n        \"plessey\": 262144,\n        \"qr_CODE\": 2048,\n        \"rss_14\": 4096,\n        \"rss_EXPANDED\": 8192,\n        \"upc_A\": 16384,\n        \"upc_E\": 32768,\n        \"upc_EAN_EXTENSION\": 65536\n        };\n  }\n\n/**\n * Read code from scanner.\n *\n * @param {Function} successCallback This function will recieve a result object: {\n         *        text : '12345-mock',    // The code that was scanned.\n         *        format : 'FORMAT_NAME', // Code format.\n         *        cancelled : true/false, // Was canceled.\n         *    }\n * @param {Function} errorCallback\n * @param config\n */\nBarcodeScanner.prototype.scan = function (successCallback, errorCallback, config) {\n\n            if (config instanceof Array) {\n                // do nothing\n            } else {\n                if (typeof(config) === 'object') {\n                    config = [ config ];\n                } else {\n                    config = [];\n                }\n            }\n\n            if (errorCallback == null) {\n                errorCallback = function () {\n                };\n            }\n\n            if (typeof errorCallback != \"function\") {\n                console.log(\"BarcodeScanner.scan failure: failure parameter not a function\");\n                return;\n            }\n\n            if (typeof successCallback != \"function\") {\n                console.log(\"BarcodeScanner.scan failure: success callback parameter must be a function\");\n                return;\n            }\n\n            if (scanInProgress) {\n                errorCallback('Scan is already in progress');\n                return;\n            }\n\n            scanInProgress = true;\n\n            exec(\n                function(result) {\n                    scanInProgress = false;\n                    successCallback(result);\n                },\n                function(error) {\n                    scanInProgress = false;\n                    errorCallback(error);\n                },\n                'BarcodeScanner',\n                'scan',\n                config\n            );\n        };\n\n        //-------------------------------------------------------------------\n        BarcodeScanner.prototype.encode = function (type, data, successCallback, errorCallback, options) {\n            if (errorCallback == null) {\n                errorCallback = function () {\n                };\n            }\n\n            if (typeof errorCallback != \"function\") {\n                console.log(\"BarcodeScanner.encode failure: failure parameter not a function\");\n                return;\n            }\n\n            if (typeof successCallback != \"function\") {\n                console.log(\"BarcodeScanner.encode failure: success callback parameter must be a function\");\n                return;\n            }\n\n            exec(successCallback, errorCallback, 'BarcodeScanner', 'encode', [\n                {\"type\": type, \"data\": data, \"options\": options}\n            ]);\n        };\n\n        var barcodeScanner = new BarcodeScanner();\n        module.exports = barcodeScanner;\n\n});\n"
  },
  {
    "path": "platforms/android/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n# Project target.\ntarget=android-25\nandroid.library.reference.1=CordovaLib\ncordova.gradle.include.1=phonegap-plugin-barcodescanner/piholedroid-barcodescanner.gradle"
  },
  {
    "path": "platforms/android/res/values/strings.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<resources>\n    <string name=\"app_name\">Pi-hole Droid</string>\n    <string name=\"launcher_name\">@string/app_name</string>\n    <string name=\"activity_name\">@string/launcher_name</string>\n</resources>\n"
  },
  {
    "path": "platforms/android/res/xml/config.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<widget id=\"friimaind.piholedroid\" version=\"1.0.4\" xmlns=\"http://www.w3.org/ns/widgets\" xmlns:cdv=\"http://cordova.apache.org/ns/1.0\">\n    <feature name=\"SplashScreen\">\n        <param name=\"android-package\" value=\"org.apache.cordova.splashscreen.SplashScreen\" />\n        <param name=\"onload\" value=\"true\" />\n    </feature>\n    <feature name=\"Whitelist\">\n        <param name=\"android-package\" value=\"org.apache.cordova.whitelist.WhitelistPlugin\" />\n        <param name=\"onload\" value=\"true\" />\n    </feature>\n    <feature name=\"BarcodeScanner\">\n        <param name=\"android-package\" value=\"com.phonegap.plugins.barcodescanner.BarcodeScanner\" />\n    </feature>\n    <name>Pi-hole Droid</name>\n    <description>\n        Monitor your Pi-hole with your Android smartphone\n    </description>\n    <author email=\"massimiliano.monaro@gmail.com\" href=\"https://blog.friimaind.it\">\n        Massimiliano Monaro\n    </author>\n    <content src=\"index.html\" />\n    <access origin=\"*\" />\n    <allow-intent href=\"http://*/*\" />\n    <allow-intent href=\"https://*/*\" />\n    <allow-intent href=\"tel:*\" />\n    <allow-intent href=\"sms:*\" />\n    <allow-intent href=\"mailto:*\" />\n    <allow-intent href=\"geo:*\" />\n    <icon density=\"ldpi\" src=\"www/assets/mipmap-ldpi/ic_launcher.png\" />\n    <icon density=\"mdpi\" src=\"www/assets/mipmap-mdpi/ic_launcher.png\" />\n    <icon density=\"hdpi\" src=\"www/assets/mipmap-hdpi/ic_launcher.png\" />\n    <icon density=\"xhdpi\" src=\"www/assets/mipmap-xhdpi/ic_launcher.png\" />\n    <allow-intent href=\"market:*\" />\n    <preference name=\"loglevel\" value=\"DEBUG\" />\n    <preference name=\"Fullscreen\" value=\"false\" />\n    <preference name=\"SplashScreenDelay\" value=\"2000\" />\n    <preference name=\"SplashScreen\" value=\"screen\" />\n    <preference name=\"SplashMaintainAspectRatio\" value=\"true\" />\n    <preference name=\"ShowSplashScreenSpinner\" value=\"false\" />\n</widget>\n"
  },
  {
    "path": "platforms/android/settings.gradle",
    "content": "// GENERATED FILE - DO NOT EDIT\ninclude \":\"\ninclude \":CordovaLib\"\n"
  },
  {
    "path": "platforms/android/src/com/phonegap/plugins/barcodescanner/BarcodeScanner.java",
    "content": "/**\n * PhoneGap is available under *either* the terms of the modified BSD license *or* the\n * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.\n *\n * Copyright (c) Matt Kane 2010\n * Copyright (c) 2011, IBM Corporation\n * Copyright (c) 2013, Maciej Nux Jaros\n */\npackage com.phonegap.plugins.barcodescanner;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport android.Manifest;\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.content.pm.PackageManager;\n\nimport org.apache.cordova.CordovaPlugin;\nimport org.apache.cordova.CallbackContext;\nimport org.apache.cordova.PluginResult;\nimport org.apache.cordova.PermissionHelper;\n\nimport com.google.zxing.client.android.CaptureActivity;\nimport com.google.zxing.client.android.encode.EncodeActivity;\nimport com.google.zxing.client.android.Intents;\n\n/**\n * This calls out to the ZXing barcode reader and returns the result.\n *\n * @sa https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java\n */\npublic class BarcodeScanner extends CordovaPlugin {\n    public static final int REQUEST_CODE = 0x0ba7c0de;\n\n    private static final String SCAN = \"scan\";\n    private static final String ENCODE = \"encode\";\n    private static final String CANCELLED = \"cancelled\";\n    private static final String FORMAT = \"format\";\n    private static final String TEXT = \"text\";\n    private static final String DATA = \"data\";\n    private static final String TYPE = \"type\";\n    private static final String PREFER_FRONTCAMERA = \"preferFrontCamera\";\n    private static final String ORIENTATION = \"orientation\";\n    private static final String SHOW_FLIP_CAMERA_BUTTON = \"showFlipCameraButton\";\n    private static final String RESULTDISPLAY_DURATION = \"resultDisplayDuration\";\n    private static final String SHOW_TORCH_BUTTON = \"showTorchButton\";\n    private static final String TORCH_ON = \"torchOn\";\n    private static final String FORMATS = \"formats\";\n    private static final String PROMPT = \"prompt\";\n    private static final String TEXT_TYPE = \"TEXT_TYPE\";\n    private static final String EMAIL_TYPE = \"EMAIL_TYPE\";\n    private static final String PHONE_TYPE = \"PHONE_TYPE\";\n    private static final String SMS_TYPE = \"SMS_TYPE\";\n\n    private static final String LOG_TAG = \"BarcodeScanner\";\n\n    private String [] permissions = { Manifest.permission.CAMERA };\n\n    private JSONArray requestArgs;\n    private CallbackContext callbackContext;\n\n    /**\n     * Constructor.\n     */\n    public BarcodeScanner() {\n    }\n\n    /**\n     * Executes the request.\n     *\n     * This method is called from the WebView thread. To do a non-trivial amount of work, use:\n     *     cordova.getThreadPool().execute(runnable);\n     *\n     * To run on the UI thread, use:\n     *     cordova.getActivity().runOnUiThread(runnable);\n     *\n     * @param action          The action to execute.\n     * @param args            The exec() arguments.\n     * @param callbackContext The callback context used when calling back into JavaScript.\n     * @return                Whether the action was valid.\n     *\n     * @sa https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java\n     */\n    @Override\n    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {\n        this.callbackContext = callbackContext;\n        this.requestArgs = args;\n\n        if (action.equals(ENCODE)) {\n            JSONObject obj = args.optJSONObject(0);\n            if (obj != null) {\n                String type = obj.optString(TYPE);\n                String data = obj.optString(DATA);\n\n                // If the type is null then force the type to text\n                if (type == null) {\n                    type = TEXT_TYPE;\n                }\n\n                if (data == null) {\n                    callbackContext.error(\"User did not specify data to encode\");\n                    return true;\n                }\n\n                encode(type, data);\n            } else {\n                callbackContext.error(\"User did not specify data to encode\");\n                return true;\n            }\n        } else if (action.equals(SCAN)) {\n\n            //android permission auto add\n            if(!hasPermisssion()) {\n              requestPermissions(0);\n            } else {\n              scan(args);\n            }\n        } else {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Starts an intent to scan and decode a barcode.\n     */\n    public void scan(final JSONArray args) {\n\n        final CordovaPlugin that = this;\n\n        cordova.getThreadPool().execute(new Runnable() {\n            public void run() {\n\n                Intent intentScan = new Intent(that.cordova.getActivity().getBaseContext(), CaptureActivity.class);\n                intentScan.setAction(Intents.Scan.ACTION);\n                intentScan.addCategory(Intent.CATEGORY_DEFAULT);\n\n                // add config as intent extras\n                if (args.length() > 0) {\n\n                    JSONObject obj;\n                    JSONArray names;\n                    String key;\n                    Object value;\n\n                    for (int i = 0; i < args.length(); i++) {\n\n                        try {\n                            obj = args.getJSONObject(i);\n                        } catch (JSONException e) {\n                            Log.i(\"CordovaLog\", e.getLocalizedMessage());\n                            continue;\n                        }\n\n                        names = obj.names();\n                        for (int j = 0; j < names.length(); j++) {\n                            try {\n                                key = names.getString(j);\n                                value = obj.get(key);\n\n                                if (value instanceof Integer) {\n                                    intentScan.putExtra(key, (Integer) value);\n                                } else if (value instanceof String) {\n                                    intentScan.putExtra(key, (String) value);\n                                }\n\n                            } catch (JSONException e) {\n                                Log.i(\"CordovaLog\", e.getLocalizedMessage());\n                            }\n                        }\n\n                        intentScan.putExtra(Intents.Scan.CAMERA_ID, obj.optBoolean(PREFER_FRONTCAMERA, false) ? 1 : 0);\n                        intentScan.putExtra(Intents.Scan.SHOW_FLIP_CAMERA_BUTTON, obj.optBoolean(SHOW_FLIP_CAMERA_BUTTON, false));\n                        intentScan.putExtra(Intents.Scan.SHOW_TORCH_BUTTON, obj.optBoolean(SHOW_TORCH_BUTTON, false));\n                        intentScan.putExtra(Intents.Scan.TORCH_ON, obj.optBoolean(TORCH_ON, false));\n                        if (obj.has(RESULTDISPLAY_DURATION)) {\n                            intentScan.putExtra(Intents.Scan.RESULT_DISPLAY_DURATION_MS, \"\" + obj.optLong(RESULTDISPLAY_DURATION));\n                        }\n                        if (obj.has(FORMATS)) {\n                            intentScan.putExtra(Intents.Scan.FORMATS, obj.optString(FORMATS));\n                        }\n                        if (obj.has(PROMPT)) {\n                            intentScan.putExtra(Intents.Scan.PROMPT_MESSAGE, obj.optString(PROMPT));\n                        }\n                        if (obj.has(ORIENTATION)) {\n                            intentScan.putExtra(Intents.Scan.ORIENTATION_LOCK, obj.optString(ORIENTATION));\n                        }\n                    }\n\n                }\n\n                // avoid calling other phonegap apps\n                intentScan.setPackage(that.cordova.getActivity().getApplicationContext().getPackageName());\n\n                that.cordova.startActivityForResult(that, intentScan, REQUEST_CODE);\n            }\n        });\n    }\n\n    /**\n     * Called when the barcode scanner intent completes.\n     *\n     * @param requestCode The request code originally supplied to startActivityForResult(),\n     *                       allowing you to identify who this result came from.\n     * @param resultCode  The integer result code returned by the child activity through its setResult().\n     * @param intent      An Intent, which can return result data to the caller (various data can be attached to Intent \"extras\").\n     */\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent intent) {\n        if (requestCode == REQUEST_CODE && this.callbackContext != null) {\n            if (resultCode == Activity.RESULT_OK) {\n                JSONObject obj = new JSONObject();\n                try {\n                    obj.put(TEXT, intent.getStringExtra(\"SCAN_RESULT\"));\n                    obj.put(FORMAT, intent.getStringExtra(\"SCAN_RESULT_FORMAT\"));\n                    obj.put(CANCELLED, false);\n                } catch (JSONException e) {\n                    Log.d(LOG_TAG, \"This should never happen\");\n                }\n                //this.success(new PluginResult(PluginResult.Status.OK, obj), this.callback);\n                this.callbackContext.success(obj);\n            } else if (resultCode == Activity.RESULT_CANCELED) {\n                JSONObject obj = new JSONObject();\n                try {\n                    obj.put(TEXT, \"\");\n                    obj.put(FORMAT, \"\");\n                    obj.put(CANCELLED, true);\n                } catch (JSONException e) {\n                    Log.d(LOG_TAG, \"This should never happen\");\n                }\n                //this.success(new PluginResult(PluginResult.Status.OK, obj), this.callback);\n                this.callbackContext.success(obj);\n            } else {\n                //this.error(new PluginResult(PluginResult.Status.ERROR), this.callback);\n                this.callbackContext.error(\"Unexpected error\");\n            }\n        }\n    }\n\n    /**\n     * Initiates a barcode encode.\n     *\n     * @param type Endoiding type.\n     * @param data The data to encode in the bar code.\n     */\n    public void encode(String type, String data) {\n        Intent intentEncode = new Intent(this.cordova.getActivity().getBaseContext(), EncodeActivity.class);\n        intentEncode.setAction(Intents.Encode.ACTION);\n        intentEncode.putExtra(Intents.Encode.TYPE, type);\n        intentEncode.putExtra(Intents.Encode.DATA, data);\n        // avoid calling other phonegap apps\n        intentEncode.setPackage(this.cordova.getActivity().getApplicationContext().getPackageName());\n\n        this.cordova.getActivity().startActivity(intentEncode);\n    }\n\n    /**\n     * check application's permissions\n     */\n   public boolean hasPermisssion() {\n       for(String p : permissions)\n       {\n           if(!PermissionHelper.hasPermission(this, p))\n           {\n               return false;\n           }\n       }\n       return true;\n   }\n\n    /**\n     * We override this so that we can access the permissions variable, which no longer exists in\n     * the parent class, since we can't initialize it reliably in the constructor!\n     *\n     * @param requestCode The code to get request action\n     */\n   public void requestPermissions(int requestCode)\n   {\n       PermissionHelper.requestPermissions(this, requestCode, permissions);\n   }\n\n   /**\n   * processes the result of permission request\n   *\n   * @param requestCode The code to get request action\n   * @param permissions The collection of permissions\n   * @param grantResults The result of grant\n   */\n  public void onRequestPermissionResult(int requestCode, String[] permissions,\n                                         int[] grantResults) throws JSONException\n   {\n       PluginResult result;\n       for (int r : grantResults) {\n           if (r == PackageManager.PERMISSION_DENIED) {\n               Log.d(LOG_TAG, \"Permission Denied!\");\n               result = new PluginResult(PluginResult.Status.ILLEGAL_ACCESS_EXCEPTION);\n               this.callbackContext.sendPluginResult(result);\n               return;\n           }\n       }\n\n       switch(requestCode)\n       {\n           case 0:\n               scan(this.requestArgs);\n               break;\n       }\n   }\n\n    /**\n     * This plugin launches an external Activity when the camera is opened, so we\n     * need to implement the save/restore API in case the Activity gets killed\n     * by the OS while it's in the background.\n     */\n    public void onRestoreStateForActivityResult(Bundle state, CallbackContext callbackContext) {\n        this.callbackContext = callbackContext;\n    }\n\n}\n"
  },
  {
    "path": "platforms/android/src/friimaind/piholedroid/MainActivity.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n */\n\npackage friimaind.piholedroid;\n\nimport android.os.Bundle;\nimport org.apache.cordova.*;\n\npublic class MainActivity extends CordovaActivity\n{\n    @Override\n    public void onCreate(Bundle savedInstanceState)\n    {\n        super.onCreate(savedInstanceState);\n\n        // enable Cordova apps to be started in the background\n        Bundle extras = getIntent().getExtras();\n        if (extras != null && extras.getBoolean(\"cdvStartInBackground\", false)) {\n            moveTaskToBack(true);\n        }\n\n        // Set by <content src=\"index.html\" /> in config.xml\n        loadUrl(launchUrl);\n    }\n}\n"
  },
  {
    "path": "platforms/android/src/org/apache/cordova/BuildHelper.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova;\n\n/*\n * This is a utility class that allows us to get the BuildConfig variable, which is required\n * for the use of different providers.  This is not guaranteed to work, and it's better for this\n * to be set in the build step in config.xml\n *\n */\n\nimport android.app.Activity;\nimport android.content.Context;\n\nimport java.lang.reflect.Field;\n\n\npublic class BuildHelper {\n\n\n    private static String TAG=\"BuildHelper\";\n\n    /*\n     * This needs to be implemented if you wish to use the Camera Plugin or other plugins\n     * that read the Build Configuration.\n     *\n     * Thanks to Phil@Medtronic and Graham Borland for finding the answer and posting it to\n     * StackOverflow.  This is annoying as hell!  However, this method does not work with\n     * ProGuard, and you should use the config.xml to define the application_id\n     *\n     */\n\n    public static Object getBuildConfigValue(Context ctx, String key)\n    {\n        try\n        {\n            Class<?> clazz = Class.forName(ctx.getPackageName() + \".BuildConfig\");\n            Field field = clazz.getField(key);\n            return field.get(null);\n        } catch (ClassNotFoundException e) {\n            LOG.d(TAG, \"Unable to get the BuildConfig, is this built with ANT?\");\n            e.printStackTrace();\n        } catch (NoSuchFieldException e) {\n            LOG.d(TAG, key + \" is not a valid field. Check your build.gradle\");\n        } catch (IllegalAccessException e) {\n            LOG.d(TAG, \"Illegal Access Exception: Let's print a stack trace.\");\n            e.printStackTrace();\n        }\n\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "platforms/android/src/org/apache/cordova/PermissionHelper.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\n\nimport org.apache.cordova.CordovaInterface;\nimport org.apache.cordova.CordovaPlugin;\nimport org.apache.cordova.LOG;\n\nimport android.content.pm.PackageManager;\n\n/**\n * This class provides reflective methods for permission requesting and checking so that plugins\n * written for cordova-android 5.0.0+ can still compile with earlier cordova-android versions.\n */\npublic class PermissionHelper {\n    private static final String LOG_TAG = \"CordovaPermissionHelper\";\n\n    /**\n     * Requests a \"dangerous\" permission for the application at runtime. This is a helper method\n     * alternative to cordovaInterface.requestPermission() that does not require the project to be\n     * built with cordova-android 5.0.0+\n     *\n     * @param plugin        The plugin the permission is being requested for\n     * @param requestCode   A requestCode to be passed to the plugin's onRequestPermissionResult()\n     *                      along with the result of the permission request\n     * @param permission    The permission to be requested\n     */\n    public static void requestPermission(CordovaPlugin plugin, int requestCode, String permission) {\n        PermissionHelper.requestPermissions(plugin, requestCode, new String[] {permission});\n    }\n\n    /**\n     * Requests \"dangerous\" permissions for the application at runtime. This is a helper method\n     * alternative to cordovaInterface.requestPermissions() that does not require the project to be\n     * built with cordova-android 5.0.0+\n     *\n     * @param plugin        The plugin the permissions are being requested for\n     * @param requestCode   A requestCode to be passed to the plugin's onRequestPermissionResult()\n     *                      along with the result of the permissions request\n     * @param permissions   The permissions to be requested\n     */\n    public static void requestPermissions(CordovaPlugin plugin, int requestCode, String[] permissions) {\n        try {\n            Method requestPermission = CordovaInterface.class.getDeclaredMethod(\n                    \"requestPermissions\", CordovaPlugin.class, int.class, String[].class);\n\n            // If there is no exception, then this is cordova-android 5.0.0+\n            requestPermission.invoke(plugin.cordova, plugin, requestCode, permissions);\n        } catch (NoSuchMethodException noSuchMethodException) {\n            // cordova-android version is less than 5.0.0, so permission is implicitly granted\n            LOG.d(LOG_TAG, \"No need to request permissions \" + Arrays.toString(permissions));\n\n            // Notify the plugin that all were granted by using more reflection\n            deliverPermissionResult(plugin, requestCode, permissions);\n        } catch (IllegalAccessException illegalAccessException) {\n            // Should never be caught; this is a public method\n            LOG.e(LOG_TAG, \"IllegalAccessException when requesting permissions \" + Arrays.toString(permissions), illegalAccessException);\n        } catch(InvocationTargetException invocationTargetException) {\n            // This method does not throw any exceptions, so this should never be caught\n            LOG.e(LOG_TAG, \"invocationTargetException when requesting permissions \" + Arrays.toString(permissions), invocationTargetException);\n        }\n    }\n\n    /**\n     * Checks at runtime to see if the application has been granted a permission. This is a helper\n     * method alternative to cordovaInterface.hasPermission() that does not require the project to\n     * be built with cordova-android 5.0.0+\n     *\n     * @param plugin        The plugin the permission is being checked against\n     * @param permission    The permission to be checked\n     *\n     * @return              True if the permission has already been granted and false otherwise\n     */\n    public static boolean hasPermission(CordovaPlugin plugin, String permission) {\n        try {\n            Method hasPermission = CordovaInterface.class.getDeclaredMethod(\"hasPermission\", String.class);\n\n            // If there is no exception, then this is cordova-android 5.0.0+\n            return (Boolean) hasPermission.invoke(plugin.cordova, permission);\n        } catch (NoSuchMethodException noSuchMethodException) {\n            // cordova-android version is less than 5.0.0, so permission is implicitly granted\n            LOG.d(LOG_TAG, \"No need to check for permission \" + permission);\n            return true;\n        } catch (IllegalAccessException illegalAccessException) {\n            // Should never be caught; this is a public method\n            LOG.e(LOG_TAG, \"IllegalAccessException when checking permission \" + permission, illegalAccessException);\n        } catch(InvocationTargetException invocationTargetException) {\n            // This method does not throw any exceptions, so this should never be caught\n            LOG.e(LOG_TAG, \"invocationTargetException when checking permission \" + permission, invocationTargetException);\n        }\n        return false;\n    }\n\n    private static void deliverPermissionResult(CordovaPlugin plugin, int requestCode, String[] permissions) {\n        // Generate the request results\n        int[] requestResults = new int[permissions.length];\n        Arrays.fill(requestResults, PackageManager.PERMISSION_GRANTED);\n\n        try {\n            Method onRequestPermissionResult = CordovaPlugin.class.getDeclaredMethod(\n                    \"onRequestPermissionResult\", int.class, String[].class, int[].class);\n\n            onRequestPermissionResult.invoke(plugin, requestCode, permissions, requestResults);\n        } catch (NoSuchMethodException noSuchMethodException) {\n            // Should never be caught since the plugin must be written for cordova-android 5.0.0+ if it\n            // made it to this point\n            LOG.e(LOG_TAG, \"NoSuchMethodException when delivering permissions results\", noSuchMethodException);\n        } catch (IllegalAccessException illegalAccessException) {\n            // Should never be caught; this is a public method\n            LOG.e(LOG_TAG, \"IllegalAccessException when delivering permissions results\", illegalAccessException);\n        } catch(InvocationTargetException invocationTargetException) {\n            // This method may throw a JSONException. We are just duplicating cordova-android's\n            // exception handling behavior here; all it does is log the exception in CordovaActivity,\n            // print the stacktrace, and ignore it\n            LOG.e(LOG_TAG, \"InvocationTargetException when delivering permissions results\", invocationTargetException);\n        }\n    }\n}\n"
  },
  {
    "path": "platforms/android/src/org/apache/cordova/splashscreen/SplashScreen.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova.splashscreen;\n\nimport android.app.Dialog;\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.res.Configuration;\nimport android.graphics.Color;\nimport android.graphics.drawable.ColorDrawable;\nimport android.os.Handler;\nimport android.view.Display;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewGroup.LayoutParams;\nimport android.view.WindowManager;\nimport android.view.animation.Animation;\nimport android.view.animation.AlphaAnimation;\nimport android.view.animation.DecelerateInterpolator;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.ProgressBar;\nimport android.widget.RelativeLayout;\n\nimport org.apache.cordova.CallbackContext;\nimport org.apache.cordova.CordovaPlugin;\nimport org.apache.cordova.CordovaWebView;\nimport org.json.JSONArray;\nimport org.json.JSONException;\n\npublic class SplashScreen extends CordovaPlugin {\n    private static final String LOG_TAG = \"SplashScreen\";\n    // Cordova 3.x.x has a copy of this plugin bundled with it (SplashScreenInternal.java).\n    // Enable functionality only if running on 4.x.x.\n    private static final boolean HAS_BUILT_IN_SPLASH_SCREEN = Integer.valueOf(CordovaWebView.CORDOVA_VERSION.split(\"\\\\.\")[0]) < 4;\n    private static final int DEFAULT_SPLASHSCREEN_DURATION = 3000;\n    private static final int DEFAULT_FADE_DURATION = 500;\n    private static Dialog splashDialog;\n    private static ProgressDialog spinnerDialog;\n    private static boolean firstShow = true;\n    private static boolean lastHideAfterDelay; // https://issues.apache.org/jira/browse/CB-9094\n\n    /**\n     * Displays the splash drawable.\n     */\n    private ImageView splashImageView;\n\n    /**\n     * Remember last device orientation to detect orientation changes.\n     */\n    private int orientation;\n\n    // Helper to be compile-time compatible with both Cordova 3.x and 4.x.\n    private View getView() {\n        try {\n            return (View)webView.getClass().getMethod(\"getView\").invoke(webView);\n        } catch (Exception e) {\n            return (View)webView;\n        }\n    }\n\n    @Override\n    protected void pluginInitialize() {\n        if (HAS_BUILT_IN_SPLASH_SCREEN) {\n            return;\n        }\n        // Make WebView invisible while loading URL\n        // CB-11326 Ensure we're calling this on UI thread\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                getView().setVisibility(View.INVISIBLE);\n            }\n        });\n        int drawableId = preferences.getInteger(\"SplashDrawableId\", 0);\n        if (drawableId == 0) {\n            String splashResource = preferences.getString(\"SplashScreen\", \"screen\");\n            if (splashResource != null) {\n                drawableId = cordova.getActivity().getResources().getIdentifier(splashResource, \"drawable\", cordova.getActivity().getClass().getPackage().getName());\n                if (drawableId == 0) {\n                    drawableId = cordova.getActivity().getResources().getIdentifier(splashResource, \"drawable\", cordova.getActivity().getPackageName());\n                }\n                preferences.set(\"SplashDrawableId\", drawableId);\n            }\n        }\n\n        // Save initial orientation.\n        orientation = cordova.getActivity().getResources().getConfiguration().orientation;\n\n        if (firstShow) {\n            boolean autoHide = preferences.getBoolean(\"AutoHideSplashScreen\", true);\n            showSplashScreen(autoHide);\n        }\n\n        if (preferences.getBoolean(\"SplashShowOnlyFirstTime\", true)) {\n            firstShow = false;\n        }\n    }\n\n    /**\n     * Shorter way to check value of \"SplashMaintainAspectRatio\" preference.\n     */\n    private boolean isMaintainAspectRatio () {\n        return preferences.getBoolean(\"SplashMaintainAspectRatio\", false);\n    }\n\n    private int getFadeDuration () {\n        int fadeSplashScreenDuration = preferences.getBoolean(\"FadeSplashScreen\", true) ?\n            preferences.getInteger(\"FadeSplashScreenDuration\", DEFAULT_FADE_DURATION) : 0;\n\n        if (fadeSplashScreenDuration < 30) {\n            // [CB-9750] This value used to be in decimal seconds, so we will assume that if someone specifies 10\n            // they mean 10 seconds, and not the meaningless 10ms\n            fadeSplashScreenDuration *= 1000;\n        }\n\n        return fadeSplashScreenDuration;\n    }\n\n    @Override\n    public void onPause(boolean multitasking) {\n        if (HAS_BUILT_IN_SPLASH_SCREEN) {\n            return;\n        }\n        // hide the splash screen to avoid leaking a window\n        this.removeSplashScreen(true);\n    }\n\n    @Override\n    public void onDestroy() {\n        if (HAS_BUILT_IN_SPLASH_SCREEN) {\n            return;\n        }\n        // hide the splash screen to avoid leaking a window\n        this.removeSplashScreen(true);\n        // If we set this to true onDestroy, we lose track when we go from page to page!\n        //firstShow = true;\n    }\n\n    @Override\n    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {\n        if (action.equals(\"hide\")) {\n            cordova.getActivity().runOnUiThread(new Runnable() {\n                public void run() {\n                    webView.postMessage(\"splashscreen\", \"hide\");\n                }\n            });\n        } else if (action.equals(\"show\")) {\n            cordova.getActivity().runOnUiThread(new Runnable() {\n                public void run() {\n                    webView.postMessage(\"splashscreen\", \"show\");\n                }\n            });\n        } else {\n            return false;\n        }\n\n        callbackContext.success();\n        return true;\n    }\n\n    @Override\n    public Object onMessage(String id, Object data) {\n        if (HAS_BUILT_IN_SPLASH_SCREEN) {\n            return null;\n        }\n        if (\"splashscreen\".equals(id)) {\n            if (\"hide\".equals(data.toString())) {\n                this.removeSplashScreen(false);\n            } else {\n                this.showSplashScreen(false);\n            }\n        } else if (\"spinner\".equals(id)) {\n            if (\"stop\".equals(data.toString())) {\n                getView().setVisibility(View.VISIBLE);\n            }\n        } else if (\"onReceivedError\".equals(id)) {\n            this.spinnerStop();\n        }\n        return null;\n    }\n\n    // Don't add @Override so that plugin still compiles on 3.x.x for a while\n    public void onConfigurationChanged(Configuration newConfig) {\n        if (newConfig.orientation != orientation) {\n            orientation = newConfig.orientation;\n\n            // Splash drawable may change with orientation, so reload it.\n            if (splashImageView != null) {\n                int drawableId = preferences.getInteger(\"SplashDrawableId\", 0);\n                if (drawableId != 0) {\n                    splashImageView.setImageDrawable(cordova.getActivity().getResources().getDrawable(drawableId));\n                }\n            }\n        }\n    }\n\n    private void removeSplashScreen(final boolean forceHideImmediately) {\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            public void run() {\n                if (splashDialog != null && splashDialog.isShowing()) {\n                    final int fadeSplashScreenDuration = getFadeDuration();\n                    // CB-10692 If the plugin is being paused/destroyed, skip the fading and hide it immediately\n                    if (fadeSplashScreenDuration > 0 && forceHideImmediately == false) {\n                        AlphaAnimation fadeOut = new AlphaAnimation(1, 0);\n                        fadeOut.setInterpolator(new DecelerateInterpolator());\n                        fadeOut.setDuration(fadeSplashScreenDuration);\n\n                        splashImageView.setAnimation(fadeOut);\n                        splashImageView.startAnimation(fadeOut);\n\n                        fadeOut.setAnimationListener(new Animation.AnimationListener() {\n                            @Override\n                            public void onAnimationStart(Animation animation) {\n                                spinnerStop();\n                            }\n\n                            @Override\n                            public void onAnimationEnd(Animation animation) {\n                                if (splashDialog != null && splashDialog.isShowing()) {\n                                    splashDialog.dismiss();\n                                    splashDialog = null;\n                                    splashImageView = null;\n                                }\n                            }\n\n                            @Override\n                            public void onAnimationRepeat(Animation animation) {\n                            }\n                        });\n                    } else {\n                        spinnerStop();\n                        splashDialog.dismiss();\n                        splashDialog = null;\n                        splashImageView = null;\n                    }\n                }\n            }\n        });\n    }\n\n    /**\n     * Shows the splash screen over the full Activity\n     */\n    @SuppressWarnings(\"deprecation\")\n    private void showSplashScreen(final boolean hideAfterDelay) {\n        final int splashscreenTime = preferences.getInteger(\"SplashScreenDelay\", DEFAULT_SPLASHSCREEN_DURATION);\n        final int drawableId = preferences.getInteger(\"SplashDrawableId\", 0);\n\n        final int fadeSplashScreenDuration = getFadeDuration();\n        final int effectiveSplashDuration = Math.max(0, splashscreenTime - fadeSplashScreenDuration);\n\n        lastHideAfterDelay = hideAfterDelay;\n\n        // If the splash dialog is showing don't try to show it again\n        if (splashDialog != null && splashDialog.isShowing()) {\n            return;\n        }\n        if (drawableId == 0 || (splashscreenTime <= 0 && hideAfterDelay)) {\n            return;\n        }\n\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            public void run() {\n                // Get reference to display\n                Display display = cordova.getActivity().getWindowManager().getDefaultDisplay();\n                Context context = webView.getContext();\n\n                // Use an ImageView to render the image because of its flexible scaling options.\n                splashImageView = new ImageView(context);\n                splashImageView.setImageResource(drawableId);\n                LayoutParams layoutParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);\n                splashImageView.setLayoutParams(layoutParams);\n\n                splashImageView.setMinimumHeight(display.getHeight());\n                splashImageView.setMinimumWidth(display.getWidth());\n\n                // TODO: Use the background color of the webView's parent instead of using the preference.\n                splashImageView.setBackgroundColor(preferences.getInteger(\"backgroundColor\", Color.BLACK));\n\n                if (isMaintainAspectRatio()) {\n                    // CENTER_CROP scale mode is equivalent to CSS \"background-size:cover\"\n                    splashImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);\n                }\n                else {\n                    // FIT_XY scales image non-uniformly to fit into image view.\n                    splashImageView.setScaleType(ImageView.ScaleType.FIT_XY);\n                }\n\n                // Create and show the dialog\n                splashDialog = new Dialog(context, android.R.style.Theme_Translucent_NoTitleBar);\n                // check to see if the splash screen should be full screen\n                if ((cordova.getActivity().getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN)\n                        == WindowManager.LayoutParams.FLAG_FULLSCREEN) {\n                    splashDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,\n                            WindowManager.LayoutParams.FLAG_FULLSCREEN);\n                }\n                splashDialog.setContentView(splashImageView);\n                splashDialog.setCancelable(false);\n                splashDialog.show();\n\n                if (preferences.getBoolean(\"ShowSplashScreenSpinner\", true)) {\n                    spinnerStart();\n                }\n\n                // Set Runnable to remove splash screen just in case\n                if (hideAfterDelay) {\n                    final Handler handler = new Handler();\n                    handler.postDelayed(new Runnable() {\n                        public void run() {\n                            if (lastHideAfterDelay) {\n                                removeSplashScreen(false);\n                            }\n                        }\n                    }, effectiveSplashDuration);\n                }\n            }\n        });\n    }\n\n    // Show only spinner in the center of the screen\n    private void spinnerStart() {\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            public void run() {\n                spinnerStop();\n\n                spinnerDialog = new ProgressDialog(webView.getContext());\n                spinnerDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {\n                    public void onCancel(DialogInterface dialog) {\n                        spinnerDialog = null;\n                    }\n                });\n\n                spinnerDialog.setCancelable(false);\n                spinnerDialog.setIndeterminate(true);\n\n                RelativeLayout centeredLayout = new RelativeLayout(cordova.getActivity());\n                centeredLayout.setGravity(Gravity.CENTER);\n                centeredLayout.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));\n\n                ProgressBar progressBar = new ProgressBar(webView.getContext());\n                RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);\n                layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);\n                progressBar.setLayoutParams(layoutParams);\n\n                centeredLayout.addView(progressBar);\n\n                spinnerDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);\n                spinnerDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));\n\n                spinnerDialog.show();\n                spinnerDialog.setContentView(centeredLayout);\n            }\n        });\n    }\n\n    private void spinnerStop() {\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            public void run() {\n                if (spinnerDialog != null && spinnerDialog.isShowing()) {\n                    spinnerDialog.dismiss();\n                    spinnerDialog = null;\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "platforms/android/src/org/apache/cordova/whitelist/WhitelistPlugin.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova.whitelist;\n\nimport org.apache.cordova.CordovaPlugin;\nimport org.apache.cordova.ConfigXmlParser;\nimport org.apache.cordova.LOG;\nimport org.apache.cordova.Whitelist;\nimport org.xmlpull.v1.XmlPullParser;\n\nimport android.content.Context;\n\npublic class WhitelistPlugin extends CordovaPlugin {\n    private static final String LOG_TAG = \"WhitelistPlugin\";\n    private Whitelist allowedNavigations;\n    private Whitelist allowedIntents;\n    private Whitelist allowedRequests;\n\n    // Used when instantiated via reflection by PluginManager\n    public WhitelistPlugin() {\n    }\n    // These can be used by embedders to allow Java-configuration of whitelists.\n    public WhitelistPlugin(Context context) {\n        this(new Whitelist(), new Whitelist(), null);\n        new CustomConfigXmlParser().parse(context);\n    }\n    public WhitelistPlugin(XmlPullParser xmlParser) {\n        this(new Whitelist(), new Whitelist(), null);\n        new CustomConfigXmlParser().parse(xmlParser);\n    }\n    public WhitelistPlugin(Whitelist allowedNavigations, Whitelist allowedIntents, Whitelist allowedRequests) {\n        if (allowedRequests == null) {\n            allowedRequests = new Whitelist();\n            allowedRequests.addWhiteListEntry(\"file:///*\", false);\n            allowedRequests.addWhiteListEntry(\"data:*\", false);\n        }\n        this.allowedNavigations = allowedNavigations;\n        this.allowedIntents = allowedIntents;\n        this.allowedRequests = allowedRequests;\n    }\n    @Override\n    public void pluginInitialize() {\n        if (allowedNavigations == null) {\n            allowedNavigations = new Whitelist();\n            allowedIntents = new Whitelist();\n            allowedRequests = new Whitelist();\n            new CustomConfigXmlParser().parse(webView.getContext());\n        }\n    }\n\n    private class CustomConfigXmlParser extends ConfigXmlParser {\n        @Override\n        public void handleStartTag(XmlPullParser xml) {\n            String strNode = xml.getName();\n            if (strNode.equals(\"content\")) {\n                String startPage = xml.getAttributeValue(null, \"src\");\n                allowedNavigations.addWhiteListEntry(startPage, false);\n            } else if (strNode.equals(\"allow-navigation\")) {\n                String origin = xml.getAttributeValue(null, \"href\");\n                if (\"*\".equals(origin)) {\n                    allowedNavigations.addWhiteListEntry(\"http://*/*\", false);\n                    allowedNavigations.addWhiteListEntry(\"https://*/*\", false);\n                    allowedNavigations.addWhiteListEntry(\"data:*\", false);\n                } else {\n                    allowedNavigations.addWhiteListEntry(origin, false);\n                }\n            } else if (strNode.equals(\"allow-intent\")) {\n                String origin = xml.getAttributeValue(null, \"href\");\n                allowedIntents.addWhiteListEntry(origin, false);\n            } else if (strNode.equals(\"access\")) {\n                String origin = xml.getAttributeValue(null, \"origin\");\n                String subdomains = xml.getAttributeValue(null, \"subdomains\");\n                boolean external = (xml.getAttributeValue(null, \"launch-external\") != null);\n                if (origin != null) {\n                    if (external) {\n                        LOG.w(LOG_TAG, \"Found <access launch-external> within config.xml. Please use <allow-intent> instead.\");\n                        allowedIntents.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase(\"true\") == 0));\n                    } else {\n                        if (\"*\".equals(origin)) {\n                            allowedRequests.addWhiteListEntry(\"http://*/*\", false);\n                            allowedRequests.addWhiteListEntry(\"https://*/*\", false);\n                        } else {\n                            allowedRequests.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase(\"true\") == 0));\n                        }\n                    }\n                }\n            }\n        }\n        @Override\n        public void handleEndTag(XmlPullParser xml) {\n        }\n    }\n\n    @Override\n    public Boolean shouldAllowNavigation(String url) {\n        if (allowedNavigations.isUrlWhiteListed(url)) {\n            return true;\n        }\n        return null; // Default policy\n    }\n\n    @Override\n    public Boolean shouldAllowRequest(String url) {\n        if (Boolean.TRUE == shouldAllowNavigation(url)) {\n            return true;\n        }\n        if (allowedRequests.isUrlWhiteListed(url)) {\n            return true;\n        }\n        return null; // Default policy\n    }\n\n    @Override\n    public Boolean shouldOpenExternalUrl(String url) {\n        if (allowedIntents.isUrlWhiteListed(url)) {\n            return true;\n        }\n        return null; // Default policy\n    }\n\n    public Whitelist getAllowedNavigations() {\n        return allowedNavigations;\n    }\n\n    public void setAllowedNavigations(Whitelist allowedNavigations) {\n        this.allowedNavigations = allowedNavigations;\n    }\n\n    public Whitelist getAllowedIntents() {\n        return allowedIntents;\n    }\n\n    public void setAllowedIntents(Whitelist allowedIntents) {\n        this.allowedIntents = allowedIntents;\n    }\n\n    public Whitelist getAllowedRequests() {\n        return allowedRequests;\n    }\n\n    public void setAllowedRequests(Whitelist allowedRequests) {\n        this.allowedRequests = allowedRequests;\n    }\n}\n"
  },
  {
    "path": "platforms/android/wrapper.gradle",
    "content": "//This file is intentionally just a comment\n"
  },
  {
    "path": "platforms/browser/browser.json",
    "content": "{\n    \"prepare_queue\": {\n        \"installed\": [],\n        \"uninstalled\": []\n    },\n    \"config_munge\": {\n        \"files\": {\n            \"config.xml\": {\n                \"parents\": {\n                    \"/*\": [\n                        {\n                            \"xml\": \"<feature name=\\\"BarcodeScanner\\\"><param name=\\\"browser-package\\\" value=\\\"BarcodeScanner\\\" /></feature>\",\n                            \"count\": 1\n                        }\n                    ]\n                }\n            }\n        }\n    },\n    \"installed_plugins\": {\n        \"cordova-plugin-whitelist\": {\n            \"PACKAGE_NAME\": \"io.cordova.hellocordova\"\n        },\n        \"cordova-plugin-splashscreen\": {\n            \"PACKAGE_NAME\": \"friimaind.piholedroid\"\n        },\n        \"phonegap-plugin-barcodescanner\": {\n            \"PACKAGE_NAME\": \"friimaind.piholedroid\"\n        }\n    },\n    \"dependent_plugins\": {},\n    \"modules\": [\n        {\n            \"file\": \"plugins/cordova-plugin-splashscreen/www/splashscreen.js\",\n            \"id\": \"cordova-plugin-splashscreen.SplashScreen\",\n            \"pluginId\": \"cordova-plugin-splashscreen\",\n            \"clobbers\": [\n                \"navigator.splashscreen\"\n            ]\n        },\n        {\n            \"file\": \"plugins/cordova-plugin-splashscreen/src/browser/SplashScreenProxy.js\",\n            \"id\": \"cordova-plugin-splashscreen.SplashScreenProxy\",\n            \"pluginId\": \"cordova-plugin-splashscreen\",\n            \"runs\": true\n        },\n        {\n            \"file\": \"plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js\",\n            \"id\": \"phonegap-plugin-barcodescanner.BarcodeScanner\",\n            \"pluginId\": \"phonegap-plugin-barcodescanner\",\n            \"clobbers\": [\n                \"cordova.plugins.barcodeScanner\"\n            ]\n        },\n        {\n            \"file\": \"plugins/phonegap-plugin-barcodescanner/src/browser/BarcodeScannerProxy.js\",\n            \"id\": \"phonegap-plugin-barcodescanner.BarcodeScannerProxy\",\n            \"pluginId\": \"phonegap-plugin-barcodescanner\",\n            \"runs\": true\n        }\n    ],\n    \"plugin_metadata\": {\n        \"cordova-plugin-whitelist\": \"1.3.1\",\n        \"cordova-plugin-splashscreen\": \"4.0.1\",\n        \"phonegap-plugin-barcodescanner\": \"6.0.6\"\n    }\n}"
  },
  {
    "path": "platforms/browser/config.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<widget id=\"friimaind.piholedroid\" version=\"1.0.4\" xmlns=\"http://www.w3.org/ns/widgets\" xmlns:cdv=\"http://cordova.apache.org/ns/1.0\">\n    <feature name=\"BarcodeScanner\">\n        <param name=\"browser-package\" value=\"BarcodeScanner\" />\n    </feature>\n    <name>Pi-hole Droid</name>\n    <description>\n        Monitor your Pi-hole with your Android smartphone\n    </description>\n    <author email=\"massimiliano.monaro@gmail.com\" href=\"https://blog.friimaind.it\">\n        Massimiliano Monaro\n    </author>\n    <content src=\"index.html\" />\n    <access origin=\"*\" />\n    <allow-intent href=\"http://*/*\" />\n    <allow-intent href=\"https://*/*\" />\n    <allow-intent href=\"tel:*\" />\n    <allow-intent href=\"sms:*\" />\n    <allow-intent href=\"mailto:*\" />\n    <allow-intent href=\"geo:*\" />\n    <preference name=\"Fullscreen\" value=\"false\" />\n    <preference name=\"SplashScreenDelay\" value=\"2000\" />\n    <preference name=\"SplashScreen\" value=\"screen\" />\n    <preference name=\"SplashMaintainAspectRatio\" value=\"true\" />\n    <preference name=\"ShowSplashScreenSpinner\" value=\"false\" />\n</widget>\n"
  },
  {
    "path": "platforms/browser/cordova/build",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\n\nvar build = require('./lib/build'),\n    args  = process.argv;\n\n// provide help\nif ( args[2] == '--help' || args[2] == '/?' || args[2] == '-h' || args[2] == '/h' ||\n                    args[2] == 'help' || args[2] == '-help' || args[2] == '/help') {\n    build.help();\n    process.exit(0);\n} else {\n\n    build.run();\n}\n"
  },
  {
    "path": "platforms/browser/cordova/build.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n::\n:: http://www.apache.org/licenses/LICENSE-2.0\n::\n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0build\"\nIF EXIST %script_path% (\n        node %script_path% %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'build' script in 'cordova' folder, aborting...>&2\n    EXIT /B 1\n)\n"
  },
  {
    "path": "platforms/browser/cordova/clean",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\n\nvar path = require('path'),\n    clean = require('./lib/clean'),\n    reqs  = require('./lib/check_reqs'),\n    args  = process.argv;\n\n// Support basic help commands\nif ( args.length > 2\n   || args[2] == '--help' || args[2] == '/?' || args[2] == '-h' ||\n                    args[2] == 'help' || args[2] == '-help' || args[2] == '/help') {\n    console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'clean')) );\n    process.exit(0);\n} else {\n    clean.cleanProject();\n}\n\n"
  },
  {
    "path": "platforms/browser/cordova/defaults.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<!--\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n-->\n<widget id=\"io.cordova.hellocordova\" version=\"0.0.1\" xmlns=\"http://www.w3.org/ns/widgets\" xmlns:cdv=\"http://cordova.apache.org/ns/1.0\">\n\n</widget>\n"
  },
  {
    "path": "platforms/browser/cordova/lib/build.js",
    "content": "#!/usr/bin/env node\n\n/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n \nvar path    = require('path'),\n    fs      = require('fs'),\n    shjs    = require('shelljs'),\n    zip     = require('adm-zip'),\n    Q       = require('q'),\n    clean   = require('./clean'),\n    check_reqs = require('./check_reqs'),\n    platformWwwDir          = path.join('platforms', 'browser', 'www'),\n    platformBuildDir        = path.join('platforms', 'browser', 'build'),\n    packageFile             = path.join(platformBuildDir, 'package.zip');\n\n/**\n * run\n *   Creates a zip file int platform/build folder\n */\nmodule.exports.run = function(){\n\n    return check_reqs.run()\n    .then(function(){\n            return clean.cleanProject();\n        },\n        function checkReqsError(err){\n            console.error('Please make sure you meet the software requirements in order to build a browser cordova project');\n    })\n    .then(function(){\n\n        if (!fs.existsSync(platformBuildDir)) {\n            fs.mkdirSync(platformBuildDir);\n        }\n\n        // add the project to a zipfile\n        var zipFile = zip();\n        zipFile.addLocalFolder(platformWwwDir, '.');\n        zipFile.writeZip(packageFile);\n\n        return Q.resolve();\n\n    });\n};\n\nmodule.exports.help = function() {\n    console.log('Usage: cordova build browser');\n    console.log('Build will create the packaged app in \\''+platformBuildDir+'\\'.');\n};\n"
  },
  {
    "path": "platforms/browser/cordova/lib/check_reqs.js",
    "content": "#!/usr/bin/env node\n\n/*\nLicensed to the Apache Software Foundation (ASF) under one\nor more contributor license agreements. See the NOTICE file\ndistributed with this work for additional information\nregarding copyright ownership. The ASF licenses this file\nto you under the Apache License, Version 2.0 (the\n\"License\"); you may not use this file except in compliance\nwith the License. You may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing,\nsoftware distributed under the License is distributed on an\n\"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\nKIND, either express or implied. See the License for the\nspecific language governing permissions and limitations\nunder the License.\n*/\n\n//add methods as we determine what are the requirements\n\nvar Q = require('q');\n\nmodule.exports.run = function() {\n    return Q.resolve();\n};\n"
  },
  {
    "path": "platforms/browser/cordova/lib/clean.js",
    "content": "#!/usr/bin/env node\n\n/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n \nvar fs = require('fs'),\n    shjs = require('shelljs'),\n    path = require('path'),\n    check_reqs = require('./check_reqs'),\n    platformBuildDir = path.join('platforms', 'browser', 'build');\n\nexports.cleanProject = function(){\n\n    // Check that requirements are (stil) met\n    if (!check_reqs.run()) {\n        console.error('Please make sure you meet the software requirements in order to clean an browser cordova project');\n        process.exit(2);\n    }\n    \n    console.log('Cleaning Browser project');\n    try {\n        if (fs.existsSync(platformBuildDir)) {\n            shjs.rm('-r', platformBuildDir);\n        }\n    }\n    catch(err) {\n        console.log('could not remove '+platformBuildDir+' : '+err.message);\n    }\n};\n\n"
  },
  {
    "path": "platforms/browser/cordova/run",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n    \n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\nvar fs = require('fs'),\n    path = require('path'),\n    nopt  = require('nopt'),\n    url = require('url'),\n    cordovaServe = require('cordova-serve');\n\nvar args = process.argv;\n\nstart(args);\n\nfunction start(argv) {\n    var args  = nopt({'help': Boolean, 'target': String, 'port': Number}, {'help': ['/?', '-h', 'help', '-help', '/help']}, argv);\n    if(args.help) {\n        help();\n    }\n\n    // defaults\n    args.port = args.port || 8000;\n    args.target = args.target || \"chrome\";\n\n    var root = path.join(__dirname, '../'),\n        configFile = path.resolve(path.join(root, 'config.xml')),\n        configXML = fs.readFileSync(configFile, 'utf8'),\n        sourceFile = /<content[\\s]+?src\\s*=\\s*\"(.*?)\"/i.exec(configXML);\n\n    var server = cordovaServe();\n    server.servePlatform('browser', {port: args.port, noServerInfo: true}).then(function () {\n        var projectUrl = url.resolve('http://localhost:' + server.port + '/', sourceFile ? sourceFile[1] : 'index.html');\n        console.log('Static file server running @ ' + projectUrl + '\\nCTRL + C to shut down');\n        return cordovaServe.launchBrowser({target: args.target, url: projectUrl});\n    }).catch(function (error) {\n        console.log(error.message || error.toString());\n        if (server.server) {\n            server.server.close();\n        }\n    });\n}\n\nfunction help() {\n    console.log(\"\\nUsage: run [ --target=<browser> ] [ --port=<number> ]\");\n    console.log(\"    --target=<browser> : Launches the specified browser. Chrome is default.\");\n    console.log(\"    --port=<number>    : Http server uses specified port number.\");\n    console.log(\"Examples:\");\n    console.log(\"    run\");\n    console.log(\"    run -- --target=ie\");\n    console.log(\"    run -- --target=chrome --port=8000\");\n    console.log(\"\");\n    process.exit(0);\n}\n"
  },
  {
    "path": "platforms/browser/cordova/run.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n::\n:: http://www.apache.org/licenses/LICENSE-2.0\n::\n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0run\"\nIF EXIST %script_path% (\n        node %script_path% %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'run' script in 'cordova' folder, aborting...>&2\n    EXIT /B 1\n)\n"
  },
  {
    "path": "platforms/browser/cordova/version",
    "content": "#!/usr/bin/env node\n\n/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\n// Coho updates this line:\nvar VERSION = \"4.1.0\";\n\nconsole.log(VERSION);\n"
  },
  {
    "path": "platforms/browser/cordova/version.bat",
    "content": ":: Licensed to the Apache Software Foundation (ASF) under one\n:: or more contributor license agreements.  See the NOTICE file\n:: distributed with this work for additional information\n:: regarding copyright ownership.  The ASF licenses this file\n:: to you under the Apache License, Version 2.0 (the\n:: \"License\"); you may not use this file except in compliance\n:: with the License.  You may obtain a copy of the License at\n::\n:: http://www.apache.org/licenses/LICENSE-2.0\n::\n:: Unless required by applicable law or agreed to in writing,\n:: software distributed under the License is distributed on an\n:: \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n:: KIND, either express or implied.  See the License for the\n:: specific language governing permissions and limitations\n:: under the License.\n\n@ECHO OFF\nSET script_path=\"%~dp0version\"\nIF EXIST %script_path% (\n        node %script_path% %*\n) ELSE (\n    ECHO.\n    ECHO ERROR: Could not find 'version' script in 'cordova' folder, aborting...>&2\n    EXIT /B 1\n)\n"
  },
  {
    "path": "platforms/browser/css/index.css",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n* {\n    -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */\n}\n\nbody {\n    -webkit-touch-callout: none;                /* prevent callout to copy image, etc when tap to hold */\n    -webkit-text-size-adjust: none;             /* prevent webkit from resizing text to fit */\n    -webkit-user-select: none;                  /* prevent copy paste, to allow, change 'none' to 'text' */\n    background-color:#E4E4E4;\n    background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);\n    background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);\n    background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);\n    background-image:-webkit-gradient(\n        linear,\n        left top,\n        left bottom,\n        color-stop(0, #A7A7A7),\n        color-stop(0.51, #E4E4E4)\n    );\n    background-attachment:fixed;\n    font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;\n    font-size:12px;\n    height:100%;\n    margin:0px;\n    padding:0px;\n    text-transform:uppercase;\n    width:100%;\n}\n\n/* Portrait layout (default) */\n.app {\n    background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */\n    position:absolute;             /* position in the center of the screen */\n    left:50%;\n    top:50%;\n    height:50px;                   /* text area height */\n    width:225px;                   /* text area width */\n    text-align:center;\n    padding:180px 0px 0px 0px;     /* image height is 200px (bottom 20px are overlapped with text) */\n    margin:-115px 0px 0px -112px;  /* offset vertical: half of image height and text area height */\n                                   /* offset horizontal: half of text area width */\n}\n\n/* Landscape layout (with min-width) */\n@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {\n    .app {\n        background-position:left center;\n        padding:75px 0px 75px 170px;  /* padding-top + padding-bottom + text area = image height */\n        margin:-90px 0px 0px -198px;  /* offset vertical: half of image height */\n                                      /* offset horizontal: half of image width and text area width */\n    }\n}\n\nh1 {\n    font-size:24px;\n    font-weight:normal;\n    margin:0px;\n    overflow:visible;\n    padding:0px;\n    text-align:center;\n}\n\n.event {\n    border-radius:4px;\n    -webkit-border-radius:4px;\n    color:#FFFFFF;\n    font-size:12px;\n    margin:0px 30px;\n    padding:2px 0px;\n}\n\n.event.listening {\n    background-color:#333333;\n    display:block;\n}\n\n.event.received {\n    background-color:#4B946A;\n    display:none;\n}\n\n@keyframes fade {\n    from { opacity: 1.0; }\n    50% { opacity: 0.4; }\n    to { opacity: 1.0; }\n}\n \n@-webkit-keyframes fade {\n    from { opacity: 1.0; }\n    50% { opacity: 0.4; }\n    to { opacity: 1.0; }\n}\n \n.blink {\n    animation:fade 3000ms infinite;\n    -webkit-animation:fade 3000ms infinite;\n}\n"
  },
  {
    "path": "platforms/browser/index.html",
    "content": "<!DOCTYPE html>\n<!--\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n     KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n-->\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <meta name=\"format-detection\" content=\"telephone=no\" />\n        <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->\n        <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi\" />\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"css/index.css\" />\n        <title>Hello World</title>\n    </head>\n    <body>\n        <div class=\"app\">\n            <h1>Apache Cordova</h1>\n            <div id=\"deviceready\" class=\"blink\">\n                <p class=\"event listening\">Connecting to Device</p>\n                <p class=\"event received\">Device is Ready</p>\n            </div>\n        </div>\n        <script type=\"text/javascript\" src=\"cordova.js\"></script>\n        <script type=\"text/javascript\" src=\"js/index.js\"></script>\n        <script type=\"text/javascript\">\n            app.initialize();\n        </script>\n    </body>\n</html>\n"
  },
  {
    "path": "platforms/browser/js/index.js",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\nvar app = {\n    // Application Constructor\n    initialize: function() {\n        this.bindEvents();\n    },\n    // Bind Event Listeners\n    //\n    // Bind any events that are required on startup. Common events are:\n    // 'load', 'deviceready', 'offline', and 'online'.\n    bindEvents: function() {\n        document.addEventListener('deviceready', this.onDeviceReady, false);\n    },\n    // deviceready Event Handler\n    //\n    // The scope of 'this' is the event. In order to call the 'receivedEvent'\n    // function, we must explicity call 'app.receivedEvent(...);'\n    onDeviceReady: function() {\n        app.receivedEvent('deviceready');\n    },\n    // Update DOM on a Received Event\n    receivedEvent: function(id) {\n        var parentElement = document.getElementById(id);\n        var listeningElement = parentElement.querySelector('.listening');\n        var receivedElement = parentElement.querySelector('.received');\n\n        listeningElement.setAttribute('style', 'display:none;');\n        receivedElement.setAttribute('style', 'display:block;');\n\n        console.log('Received Event: ' + id);\n    }\n};\n"
  },
  {
    "path": "platforms/browser/manifest.webapp",
    "content": "{\n  \"name\": \"My App\",\n  \"description\": \"Description of your app\",\n  \"launch_path\": \"/index.html\",\n  \"icons\": {\n    \"128\": \"/img/logo.png\"\n  },\n  \"default_locale\": \"en\",\n  \"type\": \"privileged\"\n}"
  },
  {
    "path": "platforms/browser/platform_www/confighelper.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nvar config;\n\nfunction Config(xhr) {\n    function loadPreferences(xhr) {\n       var parser = new DOMParser();\n       var doc = parser.parseFromString(xhr.responseText, \"application/xml\");\n\n       var preferences = doc.getElementsByTagName(\"preference\");\n       return Array.prototype.slice.call(preferences);\n    }\n\n    this.xhr = xhr;\n    this.preferences = loadPreferences(this.xhr);\n}\n\nfunction readConfig(success, error) {\n    var xhr;\n\n    if(typeof config != 'undefined') {\n        success(config);\n    }\n\n    function fail(msg) {\n        console.error(msg);\n\n        if(error) {\n            error(msg);\n        }\n    }\n\n    var xhrStatusChangeHandler = function() {\n        if (xhr.readyState == 4) {\n            if (xhr.status == 200 || xhr.status == 304 || xhr.status === 0 /* file:// */) {\n                config = new Config(xhr);\n                success(config);\n            }\n            else {\n                fail('[Browser][cordova.js][xhrStatusChangeHandler] Could not XHR config.xml: ' + xhr.statusText);\n            }\n        }\n    };\n\n    if (\"ActiveXObject\" in window) {\n        // Needed for XHR-ing via file:// protocol in IE\n        xhr = new window.ActiveXObject(\"MSXML2.XMLHTTP\");\n        xhr.onreadystatechange = xhrStatusChangeHandler;\n    } else {\n        xhr = new XMLHttpRequest();\n        xhr.addEventListener(\"load\", xhrStatusChangeHandler);\n    }\n\n    try {\n        xhr.open(\"get\", \"/config.xml\", true);\n        xhr.send();\n    } catch(e) {\n        fail('[Browser][cordova.js][readConfig] Could not XHR config.xml: ' + JSON.stringify(e));\n    }\n}\n\n/**\n * Reads a preference value from config.xml.\n * Returns preference value or undefined if it does not exist.\n * @param {String} preferenceName Preference name to read */\nConfig.prototype.getPreferenceValue = function getPreferenceValue(preferenceName) {\n    var preferenceItem = this.preferences && this.preferences.filter(function(item) {\n        return item.attributes.name && item.attributes.name.value === preferenceName;\n    });\n\n    if(preferenceItem && preferenceItem[0] && preferenceItem[0].attributes && preferenceItem[0].attributes.value) {\n        return preferenceItem[0].attributes.value.value;\n    }\n};\n\nexports.readConfig = readConfig;\n"
  },
  {
    "path": "platforms/browser/platform_www/cordova-js-src/confighelper.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nvar config;\n\nfunction Config(xhr) {\n    function loadPreferences(xhr) {\n       var parser = new DOMParser();\n       var doc = parser.parseFromString(xhr.responseText, \"application/xml\");\n\n       var preferences = doc.getElementsByTagName(\"preference\");\n       return Array.prototype.slice.call(preferences);\n    }\n\n    this.xhr = xhr;\n    this.preferences = loadPreferences(this.xhr);\n}\n\nfunction readConfig(success, error) {\n    var xhr;\n\n    if(typeof config != 'undefined') {\n        success(config);\n    }\n\n    function fail(msg) {\n        console.error(msg);\n\n        if(error) {\n            error(msg);\n        }\n    }\n\n    var xhrStatusChangeHandler = function() {\n        if (xhr.readyState == 4) {\n            if (xhr.status == 200 || xhr.status == 304 || xhr.status === 0 /* file:// */) {\n                config = new Config(xhr);\n                success(config);\n            }\n            else {\n                fail('[Browser][cordova.js][xhrStatusChangeHandler] Could not XHR config.xml: ' + xhr.statusText);\n            }\n        }\n    };\n\n    if (\"ActiveXObject\" in window) {\n        // Needed for XHR-ing via file:// protocol in IE\n        xhr = new window.ActiveXObject(\"MSXML2.XMLHTTP\");\n        xhr.onreadystatechange = xhrStatusChangeHandler;\n    } else {\n        xhr = new XMLHttpRequest();\n        xhr.addEventListener(\"load\", xhrStatusChangeHandler);\n    }\n\n    try {\n        xhr.open(\"get\", \"/config.xml\", true);\n        xhr.send();\n    } catch(e) {\n        fail('[Browser][cordova.js][readConfig] Could not XHR config.xml: ' + JSON.stringify(e));\n    }\n}\n\n/**\n * Reads a preference value from config.xml.\n * Returns preference value or undefined if it does not exist.\n * @param {String} preferenceName Preference name to read */\nConfig.prototype.getPreferenceValue = function getPreferenceValue(preferenceName) {\n    var preferenceItem = this.preferences && this.preferences.filter(function(item) {\n        return item.attributes.name && item.attributes.name.value === preferenceName;\n    });\n\n    if(preferenceItem && preferenceItem[0] && preferenceItem[0].attributes && preferenceItem[0].attributes.value) {\n        return preferenceItem[0].attributes.value.value;\n    }\n};\n\nexports.readConfig = readConfig;\n"
  },
  {
    "path": "platforms/browser/platform_www/cordova-js-src/exec.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n/*jslint sloppy:true, plusplus:true*/\n/*global require, module, console */\n\nvar cordova = require('cordova');\nvar execProxy = require('cordova/exec/proxy');\n\n/**\n * Execute a cordova command.  It is up to the native side whether this action\n * is synchronous or asynchronous.  The native side can return:\n *      Synchronous: PluginResult object as a JSON string\n *      Asynchronous: Empty string \"\"\n * If async, the native side will cordova.callbackSuccess or cordova.callbackError,\n * depending upon the result of the action.\n *\n * @param {Function} success    The success callback\n * @param {Function} fail       The fail callback\n * @param {String} service      The name of the service to use\n * @param {String} action       Action to be run in cordova\n * @param {String[]} [args]     Zero or more arguments to pass to the method\n */\nmodule.exports = function (success, fail, service, action, args) {\n\n    var proxy = execProxy.get(service, action);\n\n    args = args || [];\n\n    if (proxy) {\n        \n        var callbackId = service + cordova.callbackId++;\n        \n        if (typeof success === \"function\" || typeof fail === \"function\") {\n            cordova.callbacks[callbackId] = {success: success, fail: fail};\n        }\n        try {\n\n            \n\n            // callbackOptions param represents additional optional parameters command could pass back, like keepCallback or\n            // custom callbackId, for example {callbackId: id, keepCallback: true, status: cordova.callbackStatus.JSON_EXCEPTION }\n            var onSuccess = function (result, callbackOptions) {\n                callbackOptions = callbackOptions || {};\n                var callbackStatus;\n                // covering both undefined and null.\n                // strict null comparison was causing callbackStatus to be undefined\n                // and then no callback was called because of the check in cordova.callbackFromNative\n                // see CB-8996 Mobilespec app hang on windows\n                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {\n                    callbackStatus = callbackOptions.status;\n                }\n                else {\n                    callbackStatus = cordova.callbackStatus.OK;\n                }\n                cordova.callbackSuccess(callbackOptions.callbackId || callbackId,\n                    {\n                        status: callbackStatus,\n                        message: result,\n                        keepCallback: callbackOptions.keepCallback || false\n                    });\n            };\n            var onError = function (err, callbackOptions) {\n                callbackOptions = callbackOptions || {};\n                var callbackStatus;\n                // covering both undefined and null.\n                // strict null comparison was causing callbackStatus to be undefined\n                // and then no callback was called because of the check in cordova.callbackFromNative\n                // note: status can be 0\n                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {\n                    callbackStatus = callbackOptions.status;\n                }\n                else {\n                    callbackStatus = cordova.callbackStatus.OK;\n                }\n                cordova.callbackError(callbackOptions.callbackId || callbackId,\n                {\n                    status: callbackStatus,\n                    message: err,\n                    keepCallback: callbackOptions.keepCallback || false\n                });\n            };\n            proxy(onSuccess, onError, args);\n\n        } catch (e) {\n            console.log(\"Exception calling native with command :: \" + service + \" :: \" + action  + \" ::exception=\" + e);\n        }\n    } else {\n\n        console.log(\"Error: exec proxy not found for :: \" + service + \" :: \" + action);\n        \n        if(typeof fail === \"function\" ) {\n            fail(\"Missing Command Error\");\n        }\n    }\n};\n"
  },
  {
    "path": "platforms/browser/platform_www/cordova-js-src/platform.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nmodule.exports = {\n    id: 'browser',\n    cordovaVersion: '3.4.0',\n\n    bootstrap: function() {\n\n        var modulemapper = require('cordova/modulemapper');\n        var channel = require('cordova/channel');\n\n        modulemapper.clobbers('cordova/exec/proxy', 'cordova.commandProxy');\n\n        channel.onNativeReady.fire();\n\n        // FIXME is this the right place to clobber pause/resume? I am guessing not\n        // FIXME pause/resume should be deprecated IN CORDOVA for pagevisiblity api\n        document.addEventListener('webkitvisibilitychange', function() {\n            if (document.webkitHidden) {\n                channel.onPause.fire();\n            }\n            else {\n                channel.onResume.fire();\n            }\n        }, false);\n\n    // End of bootstrap\n    }\n};\n"
  },
  {
    "path": "platforms/browser/platform_www/cordova.js",
    "content": "// Platform: browser\n// c517ca811b4948b630e0b74dbae6c9637939da24\n/*\n Licensed to the Apache Software Foundation (ASF) under one\n or more contributor license agreements.  See the NOTICE file\n distributed with this work for additional information\n regarding copyright ownership.  The ASF licenses this file\n to you under the Apache License, Version 2.0 (the\n \"License\"); you may not use this file except in compliance\n with the License.  You may obtain a copy of the License at\n \n     http://www.apache.org/licenses/LICENSE-2.0\n \n Unless required by applicable law or agreed to in writing,\n software distributed under the License is distributed on an\n \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n KIND, either express or implied.  See the License for the\n specific language governing permissions and limitations\n under the License.\n*/\n;(function() {\nvar PLATFORM_VERSION_BUILD_LABEL = '4.1.0';\n// file: src/scripts/require.js\n\n/*jshint -W079 */\n/*jshint -W020 */\n\nvar require,\n    define;\n\n(function () {\n    var modules = {},\n    // Stack of moduleIds currently being built.\n        requireStack = [],\n    // Map of module ID -> index into requireStack of modules currently being built.\n        inProgressModules = {},\n        SEPARATOR = \".\";\n\n\n\n    function build(module) {\n        var factory = module.factory,\n            localRequire = function (id) {\n                var resultantId = id;\n                //Its a relative path, so lop off the last portion and add the id (minus \"./\")\n                if (id.charAt(0) === \".\") {\n                    resultantId = module.id.slice(0, module.id.lastIndexOf(SEPARATOR)) + SEPARATOR + id.slice(2);\n                }\n                return require(resultantId);\n            };\n        module.exports = {};\n        delete module.factory;\n        factory(localRequire, module.exports, module);\n        return module.exports;\n    }\n\n    require = function (id) {\n        if (!modules[id]) {\n            throw \"module \" + id + \" not found\";\n        } else if (id in inProgressModules) {\n            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;\n            throw \"Cycle in require graph: \" + cycle;\n        }\n        if (modules[id].factory) {\n            try {\n                inProgressModules[id] = requireStack.length;\n                requireStack.push(id);\n                return build(modules[id]);\n            } finally {\n                delete inProgressModules[id];\n                requireStack.pop();\n            }\n        }\n        return modules[id].exports;\n    };\n\n    define = function (id, factory) {\n        if (modules[id]) {\n            throw \"module \" + id + \" already defined\";\n        }\n\n        modules[id] = {\n            id: id,\n            factory: factory\n        };\n    };\n\n    define.remove = function (id) {\n        delete modules[id];\n    };\n\n    define.moduleMap = modules;\n})();\n\n//Export for use in node\nif (typeof module === \"object\" && typeof require === \"function\") {\n    module.exports.require = require;\n    module.exports.define = define;\n}\n\n// file: src/cordova.js\ndefine(\"cordova\", function(require, exports, module) {\n\n// Workaround for Windows 10 in hosted environment case\n// http://www.w3.org/html/wg/drafts/html/master/browsers.html#named-access-on-the-window-object\nif (window.cordova && !(window.cordova instanceof HTMLElement)) {\n    throw new Error(\"cordova already defined\");\n}\n\n\nvar channel = require('cordova/channel');\nvar platform = require('cordova/platform');\n\n\n/**\n * Intercept calls to addEventListener + removeEventListener and handle deviceready,\n * resume, and pause events.\n */\nvar m_document_addEventListener = document.addEventListener;\nvar m_document_removeEventListener = document.removeEventListener;\nvar m_window_addEventListener = window.addEventListener;\nvar m_window_removeEventListener = window.removeEventListener;\n\n/**\n * Houses custom event handlers to intercept on document + window event listeners.\n */\nvar documentEventHandlers = {},\n    windowEventHandlers = {};\n\ndocument.addEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    if (typeof documentEventHandlers[e] != 'undefined') {\n        documentEventHandlers[e].subscribe(handler);\n    } else {\n        m_document_addEventListener.call(document, evt, handler, capture);\n    }\n};\n\nwindow.addEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    if (typeof windowEventHandlers[e] != 'undefined') {\n        windowEventHandlers[e].subscribe(handler);\n    } else {\n        m_window_addEventListener.call(window, evt, handler, capture);\n    }\n};\n\ndocument.removeEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    // If unsubscribing from an event that is handled by a plugin\n    if (typeof documentEventHandlers[e] != \"undefined\") {\n        documentEventHandlers[e].unsubscribe(handler);\n    } else {\n        m_document_removeEventListener.call(document, evt, handler, capture);\n    }\n};\n\nwindow.removeEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    // If unsubscribing from an event that is handled by a plugin\n    if (typeof windowEventHandlers[e] != \"undefined\") {\n        windowEventHandlers[e].unsubscribe(handler);\n    } else {\n        m_window_removeEventListener.call(window, evt, handler, capture);\n    }\n};\n\nfunction createEvent(type, data) {\n    var event = document.createEvent('Events');\n    event.initEvent(type, false, false);\n    if (data) {\n        for (var i in data) {\n            if (data.hasOwnProperty(i)) {\n                event[i] = data[i];\n            }\n        }\n    }\n    return event;\n}\n\n\nvar cordova = {\n    define:define,\n    require:require,\n    version:PLATFORM_VERSION_BUILD_LABEL,\n    platformVersion:PLATFORM_VERSION_BUILD_LABEL,\n    platformId:platform.id,\n    /**\n     * Methods to add/remove your own addEventListener hijacking on document + window.\n     */\n    addWindowEventHandler:function(event) {\n        return (windowEventHandlers[event] = channel.create(event));\n    },\n    addStickyDocumentEventHandler:function(event) {\n        return (documentEventHandlers[event] = channel.createSticky(event));\n    },\n    addDocumentEventHandler:function(event) {\n        return (documentEventHandlers[event] = channel.create(event));\n    },\n    removeWindowEventHandler:function(event) {\n        delete windowEventHandlers[event];\n    },\n    removeDocumentEventHandler:function(event) {\n        delete documentEventHandlers[event];\n    },\n    /**\n     * Retrieve original event handlers that were replaced by Cordova\n     *\n     * @return object\n     */\n    getOriginalHandlers: function() {\n        return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},\n        'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};\n    },\n    /**\n     * Method to fire event from native code\n     * bNoDetach is required for events which cause an exception which needs to be caught in native code\n     */\n    fireDocumentEvent: function(type, data, bNoDetach) {\n        var evt = createEvent(type, data);\n        if (typeof documentEventHandlers[type] != 'undefined') {\n            if( bNoDetach ) {\n                documentEventHandlers[type].fire(evt);\n            }\n            else {\n                setTimeout(function() {\n                    // Fire deviceready on listeners that were registered before cordova.js was loaded.\n                    if (type == 'deviceready') {\n                        document.dispatchEvent(evt);\n                    }\n                    documentEventHandlers[type].fire(evt);\n                }, 0);\n            }\n        } else {\n            document.dispatchEvent(evt);\n        }\n    },\n    fireWindowEvent: function(type, data) {\n        var evt = createEvent(type,data);\n        if (typeof windowEventHandlers[type] != 'undefined') {\n            setTimeout(function() {\n                windowEventHandlers[type].fire(evt);\n            }, 0);\n        } else {\n            window.dispatchEvent(evt);\n        }\n    },\n\n    /**\n     * Plugin callback mechanism.\n     */\n    // Randomize the starting callbackId to avoid collisions after refreshing or navigating.\n    // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.\n    callbackId: Math.floor(Math.random() * 2000000000),\n    callbacks:  {},\n    callbackStatus: {\n        NO_RESULT: 0,\n        OK: 1,\n        CLASS_NOT_FOUND_EXCEPTION: 2,\n        ILLEGAL_ACCESS_EXCEPTION: 3,\n        INSTANTIATION_EXCEPTION: 4,\n        MALFORMED_URL_EXCEPTION: 5,\n        IO_EXCEPTION: 6,\n        INVALID_ACTION: 7,\n        JSON_EXCEPTION: 8,\n        ERROR: 9\n    },\n\n    /**\n     * Called by native code when returning successful result from an action.\n     */\n    callbackSuccess: function(callbackId, args) {\n        cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);\n    },\n\n    /**\n     * Called by native code when returning error result from an action.\n     */\n    callbackError: function(callbackId, args) {\n        // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.\n        // Derive success from status.\n        cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);\n    },\n\n    /**\n     * Called by native code when returning the result from an action.\n     */\n    callbackFromNative: function(callbackId, isSuccess, status, args, keepCallback) {\n        try {\n            var callback = cordova.callbacks[callbackId];\n            if (callback) {\n                if (isSuccess && status == cordova.callbackStatus.OK) {\n                    callback.success && callback.success.apply(null, args);\n                } else if (!isSuccess) {\n                    callback.fail && callback.fail.apply(null, args);\n                }\n                /*\n                else\n                    Note, this case is intentionally not caught.\n                    this can happen if isSuccess is true, but callbackStatus is NO_RESULT\n                    which is used to remove a callback from the list without calling the callbacks\n                    typically keepCallback is false in this case\n                */\n                // Clear callback if not expecting any more results\n                if (!keepCallback) {\n                    delete cordova.callbacks[callbackId];\n                }\n            }\n        }\n        catch (err) {\n            var msg = \"Error in \" + (isSuccess ? \"Success\" : \"Error\") + \" callbackId: \" + callbackId + \" : \" + err;\n            console && console.log && console.log(msg);\n            cordova.fireWindowEvent(\"cordovacallbackerror\", { 'message': msg });\n            throw err;\n        }\n    },\n    addConstructor: function(func) {\n        channel.onCordovaReady.subscribe(function() {\n            try {\n                func();\n            } catch(e) {\n                console.log(\"Failed to run constructor: \" + e);\n            }\n        });\n    }\n};\n\n\nmodule.exports = cordova;\n\n});\n\n// file: src/common/argscheck.js\ndefine(\"cordova/argscheck\", function(require, exports, module) {\n\nvar utils = require('cordova/utils');\n\nvar moduleExports = module.exports;\n\nvar typeMap = {\n    'A': 'Array',\n    'D': 'Date',\n    'N': 'Number',\n    'S': 'String',\n    'F': 'Function',\n    'O': 'Object'\n};\n\nfunction extractParamName(callee, argIndex) {\n    return (/.*?\\((.*?)\\)/).exec(callee)[1].split(', ')[argIndex];\n}\n\nfunction checkArgs(spec, functionName, args, opt_callee) {\n    if (!moduleExports.enableChecks) {\n        return;\n    }\n    var errMsg = null;\n    var typeName;\n    for (var i = 0; i < spec.length; ++i) {\n        var c = spec.charAt(i),\n            cUpper = c.toUpperCase(),\n            arg = args[i];\n        // Asterix means allow anything.\n        if (c == '*') {\n            continue;\n        }\n        typeName = utils.typeName(arg);\n        if ((arg === null || arg === undefined) && c == cUpper) {\n            continue;\n        }\n        if (typeName != typeMap[cUpper]) {\n            errMsg = 'Expected ' + typeMap[cUpper];\n            break;\n        }\n    }\n    if (errMsg) {\n        errMsg += ', but got ' + typeName + '.';\n        errMsg = 'Wrong type for parameter \"' + extractParamName(opt_callee || args.callee, i) + '\" of ' + functionName + ': ' + errMsg;\n        // Don't log when running unit tests.\n        if (typeof jasmine == 'undefined') {\n            console.error(errMsg);\n        }\n        throw TypeError(errMsg);\n    }\n}\n\nfunction getValue(value, defaultValue) {\n    return value === undefined ? defaultValue : value;\n}\n\nmoduleExports.checkArgs = checkArgs;\nmoduleExports.getValue = getValue;\nmoduleExports.enableChecks = true;\n\n\n});\n\n// file: src/common/base64.js\ndefine(\"cordova/base64\", function(require, exports, module) {\n\nvar base64 = exports;\n\nbase64.fromArrayBuffer = function(arrayBuffer) {\n    var array = new Uint8Array(arrayBuffer);\n    return uint8ToBase64(array);\n};\n\nbase64.toArrayBuffer = function(str) {\n    var decodedStr = typeof atob != 'undefined' ? atob(str) : new Buffer(str,'base64').toString('binary');\n    var arrayBuffer = new ArrayBuffer(decodedStr.length);\n    var array = new Uint8Array(arrayBuffer);\n    for (var i=0, len=decodedStr.length; i < len; i++) {\n        array[i] = decodedStr.charCodeAt(i);\n    }\n    return arrayBuffer;\n};\n\n//------------------------------------------------------------------------------\n\n/* This code is based on the performance tests at http://jsperf.com/b64tests\n * This 12-bit-at-a-time algorithm was the best performing version on all\n * platforms tested.\n */\n\nvar b64_6bit = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nvar b64_12bit;\n\nvar b64_12bitTable = function() {\n    b64_12bit = [];\n    for (var i=0; i<64; i++) {\n        for (var j=0; j<64; j++) {\n            b64_12bit[i*64+j] = b64_6bit[i] + b64_6bit[j];\n        }\n    }\n    b64_12bitTable = function() { return b64_12bit; };\n    return b64_12bit;\n};\n\nfunction uint8ToBase64(rawData) {\n    var numBytes = rawData.byteLength;\n    var output=\"\";\n    var segment;\n    var table = b64_12bitTable();\n    for (var i=0;i<numBytes-2;i+=3) {\n        segment = (rawData[i] << 16) + (rawData[i+1] << 8) + rawData[i+2];\n        output += table[segment >> 12];\n        output += table[segment & 0xfff];\n    }\n    if (numBytes - i == 2) {\n        segment = (rawData[i] << 16) + (rawData[i+1] << 8);\n        output += table[segment >> 12];\n        output += b64_6bit[(segment & 0xfff) >> 6];\n        output += '=';\n    } else if (numBytes - i == 1) {\n        segment = (rawData[i] << 16);\n        output += table[segment >> 12];\n        output += '==';\n    }\n    return output;\n}\n\n});\n\n// file: src/common/builder.js\ndefine(\"cordova/builder\", function(require, exports, module) {\n\nvar utils = require('cordova/utils');\n\nfunction each(objects, func, context) {\n    for (var prop in objects) {\n        if (objects.hasOwnProperty(prop)) {\n            func.apply(context, [objects[prop], prop]);\n        }\n    }\n}\n\nfunction clobber(obj, key, value) {\n    exports.replaceHookForTesting(obj, key);\n    var needsProperty = false;\n    try {\n        obj[key] = value;\n    } catch (e) {\n        needsProperty = true;\n    }\n    // Getters can only be overridden by getters.\n    if (needsProperty || obj[key] !== value) {\n        utils.defineGetter(obj, key, function() {\n            return value;\n        });\n    }\n}\n\nfunction assignOrWrapInDeprecateGetter(obj, key, value, message) {\n    if (message) {\n        utils.defineGetter(obj, key, function() {\n            console.log(message);\n            delete obj[key];\n            clobber(obj, key, value);\n            return value;\n        });\n    } else {\n        clobber(obj, key, value);\n    }\n}\n\nfunction include(parent, objects, clobber, merge) {\n    each(objects, function (obj, key) {\n        try {\n            var result = obj.path ? require(obj.path) : {};\n\n            if (clobber) {\n                // Clobber if it doesn't exist.\n                if (typeof parent[key] === 'undefined') {\n                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);\n                } else if (typeof obj.path !== 'undefined') {\n                    // If merging, merge properties onto parent, otherwise, clobber.\n                    if (merge) {\n                        recursiveMerge(parent[key], result);\n                    } else {\n                        assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);\n                    }\n                }\n                result = parent[key];\n            } else {\n                // Overwrite if not currently defined.\n                if (typeof parent[key] == 'undefined') {\n                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);\n                } else {\n                    // Set result to what already exists, so we can build children into it if they exist.\n                    result = parent[key];\n                }\n            }\n\n            if (obj.children) {\n                include(result, obj.children, clobber, merge);\n            }\n        } catch(e) {\n            utils.alert('Exception building Cordova JS globals: ' + e + ' for key \"' + key + '\"');\n        }\n    });\n}\n\n/**\n * Merge properties from one object onto another recursively.  Properties from\n * the src object will overwrite existing target property.\n *\n * @param target Object to merge properties into.\n * @param src Object to merge properties from.\n */\nfunction recursiveMerge(target, src) {\n    for (var prop in src) {\n        if (src.hasOwnProperty(prop)) {\n            if (target.prototype && target.prototype.constructor === target) {\n                // If the target object is a constructor override off prototype.\n                clobber(target.prototype, prop, src[prop]);\n            } else {\n                if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {\n                    recursiveMerge(target[prop], src[prop]);\n                } else {\n                    clobber(target, prop, src[prop]);\n                }\n            }\n        }\n    }\n}\n\nexports.buildIntoButDoNotClobber = function(objects, target) {\n    include(target, objects, false, false);\n};\nexports.buildIntoAndClobber = function(objects, target) {\n    include(target, objects, true, false);\n};\nexports.buildIntoAndMerge = function(objects, target) {\n    include(target, objects, true, true);\n};\nexports.recursiveMerge = recursiveMerge;\nexports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;\nexports.replaceHookForTesting = function() {};\n\n});\n\n// file: src/common/channel.js\ndefine(\"cordova/channel\", function(require, exports, module) {\n\nvar utils = require('cordova/utils'),\n    nextGuid = 1;\n\n/**\n * Custom pub-sub \"channel\" that can have functions subscribed to it\n * This object is used to define and control firing of events for\n * cordova initialization, as well as for custom events thereafter.\n *\n * The order of events during page load and Cordova startup is as follows:\n *\n * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.\n * onNativeReady*              Internal event that indicates the Cordova native side is ready.\n * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.\n * onDeviceReady*              User event fired to indicate that Cordova is ready\n * onResume                    User event fired to indicate a start/resume lifecycle event\n * onPause                     User event fired to indicate a pause lifecycle event\n *\n * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.\n * All listeners that subscribe after the event is fired will be executed right away.\n *\n * The only Cordova events that user code should register for are:\n *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript\n *      pause                 App has moved to background\n *      resume                App has returned to foreground\n *\n * Listeners can be registered as:\n *      document.addEventListener(\"deviceready\", myDeviceReadyListener, false);\n *      document.addEventListener(\"resume\", myResumeListener, false);\n *      document.addEventListener(\"pause\", myPauseListener, false);\n *\n * The DOM lifecycle events should be used for saving and restoring state\n *      window.onload\n *      window.onunload\n *\n */\n\n/**\n * Channel\n * @constructor\n * @param type  String the channel name\n */\nvar Channel = function(type, sticky) {\n    this.type = type;\n    // Map of guid -> function.\n    this.handlers = {};\n    // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.\n    this.state = sticky ? 1 : 0;\n    // Used in sticky mode to remember args passed to fire().\n    this.fireArgs = null;\n    // Used by onHasSubscribersChange to know if there are any listeners.\n    this.numHandlers = 0;\n    // Function that is called when the first listener is subscribed, or when\n    // the last listener is unsubscribed.\n    this.onHasSubscribersChange = null;\n},\n    channel = {\n        /**\n         * Calls the provided function only after all of the channels specified\n         * have been fired. All channels must be sticky channels.\n         */\n        join: function(h, c) {\n            var len = c.length,\n                i = len,\n                f = function() {\n                    if (!(--i)) h();\n                };\n            for (var j=0; j<len; j++) {\n                if (c[j].state === 0) {\n                    throw Error('Can only use join with sticky channels.');\n                }\n                c[j].subscribe(f);\n            }\n            if (!len) h();\n        },\n        create: function(type) {\n            return channel[type] = new Channel(type, false);\n        },\n        createSticky: function(type) {\n            return channel[type] = new Channel(type, true);\n        },\n\n        /**\n         * cordova Channels that must fire before \"deviceready\" is fired.\n         */\n        deviceReadyChannelsArray: [],\n        deviceReadyChannelsMap: {},\n\n        /**\n         * Indicate that a feature needs to be initialized before it is ready to be used.\n         * This holds up Cordova's \"deviceready\" event until the feature has been initialized\n         * and Cordova.initComplete(feature) is called.\n         *\n         * @param feature {String}     The unique feature name\n         */\n        waitForInitialization: function(feature) {\n            if (feature) {\n                var c = channel[feature] || this.createSticky(feature);\n                this.deviceReadyChannelsMap[feature] = c;\n                this.deviceReadyChannelsArray.push(c);\n            }\n        },\n\n        /**\n         * Indicate that initialization code has completed and the feature is ready to be used.\n         *\n         * @param feature {String}     The unique feature name\n         */\n        initializationComplete: function(feature) {\n            var c = this.deviceReadyChannelsMap[feature];\n            if (c) {\n                c.fire();\n            }\n        }\n    };\n\nfunction forceFunction(f) {\n    if (typeof f != 'function') throw \"Function required as first argument!\";\n}\n\n/**\n * Subscribes the given function to the channel. Any time that\n * Channel.fire is called so too will the function.\n * Optionally specify an execution context for the function\n * and a guid that can be used to stop subscribing to the channel.\n * Returns the guid.\n */\nChannel.prototype.subscribe = function(f, c) {\n    // need a function to call\n    forceFunction(f);\n    if (this.state == 2) {\n        f.apply(c || this, this.fireArgs);\n        return;\n    }\n\n    var func = f,\n        guid = f.observer_guid;\n    if (typeof c == \"object\") { func = utils.close(c, f); }\n\n    if (!guid) {\n        // first time any channel has seen this subscriber\n        guid = '' + nextGuid++;\n    }\n    func.observer_guid = guid;\n    f.observer_guid = guid;\n\n    // Don't add the same handler more than once.\n    if (!this.handlers[guid]) {\n        this.handlers[guid] = func;\n        this.numHandlers++;\n        if (this.numHandlers == 1) {\n            this.onHasSubscribersChange && this.onHasSubscribersChange();\n        }\n    }\n};\n\n/**\n * Unsubscribes the function with the given guid from the channel.\n */\nChannel.prototype.unsubscribe = function(f) {\n    // need a function to unsubscribe\n    forceFunction(f);\n\n    var guid = f.observer_guid,\n        handler = this.handlers[guid];\n    if (handler) {\n        delete this.handlers[guid];\n        this.numHandlers--;\n        if (this.numHandlers === 0) {\n            this.onHasSubscribersChange && this.onHasSubscribersChange();\n        }\n    }\n};\n\n/**\n * Calls all functions subscribed to this channel.\n */\nChannel.prototype.fire = function(e) {\n    var fail = false,\n        fireArgs = Array.prototype.slice.call(arguments);\n    // Apply stickiness.\n    if (this.state == 1) {\n        this.state = 2;\n        this.fireArgs = fireArgs;\n    }\n    if (this.numHandlers) {\n        // Copy the values first so that it is safe to modify it from within\n        // callbacks.\n        var toCall = [];\n        for (var item in this.handlers) {\n            toCall.push(this.handlers[item]);\n        }\n        for (var i = 0; i < toCall.length; ++i) {\n            toCall[i].apply(this, fireArgs);\n        }\n        if (this.state == 2 && this.numHandlers) {\n            this.numHandlers = 0;\n            this.handlers = {};\n            this.onHasSubscribersChange && this.onHasSubscribersChange();\n        }\n    }\n};\n\n\n// defining them here so they are ready super fast!\n// DOM event that is received when the web page is loaded and parsed.\nchannel.createSticky('onDOMContentLoaded');\n\n// Event to indicate the Cordova native side is ready.\nchannel.createSticky('onNativeReady');\n\n// Event to indicate that all Cordova JavaScript objects have been created\n// and it's time to run plugin constructors.\nchannel.createSticky('onCordovaReady');\n\n// Event to indicate that all automatically loaded JS plugins are loaded and ready.\n// FIXME remove this\nchannel.createSticky('onPluginsReady');\n\n// Event to indicate that Cordova is ready\nchannel.createSticky('onDeviceReady');\n\n// Event to indicate a resume lifecycle event\nchannel.create('onResume');\n\n// Event to indicate a pause lifecycle event\nchannel.create('onPause');\n\n// Channels that must fire before \"deviceready\" is fired.\nchannel.waitForInitialization('onCordovaReady');\nchannel.waitForInitialization('onDOMContentLoaded');\n\nmodule.exports = channel;\n\n});\n\n// file: e:/cordova/cordova-browser/cordova-js-src/confighelper.js\ndefine(\"cordova/confighelper\", function(require, exports, module) {\n\nvar config;\n\nfunction Config(xhr) {\n    function loadPreferences(xhr) {\n       var parser = new DOMParser();\n       var doc = parser.parseFromString(xhr.responseText, \"application/xml\");\n\n       var preferences = doc.getElementsByTagName(\"preference\");\n       return Array.prototype.slice.call(preferences);\n    }\n\n    this.xhr = xhr;\n    this.preferences = loadPreferences(this.xhr);\n}\n\nfunction readConfig(success, error) {\n    var xhr;\n\n    if(typeof config != 'undefined') {\n        success(config);\n    }\n\n    function fail(msg) {\n        console.error(msg);\n\n        if(error) {\n            error(msg);\n        }\n    }\n\n    var xhrStatusChangeHandler = function() {\n        if (xhr.readyState == 4) {\n            if (xhr.status == 200 || xhr.status == 304 || xhr.status === 0 /* file:// */) {\n                config = new Config(xhr);\n                success(config);\n            }\n            else {\n                fail('[Browser][cordova.js][xhrStatusChangeHandler] Could not XHR config.xml: ' + xhr.statusText);\n            }\n        }\n    };\n\n    if (\"ActiveXObject\" in window) {\n        // Needed for XHR-ing via file:// protocol in IE\n        xhr = new window.ActiveXObject(\"MSXML2.XMLHTTP\");\n        xhr.onreadystatechange = xhrStatusChangeHandler;\n    } else {\n        xhr = new XMLHttpRequest();\n        xhr.addEventListener(\"load\", xhrStatusChangeHandler);\n    }\n\n    try {\n        xhr.open(\"get\", \"/config.xml\", true);\n        xhr.send();\n    } catch(e) {\n        fail('[Browser][cordova.js][readConfig] Could not XHR config.xml: ' + JSON.stringify(e));\n    }\n}\n\n/**\n * Reads a preference value from config.xml.\n * Returns preference value or undefined if it does not exist.\n * @param {String} preferenceName Preference name to read */\nConfig.prototype.getPreferenceValue = function getPreferenceValue(preferenceName) {\n    var preferenceItem = this.preferences && this.preferences.filter(function(item) {\n        return item.attributes.name && item.attributes.name.value === preferenceName;\n    });\n\n    if(preferenceItem && preferenceItem[0] && preferenceItem[0].attributes && preferenceItem[0].attributes.value) {\n        return preferenceItem[0].attributes.value.value;\n    }\n};\n\nexports.readConfig = readConfig;\n\n});\n\n// file: e:/cordova/cordova-browser/cordova-js-src/exec.js\ndefine(\"cordova/exec\", function(require, exports, module) {\n\n/*jslint sloppy:true, plusplus:true*/\n/*global require, module, console */\n\nvar cordova = require('cordova');\nvar execProxy = require('cordova/exec/proxy');\n\n/**\n * Execute a cordova command.  It is up to the native side whether this action\n * is synchronous or asynchronous.  The native side can return:\n *      Synchronous: PluginResult object as a JSON string\n *      Asynchronous: Empty string \"\"\n * If async, the native side will cordova.callbackSuccess or cordova.callbackError,\n * depending upon the result of the action.\n *\n * @param {Function} success    The success callback\n * @param {Function} fail       The fail callback\n * @param {String} service      The name of the service to use\n * @param {String} action       Action to be run in cordova\n * @param {String[]} [args]     Zero or more arguments to pass to the method\n */\nmodule.exports = function (success, fail, service, action, args) {\n\n    var proxy = execProxy.get(service, action);\n\n    args = args || [];\n\n    if (proxy) {\n        \n        var callbackId = service + cordova.callbackId++;\n        \n        if (typeof success === \"function\" || typeof fail === \"function\") {\n            cordova.callbacks[callbackId] = {success: success, fail: fail};\n        }\n        try {\n\n            \n\n            // callbackOptions param represents additional optional parameters command could pass back, like keepCallback or\n            // custom callbackId, for example {callbackId: id, keepCallback: true, status: cordova.callbackStatus.JSON_EXCEPTION }\n            var onSuccess = function (result, callbackOptions) {\n                callbackOptions = callbackOptions || {};\n                var callbackStatus;\n                // covering both undefined and null.\n                // strict null comparison was causing callbackStatus to be undefined\n                // and then no callback was called because of the check in cordova.callbackFromNative\n                // see CB-8996 Mobilespec app hang on windows\n                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {\n                    callbackStatus = callbackOptions.status;\n                }\n                else {\n                    callbackStatus = cordova.callbackStatus.OK;\n                }\n                cordova.callbackSuccess(callbackOptions.callbackId || callbackId,\n                    {\n                        status: callbackStatus,\n                        message: result,\n                        keepCallback: callbackOptions.keepCallback || false\n                    });\n            };\n            var onError = function (err, callbackOptions) {\n                callbackOptions = callbackOptions || {};\n                var callbackStatus;\n                // covering both undefined and null.\n                // strict null comparison was causing callbackStatus to be undefined\n                // and then no callback was called because of the check in cordova.callbackFromNative\n                // note: status can be 0\n                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {\n                    callbackStatus = callbackOptions.status;\n                }\n                else {\n                    callbackStatus = cordova.callbackStatus.OK;\n                }\n                cordova.callbackError(callbackOptions.callbackId || callbackId,\n                {\n                    status: callbackStatus,\n                    message: err,\n                    keepCallback: callbackOptions.keepCallback || false\n                });\n            };\n            proxy(onSuccess, onError, args);\n\n        } catch (e) {\n            console.log(\"Exception calling native with command :: \" + service + \" :: \" + action  + \" ::exception=\" + e);\n        }\n    } else {\n\n        console.log(\"Error: exec proxy not found for :: \" + service + \" :: \" + action);\n        \n        if(typeof fail === \"function\" ) {\n            fail(\"Missing Command Error\");\n        }\n    }\n};\n\n});\n\n// file: src/common/exec/proxy.js\ndefine(\"cordova/exec/proxy\", function(require, exports, module) {\n\n\n// internal map of proxy function\nvar CommandProxyMap = {};\n\nmodule.exports = {\n\n    // example: cordova.commandProxy.add(\"Accelerometer\",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);\n    add:function(id,proxyObj) {\n        console.log(\"adding proxy for \" + id);\n        CommandProxyMap[id] = proxyObj;\n        return proxyObj;\n    },\n\n    // cordova.commandProxy.remove(\"Accelerometer\");\n    remove:function(id) {\n        var proxy = CommandProxyMap[id];\n        delete CommandProxyMap[id];\n        CommandProxyMap[id] = null;\n        return proxy;\n    },\n\n    get:function(service,action) {\n        return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );\n    }\n};\n});\n\n// file: src/common/init.js\ndefine(\"cordova/init\", function(require, exports, module) {\n\nvar channel = require('cordova/channel');\nvar cordova = require('cordova');\nvar modulemapper = require('cordova/modulemapper');\nvar platform = require('cordova/platform');\nvar pluginloader = require('cordova/pluginloader');\nvar utils = require('cordova/utils');\n\nvar platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];\n\nfunction logUnfiredChannels(arr) {\n    for (var i = 0; i < arr.length; ++i) {\n        if (arr[i].state != 2) {\n            console.log('Channel not fired: ' + arr[i].type);\n        }\n    }\n}\n\nwindow.setTimeout(function() {\n    if (channel.onDeviceReady.state != 2) {\n        console.log('deviceready has not fired after 5 seconds.');\n        logUnfiredChannels(platformInitChannelsArray);\n        logUnfiredChannels(channel.deviceReadyChannelsArray);\n    }\n}, 5000);\n\n// Replace navigator before any modules are required(), to ensure it happens as soon as possible.\n// We replace it so that properties that can't be clobbered can instead be overridden.\nfunction replaceNavigator(origNavigator) {\n    var CordovaNavigator = function() {};\n    CordovaNavigator.prototype = origNavigator;\n    var newNavigator = new CordovaNavigator();\n    // This work-around really only applies to new APIs that are newer than Function.bind.\n    // Without it, APIs such as getGamepads() break.\n    if (CordovaNavigator.bind) {\n        for (var key in origNavigator) {\n            if (typeof origNavigator[key] == 'function') {\n                newNavigator[key] = origNavigator[key].bind(origNavigator);\n            }\n            else {\n                (function(k) {\n                    utils.defineGetterSetter(newNavigator,key,function() {\n                        return origNavigator[k];\n                    });\n                })(key);\n            }\n        }\n    }\n    return newNavigator;\n}\n\nif (window.navigator) {\n    window.navigator = replaceNavigator(window.navigator);\n}\n\nif (!window.console) {\n    window.console = {\n        log: function(){}\n    };\n}\nif (!window.console.warn) {\n    window.console.warn = function(msg) {\n        this.log(\"warn: \" + msg);\n    };\n}\n\n// Register pause, resume and deviceready channels as events on document.\nchannel.onPause = cordova.addDocumentEventHandler('pause');\nchannel.onResume = cordova.addDocumentEventHandler('resume');\nchannel.onActivated = cordova.addDocumentEventHandler('activated');\nchannel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');\n\n// Listen for DOMContentLoaded and notify our channel subscribers.\nif (document.readyState == 'complete' || document.readyState == 'interactive') {\n    channel.onDOMContentLoaded.fire();\n} else {\n    document.addEventListener('DOMContentLoaded', function() {\n        channel.onDOMContentLoaded.fire();\n    }, false);\n}\n\n// _nativeReady is global variable that the native side can set\n// to signify that the native code is ready. It is a global since\n// it may be called before any cordova JS is ready.\nif (window._nativeReady) {\n    channel.onNativeReady.fire();\n}\n\nmodulemapper.clobbers('cordova', 'cordova');\nmodulemapper.clobbers('cordova/exec', 'cordova.exec');\nmodulemapper.clobbers('cordova/exec', 'Cordova.exec');\n\n// Call the platform-specific initialization.\nplatform.bootstrap && platform.bootstrap();\n\n// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js.\n// The delay allows the attached modules to be defined before the plugin loader looks for them.\nsetTimeout(function() {\n    pluginloader.load(function() {\n        channel.onPluginsReady.fire();\n    });\n}, 0);\n\n/**\n * Create all cordova objects once native side is ready.\n */\nchannel.join(function() {\n    modulemapper.mapModules(window);\n\n    platform.initialize && platform.initialize();\n\n    // Fire event to notify that all objects are created\n    channel.onCordovaReady.fire();\n\n    // Fire onDeviceReady event once page has fully loaded, all\n    // constructors have run and cordova info has been received from native\n    // side.\n    channel.join(function() {\n        require('cordova').fireDocumentEvent('deviceready');\n    }, channel.deviceReadyChannelsArray);\n\n}, platformInitChannelsArray);\n\n\n});\n\n// file: src/common/init_b.js\ndefine(\"cordova/init_b\", function(require, exports, module) {\n\nvar channel = require('cordova/channel');\nvar cordova = require('cordova');\nvar modulemapper = require('cordova/modulemapper');\nvar platform = require('cordova/platform');\nvar pluginloader = require('cordova/pluginloader');\nvar utils = require('cordova/utils');\n\nvar platformInitChannelsArray = [channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady];\n\n// setting exec\ncordova.exec = require('cordova/exec');\n\nfunction logUnfiredChannels(arr) {\n    for (var i = 0; i < arr.length; ++i) {\n        if (arr[i].state != 2) {\n            console.log('Channel not fired: ' + arr[i].type);\n        }\n    }\n}\n\nwindow.setTimeout(function() {\n    if (channel.onDeviceReady.state != 2) {\n        console.log('deviceready has not fired after 5 seconds.');\n        logUnfiredChannels(platformInitChannelsArray);\n        logUnfiredChannels(channel.deviceReadyChannelsArray);\n    }\n}, 5000);\n\n// Replace navigator before any modules are required(), to ensure it happens as soon as possible.\n// We replace it so that properties that can't be clobbered can instead be overridden.\nfunction replaceNavigator(origNavigator) {\n    var CordovaNavigator = function() {};\n    CordovaNavigator.prototype = origNavigator;\n    var newNavigator = new CordovaNavigator();\n    // This work-around really only applies to new APIs that are newer than Function.bind.\n    // Without it, APIs such as getGamepads() break.\n    if (CordovaNavigator.bind) {\n        for (var key in origNavigator) {\n            if (typeof origNavigator[key] == 'function') {\n                newNavigator[key] = origNavigator[key].bind(origNavigator);\n            }\n            else {\n                (function(k) {\n                    utils.defineGetterSetter(newNavigator,key,function() {\n                        return origNavigator[k];\n                    });\n                })(key);\n            }\n        }\n    }\n    return newNavigator;\n}\nif (window.navigator) {\n    window.navigator = replaceNavigator(window.navigator);\n}\n\nif (!window.console) {\n    window.console = {\n        log: function(){}\n    };\n}\nif (!window.console.warn) {\n    window.console.warn = function(msg) {\n        this.log(\"warn: \" + msg);\n    };\n}\n\n// Register pause, resume and deviceready channels as events on document.\nchannel.onPause = cordova.addDocumentEventHandler('pause');\nchannel.onResume = cordova.addDocumentEventHandler('resume');\nchannel.onActivated = cordova.addDocumentEventHandler('activated');\nchannel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');\n\n// Listen for DOMContentLoaded and notify our channel subscribers.\nif (document.readyState == 'complete' || document.readyState == 'interactive') {\n    channel.onDOMContentLoaded.fire();\n} else {\n    document.addEventListener('DOMContentLoaded', function() {\n        channel.onDOMContentLoaded.fire();\n    }, false);\n}\n\n// _nativeReady is global variable that the native side can set\n// to signify that the native code is ready. It is a global since\n// it may be called before any cordova JS is ready.\nif (window._nativeReady) {\n    channel.onNativeReady.fire();\n}\n\n// Call the platform-specific initialization.\nplatform.bootstrap && platform.bootstrap();\n\n// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js.\n// The delay allows the attached modules to be defined before the plugin loader looks for them.\nsetTimeout(function() {\n    pluginloader.load(function() {\n        channel.onPluginsReady.fire();\n    });\n}, 0);\n\n/**\n * Create all cordova objects once native side is ready.\n */\nchannel.join(function() {\n    modulemapper.mapModules(window);\n\n    platform.initialize && platform.initialize();\n\n    // Fire event to notify that all objects are created\n    channel.onCordovaReady.fire();\n\n    // Fire onDeviceReady event once page has fully loaded, all\n    // constructors have run and cordova info has been received from native\n    // side.\n    channel.join(function() {\n        require('cordova').fireDocumentEvent('deviceready');\n    }, channel.deviceReadyChannelsArray);\n\n}, platformInitChannelsArray);\n\n});\n\n// file: src/common/modulemapper.js\ndefine(\"cordova/modulemapper\", function(require, exports, module) {\n\nvar builder = require('cordova/builder'),\n    moduleMap = define.moduleMap,\n    symbolList,\n    deprecationMap;\n\nexports.reset = function() {\n    symbolList = [];\n    deprecationMap = {};\n};\n\nfunction addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {\n    if (!(moduleName in moduleMap)) {\n        throw new Error('Module ' + moduleName + ' does not exist.');\n    }\n    symbolList.push(strategy, moduleName, symbolPath);\n    if (opt_deprecationMessage) {\n        deprecationMap[symbolPath] = opt_deprecationMessage;\n    }\n}\n\n// Note: Android 2.3 does have Function.bind().\nexports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.runs = function(moduleName) {\n    addEntry('r', moduleName, null);\n};\n\nfunction prepareNamespace(symbolPath, context) {\n    if (!symbolPath) {\n        return context;\n    }\n    var parts = symbolPath.split('.');\n    var cur = context;\n    for (var i = 0, part; part = parts[i]; ++i) {\n        cur = cur[part] = cur[part] || {};\n    }\n    return cur;\n}\n\nexports.mapModules = function(context) {\n    var origSymbols = {};\n    context.CDV_origSymbols = origSymbols;\n    for (var i = 0, len = symbolList.length; i < len; i += 3) {\n        var strategy = symbolList[i];\n        var moduleName = symbolList[i + 1];\n        var module = require(moduleName);\n        // <runs/>\n        if (strategy == 'r') {\n            continue;\n        }\n        var symbolPath = symbolList[i + 2];\n        var lastDot = symbolPath.lastIndexOf('.');\n        var namespace = symbolPath.substr(0, lastDot);\n        var lastName = symbolPath.substr(lastDot + 1);\n\n        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;\n        var parentObj = prepareNamespace(namespace, context);\n        var target = parentObj[lastName];\n\n        if (strategy == 'm' && target) {\n            builder.recursiveMerge(target, module);\n        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {\n            if (!(symbolPath in origSymbols)) {\n                origSymbols[symbolPath] = target;\n            }\n            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);\n        }\n    }\n};\n\nexports.getOriginalSymbol = function(context, symbolPath) {\n    var origSymbols = context.CDV_origSymbols;\n    if (origSymbols && (symbolPath in origSymbols)) {\n        return origSymbols[symbolPath];\n    }\n    var parts = symbolPath.split('.');\n    var obj = context;\n    for (var i = 0; i < parts.length; ++i) {\n        obj = obj && obj[parts[i]];\n    }\n    return obj;\n};\n\nexports.reset();\n\n\n});\n\n// file: src/common/modulemapper_b.js\ndefine(\"cordova/modulemapper_b\", function(require, exports, module) {\n\nvar builder = require('cordova/builder'),\n    symbolList = [],\n    deprecationMap;\n\nexports.reset = function() {\n    symbolList = [];\n    deprecationMap = {};\n};\n\nfunction addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {\n    symbolList.push(strategy, moduleName, symbolPath);\n    if (opt_deprecationMessage) {\n        deprecationMap[symbolPath] = opt_deprecationMessage;\n    }\n}\n\n// Note: Android 2.3 does have Function.bind().\nexports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.runs = function(moduleName) {\n    addEntry('r', moduleName, null);\n};\n\nfunction prepareNamespace(symbolPath, context) {\n    if (!symbolPath) {\n        return context;\n    }\n    var parts = symbolPath.split('.');\n    var cur = context;\n    for (var i = 0, part; part = parts[i]; ++i) {\n        cur = cur[part] = cur[part] || {};\n    }\n    return cur;\n}\n\nexports.mapModules = function(context) {\n    var origSymbols = {};\n    context.CDV_origSymbols = origSymbols;\n    for (var i = 0, len = symbolList.length; i < len; i += 3) {\n        var strategy = symbolList[i];\n        var moduleName = symbolList[i + 1];\n        var module = require(moduleName);\n        // <runs/>\n        if (strategy == 'r') {\n            continue;\n        }\n        var symbolPath = symbolList[i + 2];\n        var lastDot = symbolPath.lastIndexOf('.');\n        var namespace = symbolPath.substr(0, lastDot);\n        var lastName = symbolPath.substr(lastDot + 1);\n\n        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;\n        var parentObj = prepareNamespace(namespace, context);\n        var target = parentObj[lastName];\n\n        if (strategy == 'm' && target) {\n            builder.recursiveMerge(target, module);\n        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {\n            if (!(symbolPath in origSymbols)) {\n                origSymbols[symbolPath] = target;\n            }\n            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);\n        }\n    }\n};\n\nexports.getOriginalSymbol = function(context, symbolPath) {\n    var origSymbols = context.CDV_origSymbols;\n    if (origSymbols && (symbolPath in origSymbols)) {\n        return origSymbols[symbolPath];\n    }\n    var parts = symbolPath.split('.');\n    var obj = context;\n    for (var i = 0; i < parts.length; ++i) {\n        obj = obj && obj[parts[i]];\n    }\n    return obj;\n};\n\nexports.reset();\n\n\n});\n\n// file: e:/cordova/cordova-browser/cordova-js-src/platform.js\ndefine(\"cordova/platform\", function(require, exports, module) {\n\nmodule.exports = {\n    id: 'browser',\n    cordovaVersion: '3.4.0',\n\n    bootstrap: function() {\n\n        var modulemapper = require('cordova/modulemapper');\n        var channel = require('cordova/channel');\n\n        modulemapper.clobbers('cordova/exec/proxy', 'cordova.commandProxy');\n\n        channel.onNativeReady.fire();\n\n        // FIXME is this the right place to clobber pause/resume? I am guessing not\n        // FIXME pause/resume should be deprecated IN CORDOVA for pagevisiblity api\n        document.addEventListener('webkitvisibilitychange', function() {\n            if (document.webkitHidden) {\n                channel.onPause.fire();\n            }\n            else {\n                channel.onResume.fire();\n            }\n        }, false);\n\n    // End of bootstrap\n    }\n};\n\n});\n\n// file: src/common/pluginloader.js\ndefine(\"cordova/pluginloader\", function(require, exports, module) {\n\nvar modulemapper = require('cordova/modulemapper');\nvar urlutil = require('cordova/urlutil');\n\n// Helper function to inject a <script> tag.\n// Exported for testing.\nexports.injectScript = function(url, onload, onerror) {\n    var script = document.createElement(\"script\");\n    // onload fires even when script fails loads with an error.\n    script.onload = onload;\n    // onerror fires for malformed URLs.\n    script.onerror = onerror;\n    script.src = url;\n    document.head.appendChild(script);\n};\n\nfunction injectIfNecessary(id, url, onload, onerror) {\n    onerror = onerror || onload;\n    if (id in define.moduleMap) {\n        onload();\n    } else {\n        exports.injectScript(url, function() {\n            if (id in define.moduleMap) {\n                onload();\n            } else {\n                onerror();\n            }\n        }, onerror);\n    }\n}\n\nfunction onScriptLoadingComplete(moduleList, finishPluginLoading) {\n    // Loop through all the plugins and then through their clobbers and merges.\n    for (var i = 0, module; module = moduleList[i]; i++) {\n        if (module.clobbers && module.clobbers.length) {\n            for (var j = 0; j < module.clobbers.length; j++) {\n                modulemapper.clobbers(module.id, module.clobbers[j]);\n            }\n        }\n\n        if (module.merges && module.merges.length) {\n            for (var k = 0; k < module.merges.length; k++) {\n                modulemapper.merges(module.id, module.merges[k]);\n            }\n        }\n\n        // Finally, if runs is truthy we want to simply require() the module.\n        if (module.runs) {\n            modulemapper.runs(module.id);\n        }\n    }\n\n    finishPluginLoading();\n}\n\n// Handler for the cordova_plugins.js content.\n// See plugman's plugin_loader.js for the details of this object.\n// This function is only called if the really is a plugins array that isn't empty.\n// Otherwise the onerror response handler will just call finishPluginLoading().\nfunction handlePluginsObject(path, moduleList, finishPluginLoading) {\n    // Now inject the scripts.\n    var scriptCounter = moduleList.length;\n\n    if (!scriptCounter) {\n        finishPluginLoading();\n        return;\n    }\n    function scriptLoadedCallback() {\n        if (!--scriptCounter) {\n            onScriptLoadingComplete(moduleList, finishPluginLoading);\n        }\n    }\n\n    for (var i = 0; i < moduleList.length; i++) {\n        injectIfNecessary(moduleList[i].id, path + moduleList[i].file, scriptLoadedCallback);\n    }\n}\n\nfunction findCordovaPath() {\n    var path = null;\n    var scripts = document.getElementsByTagName('script');\n    var term = '/cordova.js';\n    for (var n = scripts.length-1; n>-1; n--) {\n        var src = scripts[n].src.replace(/\\?.*$/, ''); // Strip any query param (CB-6007).\n        if (src.indexOf(term) == (src.length - term.length)) {\n            path = src.substring(0, src.length - term.length) + '/';\n            break;\n        }\n    }\n    return path;\n}\n\n// Tries to load all plugins' js-modules.\n// This is an async process, but onDeviceReady is blocked on onPluginsReady.\n// onPluginsReady is fired when there are no plugins to load, or they are all done.\nexports.load = function(callback) {\n    var pathPrefix = findCordovaPath();\n    if (pathPrefix === null) {\n        console.log('Could not find cordova.js script tag. Plugin loading may fail.');\n        pathPrefix = '';\n    }\n    injectIfNecessary('cordova/plugin_list', pathPrefix + 'cordova_plugins.js', function() {\n        var moduleList = require(\"cordova/plugin_list\");\n        handlePluginsObject(pathPrefix, moduleList, callback);\n    }, callback);\n};\n\n\n});\n\n// file: src/common/pluginloader_b.js\ndefine(\"cordova/pluginloader_b\", function(require, exports, module) {\n\nvar modulemapper = require('cordova/modulemapper');\n\n// Handler for the cordova_plugins.js content.\n// See plugman's plugin_loader.js for the details of this object.\nfunction handlePluginsObject(moduleList) {\n    // if moduleList is not defined or empty, we've nothing to do\n    if (!moduleList || !moduleList.length) {\n        return;\n    }\n\n    // Loop through all the modules and then through their clobbers and merges.\n    for (var i = 0, module; module = moduleList[i]; i++) {\n        if (module.clobbers && module.clobbers.length) {\n            for (var j = 0; j < module.clobbers.length; j++) {\n                modulemapper.clobbers(module.id, module.clobbers[j]);\n            }\n        }\n\n        if (module.merges && module.merges.length) {\n            for (var k = 0; k < module.merges.length; k++) {\n                modulemapper.merges(module.id, module.merges[k]);\n            }\n        }\n\n        // Finally, if runs is truthy we want to simply require() the module.\n        if (module.runs) {\n            modulemapper.runs(module.id);\n        }\n    }\n}\n\n// Loads all plugins' js-modules. Plugin loading is syncronous in browserified bundle\n// but the method accepts callback to be compatible with non-browserify flow.\n// onDeviceReady is blocked on onPluginsReady. onPluginsReady is fired when there are\n// no plugins to load, or they are all done.\nexports.load = function(callback) {\n    var moduleList = require(\"cordova/plugin_list\");\n    handlePluginsObject(moduleList);\n\n    callback();\n};\n\n\n});\n\n// file: src/common/urlutil.js\ndefine(\"cordova/urlutil\", function(require, exports, module) {\n\n\n/**\n * For already absolute URLs, returns what is passed in.\n * For relative URLs, converts them to absolute ones.\n */\nexports.makeAbsolute = function makeAbsolute(url) {\n    var anchorEl = document.createElement('a');\n    anchorEl.href = url;\n    return anchorEl.href;\n};\n\n\n});\n\n// file: src/common/utils.js\ndefine(\"cordova/utils\", function(require, exports, module) {\n\nvar utils = exports;\n\n/**\n * Defines a property getter / setter for obj[key].\n */\nutils.defineGetterSetter = function(obj, key, getFunc, opt_setFunc) {\n    if (Object.defineProperty) {\n        var desc = {\n            get: getFunc,\n            configurable: true\n        };\n        if (opt_setFunc) {\n            desc.set = opt_setFunc;\n        }\n        Object.defineProperty(obj, key, desc);\n    } else {\n        obj.__defineGetter__(key, getFunc);\n        if (opt_setFunc) {\n            obj.__defineSetter__(key, opt_setFunc);\n        }\n    }\n};\n\n/**\n * Defines a property getter for obj[key].\n */\nutils.defineGetter = utils.defineGetterSetter;\n\nutils.arrayIndexOf = function(a, item) {\n    if (a.indexOf) {\n        return a.indexOf(item);\n    }\n    var len = a.length;\n    for (var i = 0; i < len; ++i) {\n        if (a[i] == item) {\n            return i;\n        }\n    }\n    return -1;\n};\n\n/**\n * Returns whether the item was found in the array.\n */\nutils.arrayRemove = function(a, item) {\n    var index = utils.arrayIndexOf(a, item);\n    if (index != -1) {\n        a.splice(index, 1);\n    }\n    return index != -1;\n};\n\nutils.typeName = function(val) {\n    return Object.prototype.toString.call(val).slice(8, -1);\n};\n\n/**\n * Returns an indication of whether the argument is an array or not\n */\nutils.isArray = Array.isArray ||\n                function(a) {return utils.typeName(a) == 'Array';};\n\n/**\n * Returns an indication of whether the argument is a Date or not\n */\nutils.isDate = function(d) {\n    return (d instanceof Date);\n};\n\n/**\n * Does a deep clone of the object.\n */\nutils.clone = function(obj) {\n    if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') {\n        return obj;\n    }\n\n    var retVal, i;\n\n    if(utils.isArray(obj)){\n        retVal = [];\n        for(i = 0; i < obj.length; ++i){\n            retVal.push(utils.clone(obj[i]));\n        }\n        return retVal;\n    }\n\n    retVal = {};\n    for(i in obj){\n        if(!(i in retVal) || retVal[i] != obj[i]) {\n            retVal[i] = utils.clone(obj[i]);\n        }\n    }\n    return retVal;\n};\n\n/**\n * Returns a wrapped version of the function\n */\nutils.close = function(context, func, params) {\n    return function() {\n        var args = params || arguments;\n        return func.apply(context, args);\n    };\n};\n\n//------------------------------------------------------------------------------\nfunction UUIDcreatePart(length) {\n    var uuidpart = \"\";\n    for (var i=0; i<length; i++) {\n        var uuidchar = parseInt((Math.random() * 256), 10).toString(16);\n        if (uuidchar.length == 1) {\n            uuidchar = \"0\" + uuidchar;\n        }\n        uuidpart += uuidchar;\n    }\n    return uuidpart;\n}\n\n/**\n * Create a UUID\n */\nutils.createUUID = function() {\n    return UUIDcreatePart(4) + '-' +\n        UUIDcreatePart(2) + '-' +\n        UUIDcreatePart(2) + '-' +\n        UUIDcreatePart(2) + '-' +\n        UUIDcreatePart(6);\n};\n\n\n/**\n * Extends a child object from a parent object using classical inheritance\n * pattern.\n */\nutils.extend = (function() {\n    // proxy used to establish prototype chain\n    var F = function() {};\n    // extend Child from Parent\n    return function(Child, Parent) {\n\n        F.prototype = Parent.prototype;\n        Child.prototype = new F();\n        Child.__super__ = Parent.prototype;\n        Child.prototype.constructor = Child;\n    };\n}());\n\n/**\n * Alerts a message in any available way: alert or console.log.\n */\nutils.alert = function(msg) {\n    if (window.alert) {\n        window.alert(msg);\n    } else if (console && console.log) {\n        console.log(msg);\n    }\n};\n\n\n\n\n\n});\n\nwindow.cordova = require('cordova');\n// file: src/scripts/bootstrap.js\n\nrequire('cordova/init');\n\n})();"
  },
  {
    "path": "platforms/browser/platform_www/cordova_plugins.js",
    "content": "cordova.define('cordova/plugin_list', function(require, exports, module) {\nmodule.exports = [\n    {\n        \"file\": \"plugins/cordova-plugin-splashscreen/www/splashscreen.js\",\n        \"id\": \"cordova-plugin-splashscreen.SplashScreen\",\n        \"pluginId\": \"cordova-plugin-splashscreen\",\n        \"clobbers\": [\n            \"navigator.splashscreen\"\n        ]\n    },\n    {\n        \"file\": \"plugins/cordova-plugin-splashscreen/src/browser/SplashScreenProxy.js\",\n        \"id\": \"cordova-plugin-splashscreen.SplashScreenProxy\",\n        \"pluginId\": \"cordova-plugin-splashscreen\",\n        \"runs\": true\n    },\n    {\n        \"file\": \"plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js\",\n        \"id\": \"phonegap-plugin-barcodescanner.BarcodeScanner\",\n        \"pluginId\": \"phonegap-plugin-barcodescanner\",\n        \"clobbers\": [\n            \"cordova.plugins.barcodeScanner\"\n        ]\n    },\n    {\n        \"file\": \"plugins/phonegap-plugin-barcodescanner/src/browser/BarcodeScannerProxy.js\",\n        \"id\": \"phonegap-plugin-barcodescanner.BarcodeScannerProxy\",\n        \"pluginId\": \"phonegap-plugin-barcodescanner\",\n        \"runs\": true\n    }\n];\nmodule.exports.metadata = \n// TOP OF METADATA\n{\n    \"cordova-plugin-whitelist\": \"1.3.1\",\n    \"cordova-plugin-splashscreen\": \"4.0.1\",\n    \"phonegap-plugin-barcodescanner\": \"6.0.6\"\n}\n// BOTTOM OF METADATA\n});"
  },
  {
    "path": "platforms/browser/platform_www/exec.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n/*jslint sloppy:true, plusplus:true*/\n/*global require, module, console */\n\nvar cordova = require('cordova');\nvar execProxy = require('cordova/exec/proxy');\n\n/**\n * Execute a cordova command.  It is up to the native side whether this action\n * is synchronous or asynchronous.  The native side can return:\n *      Synchronous: PluginResult object as a JSON string\n *      Asynchronous: Empty string \"\"\n * If async, the native side will cordova.callbackSuccess or cordova.callbackError,\n * depending upon the result of the action.\n *\n * @param {Function} success    The success callback\n * @param {Function} fail       The fail callback\n * @param {String} service      The name of the service to use\n * @param {String} action       Action to be run in cordova\n * @param {String[]} [args]     Zero or more arguments to pass to the method\n */\nmodule.exports = function (success, fail, service, action, args) {\n\n    var proxy = execProxy.get(service, action);\n\n    args = args || [];\n\n    if (proxy) {\n        \n        var callbackId = service + cordova.callbackId++;\n        \n        if (typeof success === \"function\" || typeof fail === \"function\") {\n            cordova.callbacks[callbackId] = {success: success, fail: fail};\n        }\n        try {\n\n            \n\n            // callbackOptions param represents additional optional parameters command could pass back, like keepCallback or\n            // custom callbackId, for example {callbackId: id, keepCallback: true, status: cordova.callbackStatus.JSON_EXCEPTION }\n            var onSuccess = function (result, callbackOptions) {\n                callbackOptions = callbackOptions || {};\n                var callbackStatus;\n                // covering both undefined and null.\n                // strict null comparison was causing callbackStatus to be undefined\n                // and then no callback was called because of the check in cordova.callbackFromNative\n                // see CB-8996 Mobilespec app hang on windows\n                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {\n                    callbackStatus = callbackOptions.status;\n                }\n                else {\n                    callbackStatus = cordova.callbackStatus.OK;\n                }\n                cordova.callbackSuccess(callbackOptions.callbackId || callbackId,\n                    {\n                        status: callbackStatus,\n                        message: result,\n                        keepCallback: callbackOptions.keepCallback || false\n                    });\n            };\n            var onError = function (err, callbackOptions) {\n                callbackOptions = callbackOptions || {};\n                var callbackStatus;\n                // covering both undefined and null.\n                // strict null comparison was causing callbackStatus to be undefined\n                // and then no callback was called because of the check in cordova.callbackFromNative\n                // note: status can be 0\n                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {\n                    callbackStatus = callbackOptions.status;\n                }\n                else {\n                    callbackStatus = cordova.callbackStatus.OK;\n                }\n                cordova.callbackError(callbackOptions.callbackId || callbackId,\n                {\n                    status: callbackStatus,\n                    message: err,\n                    keepCallback: callbackOptions.keepCallback || false\n                });\n            };\n            proxy(onSuccess, onError, args);\n\n        } catch (e) {\n            console.log(\"Exception calling native with command :: \" + service + \" :: \" + action  + \" ::exception=\" + e);\n        }\n    } else {\n\n        console.log(\"Error: exec proxy not found for :: \" + service + \" :: \" + action);\n        \n        if(typeof fail === \"function\" ) {\n            fail(\"Missing Command Error\");\n        }\n    }\n};\n"
  },
  {
    "path": "platforms/browser/platform_www/platform.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nmodule.exports = {\n    id: 'browser',\n    cordovaVersion: '3.4.0',\n\n    bootstrap: function() {\n\n        var modulemapper = require('cordova/modulemapper');\n        var channel = require('cordova/channel');\n\n        modulemapper.clobbers('cordova/exec/proxy', 'cordova.commandProxy');\n\n        channel.onNativeReady.fire();\n\n        // FIXME is this the right place to clobber pause/resume? I am guessing not\n        // FIXME pause/resume should be deprecated IN CORDOVA for pagevisiblity api\n        document.addEventListener('webkitvisibilitychange', function() {\n            if (document.webkitHidden) {\n                channel.onPause.fire();\n            }\n            else {\n                channel.onResume.fire();\n            }\n        }, false);\n\n    // End of bootstrap\n    }\n};\n"
  },
  {
    "path": "platforms/browser/platform_www/plugins/cordova-plugin-splashscreen/src/browser/SplashScreenProxy.js",
    "content": "cordova.define(\"cordova-plugin-splashscreen.SplashScreenProxy\", function(require, exports, module) { /*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n// Default parameter values including image size can be changed in `config.xml`\nvar splashImageWidth = 170;\nvar splashImageHeight = 200;\nvar position = { x: 0, y: 0, width: splashImageWidth, height: splashImageHeight }; \nvar localSplash; // the image to display\nvar localSplashImage;\nvar bgColor = \"#464646\";\nvar imageSrc = '/img/logo.png';\nvar splashScreenDelay = 3000; // in milliseconds\nvar showSplashScreen = true; // show splashcreen by default\nvar cordova = require('cordova');\nvar configHelper = cordova.require('cordova/confighelper');\n\nfunction updateImageLocation() {\n    position.width = Math.min(splashImageWidth, window.innerWidth);\n    position.height = position.width * (splashImageHeight / splashImageWidth);\n\n    localSplash.style.width = window.innerWidth + \"px\";\n    localSplash.style.height = window.innerHeight + \"px\";\n    localSplash.style.top = \"0px\";\n    localSplash.style.left = \"0px\";\n\n    localSplashImage.style.top = \"50%\";\n    localSplashImage.style.left = \"50%\";\n    localSplashImage.style.height = position.height + \"px\";\n    localSplashImage.style.width = position.width + \"px\";\n    localSplashImage.style.marginTop = (-position.height / 2) + \"px\";\n    localSplashImage.style.marginLeft = (-position.width / 2) + \"px\";\n}\n\nfunction onResize() {\n    updateImageLocation();\n}\n\nvar SplashScreen = {\n    setBGColor: function (cssBGColor) {\n        bgColor = cssBGColor;\n        if (localSplash) {\n            localSplash.style.backgroundColor = bgColor;\n        }\n    },\n    show: function () {\n        if(!localSplash) {\n            window.addEventListener(\"resize\", onResize, false);\n            localSplash = document.createElement(\"div\");\n            localSplash.style.backgroundColor = bgColor;\n            localSplash.style.position = \"absolute\";\n\n            localSplashImage = document.createElement(\"img\");\n            localSplashImage.src = imageSrc;\n            localSplashImage.style.position = \"absolute\";\n\n            updateImageLocation();\n\n            localSplash.appendChild(localSplashImage);\n            document.body.appendChild(localSplash);\n        }\n    },\n    hide: function () {\n        if(localSplash) {\n            window.removeEventListener(\"resize\", onResize, false);\n            document.body.removeChild(localSplash);\n            localSplash = null;\n        }\n    }\n};\n\n/**\n * Reads preferences via ConfigHelper and substitutes default parameters.\n */\nfunction readPreferencesFromCfg(cfg) {\n    try {\n        var value = cfg.getPreferenceValue('ShowSplashScreen');\n        if(typeof value != 'undefined') {\n            showSplashScreen = value === 'true';\n        }\n\n        splashScreenDelay = cfg.getPreferenceValue('SplashScreenDelay') || splashScreenDelay;\n        imageSrc = cfg.getPreferenceValue('SplashScreen') || imageSrc;\n        bgColor = cfg.getPreferenceValue('SplashScreenBackgroundColor') || bgColor;\n        splashImageWidth = cfg.getPreferenceValue('SplashScreenWidth') || splashImageWidth;\n        splashImageHeight = cfg.getPreferenceValue('SplashScreenHeight') || splashImageHeight;\n    } catch(e) {\n        var msg = '[Browser][SplashScreen] Error occured on loading preferences from config.xml: ' + JSON.stringify(e);\n        console.error(msg);\n    }\n}\n\n/**\n * Shows and hides splashscreen if it is enabled, with a delay according the current preferences.\n */\nfunction showAndHide() {\n    if(showSplashScreen) {\n        SplashScreen.show();\n\n        window.setTimeout(function() {\n            SplashScreen.hide();\n        }, splashScreenDelay);\n    }\n}\n\n/**\n * Tries to read config.xml and override default properties and then shows and hides splashcreen if it is enabled.\n */\n(function initAndShow() {\n    configHelper.readConfig(function(config) {\n        readPreferencesFromCfg(config);\n        showAndHide();\n    }, function(err) {\n        console.error(err);\n    });\n})();\n\nmodule.exports = SplashScreen;\n\nrequire(\"cordova/exec/proxy\").add(\"SplashScreen\", SplashScreen);\n\n\n});\n"
  },
  {
    "path": "platforms/browser/platform_www/plugins/cordova-plugin-splashscreen/www/splashscreen.js",
    "content": "cordova.define(\"cordova-plugin-splashscreen.SplashScreen\", function(require, exports, module) { /*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nvar exec = require('cordova/exec');\n\nvar splashscreen = {\n    show:function() {\n        exec(null, null, \"SplashScreen\", \"show\", []);\n    },\n    hide:function() {\n        exec(null, null, \"SplashScreen\", \"hide\", []);\n    }\n};\n\nmodule.exports = splashscreen;\n\n});\n"
  },
  {
    "path": "platforms/browser/platform_www/plugins/phonegap-plugin-barcodescanner/src/browser/BarcodeScannerProxy.js",
    "content": "cordova.define(\"phonegap-plugin-barcodescanner.BarcodeScannerProxy\", function(require, exports, module) { function scan(success, error) {\n    var code = window.prompt(\"Enter barcode value (empty value will fire the error handler):\");\n    if(code) {\n        var result = {\n            text:code,\n            format:\"Fake\",\n            cancelled:false\n        };\n        success(result);\n    } else {\n        error(\"No barcode\");\n    }\n}\n\nfunction encode(type, data, success, errorCallback) {\n    success();\n}\n\nmodule.exports = {\n    scan: scan,\n    encode: encode\n};\n\nrequire(\"cordova/exec/proxy\").add(\"BarcodeScanner\",module.exports);\n});\n"
  },
  {
    "path": "platforms/browser/platform_www/plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js",
    "content": "cordova.define(\"phonegap-plugin-barcodescanner.BarcodeScanner\", function(require, exports, module) { /**\n * cordova is available under *either* the terms of the modified BSD license *or* the\n * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.\n *\n * Copyright (c) Matt Kane 2010\n * Copyright (c) 2011, IBM Corporation\n */\n\n\n        var exec = cordova.require(\"cordova/exec\");\n\n        var scanInProgress = false;\n\n        /**\n         * Constructor.\n         *\n         * @returns {BarcodeScanner}\n         */\n        function BarcodeScanner() {\n\n            /**\n             * Encoding constants.\n             *\n             * @type Object\n             */\n            this.Encode = {\n                TEXT_TYPE: \"TEXT_TYPE\",\n                EMAIL_TYPE: \"EMAIL_TYPE\",\n                PHONE_TYPE: \"PHONE_TYPE\",\n                SMS_TYPE: \"SMS_TYPE\"\n                //  CONTACT_TYPE: \"CONTACT_TYPE\",  // TODO:  not implemented, requires passing a Bundle class from Javascript to Java\n                //  LOCATION_TYPE: \"LOCATION_TYPE\" // TODO:  not implemented, requires passing a Bundle class from Javascript to Java\n            };\n\n    /**\n     * Barcode format constants, defined in ZXing library.\n     *\n     * @type Object\n     */\n    this.format = {\n        \"all_1D\": 61918,\n        \"aztec\": 1,\n        \"codabar\": 2,\n        \"code_128\": 16,\n        \"code_39\": 4,\n        \"code_93\": 8,\n        \"data_MATRIX\": 32,\n        \"ean_13\": 128,\n        \"ean_8\": 64,\n        \"itf\": 256,\n        \"maxicode\": 512,\n        \"msi\": 131072,\n        \"pdf_417\": 1024,\n        \"plessey\": 262144,\n        \"qr_CODE\": 2048,\n        \"rss_14\": 4096,\n        \"rss_EXPANDED\": 8192,\n        \"upc_A\": 16384,\n        \"upc_E\": 32768,\n        \"upc_EAN_EXTENSION\": 65536\n        };\n  }\n\n/**\n * Read code from scanner.\n *\n * @param {Function} successCallback This function will recieve a result object: {\n         *        text : '12345-mock',    // The code that was scanned.\n         *        format : 'FORMAT_NAME', // Code format.\n         *        cancelled : true/false, // Was canceled.\n         *    }\n * @param {Function} errorCallback\n * @param config\n */\nBarcodeScanner.prototype.scan = function (successCallback, errorCallback, config) {\n\n            if (config instanceof Array) {\n                // do nothing\n            } else {\n                if (typeof(config) === 'object') {\n                    config = [ config ];\n                } else {\n                    config = [];\n                }\n            }\n\n            if (errorCallback == null) {\n                errorCallback = function () {\n                };\n            }\n\n            if (typeof errorCallback != \"function\") {\n                console.log(\"BarcodeScanner.scan failure: failure parameter not a function\");\n                return;\n            }\n\n            if (typeof successCallback != \"function\") {\n                console.log(\"BarcodeScanner.scan failure: success callback parameter must be a function\");\n                return;\n            }\n\n            if (scanInProgress) {\n                errorCallback('Scan is already in progress');\n                return;\n            }\n\n            scanInProgress = true;\n\n            exec(\n                function(result) {\n                    scanInProgress = false;\n                    successCallback(result);\n                },\n                function(error) {\n                    scanInProgress = false;\n                    errorCallback(error);\n                },\n                'BarcodeScanner',\n                'scan',\n                config\n            );\n        };\n\n        //-------------------------------------------------------------------\n        BarcodeScanner.prototype.encode = function (type, data, successCallback, errorCallback, options) {\n            if (errorCallback == null) {\n                errorCallback = function () {\n                };\n            }\n\n            if (typeof errorCallback != \"function\") {\n                console.log(\"BarcodeScanner.encode failure: failure parameter not a function\");\n                return;\n            }\n\n            if (typeof successCallback != \"function\") {\n                console.log(\"BarcodeScanner.encode failure: success callback parameter must be a function\");\n                return;\n            }\n\n            exec(successCallback, errorCallback, 'BarcodeScanner', 'encode', [\n                {\"type\": type, \"data\": data, \"options\": options}\n            ]);\n        };\n\n        var barcodeScanner = new BarcodeScanner();\n        module.exports = barcodeScanner;\n\n});\n"
  },
  {
    "path": "platforms/browser/www/config.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<widget id=\"friimaind.piholedroid\" version=\"1.0.4\" xmlns=\"http://www.w3.org/ns/widgets\" xmlns:cdv=\"http://cordova.apache.org/ns/1.0\">\n    <feature name=\"BarcodeScanner\">\n        <param name=\"browser-package\" value=\"BarcodeScanner\" />\n    </feature>\n    <name>Pi-hole Droid</name>\n    <description>\n        Monitor your Pi-hole with your Android smartphone\n    </description>\n    <author email=\"massimiliano.monaro@gmail.com\" href=\"https://blog.friimaind.it\">\n        Massimiliano Monaro\n    </author>\n    <content src=\"index.html\" />\n    <access origin=\"*\" />\n    <allow-intent href=\"http://*/*\" />\n    <allow-intent href=\"https://*/*\" />\n    <allow-intent href=\"tel:*\" />\n    <allow-intent href=\"sms:*\" />\n    <allow-intent href=\"mailto:*\" />\n    <allow-intent href=\"geo:*\" />\n    <preference name=\"Fullscreen\" value=\"false\" />\n    <preference name=\"SplashScreenDelay\" value=\"2000\" />\n    <preference name=\"SplashScreen\" value=\"screen\" />\n    <preference name=\"SplashMaintainAspectRatio\" value=\"true\" />\n    <preference name=\"ShowSplashScreenSpinner\" value=\"false\" />\n</widget>\n"
  },
  {
    "path": "platforms/browser/www/confighelper.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nvar config;\n\nfunction Config(xhr) {\n    function loadPreferences(xhr) {\n       var parser = new DOMParser();\n       var doc = parser.parseFromString(xhr.responseText, \"application/xml\");\n\n       var preferences = doc.getElementsByTagName(\"preference\");\n       return Array.prototype.slice.call(preferences);\n    }\n\n    this.xhr = xhr;\n    this.preferences = loadPreferences(this.xhr);\n}\n\nfunction readConfig(success, error) {\n    var xhr;\n\n    if(typeof config != 'undefined') {\n        success(config);\n    }\n\n    function fail(msg) {\n        console.error(msg);\n\n        if(error) {\n            error(msg);\n        }\n    }\n\n    var xhrStatusChangeHandler = function() {\n        if (xhr.readyState == 4) {\n            if (xhr.status == 200 || xhr.status == 304 || xhr.status === 0 /* file:// */) {\n                config = new Config(xhr);\n                success(config);\n            }\n            else {\n                fail('[Browser][cordova.js][xhrStatusChangeHandler] Could not XHR config.xml: ' + xhr.statusText);\n            }\n        }\n    };\n\n    if (\"ActiveXObject\" in window) {\n        // Needed for XHR-ing via file:// protocol in IE\n        xhr = new window.ActiveXObject(\"MSXML2.XMLHTTP\");\n        xhr.onreadystatechange = xhrStatusChangeHandler;\n    } else {\n        xhr = new XMLHttpRequest();\n        xhr.addEventListener(\"load\", xhrStatusChangeHandler);\n    }\n\n    try {\n        xhr.open(\"get\", \"/config.xml\", true);\n        xhr.send();\n    } catch(e) {\n        fail('[Browser][cordova.js][readConfig] Could not XHR config.xml: ' + JSON.stringify(e));\n    }\n}\n\n/**\n * Reads a preference value from config.xml.\n * Returns preference value or undefined if it does not exist.\n * @param {String} preferenceName Preference name to read */\nConfig.prototype.getPreferenceValue = function getPreferenceValue(preferenceName) {\n    var preferenceItem = this.preferences && this.preferences.filter(function(item) {\n        return item.attributes.name && item.attributes.name.value === preferenceName;\n    });\n\n    if(preferenceItem && preferenceItem[0] && preferenceItem[0].attributes && preferenceItem[0].attributes.value) {\n        return preferenceItem[0].attributes.value.value;\n    }\n};\n\nexports.readConfig = readConfig;\n"
  },
  {
    "path": "platforms/browser/www/cordova-js-src/confighelper.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nvar config;\n\nfunction Config(xhr) {\n    function loadPreferences(xhr) {\n       var parser = new DOMParser();\n       var doc = parser.parseFromString(xhr.responseText, \"application/xml\");\n\n       var preferences = doc.getElementsByTagName(\"preference\");\n       return Array.prototype.slice.call(preferences);\n    }\n\n    this.xhr = xhr;\n    this.preferences = loadPreferences(this.xhr);\n}\n\nfunction readConfig(success, error) {\n    var xhr;\n\n    if(typeof config != 'undefined') {\n        success(config);\n    }\n\n    function fail(msg) {\n        console.error(msg);\n\n        if(error) {\n            error(msg);\n        }\n    }\n\n    var xhrStatusChangeHandler = function() {\n        if (xhr.readyState == 4) {\n            if (xhr.status == 200 || xhr.status == 304 || xhr.status === 0 /* file:// */) {\n                config = new Config(xhr);\n                success(config);\n            }\n            else {\n                fail('[Browser][cordova.js][xhrStatusChangeHandler] Could not XHR config.xml: ' + xhr.statusText);\n            }\n        }\n    };\n\n    if (\"ActiveXObject\" in window) {\n        // Needed for XHR-ing via file:// protocol in IE\n        xhr = new window.ActiveXObject(\"MSXML2.XMLHTTP\");\n        xhr.onreadystatechange = xhrStatusChangeHandler;\n    } else {\n        xhr = new XMLHttpRequest();\n        xhr.addEventListener(\"load\", xhrStatusChangeHandler);\n    }\n\n    try {\n        xhr.open(\"get\", \"/config.xml\", true);\n        xhr.send();\n    } catch(e) {\n        fail('[Browser][cordova.js][readConfig] Could not XHR config.xml: ' + JSON.stringify(e));\n    }\n}\n\n/**\n * Reads a preference value from config.xml.\n * Returns preference value or undefined if it does not exist.\n * @param {String} preferenceName Preference name to read */\nConfig.prototype.getPreferenceValue = function getPreferenceValue(preferenceName) {\n    var preferenceItem = this.preferences && this.preferences.filter(function(item) {\n        return item.attributes.name && item.attributes.name.value === preferenceName;\n    });\n\n    if(preferenceItem && preferenceItem[0] && preferenceItem[0].attributes && preferenceItem[0].attributes.value) {\n        return preferenceItem[0].attributes.value.value;\n    }\n};\n\nexports.readConfig = readConfig;\n"
  },
  {
    "path": "platforms/browser/www/cordova-js-src/exec.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n/*jslint sloppy:true, plusplus:true*/\n/*global require, module, console */\n\nvar cordova = require('cordova');\nvar execProxy = require('cordova/exec/proxy');\n\n/**\n * Execute a cordova command.  It is up to the native side whether this action\n * is synchronous or asynchronous.  The native side can return:\n *      Synchronous: PluginResult object as a JSON string\n *      Asynchronous: Empty string \"\"\n * If async, the native side will cordova.callbackSuccess or cordova.callbackError,\n * depending upon the result of the action.\n *\n * @param {Function} success    The success callback\n * @param {Function} fail       The fail callback\n * @param {String} service      The name of the service to use\n * @param {String} action       Action to be run in cordova\n * @param {String[]} [args]     Zero or more arguments to pass to the method\n */\nmodule.exports = function (success, fail, service, action, args) {\n\n    var proxy = execProxy.get(service, action);\n\n    args = args || [];\n\n    if (proxy) {\n        \n        var callbackId = service + cordova.callbackId++;\n        \n        if (typeof success === \"function\" || typeof fail === \"function\") {\n            cordova.callbacks[callbackId] = {success: success, fail: fail};\n        }\n        try {\n\n            \n\n            // callbackOptions param represents additional optional parameters command could pass back, like keepCallback or\n            // custom callbackId, for example {callbackId: id, keepCallback: true, status: cordova.callbackStatus.JSON_EXCEPTION }\n            var onSuccess = function (result, callbackOptions) {\n                callbackOptions = callbackOptions || {};\n                var callbackStatus;\n                // covering both undefined and null.\n                // strict null comparison was causing callbackStatus to be undefined\n                // and then no callback was called because of the check in cordova.callbackFromNative\n                // see CB-8996 Mobilespec app hang on windows\n                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {\n                    callbackStatus = callbackOptions.status;\n                }\n                else {\n                    callbackStatus = cordova.callbackStatus.OK;\n                }\n                cordova.callbackSuccess(callbackOptions.callbackId || callbackId,\n                    {\n                        status: callbackStatus,\n                        message: result,\n                        keepCallback: callbackOptions.keepCallback || false\n                    });\n            };\n            var onError = function (err, callbackOptions) {\n                callbackOptions = callbackOptions || {};\n                var callbackStatus;\n                // covering both undefined and null.\n                // strict null comparison was causing callbackStatus to be undefined\n                // and then no callback was called because of the check in cordova.callbackFromNative\n                // note: status can be 0\n                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {\n                    callbackStatus = callbackOptions.status;\n                }\n                else {\n                    callbackStatus = cordova.callbackStatus.OK;\n                }\n                cordova.callbackError(callbackOptions.callbackId || callbackId,\n                {\n                    status: callbackStatus,\n                    message: err,\n                    keepCallback: callbackOptions.keepCallback || false\n                });\n            };\n            proxy(onSuccess, onError, args);\n\n        } catch (e) {\n            console.log(\"Exception calling native with command :: \" + service + \" :: \" + action  + \" ::exception=\" + e);\n        }\n    } else {\n\n        console.log(\"Error: exec proxy not found for :: \" + service + \" :: \" + action);\n        \n        if(typeof fail === \"function\" ) {\n            fail(\"Missing Command Error\");\n        }\n    }\n};\n"
  },
  {
    "path": "platforms/browser/www/cordova-js-src/platform.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nmodule.exports = {\n    id: 'browser',\n    cordovaVersion: '3.4.0',\n\n    bootstrap: function() {\n\n        var modulemapper = require('cordova/modulemapper');\n        var channel = require('cordova/channel');\n\n        modulemapper.clobbers('cordova/exec/proxy', 'cordova.commandProxy');\n\n        channel.onNativeReady.fire();\n\n        // FIXME is this the right place to clobber pause/resume? I am guessing not\n        // FIXME pause/resume should be deprecated IN CORDOVA for pagevisiblity api\n        document.addEventListener('webkitvisibilitychange', function() {\n            if (document.webkitHidden) {\n                channel.onPause.fire();\n            }\n            else {\n                channel.onResume.fire();\n            }\n        }, false);\n\n    // End of bootstrap\n    }\n};\n"
  },
  {
    "path": "platforms/browser/www/cordova.js",
    "content": "// Platform: browser\n// c517ca811b4948b630e0b74dbae6c9637939da24\n/*\n Licensed to the Apache Software Foundation (ASF) under one\n or more contributor license agreements.  See the NOTICE file\n distributed with this work for additional information\n regarding copyright ownership.  The ASF licenses this file\n to you under the Apache License, Version 2.0 (the\n \"License\"); you may not use this file except in compliance\n with the License.  You may obtain a copy of the License at\n \n     http://www.apache.org/licenses/LICENSE-2.0\n \n Unless required by applicable law or agreed to in writing,\n software distributed under the License is distributed on an\n \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n KIND, either express or implied.  See the License for the\n specific language governing permissions and limitations\n under the License.\n*/\n;(function() {\nvar PLATFORM_VERSION_BUILD_LABEL = '4.1.0';\n// file: src/scripts/require.js\n\n/*jshint -W079 */\n/*jshint -W020 */\n\nvar require,\n    define;\n\n(function () {\n    var modules = {},\n    // Stack of moduleIds currently being built.\n        requireStack = [],\n    // Map of module ID -> index into requireStack of modules currently being built.\n        inProgressModules = {},\n        SEPARATOR = \".\";\n\n\n\n    function build(module) {\n        var factory = module.factory,\n            localRequire = function (id) {\n                var resultantId = id;\n                //Its a relative path, so lop off the last portion and add the id (minus \"./\")\n                if (id.charAt(0) === \".\") {\n                    resultantId = module.id.slice(0, module.id.lastIndexOf(SEPARATOR)) + SEPARATOR + id.slice(2);\n                }\n                return require(resultantId);\n            };\n        module.exports = {};\n        delete module.factory;\n        factory(localRequire, module.exports, module);\n        return module.exports;\n    }\n\n    require = function (id) {\n        if (!modules[id]) {\n            throw \"module \" + id + \" not found\";\n        } else if (id in inProgressModules) {\n            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;\n            throw \"Cycle in require graph: \" + cycle;\n        }\n        if (modules[id].factory) {\n            try {\n                inProgressModules[id] = requireStack.length;\n                requireStack.push(id);\n                return build(modules[id]);\n            } finally {\n                delete inProgressModules[id];\n                requireStack.pop();\n            }\n        }\n        return modules[id].exports;\n    };\n\n    define = function (id, factory) {\n        if (modules[id]) {\n            throw \"module \" + id + \" already defined\";\n        }\n\n        modules[id] = {\n            id: id,\n            factory: factory\n        };\n    };\n\n    define.remove = function (id) {\n        delete modules[id];\n    };\n\n    define.moduleMap = modules;\n})();\n\n//Export for use in node\nif (typeof module === \"object\" && typeof require === \"function\") {\n    module.exports.require = require;\n    module.exports.define = define;\n}\n\n// file: src/cordova.js\ndefine(\"cordova\", function(require, exports, module) {\n\n// Workaround for Windows 10 in hosted environment case\n// http://www.w3.org/html/wg/drafts/html/master/browsers.html#named-access-on-the-window-object\nif (window.cordova && !(window.cordova instanceof HTMLElement)) {\n    throw new Error(\"cordova already defined\");\n}\n\n\nvar channel = require('cordova/channel');\nvar platform = require('cordova/platform');\n\n\n/**\n * Intercept calls to addEventListener + removeEventListener and handle deviceready,\n * resume, and pause events.\n */\nvar m_document_addEventListener = document.addEventListener;\nvar m_document_removeEventListener = document.removeEventListener;\nvar m_window_addEventListener = window.addEventListener;\nvar m_window_removeEventListener = window.removeEventListener;\n\n/**\n * Houses custom event handlers to intercept on document + window event listeners.\n */\nvar documentEventHandlers = {},\n    windowEventHandlers = {};\n\ndocument.addEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    if (typeof documentEventHandlers[e] != 'undefined') {\n        documentEventHandlers[e].subscribe(handler);\n    } else {\n        m_document_addEventListener.call(document, evt, handler, capture);\n    }\n};\n\nwindow.addEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    if (typeof windowEventHandlers[e] != 'undefined') {\n        windowEventHandlers[e].subscribe(handler);\n    } else {\n        m_window_addEventListener.call(window, evt, handler, capture);\n    }\n};\n\ndocument.removeEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    // If unsubscribing from an event that is handled by a plugin\n    if (typeof documentEventHandlers[e] != \"undefined\") {\n        documentEventHandlers[e].unsubscribe(handler);\n    } else {\n        m_document_removeEventListener.call(document, evt, handler, capture);\n    }\n};\n\nwindow.removeEventListener = function(evt, handler, capture) {\n    var e = evt.toLowerCase();\n    // If unsubscribing from an event that is handled by a plugin\n    if (typeof windowEventHandlers[e] != \"undefined\") {\n        windowEventHandlers[e].unsubscribe(handler);\n    } else {\n        m_window_removeEventListener.call(window, evt, handler, capture);\n    }\n};\n\nfunction createEvent(type, data) {\n    var event = document.createEvent('Events');\n    event.initEvent(type, false, false);\n    if (data) {\n        for (var i in data) {\n            if (data.hasOwnProperty(i)) {\n                event[i] = data[i];\n            }\n        }\n    }\n    return event;\n}\n\n\nvar cordova = {\n    define:define,\n    require:require,\n    version:PLATFORM_VERSION_BUILD_LABEL,\n    platformVersion:PLATFORM_VERSION_BUILD_LABEL,\n    platformId:platform.id,\n    /**\n     * Methods to add/remove your own addEventListener hijacking on document + window.\n     */\n    addWindowEventHandler:function(event) {\n        return (windowEventHandlers[event] = channel.create(event));\n    },\n    addStickyDocumentEventHandler:function(event) {\n        return (documentEventHandlers[event] = channel.createSticky(event));\n    },\n    addDocumentEventHandler:function(event) {\n        return (documentEventHandlers[event] = channel.create(event));\n    },\n    removeWindowEventHandler:function(event) {\n        delete windowEventHandlers[event];\n    },\n    removeDocumentEventHandler:function(event) {\n        delete documentEventHandlers[event];\n    },\n    /**\n     * Retrieve original event handlers that were replaced by Cordova\n     *\n     * @return object\n     */\n    getOriginalHandlers: function() {\n        return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},\n        'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};\n    },\n    /**\n     * Method to fire event from native code\n     * bNoDetach is required for events which cause an exception which needs to be caught in native code\n     */\n    fireDocumentEvent: function(type, data, bNoDetach) {\n        var evt = createEvent(type, data);\n        if (typeof documentEventHandlers[type] != 'undefined') {\n            if( bNoDetach ) {\n                documentEventHandlers[type].fire(evt);\n            }\n            else {\n                setTimeout(function() {\n                    // Fire deviceready on listeners that were registered before cordova.js was loaded.\n                    if (type == 'deviceready') {\n                        document.dispatchEvent(evt);\n                    }\n                    documentEventHandlers[type].fire(evt);\n                }, 0);\n            }\n        } else {\n            document.dispatchEvent(evt);\n        }\n    },\n    fireWindowEvent: function(type, data) {\n        var evt = createEvent(type,data);\n        if (typeof windowEventHandlers[type] != 'undefined') {\n            setTimeout(function() {\n                windowEventHandlers[type].fire(evt);\n            }, 0);\n        } else {\n            window.dispatchEvent(evt);\n        }\n    },\n\n    /**\n     * Plugin callback mechanism.\n     */\n    // Randomize the starting callbackId to avoid collisions after refreshing or navigating.\n    // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.\n    callbackId: Math.floor(Math.random() * 2000000000),\n    callbacks:  {},\n    callbackStatus: {\n        NO_RESULT: 0,\n        OK: 1,\n        CLASS_NOT_FOUND_EXCEPTION: 2,\n        ILLEGAL_ACCESS_EXCEPTION: 3,\n        INSTANTIATION_EXCEPTION: 4,\n        MALFORMED_URL_EXCEPTION: 5,\n        IO_EXCEPTION: 6,\n        INVALID_ACTION: 7,\n        JSON_EXCEPTION: 8,\n        ERROR: 9\n    },\n\n    /**\n     * Called by native code when returning successful result from an action.\n     */\n    callbackSuccess: function(callbackId, args) {\n        cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);\n    },\n\n    /**\n     * Called by native code when returning error result from an action.\n     */\n    callbackError: function(callbackId, args) {\n        // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.\n        // Derive success from status.\n        cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);\n    },\n\n    /**\n     * Called by native code when returning the result from an action.\n     */\n    callbackFromNative: function(callbackId, isSuccess, status, args, keepCallback) {\n        try {\n            var callback = cordova.callbacks[callbackId];\n            if (callback) {\n                if (isSuccess && status == cordova.callbackStatus.OK) {\n                    callback.success && callback.success.apply(null, args);\n                } else if (!isSuccess) {\n                    callback.fail && callback.fail.apply(null, args);\n                }\n                /*\n                else\n                    Note, this case is intentionally not caught.\n                    this can happen if isSuccess is true, but callbackStatus is NO_RESULT\n                    which is used to remove a callback from the list without calling the callbacks\n                    typically keepCallback is false in this case\n                */\n                // Clear callback if not expecting any more results\n                if (!keepCallback) {\n                    delete cordova.callbacks[callbackId];\n                }\n            }\n        }\n        catch (err) {\n            var msg = \"Error in \" + (isSuccess ? \"Success\" : \"Error\") + \" callbackId: \" + callbackId + \" : \" + err;\n            console && console.log && console.log(msg);\n            cordova.fireWindowEvent(\"cordovacallbackerror\", { 'message': msg });\n            throw err;\n        }\n    },\n    addConstructor: function(func) {\n        channel.onCordovaReady.subscribe(function() {\n            try {\n                func();\n            } catch(e) {\n                console.log(\"Failed to run constructor: \" + e);\n            }\n        });\n    }\n};\n\n\nmodule.exports = cordova;\n\n});\n\n// file: src/common/argscheck.js\ndefine(\"cordova/argscheck\", function(require, exports, module) {\n\nvar utils = require('cordova/utils');\n\nvar moduleExports = module.exports;\n\nvar typeMap = {\n    'A': 'Array',\n    'D': 'Date',\n    'N': 'Number',\n    'S': 'String',\n    'F': 'Function',\n    'O': 'Object'\n};\n\nfunction extractParamName(callee, argIndex) {\n    return (/.*?\\((.*?)\\)/).exec(callee)[1].split(', ')[argIndex];\n}\n\nfunction checkArgs(spec, functionName, args, opt_callee) {\n    if (!moduleExports.enableChecks) {\n        return;\n    }\n    var errMsg = null;\n    var typeName;\n    for (var i = 0; i < spec.length; ++i) {\n        var c = spec.charAt(i),\n            cUpper = c.toUpperCase(),\n            arg = args[i];\n        // Asterix means allow anything.\n        if (c == '*') {\n            continue;\n        }\n        typeName = utils.typeName(arg);\n        if ((arg === null || arg === undefined) && c == cUpper) {\n            continue;\n        }\n        if (typeName != typeMap[cUpper]) {\n            errMsg = 'Expected ' + typeMap[cUpper];\n            break;\n        }\n    }\n    if (errMsg) {\n        errMsg += ', but got ' + typeName + '.';\n        errMsg = 'Wrong type for parameter \"' + extractParamName(opt_callee || args.callee, i) + '\" of ' + functionName + ': ' + errMsg;\n        // Don't log when running unit tests.\n        if (typeof jasmine == 'undefined') {\n            console.error(errMsg);\n        }\n        throw TypeError(errMsg);\n    }\n}\n\nfunction getValue(value, defaultValue) {\n    return value === undefined ? defaultValue : value;\n}\n\nmoduleExports.checkArgs = checkArgs;\nmoduleExports.getValue = getValue;\nmoduleExports.enableChecks = true;\n\n\n});\n\n// file: src/common/base64.js\ndefine(\"cordova/base64\", function(require, exports, module) {\n\nvar base64 = exports;\n\nbase64.fromArrayBuffer = function(arrayBuffer) {\n    var array = new Uint8Array(arrayBuffer);\n    return uint8ToBase64(array);\n};\n\nbase64.toArrayBuffer = function(str) {\n    var decodedStr = typeof atob != 'undefined' ? atob(str) : new Buffer(str,'base64').toString('binary');\n    var arrayBuffer = new ArrayBuffer(decodedStr.length);\n    var array = new Uint8Array(arrayBuffer);\n    for (var i=0, len=decodedStr.length; i < len; i++) {\n        array[i] = decodedStr.charCodeAt(i);\n    }\n    return arrayBuffer;\n};\n\n//------------------------------------------------------------------------------\n\n/* This code is based on the performance tests at http://jsperf.com/b64tests\n * This 12-bit-at-a-time algorithm was the best performing version on all\n * platforms tested.\n */\n\nvar b64_6bit = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nvar b64_12bit;\n\nvar b64_12bitTable = function() {\n    b64_12bit = [];\n    for (var i=0; i<64; i++) {\n        for (var j=0; j<64; j++) {\n            b64_12bit[i*64+j] = b64_6bit[i] + b64_6bit[j];\n        }\n    }\n    b64_12bitTable = function() { return b64_12bit; };\n    return b64_12bit;\n};\n\nfunction uint8ToBase64(rawData) {\n    var numBytes = rawData.byteLength;\n    var output=\"\";\n    var segment;\n    var table = b64_12bitTable();\n    for (var i=0;i<numBytes-2;i+=3) {\n        segment = (rawData[i] << 16) + (rawData[i+1] << 8) + rawData[i+2];\n        output += table[segment >> 12];\n        output += table[segment & 0xfff];\n    }\n    if (numBytes - i == 2) {\n        segment = (rawData[i] << 16) + (rawData[i+1] << 8);\n        output += table[segment >> 12];\n        output += b64_6bit[(segment & 0xfff) >> 6];\n        output += '=';\n    } else if (numBytes - i == 1) {\n        segment = (rawData[i] << 16);\n        output += table[segment >> 12];\n        output += '==';\n    }\n    return output;\n}\n\n});\n\n// file: src/common/builder.js\ndefine(\"cordova/builder\", function(require, exports, module) {\n\nvar utils = require('cordova/utils');\n\nfunction each(objects, func, context) {\n    for (var prop in objects) {\n        if (objects.hasOwnProperty(prop)) {\n            func.apply(context, [objects[prop], prop]);\n        }\n    }\n}\n\nfunction clobber(obj, key, value) {\n    exports.replaceHookForTesting(obj, key);\n    var needsProperty = false;\n    try {\n        obj[key] = value;\n    } catch (e) {\n        needsProperty = true;\n    }\n    // Getters can only be overridden by getters.\n    if (needsProperty || obj[key] !== value) {\n        utils.defineGetter(obj, key, function() {\n            return value;\n        });\n    }\n}\n\nfunction assignOrWrapInDeprecateGetter(obj, key, value, message) {\n    if (message) {\n        utils.defineGetter(obj, key, function() {\n            console.log(message);\n            delete obj[key];\n            clobber(obj, key, value);\n            return value;\n        });\n    } else {\n        clobber(obj, key, value);\n    }\n}\n\nfunction include(parent, objects, clobber, merge) {\n    each(objects, function (obj, key) {\n        try {\n            var result = obj.path ? require(obj.path) : {};\n\n            if (clobber) {\n                // Clobber if it doesn't exist.\n                if (typeof parent[key] === 'undefined') {\n                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);\n                } else if (typeof obj.path !== 'undefined') {\n                    // If merging, merge properties onto parent, otherwise, clobber.\n                    if (merge) {\n                        recursiveMerge(parent[key], result);\n                    } else {\n                        assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);\n                    }\n                }\n                result = parent[key];\n            } else {\n                // Overwrite if not currently defined.\n                if (typeof parent[key] == 'undefined') {\n                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);\n                } else {\n                    // Set result to what already exists, so we can build children into it if they exist.\n                    result = parent[key];\n                }\n            }\n\n            if (obj.children) {\n                include(result, obj.children, clobber, merge);\n            }\n        } catch(e) {\n            utils.alert('Exception building Cordova JS globals: ' + e + ' for key \"' + key + '\"');\n        }\n    });\n}\n\n/**\n * Merge properties from one object onto another recursively.  Properties from\n * the src object will overwrite existing target property.\n *\n * @param target Object to merge properties into.\n * @param src Object to merge properties from.\n */\nfunction recursiveMerge(target, src) {\n    for (var prop in src) {\n        if (src.hasOwnProperty(prop)) {\n            if (target.prototype && target.prototype.constructor === target) {\n                // If the target object is a constructor override off prototype.\n                clobber(target.prototype, prop, src[prop]);\n            } else {\n                if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {\n                    recursiveMerge(target[prop], src[prop]);\n                } else {\n                    clobber(target, prop, src[prop]);\n                }\n            }\n        }\n    }\n}\n\nexports.buildIntoButDoNotClobber = function(objects, target) {\n    include(target, objects, false, false);\n};\nexports.buildIntoAndClobber = function(objects, target) {\n    include(target, objects, true, false);\n};\nexports.buildIntoAndMerge = function(objects, target) {\n    include(target, objects, true, true);\n};\nexports.recursiveMerge = recursiveMerge;\nexports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;\nexports.replaceHookForTesting = function() {};\n\n});\n\n// file: src/common/channel.js\ndefine(\"cordova/channel\", function(require, exports, module) {\n\nvar utils = require('cordova/utils'),\n    nextGuid = 1;\n\n/**\n * Custom pub-sub \"channel\" that can have functions subscribed to it\n * This object is used to define and control firing of events for\n * cordova initialization, as well as for custom events thereafter.\n *\n * The order of events during page load and Cordova startup is as follows:\n *\n * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.\n * onNativeReady*              Internal event that indicates the Cordova native side is ready.\n * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.\n * onDeviceReady*              User event fired to indicate that Cordova is ready\n * onResume                    User event fired to indicate a start/resume lifecycle event\n * onPause                     User event fired to indicate a pause lifecycle event\n *\n * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.\n * All listeners that subscribe after the event is fired will be executed right away.\n *\n * The only Cordova events that user code should register for are:\n *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript\n *      pause                 App has moved to background\n *      resume                App has returned to foreground\n *\n * Listeners can be registered as:\n *      document.addEventListener(\"deviceready\", myDeviceReadyListener, false);\n *      document.addEventListener(\"resume\", myResumeListener, false);\n *      document.addEventListener(\"pause\", myPauseListener, false);\n *\n * The DOM lifecycle events should be used for saving and restoring state\n *      window.onload\n *      window.onunload\n *\n */\n\n/**\n * Channel\n * @constructor\n * @param type  String the channel name\n */\nvar Channel = function(type, sticky) {\n    this.type = type;\n    // Map of guid -> function.\n    this.handlers = {};\n    // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.\n    this.state = sticky ? 1 : 0;\n    // Used in sticky mode to remember args passed to fire().\n    this.fireArgs = null;\n    // Used by onHasSubscribersChange to know if there are any listeners.\n    this.numHandlers = 0;\n    // Function that is called when the first listener is subscribed, or when\n    // the last listener is unsubscribed.\n    this.onHasSubscribersChange = null;\n},\n    channel = {\n        /**\n         * Calls the provided function only after all of the channels specified\n         * have been fired. All channels must be sticky channels.\n         */\n        join: function(h, c) {\n            var len = c.length,\n                i = len,\n                f = function() {\n                    if (!(--i)) h();\n                };\n            for (var j=0; j<len; j++) {\n                if (c[j].state === 0) {\n                    throw Error('Can only use join with sticky channels.');\n                }\n                c[j].subscribe(f);\n            }\n            if (!len) h();\n        },\n        create: function(type) {\n            return channel[type] = new Channel(type, false);\n        },\n        createSticky: function(type) {\n            return channel[type] = new Channel(type, true);\n        },\n\n        /**\n         * cordova Channels that must fire before \"deviceready\" is fired.\n         */\n        deviceReadyChannelsArray: [],\n        deviceReadyChannelsMap: {},\n\n        /**\n         * Indicate that a feature needs to be initialized before it is ready to be used.\n         * This holds up Cordova's \"deviceready\" event until the feature has been initialized\n         * and Cordova.initComplete(feature) is called.\n         *\n         * @param feature {String}     The unique feature name\n         */\n        waitForInitialization: function(feature) {\n            if (feature) {\n                var c = channel[feature] || this.createSticky(feature);\n                this.deviceReadyChannelsMap[feature] = c;\n                this.deviceReadyChannelsArray.push(c);\n            }\n        },\n\n        /**\n         * Indicate that initialization code has completed and the feature is ready to be used.\n         *\n         * @param feature {String}     The unique feature name\n         */\n        initializationComplete: function(feature) {\n            var c = this.deviceReadyChannelsMap[feature];\n            if (c) {\n                c.fire();\n            }\n        }\n    };\n\nfunction forceFunction(f) {\n    if (typeof f != 'function') throw \"Function required as first argument!\";\n}\n\n/**\n * Subscribes the given function to the channel. Any time that\n * Channel.fire is called so too will the function.\n * Optionally specify an execution context for the function\n * and a guid that can be used to stop subscribing to the channel.\n * Returns the guid.\n */\nChannel.prototype.subscribe = function(f, c) {\n    // need a function to call\n    forceFunction(f);\n    if (this.state == 2) {\n        f.apply(c || this, this.fireArgs);\n        return;\n    }\n\n    var func = f,\n        guid = f.observer_guid;\n    if (typeof c == \"object\") { func = utils.close(c, f); }\n\n    if (!guid) {\n        // first time any channel has seen this subscriber\n        guid = '' + nextGuid++;\n    }\n    func.observer_guid = guid;\n    f.observer_guid = guid;\n\n    // Don't add the same handler more than once.\n    if (!this.handlers[guid]) {\n        this.handlers[guid] = func;\n        this.numHandlers++;\n        if (this.numHandlers == 1) {\n            this.onHasSubscribersChange && this.onHasSubscribersChange();\n        }\n    }\n};\n\n/**\n * Unsubscribes the function with the given guid from the channel.\n */\nChannel.prototype.unsubscribe = function(f) {\n    // need a function to unsubscribe\n    forceFunction(f);\n\n    var guid = f.observer_guid,\n        handler = this.handlers[guid];\n    if (handler) {\n        delete this.handlers[guid];\n        this.numHandlers--;\n        if (this.numHandlers === 0) {\n            this.onHasSubscribersChange && this.onHasSubscribersChange();\n        }\n    }\n};\n\n/**\n * Calls all functions subscribed to this channel.\n */\nChannel.prototype.fire = function(e) {\n    var fail = false,\n        fireArgs = Array.prototype.slice.call(arguments);\n    // Apply stickiness.\n    if (this.state == 1) {\n        this.state = 2;\n        this.fireArgs = fireArgs;\n    }\n    if (this.numHandlers) {\n        // Copy the values first so that it is safe to modify it from within\n        // callbacks.\n        var toCall = [];\n        for (var item in this.handlers) {\n            toCall.push(this.handlers[item]);\n        }\n        for (var i = 0; i < toCall.length; ++i) {\n            toCall[i].apply(this, fireArgs);\n        }\n        if (this.state == 2 && this.numHandlers) {\n            this.numHandlers = 0;\n            this.handlers = {};\n            this.onHasSubscribersChange && this.onHasSubscribersChange();\n        }\n    }\n};\n\n\n// defining them here so they are ready super fast!\n// DOM event that is received when the web page is loaded and parsed.\nchannel.createSticky('onDOMContentLoaded');\n\n// Event to indicate the Cordova native side is ready.\nchannel.createSticky('onNativeReady');\n\n// Event to indicate that all Cordova JavaScript objects have been created\n// and it's time to run plugin constructors.\nchannel.createSticky('onCordovaReady');\n\n// Event to indicate that all automatically loaded JS plugins are loaded and ready.\n// FIXME remove this\nchannel.createSticky('onPluginsReady');\n\n// Event to indicate that Cordova is ready\nchannel.createSticky('onDeviceReady');\n\n// Event to indicate a resume lifecycle event\nchannel.create('onResume');\n\n// Event to indicate a pause lifecycle event\nchannel.create('onPause');\n\n// Channels that must fire before \"deviceready\" is fired.\nchannel.waitForInitialization('onCordovaReady');\nchannel.waitForInitialization('onDOMContentLoaded');\n\nmodule.exports = channel;\n\n});\n\n// file: e:/cordova/cordova-browser/cordova-js-src/confighelper.js\ndefine(\"cordova/confighelper\", function(require, exports, module) {\n\nvar config;\n\nfunction Config(xhr) {\n    function loadPreferences(xhr) {\n       var parser = new DOMParser();\n       var doc = parser.parseFromString(xhr.responseText, \"application/xml\");\n\n       var preferences = doc.getElementsByTagName(\"preference\");\n       return Array.prototype.slice.call(preferences);\n    }\n\n    this.xhr = xhr;\n    this.preferences = loadPreferences(this.xhr);\n}\n\nfunction readConfig(success, error) {\n    var xhr;\n\n    if(typeof config != 'undefined') {\n        success(config);\n    }\n\n    function fail(msg) {\n        console.error(msg);\n\n        if(error) {\n            error(msg);\n        }\n    }\n\n    var xhrStatusChangeHandler = function() {\n        if (xhr.readyState == 4) {\n            if (xhr.status == 200 || xhr.status == 304 || xhr.status === 0 /* file:// */) {\n                config = new Config(xhr);\n                success(config);\n            }\n            else {\n                fail('[Browser][cordova.js][xhrStatusChangeHandler] Could not XHR config.xml: ' + xhr.statusText);\n            }\n        }\n    };\n\n    if (\"ActiveXObject\" in window) {\n        // Needed for XHR-ing via file:// protocol in IE\n        xhr = new window.ActiveXObject(\"MSXML2.XMLHTTP\");\n        xhr.onreadystatechange = xhrStatusChangeHandler;\n    } else {\n        xhr = new XMLHttpRequest();\n        xhr.addEventListener(\"load\", xhrStatusChangeHandler);\n    }\n\n    try {\n        xhr.open(\"get\", \"/config.xml\", true);\n        xhr.send();\n    } catch(e) {\n        fail('[Browser][cordova.js][readConfig] Could not XHR config.xml: ' + JSON.stringify(e));\n    }\n}\n\n/**\n * Reads a preference value from config.xml.\n * Returns preference value or undefined if it does not exist.\n * @param {String} preferenceName Preference name to read */\nConfig.prototype.getPreferenceValue = function getPreferenceValue(preferenceName) {\n    var preferenceItem = this.preferences && this.preferences.filter(function(item) {\n        return item.attributes.name && item.attributes.name.value === preferenceName;\n    });\n\n    if(preferenceItem && preferenceItem[0] && preferenceItem[0].attributes && preferenceItem[0].attributes.value) {\n        return preferenceItem[0].attributes.value.value;\n    }\n};\n\nexports.readConfig = readConfig;\n\n});\n\n// file: e:/cordova/cordova-browser/cordova-js-src/exec.js\ndefine(\"cordova/exec\", function(require, exports, module) {\n\n/*jslint sloppy:true, plusplus:true*/\n/*global require, module, console */\n\nvar cordova = require('cordova');\nvar execProxy = require('cordova/exec/proxy');\n\n/**\n * Execute a cordova command.  It is up to the native side whether this action\n * is synchronous or asynchronous.  The native side can return:\n *      Synchronous: PluginResult object as a JSON string\n *      Asynchronous: Empty string \"\"\n * If async, the native side will cordova.callbackSuccess or cordova.callbackError,\n * depending upon the result of the action.\n *\n * @param {Function} success    The success callback\n * @param {Function} fail       The fail callback\n * @param {String} service      The name of the service to use\n * @param {String} action       Action to be run in cordova\n * @param {String[]} [args]     Zero or more arguments to pass to the method\n */\nmodule.exports = function (success, fail, service, action, args) {\n\n    var proxy = execProxy.get(service, action);\n\n    args = args || [];\n\n    if (proxy) {\n        \n        var callbackId = service + cordova.callbackId++;\n        \n        if (typeof success === \"function\" || typeof fail === \"function\") {\n            cordova.callbacks[callbackId] = {success: success, fail: fail};\n        }\n        try {\n\n            \n\n            // callbackOptions param represents additional optional parameters command could pass back, like keepCallback or\n            // custom callbackId, for example {callbackId: id, keepCallback: true, status: cordova.callbackStatus.JSON_EXCEPTION }\n            var onSuccess = function (result, callbackOptions) {\n                callbackOptions = callbackOptions || {};\n                var callbackStatus;\n                // covering both undefined and null.\n                // strict null comparison was causing callbackStatus to be undefined\n                // and then no callback was called because of the check in cordova.callbackFromNative\n                // see CB-8996 Mobilespec app hang on windows\n                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {\n                    callbackStatus = callbackOptions.status;\n                }\n                else {\n                    callbackStatus = cordova.callbackStatus.OK;\n                }\n                cordova.callbackSuccess(callbackOptions.callbackId || callbackId,\n                    {\n                        status: callbackStatus,\n                        message: result,\n                        keepCallback: callbackOptions.keepCallback || false\n                    });\n            };\n            var onError = function (err, callbackOptions) {\n                callbackOptions = callbackOptions || {};\n                var callbackStatus;\n                // covering both undefined and null.\n                // strict null comparison was causing callbackStatus to be undefined\n                // and then no callback was called because of the check in cordova.callbackFromNative\n                // note: status can be 0\n                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {\n                    callbackStatus = callbackOptions.status;\n                }\n                else {\n                    callbackStatus = cordova.callbackStatus.OK;\n                }\n                cordova.callbackError(callbackOptions.callbackId || callbackId,\n                {\n                    status: callbackStatus,\n                    message: err,\n                    keepCallback: callbackOptions.keepCallback || false\n                });\n            };\n            proxy(onSuccess, onError, args);\n\n        } catch (e) {\n            console.log(\"Exception calling native with command :: \" + service + \" :: \" + action  + \" ::exception=\" + e);\n        }\n    } else {\n\n        console.log(\"Error: exec proxy not found for :: \" + service + \" :: \" + action);\n        \n        if(typeof fail === \"function\" ) {\n            fail(\"Missing Command Error\");\n        }\n    }\n};\n\n});\n\n// file: src/common/exec/proxy.js\ndefine(\"cordova/exec/proxy\", function(require, exports, module) {\n\n\n// internal map of proxy function\nvar CommandProxyMap = {};\n\nmodule.exports = {\n\n    // example: cordova.commandProxy.add(\"Accelerometer\",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);\n    add:function(id,proxyObj) {\n        console.log(\"adding proxy for \" + id);\n        CommandProxyMap[id] = proxyObj;\n        return proxyObj;\n    },\n\n    // cordova.commandProxy.remove(\"Accelerometer\");\n    remove:function(id) {\n        var proxy = CommandProxyMap[id];\n        delete CommandProxyMap[id];\n        CommandProxyMap[id] = null;\n        return proxy;\n    },\n\n    get:function(service,action) {\n        return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );\n    }\n};\n});\n\n// file: src/common/init.js\ndefine(\"cordova/init\", function(require, exports, module) {\n\nvar channel = require('cordova/channel');\nvar cordova = require('cordova');\nvar modulemapper = require('cordova/modulemapper');\nvar platform = require('cordova/platform');\nvar pluginloader = require('cordova/pluginloader');\nvar utils = require('cordova/utils');\n\nvar platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];\n\nfunction logUnfiredChannels(arr) {\n    for (var i = 0; i < arr.length; ++i) {\n        if (arr[i].state != 2) {\n            console.log('Channel not fired: ' + arr[i].type);\n        }\n    }\n}\n\nwindow.setTimeout(function() {\n    if (channel.onDeviceReady.state != 2) {\n        console.log('deviceready has not fired after 5 seconds.');\n        logUnfiredChannels(platformInitChannelsArray);\n        logUnfiredChannels(channel.deviceReadyChannelsArray);\n    }\n}, 5000);\n\n// Replace navigator before any modules are required(), to ensure it happens as soon as possible.\n// We replace it so that properties that can't be clobbered can instead be overridden.\nfunction replaceNavigator(origNavigator) {\n    var CordovaNavigator = function() {};\n    CordovaNavigator.prototype = origNavigator;\n    var newNavigator = new CordovaNavigator();\n    // This work-around really only applies to new APIs that are newer than Function.bind.\n    // Without it, APIs such as getGamepads() break.\n    if (CordovaNavigator.bind) {\n        for (var key in origNavigator) {\n            if (typeof origNavigator[key] == 'function') {\n                newNavigator[key] = origNavigator[key].bind(origNavigator);\n            }\n            else {\n                (function(k) {\n                    utils.defineGetterSetter(newNavigator,key,function() {\n                        return origNavigator[k];\n                    });\n                })(key);\n            }\n        }\n    }\n    return newNavigator;\n}\n\nif (window.navigator) {\n    window.navigator = replaceNavigator(window.navigator);\n}\n\nif (!window.console) {\n    window.console = {\n        log: function(){}\n    };\n}\nif (!window.console.warn) {\n    window.console.warn = function(msg) {\n        this.log(\"warn: \" + msg);\n    };\n}\n\n// Register pause, resume and deviceready channels as events on document.\nchannel.onPause = cordova.addDocumentEventHandler('pause');\nchannel.onResume = cordova.addDocumentEventHandler('resume');\nchannel.onActivated = cordova.addDocumentEventHandler('activated');\nchannel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');\n\n// Listen for DOMContentLoaded and notify our channel subscribers.\nif (document.readyState == 'complete' || document.readyState == 'interactive') {\n    channel.onDOMContentLoaded.fire();\n} else {\n    document.addEventListener('DOMContentLoaded', function() {\n        channel.onDOMContentLoaded.fire();\n    }, false);\n}\n\n// _nativeReady is global variable that the native side can set\n// to signify that the native code is ready. It is a global since\n// it may be called before any cordova JS is ready.\nif (window._nativeReady) {\n    channel.onNativeReady.fire();\n}\n\nmodulemapper.clobbers('cordova', 'cordova');\nmodulemapper.clobbers('cordova/exec', 'cordova.exec');\nmodulemapper.clobbers('cordova/exec', 'Cordova.exec');\n\n// Call the platform-specific initialization.\nplatform.bootstrap && platform.bootstrap();\n\n// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js.\n// The delay allows the attached modules to be defined before the plugin loader looks for them.\nsetTimeout(function() {\n    pluginloader.load(function() {\n        channel.onPluginsReady.fire();\n    });\n}, 0);\n\n/**\n * Create all cordova objects once native side is ready.\n */\nchannel.join(function() {\n    modulemapper.mapModules(window);\n\n    platform.initialize && platform.initialize();\n\n    // Fire event to notify that all objects are created\n    channel.onCordovaReady.fire();\n\n    // Fire onDeviceReady event once page has fully loaded, all\n    // constructors have run and cordova info has been received from native\n    // side.\n    channel.join(function() {\n        require('cordova').fireDocumentEvent('deviceready');\n    }, channel.deviceReadyChannelsArray);\n\n}, platformInitChannelsArray);\n\n\n});\n\n// file: src/common/init_b.js\ndefine(\"cordova/init_b\", function(require, exports, module) {\n\nvar channel = require('cordova/channel');\nvar cordova = require('cordova');\nvar modulemapper = require('cordova/modulemapper');\nvar platform = require('cordova/platform');\nvar pluginloader = require('cordova/pluginloader');\nvar utils = require('cordova/utils');\n\nvar platformInitChannelsArray = [channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady];\n\n// setting exec\ncordova.exec = require('cordova/exec');\n\nfunction logUnfiredChannels(arr) {\n    for (var i = 0; i < arr.length; ++i) {\n        if (arr[i].state != 2) {\n            console.log('Channel not fired: ' + arr[i].type);\n        }\n    }\n}\n\nwindow.setTimeout(function() {\n    if (channel.onDeviceReady.state != 2) {\n        console.log('deviceready has not fired after 5 seconds.');\n        logUnfiredChannels(platformInitChannelsArray);\n        logUnfiredChannels(channel.deviceReadyChannelsArray);\n    }\n}, 5000);\n\n// Replace navigator before any modules are required(), to ensure it happens as soon as possible.\n// We replace it so that properties that can't be clobbered can instead be overridden.\nfunction replaceNavigator(origNavigator) {\n    var CordovaNavigator = function() {};\n    CordovaNavigator.prototype = origNavigator;\n    var newNavigator = new CordovaNavigator();\n    // This work-around really only applies to new APIs that are newer than Function.bind.\n    // Without it, APIs such as getGamepads() break.\n    if (CordovaNavigator.bind) {\n        for (var key in origNavigator) {\n            if (typeof origNavigator[key] == 'function') {\n                newNavigator[key] = origNavigator[key].bind(origNavigator);\n            }\n            else {\n                (function(k) {\n                    utils.defineGetterSetter(newNavigator,key,function() {\n                        return origNavigator[k];\n                    });\n                })(key);\n            }\n        }\n    }\n    return newNavigator;\n}\nif (window.navigator) {\n    window.navigator = replaceNavigator(window.navigator);\n}\n\nif (!window.console) {\n    window.console = {\n        log: function(){}\n    };\n}\nif (!window.console.warn) {\n    window.console.warn = function(msg) {\n        this.log(\"warn: \" + msg);\n    };\n}\n\n// Register pause, resume and deviceready channels as events on document.\nchannel.onPause = cordova.addDocumentEventHandler('pause');\nchannel.onResume = cordova.addDocumentEventHandler('resume');\nchannel.onActivated = cordova.addDocumentEventHandler('activated');\nchannel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');\n\n// Listen for DOMContentLoaded and notify our channel subscribers.\nif (document.readyState == 'complete' || document.readyState == 'interactive') {\n    channel.onDOMContentLoaded.fire();\n} else {\n    document.addEventListener('DOMContentLoaded', function() {\n        channel.onDOMContentLoaded.fire();\n    }, false);\n}\n\n// _nativeReady is global variable that the native side can set\n// to signify that the native code is ready. It is a global since\n// it may be called before any cordova JS is ready.\nif (window._nativeReady) {\n    channel.onNativeReady.fire();\n}\n\n// Call the platform-specific initialization.\nplatform.bootstrap && platform.bootstrap();\n\n// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js.\n// The delay allows the attached modules to be defined before the plugin loader looks for them.\nsetTimeout(function() {\n    pluginloader.load(function() {\n        channel.onPluginsReady.fire();\n    });\n}, 0);\n\n/**\n * Create all cordova objects once native side is ready.\n */\nchannel.join(function() {\n    modulemapper.mapModules(window);\n\n    platform.initialize && platform.initialize();\n\n    // Fire event to notify that all objects are created\n    channel.onCordovaReady.fire();\n\n    // Fire onDeviceReady event once page has fully loaded, all\n    // constructors have run and cordova info has been received from native\n    // side.\n    channel.join(function() {\n        require('cordova').fireDocumentEvent('deviceready');\n    }, channel.deviceReadyChannelsArray);\n\n}, platformInitChannelsArray);\n\n});\n\n// file: src/common/modulemapper.js\ndefine(\"cordova/modulemapper\", function(require, exports, module) {\n\nvar builder = require('cordova/builder'),\n    moduleMap = define.moduleMap,\n    symbolList,\n    deprecationMap;\n\nexports.reset = function() {\n    symbolList = [];\n    deprecationMap = {};\n};\n\nfunction addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {\n    if (!(moduleName in moduleMap)) {\n        throw new Error('Module ' + moduleName + ' does not exist.');\n    }\n    symbolList.push(strategy, moduleName, symbolPath);\n    if (opt_deprecationMessage) {\n        deprecationMap[symbolPath] = opt_deprecationMessage;\n    }\n}\n\n// Note: Android 2.3 does have Function.bind().\nexports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.runs = function(moduleName) {\n    addEntry('r', moduleName, null);\n};\n\nfunction prepareNamespace(symbolPath, context) {\n    if (!symbolPath) {\n        return context;\n    }\n    var parts = symbolPath.split('.');\n    var cur = context;\n    for (var i = 0, part; part = parts[i]; ++i) {\n        cur = cur[part] = cur[part] || {};\n    }\n    return cur;\n}\n\nexports.mapModules = function(context) {\n    var origSymbols = {};\n    context.CDV_origSymbols = origSymbols;\n    for (var i = 0, len = symbolList.length; i < len; i += 3) {\n        var strategy = symbolList[i];\n        var moduleName = symbolList[i + 1];\n        var module = require(moduleName);\n        // <runs/>\n        if (strategy == 'r') {\n            continue;\n        }\n        var symbolPath = symbolList[i + 2];\n        var lastDot = symbolPath.lastIndexOf('.');\n        var namespace = symbolPath.substr(0, lastDot);\n        var lastName = symbolPath.substr(lastDot + 1);\n\n        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;\n        var parentObj = prepareNamespace(namespace, context);\n        var target = parentObj[lastName];\n\n        if (strategy == 'm' && target) {\n            builder.recursiveMerge(target, module);\n        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {\n            if (!(symbolPath in origSymbols)) {\n                origSymbols[symbolPath] = target;\n            }\n            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);\n        }\n    }\n};\n\nexports.getOriginalSymbol = function(context, symbolPath) {\n    var origSymbols = context.CDV_origSymbols;\n    if (origSymbols && (symbolPath in origSymbols)) {\n        return origSymbols[symbolPath];\n    }\n    var parts = symbolPath.split('.');\n    var obj = context;\n    for (var i = 0; i < parts.length; ++i) {\n        obj = obj && obj[parts[i]];\n    }\n    return obj;\n};\n\nexports.reset();\n\n\n});\n\n// file: src/common/modulemapper_b.js\ndefine(\"cordova/modulemapper_b\", function(require, exports, module) {\n\nvar builder = require('cordova/builder'),\n    symbolList = [],\n    deprecationMap;\n\nexports.reset = function() {\n    symbolList = [];\n    deprecationMap = {};\n};\n\nfunction addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {\n    symbolList.push(strategy, moduleName, symbolPath);\n    if (opt_deprecationMessage) {\n        deprecationMap[symbolPath] = opt_deprecationMessage;\n    }\n}\n\n// Note: Android 2.3 does have Function.bind().\nexports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {\n    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);\n};\n\nexports.runs = function(moduleName) {\n    addEntry('r', moduleName, null);\n};\n\nfunction prepareNamespace(symbolPath, context) {\n    if (!symbolPath) {\n        return context;\n    }\n    var parts = symbolPath.split('.');\n    var cur = context;\n    for (var i = 0, part; part = parts[i]; ++i) {\n        cur = cur[part] = cur[part] || {};\n    }\n    return cur;\n}\n\nexports.mapModules = function(context) {\n    var origSymbols = {};\n    context.CDV_origSymbols = origSymbols;\n    for (var i = 0, len = symbolList.length; i < len; i += 3) {\n        var strategy = symbolList[i];\n        var moduleName = symbolList[i + 1];\n        var module = require(moduleName);\n        // <runs/>\n        if (strategy == 'r') {\n            continue;\n        }\n        var symbolPath = symbolList[i + 2];\n        var lastDot = symbolPath.lastIndexOf('.');\n        var namespace = symbolPath.substr(0, lastDot);\n        var lastName = symbolPath.substr(lastDot + 1);\n\n        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;\n        var parentObj = prepareNamespace(namespace, context);\n        var target = parentObj[lastName];\n\n        if (strategy == 'm' && target) {\n            builder.recursiveMerge(target, module);\n        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {\n            if (!(symbolPath in origSymbols)) {\n                origSymbols[symbolPath] = target;\n            }\n            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);\n        }\n    }\n};\n\nexports.getOriginalSymbol = function(context, symbolPath) {\n    var origSymbols = context.CDV_origSymbols;\n    if (origSymbols && (symbolPath in origSymbols)) {\n        return origSymbols[symbolPath];\n    }\n    var parts = symbolPath.split('.');\n    var obj = context;\n    for (var i = 0; i < parts.length; ++i) {\n        obj = obj && obj[parts[i]];\n    }\n    return obj;\n};\n\nexports.reset();\n\n\n});\n\n// file: e:/cordova/cordova-browser/cordova-js-src/platform.js\ndefine(\"cordova/platform\", function(require, exports, module) {\n\nmodule.exports = {\n    id: 'browser',\n    cordovaVersion: '3.4.0',\n\n    bootstrap: function() {\n\n        var modulemapper = require('cordova/modulemapper');\n        var channel = require('cordova/channel');\n\n        modulemapper.clobbers('cordova/exec/proxy', 'cordova.commandProxy');\n\n        channel.onNativeReady.fire();\n\n        // FIXME is this the right place to clobber pause/resume? I am guessing not\n        // FIXME pause/resume should be deprecated IN CORDOVA for pagevisiblity api\n        document.addEventListener('webkitvisibilitychange', function() {\n            if (document.webkitHidden) {\n                channel.onPause.fire();\n            }\n            else {\n                channel.onResume.fire();\n            }\n        }, false);\n\n    // End of bootstrap\n    }\n};\n\n});\n\n// file: src/common/pluginloader.js\ndefine(\"cordova/pluginloader\", function(require, exports, module) {\n\nvar modulemapper = require('cordova/modulemapper');\nvar urlutil = require('cordova/urlutil');\n\n// Helper function to inject a <script> tag.\n// Exported for testing.\nexports.injectScript = function(url, onload, onerror) {\n    var script = document.createElement(\"script\");\n    // onload fires even when script fails loads with an error.\n    script.onload = onload;\n    // onerror fires for malformed URLs.\n    script.onerror = onerror;\n    script.src = url;\n    document.head.appendChild(script);\n};\n\nfunction injectIfNecessary(id, url, onload, onerror) {\n    onerror = onerror || onload;\n    if (id in define.moduleMap) {\n        onload();\n    } else {\n        exports.injectScript(url, function() {\n            if (id in define.moduleMap) {\n                onload();\n            } else {\n                onerror();\n            }\n        }, onerror);\n    }\n}\n\nfunction onScriptLoadingComplete(moduleList, finishPluginLoading) {\n    // Loop through all the plugins and then through their clobbers and merges.\n    for (var i = 0, module; module = moduleList[i]; i++) {\n        if (module.clobbers && module.clobbers.length) {\n            for (var j = 0; j < module.clobbers.length; j++) {\n                modulemapper.clobbers(module.id, module.clobbers[j]);\n            }\n        }\n\n        if (module.merges && module.merges.length) {\n            for (var k = 0; k < module.merges.length; k++) {\n                modulemapper.merges(module.id, module.merges[k]);\n            }\n        }\n\n        // Finally, if runs is truthy we want to simply require() the module.\n        if (module.runs) {\n            modulemapper.runs(module.id);\n        }\n    }\n\n    finishPluginLoading();\n}\n\n// Handler for the cordova_plugins.js content.\n// See plugman's plugin_loader.js for the details of this object.\n// This function is only called if the really is a plugins array that isn't empty.\n// Otherwise the onerror response handler will just call finishPluginLoading().\nfunction handlePluginsObject(path, moduleList, finishPluginLoading) {\n    // Now inject the scripts.\n    var scriptCounter = moduleList.length;\n\n    if (!scriptCounter) {\n        finishPluginLoading();\n        return;\n    }\n    function scriptLoadedCallback() {\n        if (!--scriptCounter) {\n            onScriptLoadingComplete(moduleList, finishPluginLoading);\n        }\n    }\n\n    for (var i = 0; i < moduleList.length; i++) {\n        injectIfNecessary(moduleList[i].id, path + moduleList[i].file, scriptLoadedCallback);\n    }\n}\n\nfunction findCordovaPath() {\n    var path = null;\n    var scripts = document.getElementsByTagName('script');\n    var term = '/cordova.js';\n    for (var n = scripts.length-1; n>-1; n--) {\n        var src = scripts[n].src.replace(/\\?.*$/, ''); // Strip any query param (CB-6007).\n        if (src.indexOf(term) == (src.length - term.length)) {\n            path = src.substring(0, src.length - term.length) + '/';\n            break;\n        }\n    }\n    return path;\n}\n\n// Tries to load all plugins' js-modules.\n// This is an async process, but onDeviceReady is blocked on onPluginsReady.\n// onPluginsReady is fired when there are no plugins to load, or they are all done.\nexports.load = function(callback) {\n    var pathPrefix = findCordovaPath();\n    if (pathPrefix === null) {\n        console.log('Could not find cordova.js script tag. Plugin loading may fail.');\n        pathPrefix = '';\n    }\n    injectIfNecessary('cordova/plugin_list', pathPrefix + 'cordova_plugins.js', function() {\n        var moduleList = require(\"cordova/plugin_list\");\n        handlePluginsObject(pathPrefix, moduleList, callback);\n    }, callback);\n};\n\n\n});\n\n// file: src/common/pluginloader_b.js\ndefine(\"cordova/pluginloader_b\", function(require, exports, module) {\n\nvar modulemapper = require('cordova/modulemapper');\n\n// Handler for the cordova_plugins.js content.\n// See plugman's plugin_loader.js for the details of this object.\nfunction handlePluginsObject(moduleList) {\n    // if moduleList is not defined or empty, we've nothing to do\n    if (!moduleList || !moduleList.length) {\n        return;\n    }\n\n    // Loop through all the modules and then through their clobbers and merges.\n    for (var i = 0, module; module = moduleList[i]; i++) {\n        if (module.clobbers && module.clobbers.length) {\n            for (var j = 0; j < module.clobbers.length; j++) {\n                modulemapper.clobbers(module.id, module.clobbers[j]);\n            }\n        }\n\n        if (module.merges && module.merges.length) {\n            for (var k = 0; k < module.merges.length; k++) {\n                modulemapper.merges(module.id, module.merges[k]);\n            }\n        }\n\n        // Finally, if runs is truthy we want to simply require() the module.\n        if (module.runs) {\n            modulemapper.runs(module.id);\n        }\n    }\n}\n\n// Loads all plugins' js-modules. Plugin loading is syncronous in browserified bundle\n// but the method accepts callback to be compatible with non-browserify flow.\n// onDeviceReady is blocked on onPluginsReady. onPluginsReady is fired when there are\n// no plugins to load, or they are all done.\nexports.load = function(callback) {\n    var moduleList = require(\"cordova/plugin_list\");\n    handlePluginsObject(moduleList);\n\n    callback();\n};\n\n\n});\n\n// file: src/common/urlutil.js\ndefine(\"cordova/urlutil\", function(require, exports, module) {\n\n\n/**\n * For already absolute URLs, returns what is passed in.\n * For relative URLs, converts them to absolute ones.\n */\nexports.makeAbsolute = function makeAbsolute(url) {\n    var anchorEl = document.createElement('a');\n    anchorEl.href = url;\n    return anchorEl.href;\n};\n\n\n});\n\n// file: src/common/utils.js\ndefine(\"cordova/utils\", function(require, exports, module) {\n\nvar utils = exports;\n\n/**\n * Defines a property getter / setter for obj[key].\n */\nutils.defineGetterSetter = function(obj, key, getFunc, opt_setFunc) {\n    if (Object.defineProperty) {\n        var desc = {\n            get: getFunc,\n            configurable: true\n        };\n        if (opt_setFunc) {\n            desc.set = opt_setFunc;\n        }\n        Object.defineProperty(obj, key, desc);\n    } else {\n        obj.__defineGetter__(key, getFunc);\n        if (opt_setFunc) {\n            obj.__defineSetter__(key, opt_setFunc);\n        }\n    }\n};\n\n/**\n * Defines a property getter for obj[key].\n */\nutils.defineGetter = utils.defineGetterSetter;\n\nutils.arrayIndexOf = function(a, item) {\n    if (a.indexOf) {\n        return a.indexOf(item);\n    }\n    var len = a.length;\n    for (var i = 0; i < len; ++i) {\n        if (a[i] == item) {\n            return i;\n        }\n    }\n    return -1;\n};\n\n/**\n * Returns whether the item was found in the array.\n */\nutils.arrayRemove = function(a, item) {\n    var index = utils.arrayIndexOf(a, item);\n    if (index != -1) {\n        a.splice(index, 1);\n    }\n    return index != -1;\n};\n\nutils.typeName = function(val) {\n    return Object.prototype.toString.call(val).slice(8, -1);\n};\n\n/**\n * Returns an indication of whether the argument is an array or not\n */\nutils.isArray = Array.isArray ||\n                function(a) {return utils.typeName(a) == 'Array';};\n\n/**\n * Returns an indication of whether the argument is a Date or not\n */\nutils.isDate = function(d) {\n    return (d instanceof Date);\n};\n\n/**\n * Does a deep clone of the object.\n */\nutils.clone = function(obj) {\n    if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') {\n        return obj;\n    }\n\n    var retVal, i;\n\n    if(utils.isArray(obj)){\n        retVal = [];\n        for(i = 0; i < obj.length; ++i){\n            retVal.push(utils.clone(obj[i]));\n        }\n        return retVal;\n    }\n\n    retVal = {};\n    for(i in obj){\n        if(!(i in retVal) || retVal[i] != obj[i]) {\n            retVal[i] = utils.clone(obj[i]);\n        }\n    }\n    return retVal;\n};\n\n/**\n * Returns a wrapped version of the function\n */\nutils.close = function(context, func, params) {\n    return function() {\n        var args = params || arguments;\n        return func.apply(context, args);\n    };\n};\n\n//------------------------------------------------------------------------------\nfunction UUIDcreatePart(length) {\n    var uuidpart = \"\";\n    for (var i=0; i<length; i++) {\n        var uuidchar = parseInt((Math.random() * 256), 10).toString(16);\n        if (uuidchar.length == 1) {\n            uuidchar = \"0\" + uuidchar;\n        }\n        uuidpart += uuidchar;\n    }\n    return uuidpart;\n}\n\n/**\n * Create a UUID\n */\nutils.createUUID = function() {\n    return UUIDcreatePart(4) + '-' +\n        UUIDcreatePart(2) + '-' +\n        UUIDcreatePart(2) + '-' +\n        UUIDcreatePart(2) + '-' +\n        UUIDcreatePart(6);\n};\n\n\n/**\n * Extends a child object from a parent object using classical inheritance\n * pattern.\n */\nutils.extend = (function() {\n    // proxy used to establish prototype chain\n    var F = function() {};\n    // extend Child from Parent\n    return function(Child, Parent) {\n\n        F.prototype = Parent.prototype;\n        Child.prototype = new F();\n        Child.__super__ = Parent.prototype;\n        Child.prototype.constructor = Child;\n    };\n}());\n\n/**\n * Alerts a message in any available way: alert or console.log.\n */\nutils.alert = function(msg) {\n    if (window.alert) {\n        window.alert(msg);\n    } else if (console && console.log) {\n        console.log(msg);\n    }\n};\n\n\n\n\n\n});\n\nwindow.cordova = require('cordova');\n// file: src/scripts/bootstrap.js\n\nrequire('cordova/init');\n\n})();"
  },
  {
    "path": "platforms/browser/www/cordova_plugins.js",
    "content": "cordova.define('cordova/plugin_list', function(require, exports, module) {\nmodule.exports = [\n    {\n        \"file\": \"plugins/cordova-plugin-splashscreen/www/splashscreen.js\",\n        \"id\": \"cordova-plugin-splashscreen.SplashScreen\",\n        \"pluginId\": \"cordova-plugin-splashscreen\",\n        \"clobbers\": [\n            \"navigator.splashscreen\"\n        ]\n    },\n    {\n        \"file\": \"plugins/cordova-plugin-splashscreen/src/browser/SplashScreenProxy.js\",\n        \"id\": \"cordova-plugin-splashscreen.SplashScreenProxy\",\n        \"pluginId\": \"cordova-plugin-splashscreen\",\n        \"runs\": true\n    },\n    {\n        \"file\": \"plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js\",\n        \"id\": \"phonegap-plugin-barcodescanner.BarcodeScanner\",\n        \"pluginId\": \"phonegap-plugin-barcodescanner\",\n        \"clobbers\": [\n            \"cordova.plugins.barcodeScanner\"\n        ]\n    },\n    {\n        \"file\": \"plugins/phonegap-plugin-barcodescanner/src/browser/BarcodeScannerProxy.js\",\n        \"id\": \"phonegap-plugin-barcodescanner.BarcodeScannerProxy\",\n        \"pluginId\": \"phonegap-plugin-barcodescanner\",\n        \"runs\": true\n    }\n];\nmodule.exports.metadata = \n// TOP OF METADATA\n{\n    \"cordova-plugin-whitelist\": \"1.3.1\",\n    \"cordova-plugin-splashscreen\": \"4.0.1\",\n    \"phonegap-plugin-barcodescanner\": \"6.0.6\"\n}\n// BOTTOM OF METADATA\n});"
  },
  {
    "path": "platforms/browser/www/css/responsive.css",
    "content": "/* TABLES */\n@media all and (max-width:500px) {\n    .force-landscape {\n        display: none;\n    }\n}\n@media all and (min-width:500px){\n    .please-rotate {\n        display: none;\n    }\n}\n/* /TABLES */\n\n/* MDL CARD */\n@media all and (min-width:590px) {\n    .pihole-card.pihole-card-floating > .mdl-card__actions > .material-icons{\n        padding-right: 0;\n    }\n\n    .pihole-card.pihole-card-floating > .mdl-card__actions {\n        font-size: 15px;\n    }\n\n    .pihole-card.pihole-card-floating.mdl-card{\n        display: inline-block;\n        width: 46%;\n        margin: 15px 2% 0 0;\n    }\n\n    .pihole-card.pihole-card-floating.mdl-card:nth-child(1),\n    .pihole-card.pihole-card-floating.mdl-card:nth-child(2){\n        margin-top: 0;\n    }\n\n    .pihole-card.pihole-card-floating.mdl-card:nth-of-type(even){\n        margin-right: 0;\n    }\n}\n/* /MDL CARD */"
  },
  {
    "path": "platforms/browser/www/css/styles.css",
    "content": "/* GENERAL */\nhtml, body {\n    font-family: 'Roboto', 'Helvetica', sans-serif;\n}\n\n.centered-element {\n    align-items: center;\n    justify-content: center;\n    text-align: center;\n}\n\n#main_content {\n    padding: 25px 0;\n}\n\n.fullwidth {\n    width: 100%;\n}\n\n.mdl-data-table tbody tr:hover {\n    background-color: transparent; \n}\n/* /GENERAL */\n\n/* DRAWER */\n.pihole-drawer {\n    border: none;\n}\n\n.pihole-drawer .mdl-menu .mdl-menu__item {\n    display: -webkit-flex;\n    display: -ms-flexbox;\n    display: flex;\n    -webkit-align-items: center;\n    -ms-flex-align: center;\n    align-items: center;\n}\n\n.pihole-drawer-header {\n    box-sizing: border-box;\n    display: -webkit-flex;\n    display: -ms-flexbox;\n    display: flex;\n    -webkit-flex-direction: column;\n    -ms-flex-direction: column;\n    flex-direction: column;\n    -webkit-justify-content: flex-end;\n    -ms-flex-pack: end;\n    justify-content: flex-end;\n    padding: 16px;\n}\n\n.pihole-avatar-dropdown {\n    display: -webkit-flex;\n    display: -ms-flexbox;\n    display: flex;\n    position: relative;\n    -webkit-flex-direction: row;\n    -ms-flex-direction: row;\n    flex-direction: row;\n    -webkit-align-items: center;\n    -ms-flex-align: center;\n    align-items: center;\n    width: 100%;\n}\n\n.pihole-navigation {\n    -webkit-flex-grow: 1;\n    -ms-flex-positive: 1;\n    flex-grow: 1;\n}\n\n.pihole-layout .pihole-navigation .mdl-navigation__link {\n    display: -webkit-flex !important;\n    display: -ms-flexbox !important;\n    display: flex !important;\n    -webkit-flex-direction: row;\n    -ms-flex-direction: row;\n    flex-direction: row;\n    -webkit-align-items: center;\n    -ms-flex-align: center;\n    align-items: center;\n    font-weight: 500;\n}\n\n.pihole-navigation .mdl-navigation__link .material-icons {\n    margin-right: 32px;\n}\n\n.pihole-drawer .pihole_logo {\n    width: 48px;\n    height: 48px;\n    padding-right: 10px;\n}\n/* /DRAWER */\n\n/* HEADER */\n\n.pihole-header #container-pihole-toggle {\n    padding-right: 10px;\n}\n\n.pihole-header .mdl-switch__thumb {\n    background:#dd4b39;\n}\n\n.pihole-header .mdl-switch.is-checked .mdl-switch__thumb {\n    background: #00a65a;\n}\n\n.pihole-header .mdl-switch.is-checked .mdl-switch__track {\n    background: rgba(0,0,0,.26);\n}\n\n/* /HEADER */\n\n/* CHARTS */\n.pihole-card .ct-chart {\n    margin: 0 auto;\n    width: 100%;\n    text-align: center;\n}\n\n.ct-chart .ct-slice-pie {\n    stroke: white;\n    stroke-width: 2px;\n}\n\n.ct-label {\n    font-size: 15px;\n    fill:#333;\n}\n\n.ct-fill-red {\n    fill:#f56954;\n}\n\n.ct-fill-blue{\n    fill:#3c8dbc;\n}\n\n.ct-fill-light-blue{\n    fill:#00c0ef;\n}\n\n.ct-fill-green{\n    fill:#00a65a;\n}\n\n.ct-fill-orange{\n    fill:#f39c12;\n}\n\n/* /CHARTS */\n\n/* MDL CARD */\n.pihole-card h2 {\n    margin:0;\n}\n\n.material-icons.loading {\n    -webkit-animation:fa-spin 2s infinite linear;\n    animation:fa-spin 2s infinite linear;\n}\n\n@-webkit-keyframes fa-spin {\n    0% {\n        -webkit-transform: rotate(0deg);\n        transform: rotate(0deg);\n    }\n    100% {\n        -webkit-transform: rotate(359deg);\n        transform: rotate(359deg);\n    }\n}\n@keyframes fa-spin {\n    0% {\n        -webkit-transform: rotate(0deg);\n        transform: rotate(0deg);\n    }\n    100% {\n        -webkit-transform: rotate(359deg);\n        transform: rotate(359deg);\n    }\n}\n\n.pihole-card.bg-aqua {     \n    background: #00c0ef;   \n}\n\n.pihole-card.bg-green {     \n    background: #00a65a;   \n}\n\n.pihole-card.bg-yellow {     \n    background: #f39c12;   \n}\n\n.pihole-card.bg-red {     \n    background: #dd4b39;   \n}\n\n.pihole-card.bg-white {\n    background: #fff;        \n}    \n\n.pihole-card.mdl-card {\n    width: 95%;\n    height: auto;\n    margin: 15px auto;\n    min-height: initial;\n}\n\n.pihole-card.mdl-card:first-child{\n    margin-top:0;\n}\n\n.pihole-card > .mdl-card__actions {\n    border-color: rgba(255, 255, 255, 0.2);\n}\n\n.pihole-card > .mdl-card__title {\n    align-items: flex-start;\n}\n\n.pihole-card > .mdl-card__title > h4 {\n    margin-top: 0;\n}\n\n.pihole-card > .mdl-card__actions {\n    display: flex;\n    box-sizing:border-box;\n    align-items: center;\n}\n\n.pihole-card > .mdl-card__actions > .material-icons {\n    padding-right: 10px;\n}\n\n.pihole-card:not(.bg-white) > .mdl-card__title,\n.pihole-card:not(.bg-white) > .mdl-card__actions,\n.pihole-card:not(.bg-white) > .mdl-card__actions > .mdl-button {\n    color: #fff;\n}\n/* /MDL CARD */\n\n/* DATATABLES */\n.dataTables_length,\n.dataTables_filter {\n    margin: 0 15px 15px 15px;\n}\n\ntable.dataTable thead th,\ntable.dataTable thead td,\ntable.dataTable.no-footer{\n    border-bottom: inherit;\n}\n\n@media screen and (max-width: 640px) {\n    .dataTables_wrapper .dataTables_filter {\n        margin-top:0;\n    }\n\n    .dataTables_wrapper .dataTables_length{\n        float:left;\n    }\n\n    .dataTables_wrapper .dataTables_filter {\n        float:right;\n    }\n}\n/* /DATATABLES */\n\n/* SETTINGS */\n.mdl-cell.mdl-card:first-child{\n    margin-top:0;\n}\n\n#form_settings{\n    margin:30px 0 15px 0;\n}\n\n#form_settings .mdl-button {\n    margin: 15px 0 0 0;\n}\n\n.mdl-textfield {\n    width: 100%;\n}\n\n#pihole_token {\n    width:85%;\n    display:inline-block;\n}\n\n#qrcode_scan {\n    float:right;\n    padding-top:5px;\n    opacity:.6;\n}\n/* /SETTINGS */\n\n/* ABOUT&HELP */\nh5 i.material-icons {\n    vertical-align: -4px;\n}\n/* /ABOUT&HELP */\n\n/* QUERYLOG */\n.mdl-chip.mdl-please-wait .material-icons {\n    vertical-align: -6px;\n}\n/* /QUERYLOG */"
  },
  {
    "path": "platforms/browser/www/exec.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n/*jslint sloppy:true, plusplus:true*/\n/*global require, module, console */\n\nvar cordova = require('cordova');\nvar execProxy = require('cordova/exec/proxy');\n\n/**\n * Execute a cordova command.  It is up to the native side whether this action\n * is synchronous or asynchronous.  The native side can return:\n *      Synchronous: PluginResult object as a JSON string\n *      Asynchronous: Empty string \"\"\n * If async, the native side will cordova.callbackSuccess or cordova.callbackError,\n * depending upon the result of the action.\n *\n * @param {Function} success    The success callback\n * @param {Function} fail       The fail callback\n * @param {String} service      The name of the service to use\n * @param {String} action       Action to be run in cordova\n * @param {String[]} [args]     Zero or more arguments to pass to the method\n */\nmodule.exports = function (success, fail, service, action, args) {\n\n    var proxy = execProxy.get(service, action);\n\n    args = args || [];\n\n    if (proxy) {\n        \n        var callbackId = service + cordova.callbackId++;\n        \n        if (typeof success === \"function\" || typeof fail === \"function\") {\n            cordova.callbacks[callbackId] = {success: success, fail: fail};\n        }\n        try {\n\n            \n\n            // callbackOptions param represents additional optional parameters command could pass back, like keepCallback or\n            // custom callbackId, for example {callbackId: id, keepCallback: true, status: cordova.callbackStatus.JSON_EXCEPTION }\n            var onSuccess = function (result, callbackOptions) {\n                callbackOptions = callbackOptions || {};\n                var callbackStatus;\n                // covering both undefined and null.\n                // strict null comparison was causing callbackStatus to be undefined\n                // and then no callback was called because of the check in cordova.callbackFromNative\n                // see CB-8996 Mobilespec app hang on windows\n                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {\n                    callbackStatus = callbackOptions.status;\n                }\n                else {\n                    callbackStatus = cordova.callbackStatus.OK;\n                }\n                cordova.callbackSuccess(callbackOptions.callbackId || callbackId,\n                    {\n                        status: callbackStatus,\n                        message: result,\n                        keepCallback: callbackOptions.keepCallback || false\n                    });\n            };\n            var onError = function (err, callbackOptions) {\n                callbackOptions = callbackOptions || {};\n                var callbackStatus;\n                // covering both undefined and null.\n                // strict null comparison was causing callbackStatus to be undefined\n                // and then no callback was called because of the check in cordova.callbackFromNative\n                // note: status can be 0\n                if (callbackOptions.status !== undefined && callbackOptions.status !== null) {\n                    callbackStatus = callbackOptions.status;\n                }\n                else {\n                    callbackStatus = cordova.callbackStatus.OK;\n                }\n                cordova.callbackError(callbackOptions.callbackId || callbackId,\n                {\n                    status: callbackStatus,\n                    message: err,\n                    keepCallback: callbackOptions.keepCallback || false\n                });\n            };\n            proxy(onSuccess, onError, args);\n\n        } catch (e) {\n            console.log(\"Exception calling native with command :: \" + service + \" :: \" + action  + \" ::exception=\" + e);\n        }\n    } else {\n\n        console.log(\"Error: exec proxy not found for :: \" + service + \" :: \" + action);\n        \n        if(typeof fail === \"function\" ) {\n            fail(\"Missing Command Error\");\n        }\n    }\n};\n"
  },
  {
    "path": "platforms/browser/www/index.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        <title>Pi-hole App</title>\n        <meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">\n        <meta name=\"format-detection\" content=\"telephone=no\">\n        <meta name=\"msapplication-tap-highlight\" content=\"no\">\n        <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width\">\n\n        <!-- styles -->\n        <link rel=\"stylesheet\" href=\"lib/mdl/css/fonts.min.css\">\n        <link rel=\"stylesheet\" href=\"lib/mdl/css/material.icons.min.css\">\n        <link rel=\"stylesheet\" href=\"lib/mdl/css/material.indigo-red.min.css\">\n        <link rel=\"stylesheet\" href=\"lib/chartist/chartist.min.css\">        \n        <link rel=\"stylesheet\" href=\"lib/DataTables/datatables.min.css\"/>\n        <link rel=\"stylesheet\" href=\"css/styles.css\">\n        <link rel=\"stylesheet\" href=\"css/responsive.css\">\n        <!-- /styles -->\n    </head>\n    <body>\n        <div class=\"pihole-layout mdl-layout mdl-js-layout mdl-layout--fixed-drawer mdl-layout--fixed-header\">\n            <header class=\"pihole-header mdl-layout__header\">\n                <div class=\"mdl-layout__header-row\">\n                    <span class=\"mdl-layout-title\"></span>\n                    <div class=\"mdl-layout-spacer\"></div>\n\n                    <!-- Pi-hole toggle -->\n                    <div id=\"container-pihole-toggle\" style=\"display:none\">\n                        <label id=\"label-pihole-toggle\" class=\"mdl-switch mdl-js-switch mdl-js-ripple-effect\" for=\"switch-pihole-toggle\">\n                            <input type=\"checkbox\" id=\"switch-pihole-toggle\" class=\"mdl-switch__input\" checked>\n                            <span class=\"mdl-switch__label\"></span>\n                        </label>\n                    </div>\n                </div>\n            </header>\n\n            <!-- drawer -->\n            <div class=\"pihole-drawer mdl-layout__drawer\">\n                <header id=\"header_loggedin\" style=\"display:none\" class=\"pihole-drawer-header mdl-color--primary-dark mdl-color-text--blue-grey-50\">\n                    <div class=\"pihole-avatar-dropdown\">\n                        <img class=\"pihole_logo\" src=\"img/logo.svg\">\n                        <span>You are logged in</span>\n                        <div class=\"mdl-layout-spacer\"></div>\n                        <button id=\"accbtn\" class=\"mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon\">\n                            <i class=\"material-icons\" role=\"presentation\">arrow_drop_down</i>\n                            <span class=\"visuallyhidden\">Accounts</span>\n                        </button>\n                        <ul class=\"mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect\" for=\"accbtn\">\n                            <li class=\"mdl-menu__item\" id=\"logout\"><i class=\"material-icons\">exit_to_app</i>Logout</li>\n                        </ul>\n                    </div>\n                </header>\n                <header id=\"header_guest\" class=\"pihole-drawer-header mdl-color--primary-dark mdl-color-text--blue-grey-50\">\n                    <div class=\"pihole-avatar-dropdown\">\n                        <img class=\"pihole_logo\" src=\"img/logo.svg\">\n                        <span>You are not logged in</span>\n                        <div class=\"mdl-layout-spacer\"></div>                        \n                    </div>\n                </header>\n                <nav id=\"drawer\" class=\"pihole-navigation mdl-navigation mdl-color--white\">\n                    <a class=\"mdl-navigation__link\" href=\"dashboard\"><i class=\"material-icons\" role=\"presentation\">dashboard</i>Dashboard</a>\n                    <a class=\"mdl-navigation__link\" href=\"query_log\"><i class=\"material-icons\" role=\"presentation\">filter_list</i>Query log</a>\n                    <a class=\"mdl-navigation__link\" href=\"app_settings\"><i class=\"material-icons\" role=\"presentation\">settings</i>App settings</a>\n                    <a class=\"mdl-navigation__link\" href=\"about_help\"><i class=\"material-icons\" role=\"presentation\">help_outline</i>About & Help</a>\n                </nav>\n            </div>\n            <!-- /drawer -->\n\n            <main id=\"main_content\" class=\"mdl-layout__content mdl-color--grey-100\">\n                <!-- the ajax area -->\n            </main>\n        </div>\n\n        <!-- scripts -->\n        <script type=\"text/javascript\" src=\"cordova.js\"></script>   \n        <script type=\"text/javascript\" src=\"lib/jQuery/jquery-3.1.1.min.js\"></script>\n        <script type=\"text/javascript\" src=\"lib/mdl/js/material.min.js\"></script>        \n        <script type=\"text/javascript\" src=\"lib/chartist/chartist.min.js\"></script>\n        <script type=\"text/javascript\" src=\"lib/DataTables/datatables.min.js\"></script>\n        <script type=\"text/javascript\" src=\"lib/hammerjs/hammer.min.js\"></script>\n        <script type=\"text/javascript\" src=\"lib/hammerjs/hammer-time.min.js\"></script>\n        <script type=\"text/javascript\" src=\"js/utilities.js\"></script>\n        <script type=\"text/javascript\" src=\"js/main.js\"></script>        \n        <!-- /scripts -->\n    </body>\n</html>\n"
  },
  {
    "path": "platforms/browser/www/js/main.js",
    "content": "/*\n * Check if is a cordova app or browser\n */\n\nvar isCordovaApp = (typeof window.cordova !== \"undefined\");\n\nif (isCordovaApp) {\n    document.addEventListener(\"deviceready\", init, false);\n} else {\n    init();\n}\n\n/*\n * Init app\n */\n\nfunction init() {\n\n    // Bind menu voices\n    $('.pihole-navigation a').click(function (event) {\n        event.preventDefault();\n        mdl_toggleDrawer();\n\n        if ($(this).attr('href') == 'dashboard') {\n            if (getPiholeSuccess()) {\n                pageDashboard();\n            } else {\n                pageAppSettings();\n            }\n        } else if ($(this).attr('href') == 'app_settings') {\n            pageAppSettings();\n        } else if ($(this).attr('href') == 'query_log') {\n            if (getPiholeSuccess()) {\n                pageQueryLog();\n            } else {\n                pageAppSettings();\n            }\n        } else if ($(this).attr('href') == 'about_help') {\n            pageAboutHelp();\n        }\n    });\n\n    // Update current status of toggle button\n    _updateToggleButton();\n\n    // Bind logo click enable/disable\n    $('#label-pihole-toggle input').change(function (evt) {\n        if ($(this).is(':checked')) {\n            if (confirm(\"Do you want to ENABLE Pi-hole's ad blocking?\")) {\n                $.getJSON(getPiholeHost() + \"/admin/api.php?enable&auth=\" + getPiholeToken(), function (response_data) {\n\n                });\n            } else {\n                $('#label-pihole-toggle')[0].MaterialSwitch.off();\n                evt.preventDefault();\n            }\n        } else {\n            if (confirm(\"Do you want to DISABLE Pi-hole's ad blocking?\")) {\n                $.getJSON(getPiholeHost() + \"/admin/api.php?disable&auth=\" + getPiholeToken(), function (response_data) {\n\n                });\n            } else {\n                $('#label-pihole-toggle')[0].MaterialSwitch.on();\n                evt.preventDefault();\n            }\n        }\n    });\n\n    // Bind swipe drawer actions\n    var hammertime_content = new Hammer(document.getElementById('main_content'));\n    hammertime_content.on('swiperight', function () {\n        mdl_toggleDrawer();\n    });\n\n    var hammertime_drawer = new Hammer(document.getElementById('drawer'));\n    hammertime_drawer.on('swipeleft', function () {\n        mdl_toggleDrawer();\n    });\n\n    // Start\n    if (getPiholeHost() && getPiholeToken()) {\n        _manageVisibilityToggle('show');\n        userIsLoggedIn();\n        pageDashboard();\n    } else {\n        pageAppSettings();\n    }\n\n}\n\n/*************************************************************\n * Settings page\n *************************************************************/\n\nfunction pageAppSettings() {\n    $.get(\"partial/app-settings.html\", function (data) {\n        updateAppTitle('<strong>Pi</strong>-hole app settings');\n        $(\"#main_content\").html(data);\n        mdl_upgradeDom();\n\n        // bind go_to_help click\n        $('#go_to_help').click(function () {\n            pageAboutHelp();\n        });\n\n        if (getPiholeHost()) {\n            $('#pihole_host').val(getPiholeHost());\n        }\n\n        if (getPiholeToken()) {\n            $('#pihole_token').val(getPiholeToken());\n        }\n\n        updateFloatLabel();\n\n        document.addEventListener(\"deviceready\", function () {\n            function scanQRCode() {\n                cordova.plugins.barcodeScanner.scan(\n                        function (result) {\n                            if (result.text) {\n                                $('#pihole_token').val(result.text);\n                                updateFloatLabel();\n                            }\n                        },\n                        function (error) {\n                            alert(\"Scanning failed: \" + error);\n                        },\n                        {\n                            preferFrontCamera: false,\n                            showFlipCameraButton: true,\n                            showTorchButton: true,\n                            torchOn: false,\n                            prompt: \"Place Pi-hole QR Code inside the scan area\",\n                            resultDisplayDuration: 0,\n                            formats: \"QR_CODE,PDF_417\",\n                            orientation: \"portrait\"\n                        }\n                );\n            }\n\n            $('#qrcode_scan').click(scanQRCode);\n        });\n\n        $('#form_settings').submit(function (event) {\n            event.preventDefault();\n\n            $(\"#form_settings > button[type='submit']\").html('PLEASE WAIT <i class=\"material-icons loading\">refresh</i>').prop(\"disabled\", true);\n            $(\"#form_settings > button[type='submit'] > .loading\").show();\n\n            var pihole_host = $('#pihole_host').val();\n            var pihole_token = $('#pihole_token').val();\n\n            // check if pihole_host contains http or https, otherwise add http as default\n            // TODO: complete the check\n            if (pihole_host.indexOf(\"http://\") == 0 || pihole_host.indexOf(\"https://\") == 0) {\n\n            }\n\n            _localStorage('save', 'pihole_host', pihole_host);\n            _localStorage('save', 'pihole_token', pihole_token);\n            _localStorage('remove', 'pihole_success');\n\n            $.ajax({\n                type: \"GET\",\n                url: pihole_host + \"/admin/api.php?getQuerySources&auth=\" + pihole_token,\n                success: function (data) {\n                    $.getJSON(pihole_host + \"/admin/api.php?getQuerySources&auth=\" + pihole_token, function (response) {\n                        if (jQuery.isEmptyObject(response)) {\n                            showErrorSettings();\n                        } else {\n                            _localStorage('save', 'pihole_success', 1);\n                            userIsLoggedIn();\n                            _updateToggleButton();\n                            pageDashboard();\n                        }\n                    });\n                },\n                error: function () {\n                    showErrorSettings();\n                }\n            });\n\n        });\n\n    });\n}\n\n/*\n * Show error dialog when settings are wrong\n */\n\nfunction showErrorSettings() {\n    var dialog = document.querySelector('dialog');\n    if (!dialog.showModal) {\n        dialogPolyfill.registerDialog(dialog);\n    }\n    dialog.showModal();\n    dialog.querySelector('.close').addEventListener('click', function () {\n        dialog.close();\n        $(\"#form_settings > button[type='submit']\").html('SAVE').prop(\"disabled\", false);\n    });\n}\n/*************************************************************/\n\n\n/*************************************************************\n * Dashboard page\n *************************************************************/\n\nfunction pageDashboard() {\n    $.get(\"partial/dashboard.html\", function (dataHtml) {\n        updateAppTitle('<strong>Pi</strong>-hole dashboard');\n        $(\"#main_content\").html(dataHtml);\n        mdl_upgradeDom();\n\n        /* summary */\n        var pihole_host = getPiholeHost();\n        var pihole_token = getPiholeToken();\n\n        $.getJSON(pihole_host + \"/admin/api.php?summary&auth=\" + pihole_token, function (response_data) {\n            $('#ads_blocked_today > .mdl-card__title > h2').html(response_data.ads_blocked_today);\n            $('#dns_queries_today > .mdl-card__title > h2').html(response_data.dns_queries_today);\n            $('#ads_percentage_today > .mdl-card__title > h2').html(response_data.ads_percentage_today + '%');\n            $('#domains_being_blocked > .mdl-card__title > h2').html(response_data.domains_being_blocked);\n        });\n\n        /* query types */\n        $.getJSON(pihole_host + \"/admin/api.php?getQueryTypes&auth=\" + pihole_token, function (response_data) {\n\n            var data = {\n                labels: ['A (IPv4)', 'AAAA (IPv6)'],\n                series: [{\n                        value: response_data.querytypes['A (IPv4)'],\n                        className: \"ct-fill-red\"\n                    }, {\n                        value: response_data.querytypes['AAAA (IPv6)'],\n                        className: \"ct-fill-blue\"\n                    }]\n            };\n\n            var options = {\n                height: 300,\n                chartPadding: 50,\n                labelOffset: 85\n            };\n\n            $('.ct-chart-query-types .loading').fadeOut('normal', function () {\n                new Chartist.Pie('.ct-chart-query-types', data, options);\n            });\n        });\n\n\n        /* forward destinations */\n        $.getJSON(pihole_host + \"/admin/api.php?getForwardDestinations&auth=\" + pihole_token, function (response_data) {\n            var labels_array = [];\n            var series_array = [];\n            var colors_array = [\"ct-fill-red\", \"ct-fill-blue\", \"ct-fill-light-blue\", \"ct-fill-orange\", \"ct-fill-green\"];\n\n            $.each(response_data.forward_destinations, function (key, val) {\n\n                // split key for labels\n                var label_array = key.split('|');\n                if (label_array[1]) {\n                    labels_array.push(label_array[1]);\n                } else {\n                    labels_array.push(label_array[0]);\n                }\n\n                serie_value = {value: val, className: colors_array[Math.floor(Math.random() * colors_array.length)]};\n                series_array.push(serie_value);\n            });\n\n            var data = {\n                labels: labels_array,\n                series: series_array\n            };\n\n            var options = {\n                height: 300,\n                chartPadding: 50,\n                labelOffset: 80\n            };\n\n            $('.ct-chart-forward-destinations .loading').fadeOut('normal', function () {\n                new Chartist.Pie('.ct-chart-forward-destinations', data, options);\n            });\n        });\n\n\n        /* top domains + top advertisers */\n        $.getJSON(pihole_host + \"/admin/api.php?topItems&auth=\" + pihole_token, function (response_data) {\n            $.each(response_data, function (key, val) {\n                if (key == 'top_queries') {\n                    if (jQuery.isEmptyObject(val) == false) {\n\n                        // remove loading row and replace it with results\n                        $('#tbody-table-top-queries > tr:first-child').fadeOut(400, function () {\n                            $.each(val, function (domain, domain_hits) {\n                                $('#tbody-table-top-queries:last-child').append('<tr><td class=\"mdl-data-table__cell--non-numeric\">' + domain + '</td><td>' + domain_hits + '</td></tr>');\n                            });\n                        });\n\n                    } else {\n                        // privacy mode enabled, hide the table\n                        $('#tbody-table-top-queries').parents('div.pihole-card').hide();\n                    }\n                } else if (key == 'top_ads') {\n\n                    // remove loading row and replace it with results\n                    $('#tbody-table-top-ads > tr:first-child').fadeOut(400, function () {\n                        $.each(val, function (domain, domain_hits) {\n                            $('#tbody-table-top-ads:last-child').append('<tr><td class=\"mdl-data-table__cell--non-numeric\">' + domain + '</td><td>' + domain_hits + '</td></tr>');\n                        });\n                    });\n\n                }\n            });\n        });\n\n\n        /* top clients */\n        $.getJSON(pihole_host + \"/admin/api.php?getQuerySources&auth=\" + pihole_token, function (response_data) {\n            $.each(response_data, function (key, val) {\n                if (key == 'top_sources') {\n\n                    // remove loading row and replace it with results\n                    $('#tbody-table-top-clients > tr:first-child').fadeOut(400, function () {\n                        $.each(val, function (client, client_hits) {\n                            $('#tbody-table-top-clients:last-child').append('<tr><td class=\"mdl-data-table__cell--non-numeric\">' + client + '</td><td class=\"mdl-data-table__cell--non-numeric\">' + client_hits + '</td></tr>');\n                        });\n                    });\n                }\n            });\n        });\n\n\n        /* recent items */\n        // TODO: forced PHP api version, can't find an alternative on FTL's API\n        $.getJSON(pihole_host + \"/admin/api.php?recentItems=10&PHP&auth=\" + pihole_token, function (response_data) {\n            $.each(response_data, function (key, val) {\n                if (key == 'recent_queries') {\n\n                    // remove loading row and replace it with results\n                    $('#tbody-table-recent-items > tr:first-child').fadeOut(400, function () {\n                        $.each(val, function (key_query, val_query) {\n                            $('#tbody-table-recent-items:last-child').append('<tr><td class=\"mdl-data-table__cell--non-numeric\">' + val_query.time + '</td><td>' + val_query.domain + '</td><td>' + val_query.ip + '</td></tr>');\n                        });\n                    });\n\n                }\n            });\n        });\n    });\n}\n\n/*************************************************************/\n\n\n/*************************************************************\n * Query log page\n *************************************************************/\n\nfunction pageQueryLog() {\n    $.get(\"partial/query-log.html\", function (dataHtml) {\n        updateAppTitle('<strong>Pi</strong>-hole query log');\n        $(\"#main_content\").html(dataHtml);\n        mdl_upgradeDom();\n\n        var pihole_host = getPiholeHost();\n        var pihole_token = getPiholeToken();\n\n        // TODO: add loading to tbody\n        var dataSet = [];\n        $.getJSON(pihole_host + \"/admin/api.php?getAllQueries&auth=\" + pihole_token, function (data) {\n            $.each(data, function (key, val) {\n                $.each(val, function (query) {\n\n                    // replace unnecessary long strings\n                    var client = val[query][3];\n                    var client_short = client.replace('(127.0.0.1)', '');\n\n                    var datetime = val[query][0];\n                    var datetime_short = datetime.replace('T', '<br />');\n\n                    dataSet.push([datetime_short, val[query][1], val[query][2], client_short, val[query][4]]);\n                });\n            });\n\n            $('.mdl-chip.mdl-please-wait').hide();\n\n            $('#query-log-table').DataTable({\n                data: dataSet,\n                order: [[0, \"desc\"]],\n                columns: [\n                    {title: \"Time\", class: \"mdl-data-table__cell--non-numeric fullwidth\"},\n                    {title: \"Type\"},\n                    {title: \"Domain\"},\n                    {title: \"Client\"},\n                    {title: \"Status\"}\n                ]\n            });\n        });\n    });\n}\n\n/*************************************************************/\n\n\n/*************************************************************\n * About&Help page\n *************************************************************/\n\nfunction pageAboutHelp() {\n    $.get(\"partial/about-help.html\", function (data) {\n        updateAppTitle('<strong>Pi</strong>-hole about & help');\n        $(\"#main_content\").html(data);\n        mdl_upgradeDom();\n    });\n}\n\n/*************************************************************/\n\n\n/*************************************************************\n * Helpers\n *************************************************************/\n\n// Get Pi-hole current status\nfunction _updateToggleButton() {\n    var pihole_host = getPiholeHost();\n    var pihole_token = getPiholeToken();\n\n    if (pihole_host && pihole_token) {\n        $.getJSON(pihole_host + \"/admin/api.php?status&auth=\" + pihole_token, function (response_data) {\n            var current_status = response_data.status;\n\n            if (current_status) {\n                _manageVisibilityToggle('show');\n\n                if (current_status == 'disabled') {\n                    $('#label-pihole-toggle')[0].MaterialSwitch.off();\n                } else if (current_status == 'enabled') {\n                    $('#label-pihole-toggle')[0].MaterialSwitch.on();\n                }\n            }\n        });\n    }\n}\n\n/*************************************************************/"
  },
  {
    "path": "platforms/browser/www/js/utilities.js",
    "content": "/*\n * Refresh the DOM for MDL dynamic content\n */\n\nfunction mdl_upgradeDom() {\n    componentHandler.upgradeDom();\n}\n\n/*\n * Toggle open/close of Drawer\n */\n\nfunction mdl_toggleDrawer() {\n    var layout = document.querySelector('.mdl-layout');\n    layout.MaterialLayout.toggleDrawer();\n}\n\n/*\n * Handler localStorage\n */\n\nfunction _localStorage(action, key, value) {\n    var storage = window.localStorage;\n\n    if (action == 'get') {\n        return storage.getItem(key);\n    } else if (action == 'save') {\n        if (storage.setItem(key, value)) {\n            return true;\n        }\n    } else if (action == 'remove') {\n        if (storage.removeItem(key)) {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n/*\n * Action to perform when the user is logged in\n */\n\nfunction userIsLoggedIn() {\n    _localStorage('save', 'pihole_success', 1);\n    $('#header_guest').hide();\n    $('#header_loggedin').show();\n\n    $('#logout').click(function (event) {\n        event.preventDefault();\n        _localStorage('remove', 'pihole_success');\n        _localStorage('remove', 'pihole_host');\n        _localStorage('remove', 'pihole_token');\n        userIsGuest();\n        pageAppSettings();\n    });\n}\n\n/*\n * Action to perform when the user is not logged in (guest)\n */\n\nfunction userIsGuest() {\n    $('#header_guest').show();\n    $('#header_loggedin').hide();\n    mdl_toggleDrawer();\n}\n\n/*\n * Get Pihole Hostname\n */\n\nfunction getPiholeHost() {\n    return _localStorage('get', 'pihole_host');\n}\n\n/*\n * Get Pihole Token\n */\n\nfunction getPiholeToken() {\n    return _localStorage('get', 'pihole_token');\n}\n\n/*\n * Get Pihole Success connect flag\n */\n\nfunction getPiholeSuccess() {\n    return _localStorage('get', 'pihole_success');\n}\n\n/*\n * Update MDL float label when there is a value on the input\n */\n\nfunction updateFloatLabel() {\n    var nodeList = document.querySelectorAll('.mdl-textfield');\n\n    Array.prototype.forEach.call(nodeList, function (elem) {\n        elem.MaterialTextfield.checkDirty();\n    });\n}\n\n/*\n * Update the App title according to active page\n */\n\nfunction updateAppTitle(title) {\n    $('.mdl-layout-title').html(title);\n}\n\n/*\n * Manage visibility of toggle button\n */\n\nfunction _manageVisibilityToggle(action) {\n    if(action == 'show') {\n        $('#container-pihole-toggle').show();\n    } else if(action == 'hide') {\n        $('#container-pihole-toggle').hide();\n    }\n}"
  },
  {
    "path": "platforms/browser/www/lib/DataTables/DataTables-1.10.13/css/dataTables.bootstrap.css",
    "content": "table.dataTable {\n  clear: both;\n  margin-top: 6px !important;\n  margin-bottom: 6px !important;\n  max-width: none !important;\n  border-collapse: separate !important;\n}\ntable.dataTable td,\ntable.dataTable th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable td.dataTables_empty,\ntable.dataTable th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.nowrap th,\ntable.dataTable.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper div.dataTables_length label {\n  font-weight: normal;\n  text-align: left;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_length select {\n  width: 75px;\n  display: inline-block;\n}\ndiv.dataTables_wrapper div.dataTables_filter {\n  text-align: right;\n}\ndiv.dataTables_wrapper div.dataTables_filter label {\n  font-weight: normal;\n  white-space: nowrap;\n  text-align: left;\n}\ndiv.dataTables_wrapper div.dataTables_filter input {\n  margin-left: 0.5em;\n  display: inline-block;\n  width: auto;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 8px;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_paginate {\n  margin: 0;\n  white-space: nowrap;\n  text-align: right;\n}\ndiv.dataTables_wrapper div.dataTables_paginate ul.pagination {\n  margin: 2px 0;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  margin-top: -26px;\n  text-align: center;\n  padding: 1em 0;\n}\n\ntable.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting,\ntable.dataTable thead > tr > td.sorting_asc,\ntable.dataTable thead > tr > td.sorting_desc,\ntable.dataTable thead > tr > td.sorting {\n  padding-right: 30px;\n}\ntable.dataTable thead > tr > th:active,\ntable.dataTable thead > tr > td:active {\n  outline: none;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  cursor: pointer;\n  position: relative;\n}\ntable.dataTable thead .sorting:after,\ntable.dataTable thead .sorting_asc:after,\ntable.dataTable thead .sorting_desc:after,\ntable.dataTable thead .sorting_asc_disabled:after,\ntable.dataTable thead .sorting_desc_disabled:after {\n  position: absolute;\n  bottom: 8px;\n  right: 8px;\n  display: block;\n  font-family: 'Glyphicons Halflings';\n  opacity: 0.5;\n}\ntable.dataTable thead .sorting:after {\n  opacity: 0.2;\n  content: \"\\e150\";\n  /* sort */\n}\ntable.dataTable thead .sorting_asc:after {\n  content: \"\\e155\";\n  /* sort-by-attributes */\n}\ntable.dataTable thead .sorting_desc:after {\n  content: \"\\e156\";\n  /* sort-by-attributes-alt */\n}\ntable.dataTable thead .sorting_asc_disabled:after,\ntable.dataTable thead .sorting_desc_disabled:after {\n  color: #eee;\n}\n\ndiv.dataTables_scrollHead table.dataTable {\n  margin-bottom: 0 !important;\n}\n\ndiv.dataTables_scrollBody table {\n  border-top: none;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\ndiv.dataTables_scrollBody table thead .sorting:after,\ndiv.dataTables_scrollBody table thead .sorting_asc:after,\ndiv.dataTables_scrollBody table thead .sorting_desc:after {\n  display: none;\n}\ndiv.dataTables_scrollBody table tbody tr:first-child th,\ndiv.dataTables_scrollBody table tbody tr:first-child td {\n  border-top: none;\n}\n\ndiv.dataTables_scrollFoot table {\n  margin-top: 0 !important;\n  border-top: none;\n}\n\n@media screen and (max-width: 767px) {\n  div.dataTables_wrapper div.dataTables_length,\n  div.dataTables_wrapper div.dataTables_filter,\n  div.dataTables_wrapper div.dataTables_info,\n  div.dataTables_wrapper div.dataTables_paginate {\n    text-align: center;\n  }\n}\ntable.dataTable.table-condensed > thead > tr > th {\n  padding-right: 20px;\n}\ntable.dataTable.table-condensed .sorting:after,\ntable.dataTable.table-condensed .sorting_asc:after,\ntable.dataTable.table-condensed .sorting_desc:after {\n  top: 6px;\n  right: 6px;\n}\n\ntable.table-bordered.dataTable th,\ntable.table-bordered.dataTable td {\n  border-left-width: 0;\n}\ntable.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child,\ntable.table-bordered.dataTable td:last-child,\ntable.table-bordered.dataTable td:last-child {\n  border-right-width: 0;\n}\ntable.table-bordered.dataTable tbody th,\ntable.table-bordered.dataTable tbody td {\n  border-bottom-width: 0;\n}\n\ndiv.dataTables_scrollHead table.table-bordered {\n  border-bottom-width: 0;\n}\n\ndiv.table-responsive > div.dataTables_wrapper > div.row {\n  margin: 0;\n}\ndiv.table-responsive > div.dataTables_wrapper > div.row > div[class^=\"col-\"]:first-child {\n  padding-left: 0;\n}\ndiv.table-responsive > div.dataTables_wrapper > div.row > div[class^=\"col-\"]:last-child {\n  padding-right: 0;\n}\n"
  },
  {
    "path": "platforms/browser/www/lib/DataTables/DataTables-1.10.13/css/dataTables.foundation.css",
    "content": "table.dataTable {\n  clear: both;\n  margin: 0.5em 0 !important;\n  max-width: none !important;\n  width: 100%;\n}\ntable.dataTable td,\ntable.dataTable th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable td.dataTables_empty,\ntable.dataTable th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper {\n  position: relative;\n}\ndiv.dataTables_wrapper div.dataTables_length label {\n  float: left;\n  text-align: left;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_length select {\n  width: 75px;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter label {\n  float: right;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter input {\n  display: inline-block !important;\n  width: auto !important;\n  margin-bottom: 0;\n  margin-left: 0.5em;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 2px;\n}\ndiv.dataTables_wrapper div.dataTables_paginate {\n  float: right;\n  margin: 0;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  margin-top: -26px;\n  text-align: center;\n  padding: 1rem 0;\n}\n\ntable.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting,\ntable.dataTable thead > tr > td.sorting_asc,\ntable.dataTable thead > tr > td.sorting_desc,\ntable.dataTable thead > tr > td.sorting {\n  padding-right: 1.5rem;\n}\ntable.dataTable thead > tr > th:active,\ntable.dataTable thead > tr > td:active {\n  outline: none;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc {\n  cursor: pointer;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"../images/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"../images/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"../images/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"../images/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"../images/sort_desc_disabled.png\");\n}\n\ndiv.dataTables_scrollHead table {\n  margin-bottom: 0 !important;\n}\n\ndiv.dataTables_scrollBody table {\n  border-top: none;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\ndiv.dataTables_scrollBody table tbody tr:first-child th,\ndiv.dataTables_scrollBody table tbody tr:first-child td {\n  border-top: none;\n}\n\ndiv.dataTables_scrollFoot table {\n  margin-top: 0 !important;\n  border-top: none;\n}\n"
  },
  {
    "path": "platforms/browser/www/lib/DataTables/DataTables-1.10.13/css/dataTables.jqueryui.css",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: #f6f6f6;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #fafafa;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #fafafa;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fcfcfc;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fefefe;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ececec;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #efefef;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em 1em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #979797;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  color: white !important;\n  border: 1px solid #111;\n  background-color: #585858;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #585858 0%, #111 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #585858 0%, #111 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #585858 0%, #111 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #585858 0%, #111 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  background-color: #2b2b2b;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);\n  /* W3C */\n  box-shadow: inset 0 0 3px #111;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td {\n  vertical-align: middle;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}\ntable.dataTable thead th div.DataTables_sort_wrapper {\n  position: relative;\n}\ntable.dataTable thead th div.DataTables_sort_wrapper span {\n  position: absolute;\n  top: 50%;\n  margin-top: -8px;\n  right: -18px;\n}\ntable.dataTable thead th.ui-state-default,\ntable.dataTable tfoot th.ui-state-default {\n  border-left-width: 0;\n}\ntable.dataTable thead th.ui-state-default:first-child,\ntable.dataTable tfoot th.ui-state-default:first-child {\n  border-left-width: 1px;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper .dataTables_paginate .fg-button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  border: 1px solid transparent;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:active {\n  outline: none;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:first-child {\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:last-child {\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.dataTables_wrapper .ui-widget-header {\n  font-weight: normal;\n}\n.dataTables_wrapper .ui-toolbar {\n  padding: 8px;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: none;\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: inherit;\n}\n"
  },
  {
    "path": "platforms/browser/www/lib/DataTables/DataTables-1.10.13/css/dataTables.semanticui.css",
    "content": "/*\n * Styling for DataTables with Semantic UI\n */\ntable.dataTable.table {\n  margin: 0;\n}\ntable.dataTable.table thead th,\ntable.dataTable.table thead td {\n  position: relative;\n}\ntable.dataTable.table thead th.sorting, table.dataTable.table thead th.sorting_asc, table.dataTable.table thead th.sorting_desc,\ntable.dataTable.table thead td.sorting,\ntable.dataTable.table thead td.sorting_asc,\ntable.dataTable.table thead td.sorting_desc {\n  padding-right: 20px;\n}\ntable.dataTable.table thead th.sorting:after, table.dataTable.table thead th.sorting_asc:after, table.dataTable.table thead th.sorting_desc:after,\ntable.dataTable.table thead td.sorting:after,\ntable.dataTable.table thead td.sorting_asc:after,\ntable.dataTable.table thead td.sorting_desc:after {\n  position: absolute;\n  top: 12px;\n  right: 8px;\n  display: block;\n  font-family: Icons;\n}\ntable.dataTable.table thead th.sorting:after,\ntable.dataTable.table thead td.sorting:after {\n  content: \"\\f0dc\";\n  color: #ddd;\n  font-size: 0.8em;\n}\ntable.dataTable.table thead th.sorting_asc:after,\ntable.dataTable.table thead td.sorting_asc:after {\n  content: \"\\f0de\";\n}\ntable.dataTable.table thead th.sorting_desc:after,\ntable.dataTable.table thead td.sorting_desc:after {\n  content: \"\\f0dd\";\n}\ntable.dataTable.table td,\ntable.dataTable.table th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable.table td.dataTables_empty,\ntable.dataTable.table th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.table.nowrap th,\ntable.dataTable.table.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper div.dataTables_length select {\n  vertical-align: middle;\n  min-height: 2.7142em;\n}\ndiv.dataTables_wrapper div.dataTables_length .ui.selection.dropdown {\n  min-width: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter input {\n  margin-left: 0.5em;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 13px;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  text-align: center;\n}\ndiv.dataTables_wrapper div.row.dt-table {\n  padding: 0;\n}\ndiv.dataTables_wrapper div.dataTables_scrollHead table.dataTable {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n  border-bottom: none;\n}\ndiv.dataTables_wrapper div.dataTables_scrollBody thead .sorting:after,\ndiv.dataTables_wrapper div.dataTables_scrollBody thead .sorting_asc:after,\ndiv.dataTables_wrapper div.dataTables_scrollBody thead .sorting_desc:after {\n  display: none;\n}\ndiv.dataTables_wrapper div.dataTables_scrollBody table.dataTable {\n  border-radius: 0;\n  border-top: none;\n  border-bottom-width: 0;\n}\ndiv.dataTables_wrapper div.dataTables_scrollBody table.dataTable.no-footer {\n  border-bottom-width: 1px;\n}\ndiv.dataTables_wrapper div.dataTables_scrollFoot table.dataTable {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n  border-top: none;\n}\n"
  },
  {
    "path": "platforms/browser/www/lib/DataTables/DataTables-1.10.13/css/jquery.dataTables.css",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px;\n  border-bottom: 1px solid #111;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n  border-top: 1px solid #111;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc {\n  cursor: pointer;\n  *cursor: hand;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"../images/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"../images/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"../images/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"../images/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"../images/sort_desc_disabled.png\");\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: #f6f6f6;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #fafafa;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #fafafa;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fcfcfc;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fefefe;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ececec;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #efefef;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em 1em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #979797;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  color: white !important;\n  border: 1px solid #111;\n  background-color: #585858;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #585858 0%, #111 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #585858 0%, #111 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #585858 0%, #111 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #585858 0%, #111 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  background-color: #2b2b2b;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);\n  /* W3C */\n  box-shadow: inset 0 0 3px #111;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td {\n  vertical-align: middle;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}\n"
  },
  {
    "path": "platforms/browser/www/lib/DataTables/DataTables-1.10.13/css/jquery.dataTables_themeroller.css",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable thead td,\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 4px 10px;\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting {\n  cursor: pointer;\n  *cursor: hand;\n}\ntable.dataTable thead th div.DataTables_sort_wrapper {\n  position: relative;\n  padding-right: 10px;\n}\ntable.dataTable thead th div.DataTables_sort_wrapper span {\n  position: absolute;\n  top: 50%;\n  margin-top: -8px;\n  right: -5px;\n}\ntable.dataTable thead th.ui-state-default {\n  border-right-width: 0;\n}\ntable.dataTable thead th.ui-state-default:last-child {\n  border-right-width: 1px;\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable th.center,\ntable.dataTable td.center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.right,\ntable.dataTable td.right {\n  text-align: right;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #abb9d3;\n}\ntable.dataTable.hover tbody tr:hover,\ntable.dataTable.hover tbody tr.odd:hover,\ntable.dataTable.hover tbody tr.even:hover, table.dataTable.display tbody tr:hover,\ntable.dataTable.display tbody tr.odd:hover,\ntable.dataTable.display tbody tr.even:hover {\n  background-color: whitesmoke;\n}\ntable.dataTable.hover tbody tr:hover.selected,\ntable.dataTable.hover tbody tr.odd:hover.selected,\ntable.dataTable.hover tbody tr.even:hover.selected, table.dataTable.display tbody tr:hover.selected,\ntable.dataTable.display tbody tr.odd:hover.selected,\ntable.dataTable.display tbody tr.even:hover.selected {\n  background-color: #a9b7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #f9f9f9;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad4;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b3cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a7b5ce;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b6d0;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #f9f9f9;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fbfbfb;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fdfdfd;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad4;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #adbbd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1,\ntable.dataTable.display tbody tr.odd:hover > .sorting_1,\ntable.dataTable.display tbody tr.even:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1,\ntable.dataTable.order-column.hover tbody tr.odd:hover > .sorting_1,\ntable.dataTable.order-column.hover tbody tr.even:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2,\ntable.dataTable.display tbody tr.odd:hover > .sorting_2,\ntable.dataTable.display tbody tr.even:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2,\ntable.dataTable.order-column.hover tbody tr.odd:hover > .sorting_2,\ntable.dataTable.order-column.hover tbody tr.even:hover > .sorting_2 {\n  background-color: #ebebeb;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3,\ntable.dataTable.display tbody tr.odd:hover > .sorting_3,\ntable.dataTable.display tbody tr.even:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3,\ntable.dataTable.order-column.hover tbody tr.odd:hover > .sorting_3,\ntable.dataTable.order-column.hover tbody tr.even:hover > .sorting_3 {\n  background-color: #eeeeee;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1,\ntable.dataTable.display tbody tr.odd:hover.selected > .sorting_1,\ntable.dataTable.display tbody tr.even:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1,\ntable.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_1,\ntable.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_1 {\n  background-color: #a1aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2,\ntable.dataTable.display tbody tr.odd:hover.selected > .sorting_2,\ntable.dataTable.display tbody tr.even:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2,\ntable.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_2,\ntable.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_2 {\n  background-color: #a2afc8;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3,\ntable.dataTable.display tbody tr.odd:hover.selected > .sorting_3,\ntable.dataTable.display tbody tr.even:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3,\ntable.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_3,\ntable.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_3 {\n  background-color: #a4b2cb;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 5px 9px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 5px 9px 3px 9px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px 5px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.55em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:active {\n  outline: none;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:first-child {\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:last-child {\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .ui-widget-header {\n  font-weight: normal;\n}\n.dataTables_wrapper .ui-toolbar {\n  padding: 8px;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter,\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter,\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n"
  },
  {
    "path": "platforms/browser/www/lib/DataTables/DataTables-1.10.13/js/dataTables.bootstrap.js",
    "content": "/*! DataTables Bootstrap 3 integration\n * ©2011-2015 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Bootstrap 3. This requires Bootstrap 3 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t// Require DataTables, which attaches to jQuery, including\n\t\t\t\t// jQuery if needed and have a $ property so we can access the\n\t\t\t\t// jQuery object that is used\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'row'<'col-sm-6'l><'col-sm-6'f>>\" +\n\t\t\"<'row'<'col-sm-12'tr>>\" +\n\t\t\"<'row'<'col-sm-5'i><'col-sm-7'p>>\",\n\trenderer: 'bootstrap'\n} );\n\n\n/* Default class modification */\n$.extend( DataTable.ext.classes, {\n\tsWrapper:      \"dataTables_wrapper form-inline dt-bootstrap\",\n\tsFilterInput:  \"form-control input-sm\",\n\tsLengthSelect: \"form-control input-sm\",\n\tsProcessing:   \"dataTables_processing panel panel-default\"\n} );\n\n\n/* Bootstrap paging button renderer */\nDataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api     = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang    = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass, counter=0;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'disabled';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'active' : '';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<li>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append( $('<a>', {\n\t\t\t\t\t\t\t\t'href': '#',\n\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\n\t\t\t\t\tcounter++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t// inside an iframe or frame. \n\tvar activeEl;\n\n\ttry {\n\t\t// Because this approach is destroying and recreating the paging\n\t\t// elements, focus is lost on the select button which is bad for\n\t\t// accessibility. So we want to restore focus once the draw has\n\t\t// completed\n\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t}\n\tcatch (e) {}\n\n\tattach(\n\t\t$(host).empty().html('<ul class=\"pagination\"/>').children('ul'),\n\t\tbuttons\n\t);\n\n\tif ( activeEl !== undefined ) {\n\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t}\n};\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "platforms/browser/www/lib/DataTables/DataTables-1.10.13/js/dataTables.foundation.js",
    "content": "/*! DataTables Foundation integration\n * ©2011-2015 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Foundation. This requires Foundation 5 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Foundation. See http://datatables.net/manual/styling/foundation\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n// Detect Foundation 5 / 6 as they have different element and class requirements\nvar meta = $('<meta class=\"foundation-mq\"/>').appendTo('head');\nDataTable.ext.foundationVersion = meta.css('font-family').match(/small|medium|large/) ? 6 : 5;\nmeta.remove();\n\n\n$.extend( DataTable.ext.classes, {\n\tsWrapper:    \"dataTables_wrapper dt-foundation\",\n\tsProcessing: \"dataTables_processing panel callout\"\n} );\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'row'<'small-6 columns'l><'small-6 columns'f>r>\"+\n\t\t\"t\"+\n\t\t\"<'row'<'small-6 columns'i><'small-6 columns'p>>\",\n\trenderer: 'foundation'\n} );\n\n\n/* Page button renderer */\nDataTable.ext.renderer.pageButton.foundation = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass;\n\tvar tag;\n\tvar v5 = DataTable.ext.foundationVersion === 5;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('unavailable') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\t\t\t\ttag = null;\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'unavailable disabled';\n\t\t\t\t\t\ttag = null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page > 0 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page > 0 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page < pages-1 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page < pages-1 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'current' : '';\n\t\t\t\t\t\ttag = page === button ?\n\t\t\t\t\t\t\tnull : 'a';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( v5 ) {\n\t\t\t\t\ttag = 'a';\n\t\t\t\t}\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<li>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append( tag ?\n\t\t\t\t\t\t\t$('<'+tag+'/>', {'href': '#'} ).html( btnDisplay ) :\n\t\t\t\t\t\t\tbtnDisplay\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tattach(\n\t\t$(host).empty().html('<ul class=\"pagination\"/>').children('ul'),\n\t\tbuttons\n\t);\n};\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "platforms/browser/www/lib/DataTables/DataTables-1.10.13/js/dataTables.jqueryui.js",
    "content": "/*! DataTables jQuery UI integration\n * ©2011-2014 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for jQuery UI. This requires jQuery UI and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using jQuery UI. See http://datatables.net/manual/styling/jqueryui\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar sort_prefix = 'css_right ui-icon ui-icon-';\nvar toolbar_prefix = 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix ui-corner-';\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t'<\"'+toolbar_prefix+'tl ui-corner-tr\"lfr>'+\n\t\t't'+\n\t\t'<\"'+toolbar_prefix+'bl ui-corner-br\"ip>',\n\trenderer: 'jqueryui'\n} );\n\n\n$.extend( DataTable.ext.classes, {\n\t\"sWrapper\":            \"dataTables_wrapper dt-jqueryui\",\n\n\t/* Full numbers paging buttons */\n\t\"sPageButton\":         \"fg-button ui-button ui-state-default\",\n\t\"sPageButtonActive\":   \"ui-state-disabled\",\n\t\"sPageButtonDisabled\": \"ui-state-disabled\",\n\n\t/* Features */\n\t\"sPaging\": \"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi \"+\n\t\t\"ui-buttonset-multi paging_\", /* Note that the type is postfixed */\n\n\t/* Sorting */\n\t\"sSortAsc\":            \"ui-state-default sorting_asc\",\n\t\"sSortDesc\":           \"ui-state-default sorting_desc\",\n\t\"sSortable\":           \"ui-state-default sorting\",\n\t\"sSortableAsc\":        \"ui-state-default sorting_asc_disabled\",\n\t\"sSortableDesc\":       \"ui-state-default sorting_desc_disabled\",\n\t\"sSortableNone\":       \"ui-state-default sorting_disabled\",\n\t\"sSortIcon\":           \"DataTables_sort_icon\",\n\n\t/* Scrolling */\n\t\"sScrollHead\": \"dataTables_scrollHead \"+\"ui-state-default\",\n\t\"sScrollFoot\": \"dataTables_scrollFoot \"+\"ui-state-default\",\n\n\t/* Misc */\n\t\"sHeaderTH\":  \"ui-state-default\",\n\t\"sFooterTH\":  \"ui-state-default\"\n} );\n\n\nDataTable.ext.renderer.header.jqueryui = function ( settings, cell, column, classes ) {\n\t// Calculate what the unsorted class should be\n\tvar noSortAppliedClass = sort_prefix+'carat-2-n-s';\n\tvar asc = $.inArray('asc', column.asSorting) !== -1;\n\tvar desc = $.inArray('desc', column.asSorting) !== -1;\n\n\tif ( !column.bSortable || (!asc && !desc) ) {\n\t\tnoSortAppliedClass = '';\n\t}\n\telse if ( asc && !desc ) {\n\t\tnoSortAppliedClass = sort_prefix+'carat-1-n';\n\t}\n\telse if ( !asc && desc ) {\n\t\tnoSortAppliedClass = sort_prefix+'carat-1-s';\n\t}\n\n\t// Setup the DOM structure\n\t$('<div/>')\n\t\t.addClass( 'DataTables_sort_wrapper' )\n\t\t.append( cell.contents() )\n\t\t.append( $('<span/>')\n\t\t\t.addClass( classes.sSortIcon+' '+noSortAppliedClass )\n\t\t)\n\t\t.appendTo( cell );\n\n\t// Attach a sort listener to update on sort\n\t$(settings.nTable).on( 'order.dt', function ( e, ctx, sorting, columns ) {\n\t\tif ( settings !== ctx ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar colIdx = column.idx;\n\n\t\tcell\n\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\tcolumn.sSortingClass\n\t\t\t);\n\n\t\tcell\n\t\t\t.find( 'span.'+classes.sSortIcon )\n\t\t\t.removeClass(\n\t\t\t\tsort_prefix+'triangle-1-n' +\" \"+\n\t\t\t\tsort_prefix+'triangle-1-s' +\" \"+\n\t\t\t\tsort_prefix+'carat-2-n-s' +\" \"+\n\t\t\t\tsort_prefix+'carat-1-n' +\" \"+\n\t\t\t\tsort_prefix+'carat-1-s'\n\t\t\t)\n\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\tsort_prefix+'triangle-1-n' : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\tsort_prefix+'triangle-1-s' :\n\t\t\t\t\tnoSortAppliedClass\n\t\t\t);\n\t} );\n};\n\n\n/*\n * TableTools jQuery UI compatibility\n * Required TableTools 2.1+\n */\nif ( DataTable.TableTools ) {\n\t$.extend( true, DataTable.TableTools.classes, {\n\t\t\"container\": \"DTTT_container ui-buttonset ui-buttonset-multi\",\n\t\t\"buttons\": {\n\t\t\t\"normal\": \"DTTT_button ui-button ui-state-default\"\n\t\t},\n\t\t\"collection\": {\n\t\t\t\"container\": \"DTTT_collection ui-buttonset ui-buttonset-multi\"\n\t\t}\n\t} );\n}\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "platforms/browser/www/lib/DataTables/DataTables-1.10.13/js/dataTables.semanticui.js",
    "content": "/*! DataTables Bootstrap 3 integration\n * ©2011-2015 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Bootstrap 3. This requires Bootstrap 3 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t// Require DataTables, which attaches to jQuery, including\n\t\t\t\t// jQuery if needed and have a $ property so we can access the\n\t\t\t\t// jQuery object that is used\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'ui grid'\"+\n\t\t\t\"<'row'\"+\n\t\t\t\t\"<'eight wide column'l>\"+\n\t\t\t\t\"<'right aligned eight wide column'f>\"+\n\t\t\t\">\"+\n\t\t\t\"<'row dt-table'\"+\n\t\t\t\t\"<'sixteen wide column'tr>\"+\n\t\t\t\">\"+\n\t\t\t\"<'row'\"+\n\t\t\t\t\"<'seven wide column'i>\"+\n\t\t\t\t\"<'right aligned nine wide column'p>\"+\n\t\t\t\">\"+\n\t\t\">\",\n\trenderer: 'semanticUI'\n} );\n\n\n/* Default class modification */\n$.extend( DataTable.ext.classes, {\n\tsWrapper:      \"dataTables_wrapper dt-semanticUI\",\n\tsFilter:       \"dataTables_filter ui input\",\n\tsProcessing:   \"dataTables_processing ui segment\",\n\tsPageButton:   \"paginate_button item\"\n} );\n\n\n/* Bootstrap paging button renderer */\nDataTable.ext.renderer.pageButton.semanticUI = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api     = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang    = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass, counter=0;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'disabled';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'active' : '';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tvar tag = btnClass.indexOf( 'disabled' ) === -1 ?\n\t\t\t\t\t'a' :\n\t\t\t\t\t'div';\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<'+tag+'>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t'href': '#',\n\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t'tabindex': settings.iTabIndex\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\n\t\t\t\t\tcounter++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t// inside an iframe or frame. \n\tvar activeEl;\n\n\ttry {\n\t\t// Because this approach is destroying and recreating the paging\n\t\t// elements, focus is lost on the select button which is bad for\n\t\t// accessibility. So we want to restore focus once the draw has\n\t\t// completed\n\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t}\n\tcatch (e) {}\n\n\tattach(\n\t\t$(host).empty().html('<div class=\"ui pagination menu\"/>').children(),\n\t\tbuttons\n\t);\n\n\tif ( activeEl !== undefined ) {\n\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t}\n};\n\n\n// Javascript enhancements on table initialisation\n$(document).on( 'init.dt', function (e, ctx) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\t// Length menu drop down\n\tif ( $.fn.dropdown ) {\n\t\tvar api = new $.fn.dataTable.Api( ctx );\n\n\t\t$( 'div.dataTables_length select', api.table().container() ).dropdown();\n\t}\n} );\n\n\nreturn DataTable;\n}));"
  },
  {
    "path": "platforms/browser/www/lib/DataTables/DataTables-1.10.13/js/jquery.dataTables.js",
    "content": "/*! DataTables 1.10.13\n * ©2008-2016 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     DataTables\n * @description Paginate, search and order HTML tables\n * @version     1.10.13\n * @file        jquery.dataTables.js\n * @author      SpryMedia Ltd\n * @contact     www.datatables.net\n * @copyright   Copyright 2008-2016 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n/*jslint evil: true, undef: true, browser: true */\n/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/\n\n(function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\t// CommonJS environments without a window global must pass a\n\t\t\t\t// root. This will give an error otherwise\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ ) {\n\t\t\t\t$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window\n\t\t\t\t\trequire('jquery') :\n\t\t\t\t\trequire('jquery')( root );\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}\n(function( $, window, document, undefined ) {\n\t\"use strict\";\n\n\t/**\n\t * DataTables is a plug-in for the jQuery Javascript library. It is a highly\n\t * flexible tool, based upon the foundations of progressive enhancement,\n\t * which will add advanced interaction controls to any HTML table. For a\n\t * full list of features please refer to\n\t * [DataTables.net](href=\"http://datatables.net).\n\t *\n\t * Note that the `DataTable` object is not a global variable but is aliased\n\t * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may\n\t * be  accessed.\n\t *\n\t *  @class\n\t *  @param {object} [init={}] Configuration object for DataTables. Options\n\t *    are defined by {@link DataTable.defaults}\n\t *  @requires jQuery 1.7+\n\t *\n\t *  @example\n\t *    // Basic initialisation\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable();\n\t *    } );\n\t *\n\t *  @example\n\t *    // Initialisation with configuration options - in this case, disable\n\t *    // pagination and sorting.\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable( {\n\t *        \"paginate\": false,\n\t *        \"sort\": false\n\t *      } );\n\t *    } );\n\t */\n\tvar DataTable = function ( options )\n\t{\n\t\t/**\n\t\t * Perform a jQuery selector action on the table's TR elements (from the tbody) and\n\t\t * return the resulting jQuery object.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter\n\t\t *    criterion (\"applied\") or all TR elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {object} jQuery object, filtered by the given selector.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Highlight every second row\n\t\t *      oTable.$('tr:odd').css('backgroundColor', 'blue');\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to rows with 'Webkit' in them, add a background colour and then\n\t\t *      // remove the filter, thus highlighting the 'Webkit' rows only.\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      oTable.$('tr', {\"search\": \"applied\"}).css('backgroundColor', 'blue');\n\t\t *      oTable.fnFilter('');\n\t\t *    } );\n\t\t */\n\t\tthis.$ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).$( sSelector, oOpts );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Almost identical to $ in operation, but in this case returns the data for the matched\n\t\t * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes\n\t\t * rather than any descendants, so the data can be obtained for the row/cell. If matching\n\t\t * rows are found, the data returned is the original data array/object that was used to\n\t\t * create the row (or a generated array if from a DOM source).\n\t\t *\n\t\t * This method is often useful in-combination with $ where both functions are given the\n\t\t * same parameters and the array indexes will match identically.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select elements that meet the current filter\n\t\t *    criterion (\"applied\") or all elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the data in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {array} Data for the matched elements. If any elements, as a result of the\n\t\t *    selector, were not TR, TD or TH elements in the DataTable, they will have a null\n\t\t *    entry in the array.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the data from the first row in the table\n\t\t *      var data = oTable._('tr:first');\n\t\t *\n\t\t *      // Do something useful with the data\n\t\t *      alert( \"First cell is: \"+data[0] );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to 'Webkit' and get all data for\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      var data = oTable._('tr', {\"search\": \"applied\"});\n\t\t *\n\t\t *      // Do something with the data\n\t\t *      alert( data.length+\" rows matched the search\" );\n\t\t *    } );\n\t\t */\n\t\tthis._ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).rows( sSelector, oOpts ).data();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Create a DataTables Api instance, with the currently selected tables for\n\t\t * the Api's context.\n\t\t * @param {boolean} [traditional=false] Set the API instance's context to be\n\t\t *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was\n\t\t *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),\n\t\t *   or if all tables captured in the jQuery object should be used.\n\t\t * @return {DataTables.Api}\n\t\t */\n\t\tthis.api = function ( traditional )\n\t\t{\n\t\t\treturn traditional ?\n\t\t\t\tnew _Api(\n\t\t\t\t\t_fnSettingsFromNode( this[ _ext.iApiIndex ] )\n\t\t\t\t) :\n\t\t\t\tnew _Api( this );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Add a single new row or multiple rows of data to the table. Please note\n\t\t * that this is suitable for client-side processing only - if you are using\n\t\t * server-side processing (i.e. \"bServerSide\": true), then to add data, you\n\t\t * must add it to the data source, i.e. the server-side, through an Ajax call.\n\t\t *  @param {array|object} data The data to be added to the table. This can be:\n\t\t *    <ul>\n\t\t *      <li>1D array of data - add a single row with the data provided</li>\n\t\t *      <li>2D array of arrays - add multiple rows in a single call</li>\n\t\t *      <li>object - data object when using <i>mData</i></li>\n\t\t *      <li>array of objects - multiple data objects when using <i>mData</i></li>\n\t\t *    </ul>\n\t\t *  @param {bool} [redraw=true] redraw the table or not\n\t\t *  @returns {array} An array of integers, representing the list of indexes in\n\t\t *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to\n\t\t *    the table.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Global var for counter\n\t\t *    var giCount = 2;\n\t\t *\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example').dataTable();\n\t\t *    } );\n\t\t *\n\t\t *    function fnClickAddRow() {\n\t\t *      $('#example').dataTable().fnAddData( [\n\t\t *        giCount+\".1\",\n\t\t *        giCount+\".2\",\n\t\t *        giCount+\".3\",\n\t\t *        giCount+\".4\" ]\n\t\t *      );\n\t\t *\n\t\t *      giCount++;\n\t\t *    }\n\t\t */\n\t\tthis.fnAddData = function( data, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\t/* Check if we want to add multiple rows or not */\n\t\t\tvar rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?\n\t\t\t\tapi.rows.add( data ) :\n\t\t\t\tapi.row.add( data );\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn rows.flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will make DataTables recalculate the column sizes, based on the data\n\t\t * contained in the table and the sizes applied to the columns (in the DOM, CSS or\n\t\t * through the sWidth parameter). This can be useful when the width of the table's\n\t\t * parent element changes (for example a window resize).\n\t\t *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable( {\n\t\t *        \"sScrollY\": \"200px\",\n\t\t *        \"bPaginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      $(window).on('resize', function () {\n\t\t *        oTable.fnAdjustColumnSizing();\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnAdjustColumnSizing = function ( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).columns.adjust();\n\t\t\tvar settings = api.settings()[0];\n\t\t\tvar scroll = settings.oScroll;\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw( false );\n\t\t\t}\n\t\t\telse if ( scroll.sX !== \"\" || scroll.sY !== \"\" ) {\n\t\t\t\t/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */\n\t\t\t\t_fnScrollDraw( settings );\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Quickly and simply clear a table\n\t\t *  @param {bool} [bRedraw=true] redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)\n\t\t *      oTable.fnClearTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClearTable = function( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).clear();\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * The exact opposite of 'opening' a row, this function will close any rows which\n\t\t * are currently 'open'.\n\t\t *  @param {node} nTr the table row to 'close'\n\t\t *  @returns {int} 0 on success, or 1 if failed (can't find the row)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClose = function( nTr )\n\t\t{\n\t\t\tthis.api( true ).row( nTr ).child.hide();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Remove a row for the table\n\t\t *  @param {mixed} target The index of the row from aoData to be deleted, or\n\t\t *    the TR element you want to delete\n\t\t *  @param {function|null} [callBack] Callback function\n\t\t *  @param {bool} [redraw=true] Redraw the table or not\n\t\t *  @returns {array} The row that was deleted\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately remove the first row\n\t\t *      oTable.fnDeleteRow( 0 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnDeleteRow = function( target, callback, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar rows = api.rows( target );\n\t\t\tvar settings = rows.settings()[0];\n\t\t\tvar data = settings.aoData[ rows[0][0] ];\n\t\t\n\t\t\trows.remove();\n\t\t\n\t\t\tif ( callback ) {\n\t\t\t\tcallback.call( this, settings, data );\n\t\t\t}\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn data;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Restore the table to it's original state in the DOM by removing all of DataTables\n\t\t * enhancements, alterations to the DOM structure of the table and event listeners.\n\t\t *  @param {boolean} [remove=false] Completely remove the table from the DOM\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      // This example is fairly pointless in reality, but shows how fnDestroy can be used\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnDestroy();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDestroy = function ( remove )\n\t\t{\n\t\t\tthis.api( true ).destroy( remove );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Redraw the table\n\t\t *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)\n\t\t *      oTable.fnDraw();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDraw = function( complete )\n\t\t{\n\t\t\t// Note that this isn't an exact match to the old call to _fnDraw - it takes\n\t\t\t// into account the new data, but can hold position.\n\t\t\tthis.api( true ).draw( complete );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Filter the input based on data\n\t\t *  @param {string} sInput String to filter the table on\n\t\t *  @param {int|null} [iColumn] Column to limit filtering to\n\t\t *  @param {bool} [bRegex=false] Treat as regular expression or not\n\t\t *  @param {bool} [bSmart=true] Perform smart filtering or not\n\t\t *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)\n\t\t *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sometime later - filter...\n\t\t *      oTable.fnFilter( 'test string' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === null || iColumn === undefined ) {\n\t\t\t\tapi.search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\n\t\t\tapi.draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the data for the whole table, an individual row or an individual cell based on the\n\t\t * provided parameters.\n\t\t *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as\n\t\t *    a TR node then the data source for the whole row will be returned. If given as a\n\t\t *    TD/TH cell node then iCol will be automatically calculated and the data for the\n\t\t *    cell returned. If given as an integer, then this is treated as the aoData internal\n\t\t *    data index for the row (see fnGetPosition) and the data for that row used.\n\t\t *  @param {int} [col] Optional column index that you want the data of.\n\t\t *  @returns {array|object|string} If mRow is undefined, then the data for all rows is\n\t\t *    returned. If mRow is defined, just data for that row, and is iCol is\n\t\t *    defined, only data for the designated cell is returned.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Row data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('tr').click( function () {\n\t\t *        var data = oTable.fnGetData( this );\n\t\t *        // ... do something with the array / object of data for the row\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Individual cell data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('td').click( function () {\n\t\t *        var sData = oTable.fnGetData( this );\n\t\t *        alert( 'The cell clicked on had the value of '+sData );\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetData = function( src, col )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( src !== undefined ) {\n\t\t\t\tvar type = src.nodeName ? src.nodeName.toLowerCase() : '';\n\t\t\n\t\t\t\treturn col !== undefined || type == 'td' || type == 'th' ?\n\t\t\t\t\tapi.cell( src, col ).data() :\n\t\t\t\t\tapi.row( src ).data() || null;\n\t\t\t}\n\t\t\n\t\t\treturn api.data().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get an array of the TR nodes that are used in the table's body. Note that you will\n\t\t * typically want to use the '$' API method in preference to this as it is more\n\t\t * flexible.\n\t\t *  @param {int} [iRow] Optional row index for the TR element you want\n\t\t *  @returns {array|node} If iRow is undefined, returns an array of all TR elements\n\t\t *    in the table's body, or iRow is defined, just the TR element requested.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the nodes from the table\n\t\t *      var nNodes = oTable.fnGetNodes( );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetNodes = function( iRow )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\treturn iRow !== undefined ?\n\t\t\t\tapi.row( iRow ).node() :\n\t\t\t\tapi.rows().nodes().flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the array indexes of a particular cell from it's DOM element\n\t\t * and column index including hidden columns\n\t\t *  @param {node} node this can either be a TR, TD or TH in the table's body\n\t\t *  @returns {int} If nNode is given as a TR, then a single index is returned, or\n\t\t *    if given as a cell, an array of [row index, column index (visible),\n\t\t *    column index (all)] is given.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example tbody td').click( function () {\n\t\t *        // Get the position of the current data from the node\n\t\t *        var aPos = oTable.fnGetPosition( this );\n\t\t *\n\t\t *        // Get the data array for this row\n\t\t *        var aData = oTable.fnGetData( aPos[0] );\n\t\t *\n\t\t *        // Update the data array and return the value\n\t\t *        aData[ aPos[1] ] = 'clicked';\n\t\t *        this.innerHTML = 'clicked';\n\t\t *      } );\n\t\t *\n\t\t *      // Init DataTables\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetPosition = function( node )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar nodeName = node.nodeName.toUpperCase();\n\t\t\n\t\t\tif ( nodeName == 'TR' ) {\n\t\t\t\treturn api.row( node ).index();\n\t\t\t}\n\t\t\telse if ( nodeName == 'TD' || nodeName == 'TH' ) {\n\t\t\t\tvar cell = api.cell( node ).index();\n\t\t\n\t\t\t\treturn [\n\t\t\t\t\tcell.row,\n\t\t\t\t\tcell.columnVisible,\n\t\t\t\t\tcell.column\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Check to see if a row is 'open' or not.\n\t\t *  @param {node} nTr the table row to check\n\t\t *  @returns {boolean} true if the row is currently open, false otherwise\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnIsOpen = function( nTr )\n\t\t{\n\t\t\treturn this.api( true ).row( nTr ).child.isShown();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will place a new row directly after a row which is currently\n\t\t * on display on the page, with the HTML contents that is passed into the\n\t\t * function. This can be used, for example, to ask for confirmation that a\n\t\t * particular record should be deleted.\n\t\t *  @param {node} nTr The table row to 'open'\n\t\t *  @param {string|node|jQuery} mHtml The HTML to put into the row\n\t\t *  @param {string} sClass Class to give the new TD cell\n\t\t *  @returns {node} The row opened. Note that if the table row passed in as the\n\t\t *    first parameter, is not found in the table, this method will silently\n\t\t *    return.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnOpen = function( nTr, mHtml, sClass )\n\t\t{\n\t\t\treturn this.api( true )\n\t\t\t\t.row( nTr )\n\t\t\t\t.child( mHtml, sClass )\n\t\t\t\t.show()\n\t\t\t\t.child()[0];\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Change the pagination - provides the internal logic for pagination in a simple API\n\t\t * function. With this function you can have a DataTables table go to the next,\n\t\t * previous, first or last pages.\n\t\t *  @param {string|int} mAction Paging action to take: \"first\", \"previous\", \"next\" or \"last\"\n\t\t *    or page number to jump to (integer), note that page 0 is the first page.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnPageChange( 'next' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnPageChange = function ( mAction, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).page( mAction );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw(false);\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Show a particular column\n\t\t *  @param {int} iCol The column whose display should be changed\n\t\t *  @param {bool} bShow Show (true) or hide (false) the column\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Hide the second column after initialisation\n\t\t *      oTable.fnSetColumnVis( 1, false );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSetColumnVis = function ( iCol, bShow, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).column( iCol ).visible( bShow );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.columns.adjust().draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the settings for a particular table for external manipulation\n\t\t *  @returns {object} DataTables settings object. See\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      var oSettings = oTable.fnSettings();\n\t\t *\n\t\t *      // Show an example parameter from the settings\n\t\t *      alert( oSettings._iDisplayStart );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSettings = function()\n\t\t{\n\t\t\treturn _fnSettingsFromNode( this[_ext.iApiIndex] );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Sort the table by a particular column\n\t\t *  @param {int} iCol the data index to sort on. Note that this will not match the\n\t\t *    'display index' if you have hidden data entries\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort immediately with columns 0 and 1\n\t\t *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSort = function( aaSort )\n\t\t{\n\t\t\tthis.api( true ).order( aaSort ).draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Attach a sort listener to an element for a given column\n\t\t *  @param {node} nNode the element to attach the sort listener to\n\t\t *  @param {int} iColumn the column that a click on this node will sort on\n\t\t *  @param {function} [fnCallback] callback function when sort is run\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort on column 1, when 'sorter' is clicked on\n\t\t *      oTable.fnSortListener( document.getElementById('sorter'), 1 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSortListener = function( nNode, iColumn, fnCallback )\n\t\t{\n\t\t\tthis.api( true ).order.listener( nNode, iColumn, fnCallback );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Update a table cell or row - this method will accept either a single value to\n\t\t * update the cell with, an array of values with one element for each column or\n\t\t * an object in the same format as the original data source. The function is\n\t\t * self-referencing in order to make the multi column updates easier.\n\t\t *  @param {object|array|string} mData Data to update the cell/row with\n\t\t *  @param {node|int} mRow TR element you want to update or the aoData index\n\t\t *  @param {int} [iColumn] The column to update, give as null or undefined to\n\t\t *    update a whole row.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @param {bool} [bAction=true] Perform pre-draw actions or not\n\t\t *  @returns {int} 0 on success, 1 on error\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell\n\t\t *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row\n\t\t *    } );\n\t\t */\n\t\tthis.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === undefined || iColumn === null ) {\n\t\t\t\tapi.row( mRow ).data( mData );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.cell( mRow, iColumn ).data( mData );\n\t\t\t}\n\t\t\n\t\t\tif ( bAction === undefined || bAction ) {\n\t\t\t\tapi.columns.adjust();\n\t\t\t}\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Provide a common method for plug-ins to check the version of DataTables being used, in order\n\t\t * to ensure compatibility.\n\t\t *  @param {string} sVersion Version string to check for, in the format \"X.Y.Z\". Note that the\n\t\t *    formats \"X\" and \"X.Y\" are also acceptable.\n\t\t *  @returns {boolean} true if this version of DataTables is greater or equal to the required\n\t\t *    version, or false if this version of DataTales is not suitable\n\t\t *  @method\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      alert( oTable.fnVersionCheck( '1.9.0' ) );\n\t\t *    } );\n\t\t */\n\t\tthis.fnVersionCheck = _ext.fnVersionCheck;\n\t\t\n\n\t\tvar _that = this;\n\t\tvar emptyInit = options === undefined;\n\t\tvar len = this.length;\n\n\t\tif ( emptyInit ) {\n\t\t\toptions = {};\n\t\t}\n\n\t\tthis.oApi = this.internal = _ext.internal;\n\n\t\t// Extend with old style plug-in API methods\n\t\tfor ( var fn in DataTable.ext.internal ) {\n\t\t\tif ( fn ) {\n\t\t\t\tthis[fn] = _fnExternApiFunc(fn);\n\t\t\t}\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\t// For each initialisation we want to give it a clean initialisation\n\t\t\t// object that can be bashed around\n\t\t\tvar o = {};\n\t\t\tvar oInit = len > 1 ? // optimisation for single table case\n\t\t\t\t_fnExtend( o, options, true ) :\n\t\t\t\toptions;\n\n\t\t\t/*global oInit,_that,emptyInit*/\n\t\t\tvar i=0, iLen, j, jLen, k, kLen;\n\t\t\tvar sId = this.getAttribute( 'id' );\n\t\t\tvar bInitHandedOff = false;\n\t\t\tvar defaults = DataTable.defaults;\n\t\t\tvar $this = $(this);\n\t\t\t\n\t\t\t\n\t\t\t/* Sanity check */\n\t\t\tif ( this.nodeName.toLowerCase() != 'table' )\n\t\t\t{\n\t\t\t\t_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/* Backwards compatibility for the defaults */\n\t\t\t_fnCompatOpts( defaults );\n\t\t\t_fnCompatCols( defaults.column );\n\t\t\t\n\t\t\t/* Convert the camel-case defaults to Hungarian */\n\t\t\t_fnCamelToHungarian( defaults, defaults, true );\n\t\t\t_fnCamelToHungarian( defaults.column, defaults.column, true );\n\t\t\t\n\t\t\t/* Setting up the initialisation object */\n\t\t\t_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/* Check to see if we are re-initialising a table */\n\t\t\tvar allSettings = DataTable.settings;\n\t\t\tfor ( i=0, iLen=allSettings.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tvar s = allSettings[i];\n\t\t\t\n\t\t\t\t/* Base check on table node */\n\t\t\t\tif ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )\n\t\t\t\t{\n\t\t\t\t\tvar bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;\n\t\t\t\t\tvar bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;\n\t\t\t\n\t\t\t\t\tif ( emptyInit || bRetrieve )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn s.oInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( bDestroy )\n\t\t\t\t\t{\n\t\t\t\t\t\ts.oInstance.fnDestroy();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* If the element we are initialising has the same ID as a table which was previously\n\t\t\t\t * initialised, but the table nodes don't match (from before) then we destroy the old\n\t\t\t\t * instance by simply deleting it. This is under the assumption that the table has been\n\t\t\t\t * destroyed by other methods. Anyone using non-id selectors will need to do this manually\n\t\t\t\t */\n\t\t\t\tif ( s.sTableId == this.id )\n\t\t\t\t{\n\t\t\t\t\tallSettings.splice( i, 1 );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Ensure the table has an ID - required for accessibility */\n\t\t\tif ( sId === null || sId === \"\" )\n\t\t\t{\n\t\t\t\tsId = \"DataTables_Table_\"+(DataTable.ext._unique++);\n\t\t\t\tthis.id = sId;\n\t\t\t}\n\t\t\t\n\t\t\t/* Create the settings object for this table and set some of the default parameters */\n\t\t\tvar oSettings = $.extend( true, {}, DataTable.models.oSettings, {\n\t\t\t\t\"sDestroyWidth\": $this[0].style.width,\n\t\t\t\t\"sInstance\":     sId,\n\t\t\t\t\"sTableId\":      sId\n\t\t\t} );\n\t\t\toSettings.nTable = this;\n\t\t\toSettings.oApi   = _that.internal;\n\t\t\toSettings.oInit  = oInit;\n\t\t\t\n\t\t\tallSettings.push( oSettings );\n\t\t\t\n\t\t\t// Need to add the instance after the instance after the settings object has been added\n\t\t\t// to the settings array, so we can self reference the table instance if more than one\n\t\t\toSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();\n\t\t\t\n\t\t\t// Backwards compatibility, before we apply all the defaults\n\t\t\t_fnCompatOpts( oInit );\n\t\t\t\n\t\t\tif ( oInit.oLanguage )\n\t\t\t{\n\t\t\t\t_fnLanguageCompat( oInit.oLanguage );\n\t\t\t}\n\t\t\t\n\t\t\t// If the length menu is given, but the init display length is not, use the length menu\n\t\t\tif ( oInit.aLengthMenu && ! oInit.iDisplayLength )\n\t\t\t{\n\t\t\t\toInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?\n\t\t\t\t\toInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];\n\t\t\t}\n\t\t\t\n\t\t\t// Apply the defaults and init options to make a single init object will all\n\t\t\t// options defined from defaults and instance options.\n\t\t\toInit = _fnExtend( $.extend( true, {}, defaults ), oInit );\n\t\t\t\n\t\t\t\n\t\t\t// Map the initialisation options onto the settings object\n\t\t\t_fnMap( oSettings.oFeatures, oInit, [\n\t\t\t\t\"bPaginate\",\n\t\t\t\t\"bLengthChange\",\n\t\t\t\t\"bFilter\",\n\t\t\t\t\"bSort\",\n\t\t\t\t\"bSortMulti\",\n\t\t\t\t\"bInfo\",\n\t\t\t\t\"bProcessing\",\n\t\t\t\t\"bAutoWidth\",\n\t\t\t\t\"bSortClasses\",\n\t\t\t\t\"bServerSide\",\n\t\t\t\t\"bDeferRender\"\n\t\t\t] );\n\t\t\t_fnMap( oSettings, oInit, [\n\t\t\t\t\"asStripeClasses\",\n\t\t\t\t\"ajax\",\n\t\t\t\t\"fnServerData\",\n\t\t\t\t\"fnFormatNumber\",\n\t\t\t\t\"sServerMethod\",\n\t\t\t\t\"aaSorting\",\n\t\t\t\t\"aaSortingFixed\",\n\t\t\t\t\"aLengthMenu\",\n\t\t\t\t\"sPaginationType\",\n\t\t\t\t\"sAjaxSource\",\n\t\t\t\t\"sAjaxDataProp\",\n\t\t\t\t\"iStateDuration\",\n\t\t\t\t\"sDom\",\n\t\t\t\t\"bSortCellsTop\",\n\t\t\t\t\"iTabIndex\",\n\t\t\t\t\"fnStateLoadCallback\",\n\t\t\t\t\"fnStateSaveCallback\",\n\t\t\t\t\"renderer\",\n\t\t\t\t\"searchDelay\",\n\t\t\t\t\"rowId\",\n\t\t\t\t[ \"iCookieDuration\", \"iStateDuration\" ], // backwards compat\n\t\t\t\t[ \"oSearch\", \"oPreviousSearch\" ],\n\t\t\t\t[ \"aoSearchCols\", \"aoPreSearchCols\" ],\n\t\t\t\t[ \"iDisplayLength\", \"_iDisplayLength\" ],\n\t\t\t\t[ \"bJQueryUI\", \"bJUI\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oScroll, oInit, [\n\t\t\t\t[ \"sScrollX\", \"sX\" ],\n\t\t\t\t[ \"sScrollXInner\", \"sXInner\" ],\n\t\t\t\t[ \"sScrollY\", \"sY\" ],\n\t\t\t\t[ \"bScrollCollapse\", \"bCollapse\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oLanguage, oInit, \"fnInfoCallback\" );\n\t\t\t\n\t\t\t/* Callback functions which are array driven */\n\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );\n\t\t\t\n\t\t\toSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );\n\t\t\t\n\t\t\t/* Browser support detection */\n\t\t\t_fnBrowserDetect( oSettings );\n\t\t\t\n\t\t\tvar oClasses = oSettings.oClasses;\n\t\t\t\n\t\t\t// @todo Remove in 1.11\n\t\t\tif ( oInit.bJQueryUI )\n\t\t\t{\n\t\t\t\t/* Use the JUI classes object for display. You could clone the oStdClasses object if\n\t\t\t\t * you want to have multiple tables with multiple independent classes\n\t\t\t\t */\n\t\t\t\t$.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );\n\t\t\t\n\t\t\t\tif ( oInit.sDom === defaults.sDom && defaults.sDom === \"lfrtip\" )\n\t\t\t\t{\n\t\t\t\t\t/* Set the DOM to use a layout suitable for jQuery UI's theming */\n\t\t\t\t\toSettings.sDom = '<\"H\"lfr>t<\"F\"ip>';\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( ! oSettings.renderer ) {\n\t\t\t\t\toSettings.renderer = 'jqueryui';\n\t\t\t\t}\n\t\t\t\telse if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {\n\t\t\t\t\toSettings.renderer.header = 'jqueryui';\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );\n\t\t\t}\n\t\t\t$this.addClass( oClasses.sTable );\n\t\t\t\n\t\t\t\n\t\t\tif ( oSettings.iInitDisplayStart === undefined )\n\t\t\t{\n\t\t\t\t/* Display start point, taking into account the save saving */\n\t\t\t\toSettings.iInitDisplayStart = oInit.iDisplayStart;\n\t\t\t\toSettings._iDisplayStart = oInit.iDisplayStart;\n\t\t\t}\n\t\t\t\n\t\t\tif ( oInit.iDeferLoading !== null )\n\t\t\t{\n\t\t\t\toSettings.bDeferLoading = true;\n\t\t\t\tvar tmp = $.isArray( oInit.iDeferLoading );\n\t\t\t\toSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;\n\t\t\t\toSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;\n\t\t\t}\n\t\t\t\n\t\t\t/* Language definitions */\n\t\t\tvar oLanguage = oSettings.oLanguage;\n\t\t\t$.extend( true, oLanguage, oInit.oLanguage );\n\t\t\t\n\t\t\tif ( oLanguage.sUrl )\n\t\t\t{\n\t\t\t\t/* Get the language definitions from a file - because this Ajax call makes the language\n\t\t\t\t * get async to the remainder of this function we use bInitHandedOff to indicate that\n\t\t\t\t * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor\n\t\t\t\t */\n\t\t\t\t$.ajax( {\n\t\t\t\t\tdataType: 'json',\n\t\t\t\t\turl: oLanguage.sUrl,\n\t\t\t\t\tsuccess: function ( json ) {\n\t\t\t\t\t\t_fnLanguageCompat( json );\n\t\t\t\t\t\t_fnCamelToHungarian( defaults.oLanguage, json );\n\t\t\t\t\t\t$.extend( true, oLanguage, json );\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t},\n\t\t\t\t\terror: function () {\n\t\t\t\t\t\t// Error occurred loading language file, continue on as best we can\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tbInitHandedOff = true;\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Stripes\n\t\t\t */\n\t\t\tif ( oInit.asStripeClasses === null )\n\t\t\t{\n\t\t\t\toSettings.asStripeClasses =[\n\t\t\t\t\toClasses.sStripeOdd,\n\t\t\t\t\toClasses.sStripeEven\n\t\t\t\t];\n\t\t\t}\n\t\t\t\n\t\t\t/* Remove row stripe classes if they are already on the table row */\n\t\t\tvar stripeClasses = oSettings.asStripeClasses;\n\t\t\tvar rowOne = $this.children('tbody').find('tr').eq(0);\n\t\t\tif ( $.inArray( true, $.map( stripeClasses, function(el, i) {\n\t\t\t\treturn rowOne.hasClass(el);\n\t\t\t} ) ) !== -1 ) {\n\t\t\t\t$('tbody tr', this).removeClass( stripeClasses.join(' ') );\n\t\t\t\toSettings.asDestroyStripes = stripeClasses.slice();\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Columns\n\t\t\t * See if we should load columns automatically or use defined ones\n\t\t\t */\n\t\t\tvar anThs = [];\n\t\t\tvar aoColumnsInit;\n\t\t\tvar nThead = this.getElementsByTagName('thead');\n\t\t\tif ( nThead.length !== 0 )\n\t\t\t{\n\t\t\t\t_fnDetectHeader( oSettings.aoHeader, nThead[0] );\n\t\t\t\tanThs = _fnGetUniqueThs( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* If not given a column array, generate one with nulls */\n\t\t\tif ( oInit.aoColumns === null )\n\t\t\t{\n\t\t\t\taoColumnsInit = [];\n\t\t\t\tfor ( i=0, iLen=anThs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\taoColumnsInit.push( null );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoColumnsInit = oInit.aoColumns;\n\t\t\t}\n\t\t\t\n\t\t\t/* Add the columns */\n\t\t\tfor ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t_fnAddColumn( oSettings, anThs ? anThs[i] : null );\n\t\t\t}\n\t\t\t\n\t\t\t/* Apply the column definitions */\n\t\t\t_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {\n\t\t\t\t_fnColumnOptions( oSettings, iCol, oDef );\n\t\t\t} );\n\t\t\t\n\t\t\t/* HTML5 attribute detection - build an mData object automatically if the\n\t\t\t * attributes are found\n\t\t\t */\n\t\t\tif ( rowOne.length ) {\n\t\t\t\tvar a = function ( cell, name ) {\n\t\t\t\t\treturn cell.getAttribute( 'data-'+name ) !== null ? name : null;\n\t\t\t\t};\n\t\t\t\n\t\t\t\t$( rowOne[0] ).children('th, td').each( function (i, cell) {\n\t\t\t\t\tvar col = oSettings.aoColumns[i];\n\t\t\t\n\t\t\t\t\tif ( col.mData === i ) {\n\t\t\t\t\t\tvar sort = a( cell, 'sort' ) || a( cell, 'order' );\n\t\t\t\t\t\tvar filter = a( cell, 'filter' ) || a( cell, 'search' );\n\t\t\t\n\t\t\t\t\t\tif ( sort !== null || filter !== null ) {\n\t\t\t\t\t\t\tcol.mData = {\n\t\t\t\t\t\t\t\t_:      i+'.display',\n\t\t\t\t\t\t\t\tsort:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\ttype:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\tfilter: filter !== null ? i+'.@data-'+filter : undefined\n\t\t\t\t\t\t\t};\n\t\t\t\n\t\t\t\t\t\t\t_fnColumnOptions( oSettings, i );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\t\n\t\t\tvar features = oSettings.oFeatures;\n\t\t\tvar loadedInit = function () {\n\t\t\t\t/*\n\t\t\t\t * Sorting\n\t\t\t\t * @todo For modularisation (1.11) this needs to do into a sort start up handler\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// If aaSorting is not defined, then we use the first indicator in asSorting\n\t\t\t\t// in case that has been altered, so the default sort reflects that option\n\t\t\t\tif ( oInit.aaSorting === undefined ) {\n\t\t\t\t\tvar sorting = oSettings.aaSorting;\n\t\t\t\t\tfor ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {\n\t\t\t\t\t\tsorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Do a first pass on the sorting classes (allows any size changes to be taken into\n\t\t\t\t * account, and also will apply sorting disabled classes if disabled\n\t\t\t\t */\n\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\n\t\t\t\tif ( features.bSort ) {\n\t\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\t\tif ( oSettings.bSorted ) {\n\t\t\t\t\t\t\tvar aSort = _fnSortFlatten( oSettings );\n\t\t\t\t\t\t\tvar sortedColumns = {};\n\t\t\t\n\t\t\t\t\t\t\t$.each( aSort, function (i, val) {\n\t\t\t\t\t\t\t\tsortedColumns[ val.src ] = val.dir;\n\t\t\t\t\t\t\t} );\n\t\t\t\n\t\t\t\t\t\t\t_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );\n\t\t\t\t\t\t\t_fnSortAria( oSettings );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\tif ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {\n\t\t\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\t\t}\n\t\t\t\t}, 'sc' );\n\t\t\t\n\t\t\t\n\t\t\t\t/*\n\t\t\t\t * Final init\n\t\t\t\t * Cache the header, body and footer as required, creating them if needed\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// Work around for Webkit bug 83867 - store the caption-side before removing from doc\n\t\t\t\tvar captions = $this.children('caption').each( function () {\n\t\t\t\t\tthis._captionSide = $(this).css('caption-side');\n\t\t\t\t} );\n\t\t\t\n\t\t\t\tvar thead = $this.children('thead');\n\t\t\t\tif ( thead.length === 0 ) {\n\t\t\t\t\tthead = $('<thead/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTHead = thead[0];\n\t\t\t\n\t\t\t\tvar tbody = $this.children('tbody');\n\t\t\t\tif ( tbody.length === 0 ) {\n\t\t\t\t\ttbody = $('<tbody/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTBody = tbody[0];\n\t\t\t\n\t\t\t\tvar tfoot = $this.children('tfoot');\n\t\t\t\tif ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\") ) {\n\t\t\t\t\t// If we are a scrolling table, and no footer has been given, then we need to create\n\t\t\t\t\t// a tfoot element for the caption element to be appended to\n\t\t\t\t\ttfoot = $('<tfoot/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( tfoot.length === 0 || tfoot.children().length === 0 ) {\n\t\t\t\t\t$this.addClass( oClasses.sNoFooter );\n\t\t\t\t}\n\t\t\t\telse if ( tfoot.length > 0 ) {\n\t\t\t\t\toSettings.nTFoot = tfoot[0];\n\t\t\t\t\t_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Check if there is data passing into the constructor */\n\t\t\t\tif ( oInit.aaData ) {\n\t\t\t\t\tfor ( i=0 ; i<oInit.aaData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( oSettings, oInit.aaData[ i ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {\n\t\t\t\t\t/* Grab the data from the page - only do this when deferred loading or no Ajax\n\t\t\t\t\t * source since there is no point in reading the DOM data if we are then going\n\t\t\t\t\t * to replace it with Ajax data\n\t\t\t\t\t */\n\t\t\t\t\t_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Copy the data index array */\n\t\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\n\t\t\t\t/* Initialisation complete - table can be drawn */\n\t\t\t\toSettings.bInitialised = true;\n\t\t\t\n\t\t\t\t/* Check if we need to initialise the table (it might not have been handed off to the\n\t\t\t\t * language processor)\n\t\t\t\t */\n\t\t\t\tif ( bInitHandedOff === false ) {\n\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\t/* Must be done after everything which can be overridden by the state saving! */\n\t\t\tif ( oInit.bStateSave )\n\t\t\t{\n\t\t\t\tfeatures.bStateSave = true;\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );\n\t\t\t\t_fnLoadState( oSettings, oInit, loadedInit );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadedInit();\n\t\t\t}\n\t\t\t\n\t\t} );\n\t\t_that = null;\n\t\treturn this;\n\t};\n\n\t\n\t/*\n\t * It is useful to have variables which are scoped locally so only the\n\t * DataTables functions can access them and they don't leak into global space.\n\t * At the same time these functions are often useful over multiple files in the\n\t * core and API, so we list, or at least document, all variables which are used\n\t * by DataTables as private variables here. This also ensures that there is no\n\t * clashing of variable names and that they can easily referenced for reuse.\n\t */\n\t\n\t\n\t// Defined else where\n\t//  _selector_run\n\t//  _selector_opts\n\t//  _selector_first\n\t//  _selector_row_indexes\n\t\n\tvar _ext; // DataTable.ext\n\tvar _Api; // DataTable.Api\n\tvar _api_register; // DataTable.Api.register\n\tvar _api_registerPlural; // DataTable.Api.registerPlural\n\t\n\tvar _re_dic = {};\n\tvar _re_new_lines = /[\\r\\n]/g;\n\tvar _re_html = /<.*?>/g;\n\t\n\t// This is not strict ISO8601 - Date.parse() is quite lax, although\n\t// implementations differ between browsers.\n\tvar _re_date = /^\\d{2,4}[\\.\\/\\-]\\d{1,2}[\\.\\/\\-]\\d{1,2}([T ]{1}\\d{1,2}[:\\.]\\d{2}([\\.:]\\d{2})?)?$/;\n\t\n\t// Escape regular expression special characters\n\tvar _re_escape_regex = new RegExp( '(\\\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\\\', '$', '^', '-' ].join('|\\\\') + ')', 'g' );\n\t\n\t// http://en.wikipedia.org/wiki/Foreign_exchange_market\n\t// - \\u20BD - Russian ruble.\n\t// - \\u20a9 - South Korean Won\n\t// - \\u20BA - Turkish Lira\n\t// - \\u20B9 - Indian Rupee\n\t// - R - Brazil (R$) and South Africa\n\t// - fr - Swiss Franc\n\t// - kr - Swedish krona, Norwegian krone and Danish krone\n\t// - \\u2009 is thin space and \\u202F is narrow no-break space, both used in many\n\t//   standards as thousands separators.\n\tvar _re_formatted_numeric = /[',$£€¥%\\u2009\\u202F\\u20BD\\u20a9\\u20BArfk]/gi;\n\t\n\t\n\tvar _empty = function ( d ) {\n\t\treturn !d || d === true || d === '-' ? true : false;\n\t};\n\t\n\t\n\tvar _intVal = function ( s ) {\n\t\tvar integer = parseInt( s, 10 );\n\t\treturn !isNaN(integer) && isFinite(s) ? integer : null;\n\t};\n\t\n\t// Convert from a formatted number with characters other than `.` as the\n\t// decimal place, to a Javascript number\n\tvar _numToDecimal = function ( num, decimalPoint ) {\n\t\t// Cache created regular expressions for speed as this function is called often\n\t\tif ( ! _re_dic[ decimalPoint ] ) {\n\t\t\t_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );\n\t\t}\n\t\treturn typeof num === 'string' && decimalPoint !== '.' ?\n\t\t\tnum.replace( /\\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :\n\t\t\tnum;\n\t};\n\t\n\t\n\tvar _isNumber = function ( d, decimalPoint, formatted ) {\n\t\tvar strType = typeof d === 'string';\n\t\n\t\t// If empty return immediately so there must be a number if it is a\n\t\t// formatted string (this stops the string \"k\", or \"kr\", etc being detected\n\t\t// as a formatted number for currency\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tif ( decimalPoint && strType ) {\n\t\t\td = _numToDecimal( d, decimalPoint );\n\t\t}\n\t\n\t\tif ( formatted && strType ) {\n\t\t\td = d.replace( _re_formatted_numeric, '' );\n\t\t}\n\t\n\t\treturn !isNaN( parseFloat(d) ) && isFinite( d );\n\t};\n\t\n\t\n\t// A string without HTML in it can be considered to be HTML still\n\tvar _isHtml = function ( d ) {\n\t\treturn _empty( d ) || typeof d === 'string';\n\t};\n\t\n\t\n\tvar _htmlNumeric = function ( d, decimalPoint, formatted ) {\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tvar html = _isHtml( d );\n\t\treturn ! html ?\n\t\t\tnull :\n\t\t\t_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?\n\t\t\t\ttrue :\n\t\t\t\tnull;\n\t};\n\t\n\t\n\tvar _pluck = function ( a, prop, prop2 ) {\n\t\tvar out = [];\n\t\tvar i=0, ien=a.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] && a[i][ prop ] ) {\n\t\t\t\t\tout.push( a[i][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] ) {\n\t\t\t\t\tout.push( a[i][ prop ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t// Basically the same as _pluck, but rather than looping over `a` we use `order`\n\t// as the indexes to pick from `a`\n\tvar _pluck_order = function ( a, order, prop, prop2 )\n\t{\n\t\tvar out = [];\n\t\tvar i=0, ien=order.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[ order[i] ][ prop ] ) {\n\t\t\t\t\tout.push( a[ order[i] ][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tout.push( a[ order[i] ][ prop ] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _range = function ( len, start )\n\t{\n\t\tvar out = [];\n\t\tvar end;\n\t\n\t\tif ( start === undefined ) {\n\t\t\tstart = 0;\n\t\t\tend = len;\n\t\t}\n\t\telse {\n\t\t\tend = start;\n\t\t\tstart = len;\n\t\t}\n\t\n\t\tfor ( var i=start ; i<end ; i++ ) {\n\t\t\tout.push( i );\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _removeEmpty = function ( a )\n\t{\n\t\tvar out = [];\n\t\n\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\tif ( a[i] ) { // careful - will remove all falsy values!\n\t\t\t\tout.push( a[i] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _stripHtml = function ( d ) {\n\t\treturn d.replace( _re_html, '' );\n\t};\n\t\n\t\n\t/**\n\t * Find the unique elements in a source array.\n\t *\n\t * @param  {array} src Source array\n\t * @return {array} Array of unique items\n\t * @ignore\n\t */\n\tvar _unique = function ( src )\n\t{\n\t\t// A faster unique method is to use object keys to identify used values,\n\t\t// but this doesn't work with arrays or objects, which we must also\n\t\t// consider. See jsperf.com/compare-array-unique-versions/4 for more\n\t\t// information.\n\t\tvar\n\t\t\tout = [],\n\t\t\tval,\n\t\t\ti, ien=src.length,\n\t\t\tj, k=0;\n\t\n\t\tagain: for ( i=0 ; i<ien ; i++ ) {\n\t\t\tval = src[i];\n\t\n\t\t\tfor ( j=0 ; j<k ; j++ ) {\n\t\t\t\tif ( out[j] === val ) {\n\t\t\t\t\tcontinue again;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tout.push( val );\n\t\t\tk++;\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t/**\n\t * DataTables utility methods\n\t * \n\t * This namespace provides helper methods that DataTables uses internally to\n\t * create a DataTable, but which are not exclusively used only for DataTables.\n\t * These methods can be used by extension authors to save the duplication of\n\t * code.\n\t *\n\t *  @namespace\n\t */\n\tDataTable.util = {\n\t\t/**\n\t\t * Throttle the calls to a function. Arguments and context are maintained\n\t\t * for the throttled function.\n\t\t *\n\t\t * @param {function} fn Function to be called\n\t\t * @param {integer} freq Call frequency in mS\n\t\t * @return {function} Wrapped function\n\t\t */\n\t\tthrottle: function ( fn, freq ) {\n\t\t\tvar\n\t\t\t\tfrequency = freq !== undefined ? freq : 200,\n\t\t\t\tlast,\n\t\t\t\ttimer;\n\t\n\t\t\treturn function () {\n\t\t\t\tvar\n\t\t\t\t\tthat = this,\n\t\t\t\t\tnow  = +new Date(),\n\t\t\t\t\targs = arguments;\n\t\n\t\t\t\tif ( last && now < last + frequency ) {\n\t\t\t\t\tclearTimeout( timer );\n\t\n\t\t\t\t\ttimer = setTimeout( function () {\n\t\t\t\t\t\tlast = undefined;\n\t\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t\t}, frequency );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlast = now;\n\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Escape a string such that it can be used in a regular expression\n\t\t *\n\t\t *  @param {string} val string to escape\n\t\t *  @returns {string} escaped string\n\t\t */\n\t\tescapeRegex: function ( val ) {\n\t\t\treturn val.replace( _re_escape_regex, '\\\\$1' );\n\t\t}\n\t};\n\t\n\t\n\t\n\t/**\n\t * Create a mapping object that allows camel case parameters to be looked up\n\t * for their Hungarian counterparts. The mapping is stored in a private\n\t * parameter called `_hungarianMap` which can be accessed on the source object.\n\t *  @param {object} o\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnHungarianMap ( o )\n\t{\n\t\tvar\n\t\t\thungarian = 'a aa ai ao as b fn i m o s ',\n\t\t\tmatch,\n\t\t\tnewKey,\n\t\t\tmap = {};\n\t\n\t\t$.each( o, function (key, val) {\n\t\t\tmatch = key.match(/^([^A-Z]+?)([A-Z])/);\n\t\n\t\t\tif ( match && hungarian.indexOf(match[1]+' ') !== -1 )\n\t\t\t{\n\t\t\t\tnewKey = key.replace( match[0], match[2].toLowerCase() );\n\t\t\t\tmap[ newKey ] = key;\n\t\n\t\t\t\tif ( match[1] === 'o' )\n\t\t\t\t{\n\t\t\t\t\t_fnHungarianMap( o[key] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\n\t\to._hungarianMap = map;\n\t}\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian, based on a Hungarian map\n\t * created by _fnHungarianMap.\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCamelToHungarian ( src, user, force )\n\t{\n\t\tif ( ! src._hungarianMap ) {\n\t\t\t_fnHungarianMap( src );\n\t\t}\n\t\n\t\tvar hungarianKey;\n\t\n\t\t$.each( user, function (key, val) {\n\t\t\thungarianKey = src._hungarianMap[ key ];\n\t\n\t\t\tif ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )\n\t\t\t{\n\t\t\t\t// For objects, we need to buzz down into the object to copy parameters\n\t\t\t\tif ( hungarianKey.charAt(0) === 'o' )\n\t\t\t\t{\n\t\t\t\t\t// Copy the camelCase options over to the hungarian\n\t\t\t\t\tif ( ! user[ hungarianKey ] ) {\n\t\t\t\t\t\tuser[ hungarianKey ] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, user[hungarianKey], user[key] );\n\t\n\t\t\t\t\t_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tuser[hungarianKey] = user[ key ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Language compatibility - when certain options are given, and others aren't, we\n\t * need to duplicate the values over, in order to provide backwards compatibility\n\t * with older language files.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLanguageCompat( lang )\n\t{\n\t\tvar defaults = DataTable.defaults.oLanguage;\n\t\tvar zeroRecords = lang.sZeroRecords;\n\t\n\t\t/* Backwards compatibility - if there is no sEmptyTable given, then use the same as\n\t\t * sZeroRecords - assuming that is given.\n\t\t */\n\t\tif ( ! lang.sEmptyTable && zeroRecords &&\n\t\t\tdefaults.sEmptyTable === \"No data available in table\" )\n\t\t{\n\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );\n\t\t}\n\t\n\t\t/* Likewise with loading records */\n\t\tif ( ! lang.sLoadingRecords && zeroRecords &&\n\t\t\tdefaults.sLoadingRecords === \"Loading...\" )\n\t\t{\n\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );\n\t\t}\n\t\n\t\t// Old parameter name of the thousands separator mapped onto the new\n\t\tif ( lang.sInfoThousands ) {\n\t\t\tlang.sThousands = lang.sInfoThousands;\n\t\t}\n\t\n\t\tvar decimal = lang.sDecimal;\n\t\tif ( decimal ) {\n\t\t\t_addNumericSort( decimal );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Map one parameter onto another\n\t *  @param {object} o Object to map\n\t *  @param {*} knew The new parameter name\n\t *  @param {*} old The old parameter name\n\t */\n\tvar _fnCompatMap = function ( o, knew, old ) {\n\t\tif ( o[ knew ] !== undefined ) {\n\t\t\to[ old ] = o[ knew ];\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for the main DT options. Note that the new\n\t * options are mapped onto the old parameters, so this is an external interface\n\t * change only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatOpts ( init )\n\t{\n\t\t_fnCompatMap( init, 'ordering',      'bSort' );\n\t\t_fnCompatMap( init, 'orderMulti',    'bSortMulti' );\n\t\t_fnCompatMap( init, 'orderClasses',  'bSortClasses' );\n\t\t_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );\n\t\t_fnCompatMap( init, 'order',         'aaSorting' );\n\t\t_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );\n\t\t_fnCompatMap( init, 'paging',        'bPaginate' );\n\t\t_fnCompatMap( init, 'pagingType',    'sPaginationType' );\n\t\t_fnCompatMap( init, 'pageLength',    'iDisplayLength' );\n\t\t_fnCompatMap( init, 'searching',     'bFilter' );\n\t\n\t\t// Boolean initialisation of x-scrolling\n\t\tif ( typeof init.sScrollX === 'boolean' ) {\n\t\t\tinit.sScrollX = init.sScrollX ? '100%' : '';\n\t\t}\n\t\tif ( typeof init.scrollX === 'boolean' ) {\n\t\t\tinit.scrollX = init.scrollX ? '100%' : '';\n\t\t}\n\t\n\t\t// Column search objects are in an array, so it needs to be converted\n\t\t// element by element\n\t\tvar searchCols = init.aoSearchCols;\n\t\n\t\tif ( searchCols ) {\n\t\t\tfor ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {\n\t\t\t\tif ( searchCols[i] ) {\n\t\t\t\t\t_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for column options. Note that the new options\n\t * are mapped onto the old parameters, so this is an external interface change\n\t * only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatCols ( init )\n\t{\n\t\t_fnCompatMap( init, 'orderable',     'bSortable' );\n\t\t_fnCompatMap( init, 'orderData',     'aDataSort' );\n\t\t_fnCompatMap( init, 'orderSequence', 'asSorting' );\n\t\t_fnCompatMap( init, 'orderDataType', 'sortDataType' );\n\t\n\t\t// orderData can be given as an integer\n\t\tvar dataSort = init.aDataSort;\n\t\tif ( dataSort && ! $.isArray( dataSort ) ) {\n\t\t\tinit.aDataSort = [ dataSort ];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Browser feature detection for capabilities, quirks\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBrowserDetect( settings )\n\t{\n\t\t// We don't need to do this every time DataTables is constructed, the values\n\t\t// calculated are specific to the browser and OS configuration which we\n\t\t// don't expect to change between initialisations\n\t\tif ( ! DataTable.__browser ) {\n\t\t\tvar browser = {};\n\t\t\tDataTable.__browser = browser;\n\t\n\t\t\t// Scrolling feature / quirks detection\n\t\t\tvar n = $('<div/>')\n\t\t\t\t.css( {\n\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: $(window).scrollLeft()*-1, // allow for scrolling\n\t\t\t\t\theight: 1,\n\t\t\t\t\twidth: 1,\n\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t} )\n\t\t\t\t.append(\n\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\ttop: 1,\n\t\t\t\t\t\t\tleft: 1,\n\t\t\t\t\t\t\twidth: 100,\n\t\t\t\t\t\t\toverflow: 'scroll'\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t\t\t\theight: 10\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t.appendTo( 'body' );\n\t\n\t\t\tvar outer = n.children();\n\t\t\tvar inner = outer.children();\n\t\n\t\t\t// Numbers below, in order, are:\n\t\t\t// inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth\n\t\t\t//\n\t\t\t// IE6 XP:                           100 100 100  83\n\t\t\t// IE7 Vista:                        100 100 100  83\n\t\t\t// IE 8+ Windows:                     83  83 100  83\n\t\t\t// Evergreen Windows:                 83  83 100  83\n\t\t\t// Evergreen Mac with scrollbars:     85  85 100  85\n\t\t\t// Evergreen Mac without scrollbars: 100 100 100 100\n\t\n\t\t\t// Get scrollbar width\n\t\t\tbrowser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;\n\t\n\t\t\t// IE6/7 will oversize a width 100% element inside a scrolling element, to\n\t\t\t// include the width of the scrollbar, while other browsers ensure the inner\n\t\t\t// element is contained without forcing scrolling\n\t\t\tbrowser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;\n\t\n\t\t\t// In rtl text layout, some browsers (most, but not all) will place the\n\t\t\t// scrollbar on the left, rather than the right.\n\t\t\tbrowser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;\n\t\n\t\t\t// IE8- don't provide height and width for getBoundingClientRect\n\t\t\tbrowser.bBounding = n[0].getBoundingClientRect().width ? true : false;\n\t\n\t\t\tn.remove();\n\t\t}\n\t\n\t\t$.extend( settings.oBrowser, DataTable.__browser );\n\t\tsettings.oScroll.iBarWidth = DataTable.__browser.barWidth;\n\t}\n\t\n\t\n\t/**\n\t * Array.prototype reduce[Right] method, used for browsers which don't support\n\t * JS 1.6. Done this way to reduce code size, since we iterate either way\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReduce ( that, fn, init, start, end, inc )\n\t{\n\t\tvar\n\t\t\ti = start,\n\t\t\tvalue,\n\t\t\tisSet = false;\n\t\n\t\tif ( init !== undefined ) {\n\t\t\tvalue = init;\n\t\t\tisSet = true;\n\t\t}\n\t\n\t\twhile ( i !== end ) {\n\t\t\tif ( ! that.hasOwnProperty(i) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\tvalue = isSet ?\n\t\t\t\tfn( value, that[i], i, that ) :\n\t\t\t\tthat[i];\n\t\n\t\t\tisSet = true;\n\t\t\ti += inc;\n\t\t}\n\t\n\t\treturn value;\n\t}\n\t\n\t/**\n\t * Add a column to the list used for the table with default values\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nTh The th element for this column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddColumn( oSettings, nTh )\n\t{\n\t\t// Add column to aoColumns array\n\t\tvar oDefaults = DataTable.defaults.column;\n\t\tvar iCol = oSettings.aoColumns.length;\n\t\tvar oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {\n\t\t\t\"nTh\": nTh ? nTh : document.createElement('th'),\n\t\t\t\"sTitle\":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',\n\t\t\t\"aDataSort\": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],\n\t\t\t\"mData\": oDefaults.mData ? oDefaults.mData : iCol,\n\t\t\tidx: iCol\n\t\t} );\n\t\toSettings.aoColumns.push( oCol );\n\t\n\t\t// Add search object for column specific search. Note that the `searchCols[ iCol ]`\n\t\t// passed into extend can be undefined. This allows the user to give a default\n\t\t// with only some of the parameters defined, and also not give a default\n\t\tvar searchCols = oSettings.aoPreSearchCols;\n\t\tsearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );\n\t\n\t\t// Use the default column options function to initialise classes etc\n\t\t_fnColumnOptions( oSettings, iCol, $(nTh).data() );\n\t}\n\t\n\t\n\t/**\n\t * Apply options for a column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iCol column index to consider\n\t *  @param {object} oOptions object with sType, bVisible and bSearchable etc\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnOptions( oSettings, iCol, oOptions )\n\t{\n\t\tvar oCol = oSettings.aoColumns[ iCol ];\n\t\tvar oClasses = oSettings.oClasses;\n\t\tvar th = $(oCol.nTh);\n\t\n\t\t// Try to get width information from the DOM. We can't get it from CSS\n\t\t// as we'd need to parse the CSS stylesheet. `width` option can override\n\t\tif ( ! oCol.sWidthOrig ) {\n\t\t\t// Width attribute\n\t\t\toCol.sWidthOrig = th.attr('width') || null;\n\t\n\t\t\t// Style attribute\n\t\t\tvar t = (th.attr('style') || '').match(/width:\\s*(\\d+[pxem%]+)/);\n\t\t\tif ( t ) {\n\t\t\t\toCol.sWidthOrig = t[1];\n\t\t\t}\n\t\t}\n\t\n\t\t/* User specified column options */\n\t\tif ( oOptions !== undefined && oOptions !== null )\n\t\t{\n\t\t\t// Backwards compatibility\n\t\t\t_fnCompatCols( oOptions );\n\t\n\t\t\t// Map camel case parameters to their Hungarian counterparts\n\t\t\t_fnCamelToHungarian( DataTable.defaults.column, oOptions );\n\t\n\t\t\t/* Backwards compatibility for mDataProp */\n\t\t\tif ( oOptions.mDataProp !== undefined && !oOptions.mData )\n\t\t\t{\n\t\t\t\toOptions.mData = oOptions.mDataProp;\n\t\t\t}\n\t\n\t\t\tif ( oOptions.sType )\n\t\t\t{\n\t\t\t\toCol._sManualType = oOptions.sType;\n\t\t\t}\n\t\n\t\t\t// `class` is a reserved word in Javascript, so we need to provide\n\t\t\t// the ability to use a valid name for the camel case input\n\t\t\tif ( oOptions.className && ! oOptions.sClass )\n\t\t\t{\n\t\t\t\toOptions.sClass = oOptions.className;\n\t\t\t}\n\t\n\t\t\t$.extend( oCol, oOptions );\n\t\t\t_fnMap( oCol, oOptions, \"sWidth\", \"sWidthOrig\" );\n\t\n\t\t\t/* iDataSort to be applied (backwards compatibility), but aDataSort will take\n\t\t\t * priority if defined\n\t\t\t */\n\t\t\tif ( oOptions.iDataSort !== undefined )\n\t\t\t{\n\t\t\t\toCol.aDataSort = [ oOptions.iDataSort ];\n\t\t\t}\n\t\t\t_fnMap( oCol, oOptions, \"aDataSort\" );\n\t\t}\n\t\n\t\t/* Cache the data get and set functions for speed */\n\t\tvar mDataSrc = oCol.mData;\n\t\tvar mData = _fnGetObjectDataFn( mDataSrc );\n\t\tvar mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;\n\t\n\t\tvar attrTest = function( src ) {\n\t\t\treturn typeof src === 'string' && src.indexOf('@') !== -1;\n\t\t};\n\t\toCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (\n\t\t\tattrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)\n\t\t);\n\t\toCol._setter = null;\n\t\n\t\toCol.fnGetData = function (rowData, type, meta) {\n\t\t\tvar innerData = mData( rowData, type, undefined, meta );\n\t\n\t\t\treturn mRender && type ?\n\t\t\t\tmRender( innerData, type, rowData, meta ) :\n\t\t\t\tinnerData;\n\t\t};\n\t\toCol.fnSetData = function ( rowData, val, meta ) {\n\t\t\treturn _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );\n\t\t};\n\t\n\t\t// Indicate if DataTables should read DOM data as an object or array\n\t\t// Used in _fnGetRowElements\n\t\tif ( typeof mDataSrc !== 'number' ) {\n\t\t\toSettings._rowReadObject = true;\n\t\t}\n\t\n\t\t/* Feature sorting overrides column specific when off */\n\t\tif ( !oSettings.oFeatures.bSort )\n\t\t{\n\t\t\toCol.bSortable = false;\n\t\t\tth.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called\n\t\t}\n\t\n\t\t/* Check that the class assignment is correct for sorting */\n\t\tvar bAsc = $.inArray('asc', oCol.asSorting) !== -1;\n\t\tvar bDesc = $.inArray('desc', oCol.asSorting) !== -1;\n\t\tif ( !oCol.bSortable || (!bAsc && !bDesc) )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableNone;\n\t\t\toCol.sSortingClassJUI = \"\";\n\t\t}\n\t\telse if ( bAsc && !bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableAsc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;\n\t\t}\n\t\telse if ( !bAsc && bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableDesc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;\n\t\t}\n\t\telse\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortable;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUI;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Adjust the table column widths for new data. Note: you would probably want to\n\t * do a redraw after calling this function!\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAdjustColumnSizing ( settings )\n\t{\n\t\t/* Not interested in doing column width calculation if auto-width is disabled */\n\t\tif ( settings.oFeatures.bAutoWidth !== false )\n\t\t{\n\t\t\tvar columns = settings.aoColumns;\n\t\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t\tfor ( var i=0 , iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tcolumns[i].nTh.style.width = columns[i].sWidth;\n\t\t\t}\n\t\t}\n\t\n\t\tvar scroll = settings.oScroll;\n\t\tif ( scroll.sY !== '' || scroll.sX !== '')\n\t\t{\n\t\t\t_fnScrollDraw( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'column-sizing', [settings] );\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of a visible column to the index in the data array (take account\n\t * of hidden columns)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iMatch Visible column index to lookup\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisibleToColumnIndex( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\n\t\treturn typeof aiVis[iMatch] === 'number' ?\n\t\t\taiVis[iMatch] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of an index in the data array and convert it to the visible\n\t *   column index (take account of hidden columns)\n\t *  @param {int} iMatch Column index to lookup\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnIndexToVisible( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\tvar iPos = $.inArray( iMatch, aiVis );\n\t\n\t\treturn iPos !== -1 ? iPos : null;\n\t}\n\t\n\t\n\t/**\n\t * Get the number of visible columns\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the number of visible columns\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisbleColumns( oSettings )\n\t{\n\t\tvar vis = 0;\n\t\n\t\t// No reduce in IE8, use a loop for now\n\t\t$.each( oSettings.aoColumns, function ( i, col ) {\n\t\t\tif ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {\n\t\t\t\tvis++;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn vis;\n\t}\n\t\n\t\n\t/**\n\t * Get an array of column indexes that match a given property\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sParam Parameter in aoColumns to look for - typically\n\t *    bVisible or bSearchable\n\t *  @returns {array} Array of indexes with matched properties\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetColumns( oSettings, sParam )\n\t{\n\t\tvar a = [];\n\t\n\t\t$.map( oSettings.aoColumns, function(val, i) {\n\t\t\tif ( val[sParam] ) {\n\t\t\t\ta.push( i );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn a;\n\t}\n\t\n\t\n\t/**\n\t * Calculate the 'type' of a column\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnTypes ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar data = settings.aoData;\n\t\tvar types = DataTable.ext.type.detect;\n\t\tvar i, ien, j, jen, k, ken;\n\t\tvar col, cell, detectedType, cache;\n\t\n\t\t// For each column, spin over the \n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcol = columns[i];\n\t\t\tcache = [];\n\t\n\t\t\tif ( ! col.sType && col._sManualType ) {\n\t\t\t\tcol.sType = col._sManualType;\n\t\t\t}\n\t\t\telse if ( ! col.sType ) {\n\t\t\t\tfor ( j=0, jen=types.length ; j<jen ; j++ ) {\n\t\t\t\t\tfor ( k=0, ken=data.length ; k<ken ; k++ ) {\n\t\t\t\t\t\t// Use a cache array so we only need to get the type data\n\t\t\t\t\t\t// from the formatter once (when using multiple detectors)\n\t\t\t\t\t\tif ( cache[k] === undefined ) {\n\t\t\t\t\t\t\tcache[k] = _fnGetCellData( settings, k, i, 'type' );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tdetectedType = types[j]( cache[k], settings );\n\t\n\t\t\t\t\t\t// If null, then this type can't apply to this column, so\n\t\t\t\t\t\t// rather than testing all cells, break out. There is an\n\t\t\t\t\t\t// exception for the last type which is `html`. We need to\n\t\t\t\t\t\t// scan all rows since it is possible to mix string and HTML\n\t\t\t\t\t\t// types\n\t\t\t\t\t\tif ( ! detectedType && j !== types.length-1 ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Only a single match is needed for html type since it is\n\t\t\t\t\t\t// bottom of the pile and very similar to string\n\t\t\t\t\t\tif ( detectedType === 'html' ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Type is valid for all data points in the column - use this\n\t\t\t\t\t// type\n\t\t\t\t\tif ( detectedType ) {\n\t\t\t\t\t\tcol.sType = detectedType;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Fall back - if no type was detected, always use string\n\t\t\t\tif ( ! col.sType ) {\n\t\t\t\t\tcol.sType = 'string';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Take the column definitions and static columns arrays and calculate how\n\t * they relate to column indexes. The callback function will then apply the\n\t * definition found for a column to a suitable configuration object.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aoColDefs The aoColumnDefs array that is to be applied\n\t *  @param {array} aoCols The aoColumns array that defines columns individually\n\t *  @param {function} fn Callback function - takes two parameters, the calculated\n\t *    column index and the definition for that column.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, def;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Column definitions with aTargets\n\t\tif ( aoColDefs )\n\t\t{\n\t\t\t/* Loop over the definitions array - loop in reverse so first instance has priority */\n\t\t\tfor ( i=aoColDefs.length-1 ; i>=0 ; i-- )\n\t\t\t{\n\t\t\t\tdef = aoColDefs[i];\n\t\n\t\t\t\t/* Each definition can target multiple columns, as it is an array */\n\t\t\t\tvar aTargets = def.targets !== undefined ?\n\t\t\t\t\tdef.targets :\n\t\t\t\t\tdef.aTargets;\n\t\n\t\t\t\tif ( ! $.isArray( aTargets ) )\n\t\t\t\t{\n\t\t\t\t\taTargets = [ aTargets ];\n\t\t\t\t}\n\t\n\t\t\t\tfor ( j=0, jLen=aTargets.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Add columns that we don't yet know about */\n\t\t\t\t\t\twhile( columns.length <= aTargets[j] )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_fnAddColumn( oSettings );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t/* Integer, basic index */\n\t\t\t\t\t\tfn( aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Negative integer, right to left column counting */\n\t\t\t\t\t\tfn( columns.length+aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'string' )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Class name matching on TH element */\n\t\t\t\t\t\tfor ( k=0, kLen=columns.length ; k<kLen ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( aTargets[j] == \"_all\" ||\n\t\t\t\t\t\t\t     $(columns[k].nTh).hasClass( aTargets[j] ) )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfn( k, def );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// Statically defined columns array\n\t\tif ( aoCols )\n\t\t{\n\t\t\tfor ( i=0, iLen=aoCols.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfn( i, aoCols[i] );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * Add a data array to the table, creating DOM node etc. This is the parallel to\n\t * _fnGatherData, but for adding rows from a Javascript source, rather than a\n\t * DOM source.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aData data array to be added\n\t *  @param {node} [nTr] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddData ( oSettings, aDataIn, nTr, anTds )\n\t{\n\t\t/* Create the object for storing information about this new row */\n\t\tvar iRow = oSettings.aoData.length;\n\t\tvar oData = $.extend( true, {}, DataTable.models.oRow, {\n\t\t\tsrc: nTr ? 'dom' : 'data',\n\t\t\tidx: iRow\n\t\t} );\n\t\n\t\toData._aData = aDataIn;\n\t\toSettings.aoData.push( oData );\n\t\n\t\t/* Create the cells */\n\t\tvar nTd, sThisType;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Invalidate the column types as the new data needs to be revalidated\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tcolumns[i].sType = null;\n\t\t}\n\t\n\t\t/* Add to the display array */\n\t\toSettings.aiDisplayMaster.push( iRow );\n\t\n\t\tvar id = oSettings.rowIdFn( aDataIn );\n\t\tif ( id !== undefined ) {\n\t\t\toSettings.aIds[ id ] = oData;\n\t\t}\n\t\n\t\t/* Create the DOM information, or register it if already present */\n\t\tif ( nTr || ! oSettings.oFeatures.bDeferRender )\n\t\t{\n\t\t\t_fnCreateTr( oSettings, iRow, nTr, anTds );\n\t\t}\n\t\n\t\treturn iRow;\n\t}\n\t\n\t\n\t/**\n\t * Add one or more TR elements to the table. Generally we'd expect to\n\t * use this for reading data from a DOM sourced table, but it could be\n\t * used for an TR element. Note that if a TR is given, it is used (i.e.\n\t * it is not cloned).\n\t *  @param {object} settings dataTables settings object\n\t *  @param {array|node|jQuery} trs The TR element(s) to add to the table\n\t *  @returns {array} Array of indexes for the added rows\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddTr( settings, trs )\n\t{\n\t\tvar row;\n\t\n\t\t// Allow an individual node to be passed in\n\t\tif ( ! (trs instanceof $) ) {\n\t\t\ttrs = $(trs);\n\t\t}\n\t\n\t\treturn trs.map( function (i, el) {\n\t\t\trow = _fnGetRowElements( settings, el );\n\t\t\treturn _fnAddData( settings, row.data, el, row.cells );\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Take a TR element and convert it to an index in aoData\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} n the TR element to find\n\t *  @returns {int} index if the node is found, null if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToDataIndex( oSettings, n )\n\t{\n\t\treturn (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;\n\t}\n\t\n\t\n\t/**\n\t * Take a TD element and convert it into a column data index (not the visible index)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow The row number the TD/TH can be found in\n\t *  @param {node} n The TD/TH element to find\n\t *  @returns {int} index if the node is found, -1 if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToColumnIndex( oSettings, iRow, n )\n\t{\n\t\treturn $.inArray( n, oSettings.aoData[ iRow ].anCells );\n\t}\n\t\n\t\n\t/**\n\t * Get the data for a given cell from the internal cache, taking into account data mapping\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {string} type data get type ('display', 'type' 'filter' 'sort')\n\t *  @returns {*} Cell data\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetCellData( settings, rowIdx, colIdx, type )\n\t{\n\t\tvar draw           = settings.iDraw;\n\t\tvar col            = settings.aoColumns[colIdx];\n\t\tvar rowData        = settings.aoData[rowIdx]._aData;\n\t\tvar defaultContent = col.sDefaultContent;\n\t\tvar cellData       = col.fnGetData( rowData, type, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t} );\n\t\n\t\tif ( cellData === undefined ) {\n\t\t\tif ( settings.iDrawError != draw && defaultContent === null ) {\n\t\t\t\t_fnLog( settings, 0, \"Requested unknown parameter \"+\n\t\t\t\t\t(typeof col.mData=='function' ? '{function}' : \"'\"+col.mData+\"'\")+\n\t\t\t\t\t\" for row \"+rowIdx+\", column \"+colIdx, 4 );\n\t\t\t\tsettings.iDrawError = draw;\n\t\t\t}\n\t\t\treturn defaultContent;\n\t\t}\n\t\n\t\t// When the data source is null and a specific data type is requested (i.e.\n\t\t// not the original data), we can use default column data\n\t\tif ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {\n\t\t\tcellData = defaultContent;\n\t\t}\n\t\telse if ( typeof cellData === 'function' ) {\n\t\t\t// If the data source is a function, then we run it and use the return,\n\t\t\t// executing in the scope of the data object (for instances)\n\t\t\treturn cellData.call( rowData );\n\t\t}\n\t\n\t\tif ( cellData === null && type == 'display' ) {\n\t\t\treturn '';\n\t\t}\n\t\treturn cellData;\n\t}\n\t\n\t\n\t/**\n\t * Set the value for a specific cell, into the internal data cache\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {*} val Value to set\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetCellData( settings, rowIdx, colIdx, val )\n\t{\n\t\tvar col     = settings.aoColumns[colIdx];\n\t\tvar rowData = settings.aoData[rowIdx]._aData;\n\t\n\t\tcol.fnSetData( rowData, val, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t}  );\n\t}\n\t\n\t\n\t// Private variable that is used to match action syntax in the data property object\n\tvar __reArray = /\\[.*?\\]$/;\n\tvar __reFn = /\\(\\)$/;\n\t\n\t/**\n\t * Split string on periods, taking into account escaped periods\n\t * @param  {string} str String to split\n\t * @return {array} Split string\n\t */\n\tfunction _fnSplitObjNotation( str )\n\t{\n\t\treturn $.map( str.match(/(\\\\.|[^\\.])+/g) || [''], function ( s ) {\n\t\t\treturn s.replace(/\\\\\\./g, '.');\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to get data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data get function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Build an object of get functions, and wrap them in a single call */\n\t\t\tvar o = {};\n\t\t\t$.each( mSource, function (key, val) {\n\t\t\t\tif ( val ) {\n\t\t\t\t\to[key] = _fnGetObjectDataFn( val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\tvar t = o[type] || o._;\n\t\t\t\treturn t !== undefined ?\n\t\t\t\t\tt(data, type, row, meta) :\n\t\t\t\t\tdata;\n\t\t\t};\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Give an empty string for rendering / sorting etc */\n\t\t\treturn function (data) { // type, row and meta also passed, but not used\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\treturn mSource( data, type, row, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* If there is a . in the source string then the data source is in a\n\t\t\t * nested object so we loop over the data for each level to get the next\n\t\t\t * level down. On each loop we test for undefined, and if found immediately\n\t\t\t * return. This allows entire objects to be missing and sDefaultContent to\n\t\t\t * be used if defined, rather than throwing an error\n\t\t\t */\n\t\t\tvar fetchData = function (data, type, src) {\n\t\t\t\tvar arrayNotation, funcNotation, out, innerSrc;\n\t\n\t\t\t\tif ( src !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tvar a = _fnSplitObjNotation( src );\n\t\n\t\t\t\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if we are dealing with special notation\n\t\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Array notation\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\n\t\t\t\t\t\t\t// Condition allows simply [] to be passed in\n\t\t\t\t\t\t\tif ( a[i] !== \"\" ) {\n\t\t\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tout = [];\n\t\n\t\t\t\t\t\t\t// Get the remainder of the nested object to get\n\t\t\t\t\t\t\ta.splice( 0, i+1 );\n\t\t\t\t\t\t\tinnerSrc = a.join('.');\n\t\n\t\t\t\t\t\t\t// Traverse each entry in the array getting the properties requested\n\t\t\t\t\t\t\tif ( $.isArray( data ) ) {\n\t\t\t\t\t\t\t\tfor ( var j=0, jLen=data.length ; j<jLen ; j++ ) {\n\t\t\t\t\t\t\t\t\tout.push( fetchData( data[j], type, innerSrc ) );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\t// If a string is given in between the array notation indicators, that\n\t\t\t\t\t\t\t// is used to join the strings together, otherwise an array is returned\n\t\t\t\t\t\t\tvar join = arrayNotation[0].substring(1, arrayNotation[0].length-1);\n\t\t\t\t\t\t\tdata = (join===\"\") ? out : out.join(join);\n\t\n\t\t\t\t\t\t\t// The inner call to fetchData has already traversed through the remainder\n\t\t\t\t\t\t\t// of the source requested, so we exit from the loop\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Function call\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\t\tdata = data[ a[i] ]();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( data === null || data[ a[i] ] === undefined )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn data;\n\t\t\t};\n\t\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn fetchData( data, type, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn data[mSource];\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to set data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data set function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Unlike get, only the underscore (global) option is used for for\n\t\t\t * setting data since we don't know the type here. This is why an object\n\t\t\t * option is not documented for `mData` (which is read/write), but it is\n\t\t\t * for `mRender` which is read only.\n\t\t\t */\n\t\t\treturn _fnSetObjectDataFn( mSource._ );\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Nothing to do when the data source is null */\n\t\t\treturn function () {};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, val, meta) {\n\t\t\t\tmSource( data, 'set', val, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* Like the get, we need to get data from a nested object */\n\t\t\tvar setData = function (data, val, src) {\n\t\t\t\tvar a = _fnSplitObjNotation( src ), b;\n\t\t\t\tvar aLast = a[a.length-1];\n\t\t\t\tvar arrayNotation, funcNotation, o, innerSrc;\n\t\n\t\t\t\tfor ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\t// Check if we are dealing with an array notation request\n\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\t\t\t\t\tdata[ a[i] ] = [];\n\t\n\t\t\t\t\t\t// Get the remainder of the nested object to set so we can recurse\n\t\t\t\t\t\tb = a.slice();\n\t\t\t\t\t\tb.splice( 0, i+1 );\n\t\t\t\t\t\tinnerSrc = b.join('.');\n\t\n\t\t\t\t\t\t// Traverse each entry in the array setting the properties requested\n\t\t\t\t\t\tif ( $.isArray( val ) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor ( var j=0, jLen=val.length ; j<jLen ; j++ )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\to = {};\n\t\t\t\t\t\t\t\tsetData( o, val[j], innerSrc );\n\t\t\t\t\t\t\t\tdata[ a[i] ].push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We've been asked to save data to an array, but it\n\t\t\t\t\t\t\t// isn't array data to be saved. Best that can be done\n\t\t\t\t\t\t\t// is to just save the value.\n\t\t\t\t\t\t\tdata[ a[i] ] = val;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// The inner call to setData has already traversed through the remainder\n\t\t\t\t\t\t// of the source and has set the data, thus we can exit here\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Function call\n\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\tdata = data[ a[i] ]( val );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If the nested object doesn't currently exist - since we are\n\t\t\t\t\t// trying to set the value - create it\n\t\t\t\t\tif ( data[ a[i] ] === null || data[ a[i] ] === undefined )\n\t\t\t\t\t{\n\t\t\t\t\t\tdata[ a[i] ] = {};\n\t\t\t\t\t}\n\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t}\n\t\n\t\t\t\t// Last item in the input - i.e, the actual set\n\t\t\t\tif ( aLast.match(__reFn ) )\n\t\t\t\t{\n\t\t\t\t\t// Function call\n\t\t\t\t\tdata = data[ aLast.replace(__reFn, '') ]( val );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// If array notation is used, we just want to strip it and use the property name\n\t\t\t\t\t// and assign the value. If it isn't used, then we get the result we want anyway\n\t\t\t\t\tdata[ aLast.replace(__reArray, '') ] = val;\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\treturn setData( data, val, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\tdata[mSource] = val;\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return an array with the full table data\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns array {array} aData Master data array\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetDataMaster ( settings )\n\t{\n\t\treturn _pluck( settings.aoData, '_aData' );\n\t}\n\t\n\t\n\t/**\n\t * Nuke the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnClearTable( settings )\n\t{\n\t\tsettings.aoData.length = 0;\n\t\tsettings.aiDisplayMaster.length = 0;\n\t\tsettings.aiDisplay.length = 0;\n\t\tsettings.aIds = {};\n\t}\n\t\n\t\n\t /**\n\t * Take an array of integers (index array) and remove a target integer (value - not\n\t * the key!)\n\t *  @param {array} a Index array to target\n\t *  @param {int} iTarget value to find\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDeleteIndex( a, iTarget, splice )\n\t{\n\t\tvar iTargetIndex = -1;\n\t\n\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( a[i] == iTarget )\n\t\t\t{\n\t\t\t\tiTargetIndex = i;\n\t\t\t}\n\t\t\telse if ( a[i] > iTarget )\n\t\t\t{\n\t\t\t\ta[i]--;\n\t\t\t}\n\t\t}\n\t\n\t\tif ( iTargetIndex != -1 && splice === undefined )\n\t\t{\n\t\t\ta.splice( iTargetIndex, 1 );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Mark cached data as invalid such that a re-read of the data will occur when\n\t * the cached data is next requested. Also update from the data source object.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {int}    rowIdx   Row index to invalidate\n\t * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'\n\t *     or 'data'\n\t * @param {int}    [colIdx] Column index to invalidate. If undefined the whole\n\t *     row will be invalidated\n\t * @memberof DataTable#oApi\n\t *\n\t * @todo For the modularisation of v1.11 this will need to become a callback, so\n\t *   the sort and filter methods can subscribe to it. That will required\n\t *   initialisation options for sorting, which is why it is not already baked in\n\t */\n\tfunction _fnInvalidate( settings, rowIdx, src, colIdx )\n\t{\n\t\tvar row = settings.aoData[ rowIdx ];\n\t\tvar i, ien;\n\t\tvar cellWrite = function ( cell, col ) {\n\t\t\t// This is very frustrating, but in IE if you just write directly\n\t\t\t// to innerHTML, and elements that are overwritten are GC'ed,\n\t\t\t// even if there is a reference to them elsewhere\n\t\t\twhile ( cell.childNodes.length ) {\n\t\t\t\tcell.removeChild( cell.firstChild );\n\t\t\t}\n\t\n\t\t\tcell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );\n\t\t};\n\t\n\t\t// Are we reading last data from DOM or the data object?\n\t\tif ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {\n\t\t\t// Read the data from the DOM\n\t\t\trow._aData = _fnGetRowElements(\n\t\t\t\t\tsettings, row, colIdx, colIdx === undefined ? undefined : row._aData\n\t\t\t\t)\n\t\t\t\t.data;\n\t\t}\n\t\telse {\n\t\t\t// Reading from data object, update the DOM\n\t\t\tvar cells = row.anCells;\n\t\n\t\t\tif ( cells ) {\n\t\t\t\tif ( colIdx !== undefined ) {\n\t\t\t\t\tcellWrite( cells[colIdx], colIdx );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tcellWrite( cells[i], i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// For both row and cell invalidation, the cached data for sorting and\n\t\t// filtering is nulled out\n\t\trow._aSortData = null;\n\t\trow._aFilterData = null;\n\t\n\t\t// Invalidate the type for a specific column (if given) or all columns since\n\t\t// the data might have changed\n\t\tvar cols = settings.aoColumns;\n\t\tif ( colIdx !== undefined ) {\n\t\t\tcols[ colIdx ].sType = null;\n\t\t}\n\t\telse {\n\t\t\tfor ( i=0, ien=cols.length ; i<ien ; i++ ) {\n\t\t\t\tcols[i].sType = null;\n\t\t\t}\n\t\n\t\t\t// Update DataTables special `DT_*` attributes for the row\n\t\t\t_fnRowAttributes( settings, row );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a data source object from an HTML row, reading the contents of the\n\t * cells that are in the row.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {node|object} TR element from which to read data or existing row\n\t *   object from which to re-read the data from the cells\n\t * @param {int} [colIdx] Optional column index\n\t * @param {array|object} [d] Data source object. If `colIdx` is given then this\n\t *   parameter should also be given and will be used to write the data into.\n\t *   Only the column in question will be written\n\t * @returns {object} Object with two parameters: `data` the data read, in\n\t *   document order, and `cells` and array of nodes (they can be useful to the\n\t *   caller, so rather than needing a second traversal to get them, just return\n\t *   them from here).\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetRowElements( settings, row, colIdx, d )\n\t{\n\t\tvar\n\t\t\ttds = [],\n\t\t\ttd = row.firstChild,\n\t\t\tname, col, o, i=0, contents,\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tobjectRead = settings._rowReadObject;\n\t\n\t\t// Allow the data object to be passed in, or construct\n\t\td = d !== undefined ?\n\t\t\td :\n\t\t\tobjectRead ?\n\t\t\t\t{} :\n\t\t\t\t[];\n\t\n\t\tvar attr = function ( str, td  ) {\n\t\t\tif ( typeof str === 'string' ) {\n\t\t\t\tvar idx = str.indexOf('@');\n\t\n\t\t\t\tif ( idx !== -1 ) {\n\t\t\t\t\tvar attr = str.substring( idx+1 );\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( str );\n\t\t\t\t\tsetter( d, td.getAttribute( attr ) );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\n\t\t// Read data from a cell and store into the data object\n\t\tvar cellProcess = function ( cell ) {\n\t\t\tif ( colIdx === undefined || colIdx === i ) {\n\t\t\t\tcol = columns[i];\n\t\t\t\tcontents = $.trim(cell.innerHTML);\n\t\n\t\t\t\tif ( col && col._bAttrSrc ) {\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( col.mData._ );\n\t\t\t\t\tsetter( d, contents );\n\t\n\t\t\t\t\tattr( col.mData.sort, cell );\n\t\t\t\t\tattr( col.mData.type, cell );\n\t\t\t\t\tattr( col.mData.filter, cell );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Depending on the `data` option for the columns the data can\n\t\t\t\t\t// be read to either an object or an array.\n\t\t\t\t\tif ( objectRead ) {\n\t\t\t\t\t\tif ( ! col._setter ) {\n\t\t\t\t\t\t\t// Cache the setter function\n\t\t\t\t\t\t\tcol._setter = _fnSetObjectDataFn( col.mData );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcol._setter( d, contents );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\td[i] = contents;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t};\n\t\n\t\tif ( td ) {\n\t\t\t// `tr` element was passed in\n\t\t\twhile ( td ) {\n\t\t\t\tname = td.nodeName.toUpperCase();\n\t\n\t\t\t\tif ( name == \"TD\" || name == \"TH\" ) {\n\t\t\t\t\tcellProcess( td );\n\t\t\t\t\ttds.push( td );\n\t\t\t\t}\n\t\n\t\t\t\ttd = td.nextSibling;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Existing row object passed in\n\t\t\ttds = row.anCells;\n\t\n\t\t\tfor ( var j=0, jen=tds.length ; j<jen ; j++ ) {\n\t\t\t\tcellProcess( tds[j] );\n\t\t\t}\n\t\t}\n\t\n\t\t// Read the ID from the DOM if present\n\t\tvar rowNode = row.firstChild ? row : row.nTr;\n\t\n\t\tif ( rowNode ) {\n\t\t\tvar id = rowNode.getAttribute( 'id' );\n\t\n\t\t\tif ( id ) {\n\t\t\t\t_fnSetObjectDataFn( settings.rowId )( d, id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn {\n\t\t\tdata: d,\n\t\t\tcells: tds\n\t\t};\n\t}\n\t/**\n\t * Create a new TR element (and it's TD children) for a row\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow Row to consider\n\t *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCreateTr ( oSettings, iRow, nTrIn, anTds )\n\t{\n\t\tvar\n\t\t\trow = oSettings.aoData[iRow],\n\t\t\trowData = row._aData,\n\t\t\tcells = [],\n\t\t\tnTr, nTd, oCol,\n\t\t\ti, iLen;\n\t\n\t\tif ( row.nTr === null )\n\t\t{\n\t\t\tnTr = nTrIn || document.createElement('tr');\n\t\n\t\t\trow.nTr = nTr;\n\t\t\trow.anCells = cells;\n\t\n\t\t\t/* Use a private property on the node to allow reserve mapping from the node\n\t\t\t * to the aoData array for fast look up\n\t\t\t */\n\t\t\tnTr._DT_RowIndex = iRow;\n\t\n\t\t\t/* Special parameters can be given by the data source to be used on the row */\n\t\t\t_fnRowAttributes( oSettings, row );\n\t\n\t\t\t/* Process each column */\n\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toCol = oSettings.aoColumns[i];\n\t\n\t\t\t\tnTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );\n\t\t\t\tnTd._DT_CellIndex = {\n\t\t\t\t\trow: iRow,\n\t\t\t\t\tcolumn: i\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tcells.push( nTd );\n\t\n\t\t\t\t// Need to create the HTML if new, or if a rendering function is defined\n\t\t\t\tif ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&\n\t\t\t\t\t (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')\n\t\t\t\t) {\n\t\t\t\t\tnTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );\n\t\t\t\t}\n\t\n\t\t\t\t/* Add user defined class */\n\t\t\t\tif ( oCol.sClass )\n\t\t\t\t{\n\t\t\t\t\tnTd.className += ' '+oCol.sClass;\n\t\t\t\t}\n\t\n\t\t\t\t// Visibility - add or remove as required\n\t\t\t\tif ( oCol.bVisible && ! nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTr.appendChild( nTd );\n\t\t\t\t}\n\t\t\t\telse if ( ! oCol.bVisible && nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTd.parentNode.removeChild( nTd );\n\t\t\t\t}\n\t\n\t\t\t\tif ( oCol.fnCreatedCell )\n\t\t\t\t{\n\t\t\t\t\toCol.fnCreatedCell.call( oSettings.oInstance,\n\t\t\t\t\t\tnTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );\n\t\t}\n\t\n\t\t// Remove once webkit bug 131819 and Chromium bug 365619 have been resolved\n\t\t// and deployed\n\t\trow.nTr.setAttribute( 'role', 'row' );\n\t}\n\t\n\t\n\t/**\n\t * Add attributes to a row based on the special `DT_*` parameters in a data\n\t * source object.\n\t *  @param {object} settings DataTables settings object\n\t *  @param {object} DataTables row object for the row to be modified\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnRowAttributes( settings, row )\n\t{\n\t\tvar tr = row.nTr;\n\t\tvar data = row._aData;\n\t\n\t\tif ( tr ) {\n\t\t\tvar id = settings.rowIdFn( data );\n\t\n\t\t\tif ( id ) {\n\t\t\t\ttr.id = id;\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowClass ) {\n\t\t\t\t// Remove any classes added by DT_RowClass before\n\t\t\t\tvar a = data.DT_RowClass.split(' ');\n\t\t\t\trow.__rowc = row.__rowc ?\n\t\t\t\t\t_unique( row.__rowc.concat( a ) ) :\n\t\t\t\t\ta;\n\t\n\t\t\t\t$(tr)\n\t\t\t\t\t.removeClass( row.__rowc.join(' ') )\n\t\t\t\t\t.addClass( data.DT_RowClass );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowAttr ) {\n\t\t\t\t$(tr).attr( data.DT_RowAttr );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowData ) {\n\t\t\t\t$(tr).data( data.DT_RowData );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Create the HTML header for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBuildHead( oSettings )\n\t{\n\t\tvar i, ien, cell, row, column;\n\t\tvar thead = oSettings.nTHead;\n\t\tvar tfoot = oSettings.nTFoot;\n\t\tvar createHeader = $('th, td', thead).length === 0;\n\t\tvar classes = oSettings.oClasses;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\tif ( createHeader ) {\n\t\t\trow = $('<tr/>').appendTo( thead );\n\t\t}\n\t\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcell = $( column.nTh ).addClass( column.sClass );\n\t\n\t\t\tif ( createHeader ) {\n\t\t\t\tcell.appendTo( row );\n\t\t\t}\n\t\n\t\t\t// 1.11 move into sorting\n\t\t\tif ( oSettings.oFeatures.bSort ) {\n\t\t\t\tcell.addClass( column.sSortingClass );\n\t\n\t\t\t\tif ( column.bSortable !== false ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.attr( 'tabindex', oSettings.iTabIndex )\n\t\t\t\t\t\t.attr( 'aria-controls', oSettings.sTableId );\n\t\n\t\t\t\t\t_fnSortAttachListener( oSettings, column.nTh, i );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( column.sTitle != cell[0].innerHTML ) {\n\t\t\t\tcell.html( column.sTitle );\n\t\t\t}\n\t\n\t\t\t_fnRenderer( oSettings, 'header' )(\n\t\t\t\toSettings, cell, column, classes\n\t\t\t);\n\t\t}\n\t\n\t\tif ( createHeader ) {\n\t\t\t_fnDetectHeader( oSettings.aoHeader, thead );\n\t\t}\n\t\t\n\t\t/* ARIA role for the rows */\n\t \t$(thead).find('>tr').attr('role', 'row');\n\t\n\t\t/* Deal with the footer - add classes if required */\n\t\t$(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );\n\t\t$(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );\n\t\n\t\t// Cache the footer cells. Note that we only take the cells from the first\n\t\t// row in the footer. If there is more than one row the user wants to\n\t\t// interact with, they need to use the table().foot() method. Note also this\n\t\t// allows cells to be used for multiple columns using colspan\n\t\tif ( tfoot !== null ) {\n\t\t\tvar cells = oSettings.aoFooter[0];\n\t\n\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tcolumn = columns[i];\n\t\t\t\tcolumn.nTf = cells[i].cell;\n\t\n\t\t\t\tif ( column.sClass ) {\n\t\t\t\t\t$(column.nTf).addClass( column.sClass );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the header (or footer) element based on the column visibility states. The\n\t * methodology here is to use the layout array from _fnDetectHeader, modified for\n\t * the instantaneous column visibility, to construct the new layout. The grid is\n\t * traversed over cell at a time in a rows x columns grid fashion, although each\n\t * cell insert can cover multiple elements in the grid - which is tracks using the\n\t * aApplied array. Cell inserts in the grid will only occur where there isn't\n\t * already a cell in that position.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param array {objects} aoSource Layout array from _fnDetectHeader\n\t *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDrawHead( oSettings, aoSource, bIncludeHidden )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, n, nLocalTr;\n\t\tvar aoLocal = [];\n\t\tvar aApplied = [];\n\t\tvar iColumns = oSettings.aoColumns.length;\n\t\tvar iRowspan, iColspan;\n\t\n\t\tif ( ! aoSource )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif (  bIncludeHidden === undefined )\n\t\t{\n\t\t\tbIncludeHidden = false;\n\t\t}\n\t\n\t\t/* Make a copy of the master layout array, but without the visible columns in it */\n\t\tfor ( i=0, iLen=aoSource.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taoLocal[i] = aoSource[i].slice();\n\t\t\taoLocal[i].nTr = aoSource[i].nTr;\n\t\n\t\t\t/* Remove any columns which are currently hidden */\n\t\t\tfor ( j=iColumns-1 ; j>=0 ; j-- )\n\t\t\t{\n\t\t\t\tif ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )\n\t\t\t\t{\n\t\t\t\t\taoLocal[i].splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Prep the applied array - it needs an element for each row */\n\t\t\taApplied.push( [] );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnLocalTr = aoLocal[i].nTr;\n\t\n\t\t\t/* All cells are going to be replaced, so empty out the row */\n\t\t\tif ( nLocalTr )\n\t\t\t{\n\t\t\t\twhile( (n = nLocalTr.firstChild) )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.removeChild( n );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tfor ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tiRowspan = 1;\n\t\t\t\tiColspan = 1;\n\t\n\t\t\t\t/* Check to see if there is already a cell (row/colspan) covering our target\n\t\t\t\t * insert point. If there is, then there is nothing to do.\n\t\t\t\t */\n\t\t\t\tif ( aApplied[i][j] === undefined )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.appendChild( aoLocal[i][j].cell );\n\t\t\t\t\taApplied[i][j] = 1;\n\t\n\t\t\t\t\t/* Expand the cell to cover as many rows as needed */\n\t\t\t\t\twhile ( aoLocal[i+iRowspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\taApplied[i+iRowspan][j] = 1;\n\t\t\t\t\t\tiRowspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Expand the cell to cover as many columns as needed */\n\t\t\t\t\twhile ( aoLocal[i][j+iColspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Must update the applied array over the rows for the columns */\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taApplied[i+k][j+iColspan] = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiColspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Do the actual expansion in the DOM */\n\t\t\t\t\t$(aoLocal[i][j].cell)\n\t\t\t\t\t\t.attr('rowspan', iRowspan)\n\t\t\t\t\t\t.attr('colspan', iColspan);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Insert the required TR nodes into the table for display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDraw( oSettings )\n\t{\n\t\t/* Provide a pre-callback function which can be used to cancel the draw is false is returned */\n\t\tvar aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );\n\t\tif ( $.inArray( false, aPreDraw ) !== -1 )\n\t\t{\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar i, iLen, n;\n\t\tvar anRows = [];\n\t\tvar iRowCount = 0;\n\t\tvar asStripeClasses = oSettings.asStripeClasses;\n\t\tvar iStripes = asStripeClasses.length;\n\t\tvar iOpenRows = oSettings.aoOpenRows.length;\n\t\tvar oLang = oSettings.oLanguage;\n\t\tvar iInitDisplayStart = oSettings.iInitDisplayStart;\n\t\tvar bServerSide = _fnDataSource( oSettings ) == 'ssp';\n\t\tvar aiDisplay = oSettings.aiDisplay;\n\t\n\t\toSettings.bDrawing = true;\n\t\n\t\t/* Check and see if we have an initial draw position from state saving */\n\t\tif ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )\n\t\t{\n\t\t\toSettings._iDisplayStart = bServerSide ?\n\t\t\t\tiInitDisplayStart :\n\t\t\t\tiInitDisplayStart >= oSettings.fnRecordsDisplay() ?\n\t\t\t\t\t0 :\n\t\t\t\t\tiInitDisplayStart;\n\t\n\t\t\toSettings.iInitDisplayStart = -1;\n\t\t}\n\t\n\t\tvar iDisplayStart = oSettings._iDisplayStart;\n\t\tvar iDisplayEnd = oSettings.fnDisplayEnd();\n\t\n\t\t/* Server-side processing draw intercept */\n\t\tif ( oSettings.bDeferLoading )\n\t\t{\n\t\t\toSettings.bDeferLoading = false;\n\t\t\toSettings.iDraw++;\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t}\n\t\telse if ( !bServerSide )\n\t\t{\n\t\t\toSettings.iDraw++;\n\t\t}\n\t\telse if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( aiDisplay.length !== 0 )\n\t\t{\n\t\t\tvar iStart = bServerSide ? 0 : iDisplayStart;\n\t\t\tvar iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;\n\t\n\t\t\tfor ( var j=iStart ; j<iEnd ; j++ )\n\t\t\t{\n\t\t\t\tvar iDataIndex = aiDisplay[j];\n\t\t\t\tvar aoData = oSettings.aoData[ iDataIndex ];\n\t\t\t\tif ( aoData.nTr === null )\n\t\t\t\t{\n\t\t\t\t\t_fnCreateTr( oSettings, iDataIndex );\n\t\t\t\t}\n\t\n\t\t\t\tvar nRow = aoData.nTr;\n\t\n\t\t\t\t/* Remove the old striping classes and then add the new one */\n\t\t\t\tif ( iStripes !== 0 )\n\t\t\t\t{\n\t\t\t\t\tvar sStripe = asStripeClasses[ iRowCount % iStripes ];\n\t\t\t\t\tif ( aoData._sRowStripe != sStripe )\n\t\t\t\t\t{\n\t\t\t\t\t\t$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );\n\t\t\t\t\t\taoData._sRowStripe = sStripe;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Row callback functions - might want to manipulate the row\n\t\t\t\t// iRowCount and j are not currently documented. Are they at all\n\t\t\t\t// useful?\n\t\t\t\t_fnCallbackFire( oSettings, 'aoRowCallback', null,\n\t\t\t\t\t[nRow, aoData._aData, iRowCount, j] );\n\t\n\t\t\t\tanRows.push( nRow );\n\t\t\t\tiRowCount++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Table is empty - create a row with an empty message in it */\n\t\t\tvar sZero = oLang.sZeroRecords;\n\t\t\tif ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )\n\t\t\t{\n\t\t\t\tsZero = oLang.sLoadingRecords;\n\t\t\t}\n\t\t\telse if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )\n\t\t\t{\n\t\t\t\tsZero = oLang.sEmptyTable;\n\t\t\t}\n\t\n\t\t\tanRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )\n\t\t\t\t.append( $('<td />', {\n\t\t\t\t\t'valign':  'top',\n\t\t\t\t\t'colSpan': _fnVisbleColumns( oSettings ),\n\t\t\t\t\t'class':   oSettings.oClasses.sRowEmpty\n\t\t\t\t} ).html( sZero ) )[0];\n\t\t}\n\t\n\t\t/* Header and footer callbacks */\n\t\t_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\t_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\tvar body = $(oSettings.nTBody);\n\t\n\t\tbody.children().detach();\n\t\tbody.append( $(anRows) );\n\t\n\t\t/* Call all required callback functions for the end of a draw */\n\t\t_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );\n\t\n\t\t/* Draw is complete, sorting and filtering must be as well */\n\t\toSettings.bSorted = false;\n\t\toSettings.bFiltered = false;\n\t\toSettings.bDrawing = false;\n\t}\n\t\n\t\n\t/**\n\t * Redraw the table - taking account of the various features which are enabled\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {boolean} [holdPosition] Keep the current paging position. By default\n\t *    the paging is reset to the first page\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReDraw( settings, holdPosition )\n\t{\n\t\tvar\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tsort     = features.bSort,\n\t\t\tfilter   = features.bFilter;\n\t\n\t\tif ( sort ) {\n\t\t\t_fnSort( settings );\n\t\t}\n\t\n\t\tif ( filter ) {\n\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch );\n\t\t}\n\t\telse {\n\t\t\t// No filtering, so we want to just use the display master\n\t\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\t}\n\t\n\t\tif ( holdPosition !== true ) {\n\t\t\tsettings._iDisplayStart = 0;\n\t\t}\n\t\n\t\t// Let any modules know about the draw hold position state (used by\n\t\t// scrolling internally)\n\t\tsettings._drawHold = holdPosition;\n\t\n\t\t_fnDraw( settings );\n\t\n\t\tsettings._drawHold = false;\n\t}\n\t\n\t\n\t/**\n\t * Add the options to the page HTML for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddOptionsHtml ( oSettings )\n\t{\n\t\tvar classes = oSettings.oClasses;\n\t\tvar table = $(oSettings.nTable);\n\t\tvar holding = $('<div/>').insertBefore( table ); // Holding element for speed\n\t\tvar features = oSettings.oFeatures;\n\t\n\t\t// All DataTables are wrapped in a div\n\t\tvar insert = $('<div/>', {\n\t\t\tid:      oSettings.sTableId+'_wrapper',\n\t\t\t'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)\n\t\t} );\n\t\n\t\toSettings.nHolding = holding[0];\n\t\toSettings.nTableWrapper = insert[0];\n\t\toSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;\n\t\n\t\t/* Loop over the user set positioning and place the elements as needed */\n\t\tvar aDom = oSettings.sDom.split('');\n\t\tvar featureNode, cOption, nNewNode, cNext, sAttr, j;\n\t\tfor ( var i=0 ; i<aDom.length ; i++ )\n\t\t{\n\t\t\tfeatureNode = null;\n\t\t\tcOption = aDom[i];\n\t\n\t\t\tif ( cOption == '<' )\n\t\t\t{\n\t\t\t\t/* New container div */\n\t\t\t\tnNewNode = $('<div/>')[0];\n\t\n\t\t\t\t/* Check to see if we should append an id and/or a class name to the container */\n\t\t\t\tcNext = aDom[i+1];\n\t\t\t\tif ( cNext == \"'\" || cNext == '\"' )\n\t\t\t\t{\n\t\t\t\t\tsAttr = \"\";\n\t\t\t\t\tj = 2;\n\t\t\t\t\twhile ( aDom[i+j] != cNext )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr += aDom[i+j];\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Replace jQuery UI constants @todo depreciated */\n\t\t\t\t\tif ( sAttr == \"H\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIHeader;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr == \"F\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIFooter;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* The attribute can be in the format of \"#id.class\", \"#id\" or \"class\" This logic\n\t\t\t\t\t * breaks the string into parts and applies them as needed\n\t\t\t\t\t */\n\t\t\t\t\tif ( sAttr.indexOf('.') != -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar aSplit = sAttr.split('.');\n\t\t\t\t\t\tnNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);\n\t\t\t\t\t\tnNewNode.className = aSplit[1];\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr.charAt(0) == \"#\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.id = sAttr.substr(1, sAttr.length-1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.className = sAttr;\n\t\t\t\t\t}\n\t\n\t\t\t\t\ti += j; /* Move along the position array */\n\t\t\t\t}\n\t\n\t\t\t\tinsert.append( nNewNode );\n\t\t\t\tinsert = $(nNewNode);\n\t\t\t}\n\t\t\telse if ( cOption == '>' )\n\t\t\t{\n\t\t\t\t/* End container div */\n\t\t\t\tinsert = insert.parent();\n\t\t\t}\n\t\t\t// @todo Move options into their own plugins?\n\t\t\telse if ( cOption == 'l' && features.bPaginate && features.bLengthChange )\n\t\t\t{\n\t\t\t\t/* Length */\n\t\t\t\tfeatureNode = _fnFeatureHtmlLength( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'f' && features.bFilter )\n\t\t\t{\n\t\t\t\t/* Filter */\n\t\t\t\tfeatureNode = _fnFeatureHtmlFilter( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'r' && features.bProcessing )\n\t\t\t{\n\t\t\t\t/* pRocessing */\n\t\t\t\tfeatureNode = _fnFeatureHtmlProcessing( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 't' )\n\t\t\t{\n\t\t\t\t/* Table */\n\t\t\t\tfeatureNode = _fnFeatureHtmlTable( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption ==  'i' && features.bInfo )\n\t\t\t{\n\t\t\t\t/* Info */\n\t\t\t\tfeatureNode = _fnFeatureHtmlInfo( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'p' && features.bPaginate )\n\t\t\t{\n\t\t\t\t/* Pagination */\n\t\t\t\tfeatureNode = _fnFeatureHtmlPaginate( oSettings );\n\t\t\t}\n\t\t\telse if ( DataTable.ext.feature.length !== 0 )\n\t\t\t{\n\t\t\t\t/* Plug-in features */\n\t\t\t\tvar aoFeatures = DataTable.ext.feature;\n\t\t\t\tfor ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )\n\t\t\t\t{\n\t\t\t\t\tif ( cOption == aoFeatures[k].cFeature )\n\t\t\t\t\t{\n\t\t\t\t\t\tfeatureNode = aoFeatures[k].fnInit( oSettings );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Add to the 2D features array */\n\t\t\tif ( featureNode )\n\t\t\t{\n\t\t\t\tvar aanFeatures = oSettings.aanFeatures;\n\t\n\t\t\t\tif ( ! aanFeatures[cOption] )\n\t\t\t\t{\n\t\t\t\t\taanFeatures[cOption] = [];\n\t\t\t\t}\n\t\n\t\t\t\taanFeatures[cOption].push( featureNode );\n\t\t\t\tinsert.append( featureNode );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Built our DOM structure - replace the holding div with what we want */\n\t\tholding.replaceWith( insert );\n\t\toSettings.nHolding = null;\n\t}\n\t\n\t\n\t/**\n\t * Use the DOM source to create up an array of header cells. The idea here is to\n\t * create a layout grid (array) of rows x columns, which contains a reference\n\t * to the cell that that point in the grid (regardless of col/rowspan), such that\n\t * any column / row could be removed and the new grid constructed\n\t *  @param array {object} aLayout Array to store the calculated layout in\n\t *  @param {node} nThead The header/footer element for the table\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDetectHeader ( aLayout, nThead )\n\t{\n\t\tvar nTrs = $(nThead).children('tr');\n\t\tvar nTr, nCell;\n\t\tvar i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;\n\t\tvar bUnique;\n\t\tvar fnShiftCol = function ( a, i, j ) {\n\t\t\tvar k = a[i];\n\t                while ( k[j] ) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\treturn j;\n\t\t};\n\t\n\t\taLayout.splice( 0, aLayout.length );\n\t\n\t\t/* We know how many rows there are in the layout - so prep it */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taLayout.push( [] );\n\t\t}\n\t\n\t\t/* Calculate a layout array */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnTr = nTrs[i];\n\t\t\tiColumn = 0;\n\t\n\t\t\t/* For every cell in the row... */\n\t\t\tnCell = nTr.firstChild;\n\t\t\twhile ( nCell ) {\n\t\t\t\tif ( nCell.nodeName.toUpperCase() == \"TD\" ||\n\t\t\t\t     nCell.nodeName.toUpperCase() == \"TH\" )\n\t\t\t\t{\n\t\t\t\t\t/* Get the col and rowspan attributes from the DOM and sanitise them */\n\t\t\t\t\tiColspan = nCell.getAttribute('colspan') * 1;\n\t\t\t\t\tiRowspan = nCell.getAttribute('rowspan') * 1;\n\t\t\t\t\tiColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;\n\t\t\t\t\tiRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;\n\t\n\t\t\t\t\t/* There might be colspan cells already in this row, so shift our target\n\t\t\t\t\t * accordingly\n\t\t\t\t\t */\n\t\t\t\t\tiColShifted = fnShiftCol( aLayout, i, iColumn );\n\t\n\t\t\t\t\t/* Cache calculation for unique columns */\n\t\t\t\t\tbUnique = iColspan === 1 ? true : false;\n\t\n\t\t\t\t\t/* If there is col / rowspan, copy the information into the layout grid */\n\t\t\t\t\tfor ( l=0 ; l<iColspan ; l++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taLayout[i+k][iColShifted+l] = {\n\t\t\t\t\t\t\t\t\"cell\": nCell,\n\t\t\t\t\t\t\t\t\"unique\": bUnique\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\taLayout[i+k].nTr = nTr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnCell = nCell.nextSibling;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Get an array of unique th elements, one for each column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nHeader automatically detect the layout from this node - optional\n\t *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional\n\t *  @returns array {node} aReturn list of unique th's\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetUniqueThs ( oSettings, nHeader, aLayout )\n\t{\n\t\tvar aReturn = [];\n\t\tif ( !aLayout )\n\t\t{\n\t\t\taLayout = oSettings.aoHeader;\n\t\t\tif ( nHeader )\n\t\t\t{\n\t\t\t\taLayout = [];\n\t\t\t\t_fnDetectHeader( aLayout, nHeader );\n\t\t\t}\n\t\t}\n\t\n\t\tfor ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfor ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( aLayout[i][j].unique &&\n\t\t\t\t\t (!aReturn[j] || !oSettings.bSortCellsTop) )\n\t\t\t\t{\n\t\t\t\t\taReturn[j] = aLayout[i][j].cell;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn aReturn;\n\t}\n\t\n\t/**\n\t * Create an Ajax call based on the table's settings, taking into account that\n\t * parameters can have multiple forms, and backwards compatibility.\n\t *\n\t * @param {object} oSettings dataTables settings object\n\t * @param {array} data Data to send to the server, required by\n\t *     DataTables - may be augmented by developer callbacks\n\t * @param {function} fn Callback function to run when data is obtained\n\t */\n\tfunction _fnBuildAjax( oSettings, data, fn )\n\t{\n\t\t// Compatibility with 1.9-, allow fnServerData and event to manipulate\n\t\t_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );\n\t\n\t\t// Convert to object based for 1.10+ if using the old array scheme which can\n\t\t// come from server-side processing or serverParams\n\t\tif ( data && $.isArray(data) ) {\n\t\t\tvar tmp = {};\n\t\t\tvar rbracket = /(.*?)\\[\\]$/;\n\t\n\t\t\t$.each( data, function (key, val) {\n\t\t\t\tvar match = val.name.match(rbracket);\n\t\n\t\t\t\tif ( match ) {\n\t\t\t\t\t// Support for arrays\n\t\t\t\t\tvar name = match[0];\n\t\n\t\t\t\t\tif ( ! tmp[ name ] ) {\n\t\t\t\t\t\ttmp[ name ] = [];\n\t\t\t\t\t}\n\t\t\t\t\ttmp[ name ].push( val.value );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttmp[val.name] = val.value;\n\t\t\t\t}\n\t\t\t} );\n\t\t\tdata = tmp;\n\t\t}\n\t\n\t\tvar ajaxData;\n\t\tvar ajax = oSettings.ajax;\n\t\tvar instance = oSettings.oInstance;\n\t\tvar callback = function ( json ) {\n\t\t\t_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );\n\t\t\tfn( json );\n\t\t};\n\t\n\t\tif ( $.isPlainObject( ajax ) && ajax.data )\n\t\t{\n\t\t\tajaxData = ajax.data;\n\t\n\t\t\tvar newData = $.isFunction( ajaxData ) ?\n\t\t\t\tajaxData( data, oSettings ) :  // fn can manipulate data or return\n\t\t\t\tajaxData;                      // an object object or array to merge\n\t\n\t\t\t// If the function returned something, use that alone\n\t\t\tdata = $.isFunction( ajaxData ) && newData ?\n\t\t\t\tnewData :\n\t\t\t\t$.extend( true, data, newData );\n\t\n\t\t\t// Remove the data property as we've resolved it already and don't want\n\t\t\t// jQuery to do it again (it is restored at the end of the function)\n\t\t\tdelete ajax.data;\n\t\t}\n\t\n\t\tvar baseAjax = {\n\t\t\t\"data\": data,\n\t\t\t\"success\": function (json) {\n\t\t\t\tvar error = json.error || json.sError;\n\t\t\t\tif ( error ) {\n\t\t\t\t\t_fnLog( oSettings, 0, error );\n\t\t\t\t}\n\t\n\t\t\t\toSettings.json = json;\n\t\t\t\tcallback( json );\n\t\t\t},\n\t\t\t\"dataType\": \"json\",\n\t\t\t\"cache\": false,\n\t\t\t\"type\": oSettings.sServerMethod,\n\t\t\t\"error\": function (xhr, error, thrown) {\n\t\t\t\tvar ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );\n\t\n\t\t\t\tif ( $.inArray( true, ret ) === -1 ) {\n\t\t\t\t\tif ( error == \"parsererror\" ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Invalid JSON response', 1 );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( xhr.readyState === 4 ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Ajax error', 7 );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\t}\n\t\t};\n\t\n\t\t// Store the data submitted for the API\n\t\toSettings.oAjaxData = data;\n\t\n\t\t// Allow plug-ins and external processes to modify the data\n\t\t_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );\n\t\n\t\tif ( oSettings.fnServerData )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.fnServerData.call( instance,\n\t\t\t\toSettings.sAjaxSource,\n\t\t\t\t$.map( data, function (val, key) { // Need to convert back to 1.9 trad format\n\t\t\t\t\treturn { name: key, value: val };\n\t\t\t\t} ),\n\t\t\t\tcallback,\n\t\t\t\toSettings\n\t\t\t);\n\t\t}\n\t\telse if ( oSettings.sAjaxSource || typeof ajax === 'string' )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, {\n\t\t\t\turl: ajax || oSettings.sAjaxSource\n\t\t\t} ) );\n\t\t}\n\t\telse if ( $.isFunction( ajax ) )\n\t\t{\n\t\t\t// Is a function - let the caller define what needs to be done\n\t\t\toSettings.jqXHR = ajax.call( instance, data, callback, oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Object to extend the base settings\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );\n\t\n\t\t\t// Restore for next time around\n\t\t\tajax.data = ajaxData;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Update the table using an Ajax call\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {boolean} Block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdate( settings )\n\t{\n\t\tif ( settings.bAjaxDataGet ) {\n\t\t\tsettings.iDraw++;\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t_fnBuildAjax(\n\t\t\t\tsettings,\n\t\t\t\t_fnAjaxParameters( settings ),\n\t\t\t\tfunction(json) {\n\t\t\t\t\t_fnAjaxUpdateDraw( settings, json );\n\t\t\t\t}\n\t\t\t);\n\t\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\t\n\t/**\n\t * Build up the parameters in an object needed for a server-side processing\n\t * request. Note that this is basically done twice, is different ways - a modern\n\t * method which is used by default in DataTables 1.10 which uses objects and\n\t * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if\n\t * the sAjaxSource option is used in the initialisation, or the legacyAjax\n\t * option is set.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {bool} block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxParameters( settings )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tcolumnCount = columns.length,\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tpreSearch = settings.oPreviousSearch,\n\t\t\tpreColSearch = settings.aoPreSearchCols,\n\t\t\ti, data = [], dataProp, column, columnSearch,\n\t\t\tsort = _fnSortFlatten( settings ),\n\t\t\tdisplayStart = settings._iDisplayStart,\n\t\t\tdisplayLength = features.bPaginate !== false ?\n\t\t\t\tsettings._iDisplayLength :\n\t\t\t\t-1;\n\t\n\t\tvar param = function ( name, value ) {\n\t\t\tdata.push( { 'name': name, 'value': value } );\n\t\t};\n\t\n\t\t// DataTables 1.9- compatible method\n\t\tparam( 'sEcho',          settings.iDraw );\n\t\tparam( 'iColumns',       columnCount );\n\t\tparam( 'sColumns',       _pluck( columns, 'sName' ).join(',') );\n\t\tparam( 'iDisplayStart',  displayStart );\n\t\tparam( 'iDisplayLength', displayLength );\n\t\n\t\t// DataTables 1.10+ method\n\t\tvar d = {\n\t\t\tdraw:    settings.iDraw,\n\t\t\tcolumns: [],\n\t\t\torder:   [],\n\t\t\tstart:   displayStart,\n\t\t\tlength:  displayLength,\n\t\t\tsearch:  {\n\t\t\t\tvalue: preSearch.sSearch,\n\t\t\t\tregex: preSearch.bRegex\n\t\t\t}\n\t\t};\n\t\n\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcolumnSearch = preColSearch[i];\n\t\t\tdataProp = typeof column.mData==\"function\" ? 'function' : column.mData ;\n\t\n\t\t\td.columns.push( {\n\t\t\t\tdata:       dataProp,\n\t\t\t\tname:       column.sName,\n\t\t\t\tsearchable: column.bSearchable,\n\t\t\t\torderable:  column.bSortable,\n\t\t\t\tsearch:     {\n\t\t\t\t\tvalue: columnSearch.sSearch,\n\t\t\t\t\tregex: columnSearch.bRegex\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\tparam( \"mDataProp_\"+i, dataProp );\n\t\n\t\t\tif ( features.bFilter ) {\n\t\t\t\tparam( 'sSearch_'+i,     columnSearch.sSearch );\n\t\t\t\tparam( 'bRegex_'+i,      columnSearch.bRegex );\n\t\t\t\tparam( 'bSearchable_'+i, column.bSearchable );\n\t\t\t}\n\t\n\t\t\tif ( features.bSort ) {\n\t\t\t\tparam( 'bSortable_'+i, column.bSortable );\n\t\t\t}\n\t\t}\n\t\n\t\tif ( features.bFilter ) {\n\t\t\tparam( 'sSearch', preSearch.sSearch );\n\t\t\tparam( 'bRegex', preSearch.bRegex );\n\t\t}\n\t\n\t\tif ( features.bSort ) {\n\t\t\t$.each( sort, function ( i, val ) {\n\t\t\t\td.order.push( { column: val.col, dir: val.dir } );\n\t\n\t\t\t\tparam( 'iSortCol_'+i, val.col );\n\t\t\t\tparam( 'sSortDir_'+i, val.dir );\n\t\t\t} );\n\t\n\t\t\tparam( 'iSortingCols', sort.length );\n\t\t}\n\t\n\t\t// If the legacy.ajax parameter is null, then we automatically decide which\n\t\t// form to use, based on sAjaxSource\n\t\tvar legacy = DataTable.ext.legacy.ajax;\n\t\tif ( legacy === null ) {\n\t\t\treturn settings.sAjaxSource ? data : d;\n\t\t}\n\t\n\t\t// Otherwise, if legacy has been specified then we use that to decide on the\n\t\t// form\n\t\treturn legacy ? data : d;\n\t}\n\t\n\t\n\t/**\n\t * Data the data from the server (nuking the old) and redraw the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} json json data return from the server.\n\t *  @param {string} json.sEcho Tracking flag for DataTables to match requests\n\t *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering\n\t *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering\n\t *  @param {array} json.aaData The data to display on this page\n\t *  @param {string} [json.sColumns] Column ordering (sName, comma separated)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdateDraw ( settings, json )\n\t{\n\t\t// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.\n\t\t// Support both\n\t\tvar compat = function ( old, modern ) {\n\t\t\treturn json[old] !== undefined ? json[old] : json[modern];\n\t\t};\n\t\n\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\tvar draw            = compat( 'sEcho',                'draw' );\n\t\tvar recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );\n\t\tvar recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );\n\t\n\t\tif ( draw ) {\n\t\t\t// Protect against out of sequence returns\n\t\t\tif ( draw*1 < settings.iDraw ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettings.iDraw = draw * 1;\n\t\t}\n\t\n\t\t_fnClearTable( settings );\n\t\tsettings._iRecordsTotal   = parseInt(recordsTotal, 10);\n\t\tsettings._iRecordsDisplay = parseInt(recordsFiltered, 10);\n\t\n\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t_fnAddData( settings, data[i] );\n\t\t}\n\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\n\t\tsettings.bAjaxDataGet = false;\n\t\t_fnDraw( settings );\n\t\n\t\tif ( ! settings._bInitComplete ) {\n\t\t\t_fnInitComplete( settings, json );\n\t\t}\n\t\n\t\tsettings.bAjaxDataGet = true;\n\t\t_fnProcessingDisplay( settings, false );\n\t}\n\t\n\t\n\t/**\n\t * Get the data from the JSON data source to use for drawing a table. Using\n\t * `_fnGetObjectDataFn` allows the data to be sourced from a property of the\n\t * source object, or from a processing function.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param  {object} json Data source object / array from the server\n\t *  @return {array} Array of data to use\n\t */\n\tfunction _fnAjaxDataSrc ( oSettings, json )\n\t{\n\t\tvar dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?\n\t\t\toSettings.ajax.dataSrc :\n\t\t\toSettings.sAjaxDataProp; // Compatibility with 1.9-.\n\t\n\t\t// Compatibility with 1.9-. In order to read from aaData, check if the\n\t\t// default has been changed, if not, check for aaData\n\t\tif ( dataSrc === 'data' ) {\n\t\t\treturn json.aaData || json[dataSrc];\n\t\t}\n\t\n\t\treturn dataSrc !== \"\" ?\n\t\t\t_fnGetObjectDataFn( dataSrc )( json ) :\n\t\t\tjson;\n\t}\n\t\n\t/**\n\t * Generate the node required for filtering text\n\t *  @returns {node} Filter control element\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlFilter ( settings )\n\t{\n\t\tvar classes = settings.oClasses;\n\t\tvar tableId = settings.sTableId;\n\t\tvar language = settings.oLanguage;\n\t\tvar previousSearch = settings.oPreviousSearch;\n\t\tvar features = settings.aanFeatures;\n\t\tvar input = '<input type=\"search\" class=\"'+classes.sFilterInput+'\"/>';\n\t\n\t\tvar str = language.sSearch;\n\t\tstr = str.match(/_INPUT_/) ?\n\t\t\tstr.replace('_INPUT_', input) :\n\t\t\tstr+input;\n\t\n\t\tvar filter = $('<div/>', {\n\t\t\t\t'id': ! features.f ? tableId+'_filter' : null,\n\t\t\t\t'class': classes.sFilter\n\t\t\t} )\n\t\t\t.append( $('<label/>' ).append( str ) );\n\t\n\t\tvar searchFn = function() {\n\t\t\t/* Update all other filter input elements for the new display */\n\t\t\tvar n = features.f;\n\t\t\tvar val = !this.value ? \"\" : this.value; // mental IE8 fix :-(\n\t\n\t\t\t/* Now do the filter */\n\t\t\tif ( val != previousSearch.sSearch ) {\n\t\t\t\t_fnFilterComplete( settings, {\n\t\t\t\t\t\"sSearch\": val,\n\t\t\t\t\t\"bRegex\": previousSearch.bRegex,\n\t\t\t\t\t\"bSmart\": previousSearch.bSmart ,\n\t\t\t\t\t\"bCaseInsensitive\": previousSearch.bCaseInsensitive\n\t\t\t\t} );\n\t\n\t\t\t\t// Need to redraw, without resorting\n\t\t\t\tsettings._iDisplayStart = 0;\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t};\n\t\n\t\tvar searchDelay = settings.searchDelay !== null ?\n\t\t\tsettings.searchDelay :\n\t\t\t_fnDataSource( settings ) === 'ssp' ?\n\t\t\t\t400 :\n\t\t\t\t0;\n\t\n\t\tvar jqFilter = $('input', filter)\n\t\t\t.val( previousSearch.sSearch )\n\t\t\t.attr( 'placeholder', language.sSearchPlaceholder )\n\t\t\t.on(\n\t\t\t\t'keyup.DT search.DT input.DT paste.DT cut.DT',\n\t\t\t\tsearchDelay ?\n\t\t\t\t\t_fnThrottle( searchFn, searchDelay ) :\n\t\t\t\t\tsearchFn\n\t\t\t)\n\t\t\t.on( 'keypress.DT', function(e) {\n\t\t\t\t/* Prevent form submission */\n\t\t\t\tif ( e.keyCode == 13 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.attr('aria-controls', tableId);\n\t\n\t\t// Update the input elements whenever the table is filtered\n\t\t$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame...\n\t\t\t\ttry {\n\t\t\t\t\tif ( jqFilter[0] !== document.activeElement ) {\n\t\t\t\t\t\tjqFilter.val( previousSearch.sSearch );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch ( e ) {}\n\t\t\t}\n\t\t} );\n\t\n\t\treturn filter[0];\n\t}\n\t\n\t\n\t/**\n\t * Filter the table using both the global filter and column based filtering\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oSearch search information\n\t *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterComplete ( oSettings, oInput, iForce )\n\t{\n\t\tvar oPrevSearch = oSettings.oPreviousSearch;\n\t\tvar aoPrevSearch = oSettings.aoPreSearchCols;\n\t\tvar fnSaveFilter = function ( oFilter ) {\n\t\t\t/* Save the filtering values */\n\t\t\toPrevSearch.sSearch = oFilter.sSearch;\n\t\t\toPrevSearch.bRegex = oFilter.bRegex;\n\t\t\toPrevSearch.bSmart = oFilter.bSmart;\n\t\t\toPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;\n\t\t};\n\t\tvar fnRegex = function ( o ) {\n\t\t\t// Backwards compatibility with the bEscapeRegex option\n\t\t\treturn o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;\n\t\t};\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo As per sort - can this be moved into an event handler?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\t/* In server-side processing all filtering is done by the server, so no point hanging around here */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' )\n\t\t{\n\t\t\t/* Global filter */\n\t\t\t_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );\n\t\t\tfnSaveFilter( oInput );\n\t\n\t\t\t/* Now do the individual column filter */\n\t\t\tfor ( var i=0 ; i<aoPrevSearch.length ; i++ )\n\t\t\t{\n\t\t\t\t_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),\n\t\t\t\t\taoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );\n\t\t\t}\n\t\n\t\t\t/* Custom filtering */\n\t\t\t_fnFilterCustom( oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfnSaveFilter( oInput );\n\t\t}\n\t\n\t\t/* Tell the draw function we have been filtering */\n\t\toSettings.bFiltered = true;\n\t\t_fnCallbackFire( oSettings, null, 'search', [oSettings] );\n\t}\n\t\n\t\n\t/**\n\t * Apply custom filtering functions\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCustom( settings )\n\t{\n\t\tvar filters = DataTable.ext.search;\n\t\tvar displayRows = settings.aiDisplay;\n\t\tvar row, rowIdx;\n\t\n\t\tfor ( var i=0, ien=filters.length ; i<ien ; i++ ) {\n\t\t\tvar rows = [];\n\t\n\t\t\t// Loop over each row and see if it should be included\n\t\t\tfor ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {\n\t\t\t\trowIdx = displayRows[ j ];\n\t\t\t\trow = settings.aoData[ rowIdx ];\n\t\n\t\t\t\tif ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {\n\t\t\t\t\trows.push( rowIdx );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// So the array reference doesn't break set the results into the\n\t\t\t// existing array\n\t\t\tdisplayRows.length = 0;\n\t\t\t$.merge( displayRows, rows );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Filter the table on a per-column basis\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sInput string to filter on\n\t *  @param {int} iColumn column to filter\n\t *  @param {bool} bRegex treat search string as a regular expression or not\n\t *  @param {bool} bSmart use smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )\n\t{\n\t\tif ( searchStr === '' ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar data;\n\t\tvar out = [];\n\t\tvar display = settings.aiDisplay;\n\t\tvar rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );\n\t\n\t\tfor ( var i=0 ; i<display.length ; i++ ) {\n\t\t\tdata = settings.aoData[ display[i] ]._aFilterData[ colIdx ];\n\t\n\t\t\tif ( rpSearch.test( data ) ) {\n\t\t\t\tout.push( display[i] );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aiDisplay = out;\n\t}\n\t\n\t\n\t/**\n\t * Filter the data table based on user input and draw the table\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} input string to filter on\n\t *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)\n\t *  @param {bool} regex treat as a regular expression or not\n\t *  @param {bool} smart perform smart filtering or not\n\t *  @param {bool} caseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilter( settings, input, force, regex, smart, caseInsensitive )\n\t{\n\t\tvar rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );\n\t\tvar prevSearch = settings.oPreviousSearch.sSearch;\n\t\tvar displayMaster = settings.aiDisplayMaster;\n\t\tvar display, invalidated, i;\n\t\tvar filtered = [];\n\t\n\t\t// Need to take account of custom filtering functions - always filter\n\t\tif ( DataTable.ext.search.length !== 0 ) {\n\t\t\tforce = true;\n\t\t}\n\t\n\t\t// Check if any of the rows were invalidated\n\t\tinvalidated = _fnFilterData( settings );\n\t\n\t\t// If the input is blank - we just want the full data set\n\t\tif ( input.length <= 0 ) {\n\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t}\n\t\telse {\n\t\t\t// New search - start from the master array\n\t\t\tif ( invalidated ||\n\t\t\t\t force ||\n\t\t\t\t prevSearch.length > input.length ||\n\t\t\t\t input.indexOf(prevSearch) !== 0 ||\n\t\t\t\t settings.bSorted // On resort, the display master needs to be\n\t\t\t\t                  // re-filtered since indexes will have changed\n\t\t\t) {\n\t\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t\t}\n\t\n\t\t\t// Search the display array\n\t\t\tdisplay = settings.aiDisplay;\n\t\n\t\t\tfor ( i=0 ; i<display.length ; i++ ) {\n\t\t\t\tif ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {\n\t\t\t\t\tfiltered.push( display[i] );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tsettings.aiDisplay = filtered;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a regular expression object suitable for searching a table\n\t *  @param {string} sSearch string to search for\n\t *  @param {bool} bRegex treat as a regular expression or not\n\t *  @param {bool} bSmart perform smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insensitive matching or not\n\t *  @returns {RegExp} constructed object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCreateSearch( search, regex, smart, caseInsensitive )\n\t{\n\t\tsearch = regex ?\n\t\t\tsearch :\n\t\t\t_fnEscapeRegex( search );\n\t\t\n\t\tif ( smart ) {\n\t\t\t/* For smart filtering we want to allow the search to work regardless of\n\t\t\t * word order. We also want double quoted text to be preserved, so word\n\t\t\t * order is important - a la google. So this is what we want to\n\t\t\t * generate:\n\t\t\t * \n\t\t\t * ^(?=.*?\\bone\\b)(?=.*?\\btwo three\\b)(?=.*?\\bfour\\b).*$\n\t\t\t */\n\t\t\tvar a = $.map( search.match( /\"[^\"]+\"|[^ ]+/g ) || [''], function ( word ) {\n\t\t\t\tif ( word.charAt(0) === '\"' ) {\n\t\t\t\t\tvar m = word.match( /^\"(.*)\"$/ );\n\t\t\t\t\tword = m ? m[1] : word;\n\t\t\t\t}\n\t\n\t\t\t\treturn word.replace('\"', '');\n\t\t\t} );\n\t\n\t\t\tsearch = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';\n\t\t}\n\t\n\t\treturn new RegExp( search, caseInsensitive ? 'i' : '' );\n\t}\n\t\n\t\n\t/**\n\t * Escape a string such that it can be used in a regular expression\n\t *  @param {string} sVal string to escape\n\t *  @returns {string} escaped string\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnEscapeRegex = DataTable.util.escapeRegex;\n\t\n\tvar __filter_div = $('<div>')[0];\n\tvar __filter_div_textContent = __filter_div.textContent !== undefined;\n\t\n\t// Update the filtering data for each row if needed (by invalidation or first run)\n\tfunction _fnFilterData ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar column;\n\t\tvar i, j, ien, jen, filterData, cellData, row;\n\t\tvar fomatters = DataTable.ext.type.search;\n\t\tvar wasInvalidated = false;\n\t\n\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aFilterData ) {\n\t\t\t\tfilterData = [];\n\t\n\t\t\t\tfor ( j=0, jen=columns.length ; j<jen ; j++ ) {\n\t\t\t\t\tcolumn = columns[j];\n\t\n\t\t\t\t\tif ( column.bSearchable ) {\n\t\t\t\t\t\tcellData = _fnGetCellData( settings, i, j, 'filter' );\n\t\n\t\t\t\t\t\tif ( fomatters[ column.sType ] ) {\n\t\t\t\t\t\t\tcellData = fomatters[ column.sType ]( cellData );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Search in DataTables 1.10 is string based. In 1.11 this\n\t\t\t\t\t\t// should be altered to also allow strict type checking.\n\t\t\t\t\t\tif ( cellData === null ) {\n\t\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( typeof cellData !== 'string' && cellData.toString ) {\n\t\t\t\t\t\t\tcellData = cellData.toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If it looks like there is an HTML entity in the string,\n\t\t\t\t\t// attempt to decode it so sorting works as expected. Note that\n\t\t\t\t\t// we could use a single line of jQuery to do this, but the DOM\n\t\t\t\t\t// method used here is much faster http://jsperf.com/html-decode\n\t\t\t\t\tif ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {\n\t\t\t\t\t\t__filter_div.innerHTML = cellData;\n\t\t\t\t\t\tcellData = __filter_div_textContent ?\n\t\t\t\t\t\t\t__filter_div.textContent :\n\t\t\t\t\t\t\t__filter_div.innerText;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tif ( cellData.replace ) {\n\t\t\t\t\t\tcellData = cellData.replace(/[\\r\\n]/g, '');\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfilterData.push( cellData );\n\t\t\t\t}\n\t\n\t\t\t\trow._aFilterData = filterData;\n\t\t\t\trow._sFilterRow = filterData.join('  ');\n\t\t\t\twasInvalidated = true;\n\t\t\t}\n\t\t}\n\t\n\t\treturn wasInvalidated;\n\t}\n\t\n\t\n\t/**\n\t * Convert from the internal Hungarian notation to camelCase for external\n\t * interaction\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToCamel ( obj )\n\t{\n\t\treturn {\n\t\t\tsearch:          obj.sSearch,\n\t\t\tsmart:           obj.bSmart,\n\t\t\tregex:           obj.bRegex,\n\t\t\tcaseInsensitive: obj.bCaseInsensitive\n\t\t};\n\t}\n\t\n\t\n\t\n\t/**\n\t * Convert from camelCase notation to the internal Hungarian. We could use the\n\t * Hungarian convert function here, but this is cleaner\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToHung ( obj )\n\t{\n\t\treturn {\n\t\t\tsSearch:          obj.search,\n\t\t\tbSmart:           obj.smart,\n\t\t\tbRegex:           obj.regex,\n\t\t\tbCaseInsensitive: obj.caseInsensitive\n\t\t};\n\t}\n\t\n\t/**\n\t * Generate the node required for the info display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Information element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlInfo ( settings )\n\t{\n\t\tvar\n\t\t\ttid = settings.sTableId,\n\t\t\tnodes = settings.aanFeatures.i,\n\t\t\tn = $('<div/>', {\n\t\t\t\t'class': settings.oClasses.sInfo,\n\t\t\t\t'id': ! nodes ? tid+'_info' : null\n\t\t\t} );\n\t\n\t\tif ( ! nodes ) {\n\t\t\t// Update display on each draw\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": _fnUpdateInfo,\n\t\t\t\t\"sName\": \"information\"\n\t\t\t} );\n\t\n\t\t\tn\n\t\t\t\t.attr( 'role', 'status' )\n\t\t\t\t.attr( 'aria-live', 'polite' );\n\t\n\t\t\t// Table is described by our info div\n\t\t\t$(settings.nTable).attr( 'aria-describedby', tid+'_info' );\n\t\t}\n\t\n\t\treturn n[0];\n\t}\n\t\n\t\n\t/**\n\t * Update the information elements in the display\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnUpdateInfo ( settings )\n\t{\n\t\t/* Show information about the table */\n\t\tvar nodes = settings.aanFeatures.i;\n\t\tif ( nodes.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\tlang  = settings.oLanguage,\n\t\t\tstart = settings._iDisplayStart+1,\n\t\t\tend   = settings.fnDisplayEnd(),\n\t\t\tmax   = settings.fnRecordsTotal(),\n\t\t\ttotal = settings.fnRecordsDisplay(),\n\t\t\tout   = total ?\n\t\t\t\tlang.sInfo :\n\t\t\t\tlang.sInfoEmpty;\n\t\n\t\tif ( total !== max ) {\n\t\t\t/* Record set after filtering */\n\t\t\tout += ' ' + lang.sInfoFiltered;\n\t\t}\n\t\n\t\t// Convert the macros\n\t\tout += lang.sInfoPostFix;\n\t\tout = _fnInfoMacros( settings, out );\n\t\n\t\tvar callback = lang.fnInfoCallback;\n\t\tif ( callback !== null ) {\n\t\t\tout = callback.call( settings.oInstance,\n\t\t\t\tsettings, start, end, max, total, out\n\t\t\t);\n\t\t}\n\t\n\t\t$(nodes).html( out );\n\t}\n\t\n\t\n\tfunction _fnInfoMacros ( settings, str )\n\t{\n\t\t// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only\n\t\t// internally\n\t\tvar\n\t\t\tformatter  = settings.fnFormatNumber,\n\t\t\tstart      = settings._iDisplayStart+1,\n\t\t\tlen        = settings._iDisplayLength,\n\t\t\tvis        = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn str.\n\t\t\treplace(/_START_/g, formatter.call( settings, start ) ).\n\t\t\treplace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).\n\t\t\treplace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).\n\t\t\treplace(/_TOTAL_/g, formatter.call( settings, vis ) ).\n\t\t\treplace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).\n\t\t\treplace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );\n\t}\n\t\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitialise ( settings )\n\t{\n\t\tvar i, iLen, iAjaxStart=settings.iInitDisplayStart;\n\t\tvar columns = settings.aoColumns, column;\n\t\tvar features = settings.oFeatures;\n\t\tvar deferLoading = settings.bDeferLoading; // value modified by the draw\n\t\n\t\t/* Ensure that the table data is fully initialised */\n\t\tif ( ! settings.bInitialised ) {\n\t\t\tsetTimeout( function(){ _fnInitialise( settings ); }, 200 );\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Show the display HTML options */\n\t\t_fnAddOptionsHtml( settings );\n\t\n\t\t/* Build and draw the header / footer for the table */\n\t\t_fnBuildHead( settings );\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t/* Okay to show that something is going on now */\n\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t/* Calculate sizes for columns */\n\t\tif ( features.bAutoWidth ) {\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\n\t\t\tif ( column.sWidth ) {\n\t\t\t\tcolumn.nTh.style.width = _fnStringToCss( column.sWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'preInit', [settings] );\n\t\n\t\t// If there is default sorting required - let's do it. The sort function\n\t\t// will do the drawing for us. Otherwise we draw the table regardless of the\n\t\t// Ajax source - this allows the table to look initialised for Ajax sourcing\n\t\t// data (show 'loading' message possibly)\n\t\t_fnReDraw( settings );\n\t\n\t\t// Server-side processing init complete is done by _fnAjaxUpdateDraw\n\t\tvar dataSrc = _fnDataSource( settings );\n\t\tif ( dataSrc != 'ssp' || deferLoading ) {\n\t\t\t// if there is an ajax source load the data\n\t\t\tif ( dataSrc == 'ajax' ) {\n\t\t\t\t_fnBuildAjax( settings, [], function(json) {\n\t\t\t\t\tvar aData = _fnAjaxDataSrc( settings, json );\n\t\n\t\t\t\t\t// Got the data - add it to the table\n\t\t\t\t\tfor ( i=0 ; i<aData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( settings, aData[i] );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Reset the init display for cookie saving. We've already done\n\t\t\t\t\t// a filter, and therefore cleared it before. So we need to make\n\t\t\t\t\t// it appear 'fresh'\n\t\t\t\t\tsettings.iInitDisplayStart = iAjaxStart;\n\t\n\t\t\t\t\t_fnReDraw( settings );\n\t\n\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t_fnInitComplete( settings, json );\n\t\t\t\t}, settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t_fnInitComplete( settings );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} [json] JSON from the server that completed the table, if using Ajax source\n\t *    with client-side processing (optional)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitComplete ( settings, json )\n\t{\n\t\tsettings._bInitComplete = true;\n\t\n\t\t// When data was added after the initialisation (data or Ajax) we need to\n\t\t// calculate the column sizing\n\t\tif ( json || settings.oInit.aaData ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'plugin-init', [settings, json] );\n\t\t_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );\n\t}\n\t\n\t\n\tfunction _fnLengthChange ( settings, val )\n\t{\n\t\tvar len = parseInt( val, 10 );\n\t\tsettings._iDisplayLength = len;\n\t\n\t\t_fnLengthOverflow( settings );\n\t\n\t\t// Fire length change event\n\t\t_fnCallbackFire( settings, null, 'length', [settings, len] );\n\t}\n\t\n\t\n\t/**\n\t * Generate the node required for user display length changing\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Display length feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlLength ( settings )\n\t{\n\t\tvar\n\t\t\tclasses  = settings.oClasses,\n\t\t\ttableId  = settings.sTableId,\n\t\t\tmenu     = settings.aLengthMenu,\n\t\t\td2       = $.isArray( menu[0] ),\n\t\t\tlengths  = d2 ? menu[0] : menu,\n\t\t\tlanguage = d2 ? menu[1] : menu;\n\t\n\t\tvar select = $('<select/>', {\n\t\t\t'name':          tableId+'_length',\n\t\t\t'aria-controls': tableId,\n\t\t\t'class':         classes.sLengthSelect\n\t\t} );\n\t\n\t\tfor ( var i=0, ien=lengths.length ; i<ien ; i++ ) {\n\t\t\tselect[0][ i ] = new Option( language[i], lengths[i] );\n\t\t}\n\t\n\t\tvar div = $('<div><label/></div>').addClass( classes.sLength );\n\t\tif ( ! settings.aanFeatures.l ) {\n\t\t\tdiv[0].id = tableId+'_length';\n\t\t}\n\t\n\t\tdiv.children().append(\n\t\t\tsettings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )\n\t\t);\n\t\n\t\t// Can't use `select` variable as user might provide their own and the\n\t\t// reference is broken by the use of outerHTML\n\t\t$('select', div)\n\t\t\t.val( settings._iDisplayLength )\n\t\t\t.on( 'change.DT', function(e) {\n\t\t\t\t_fnLengthChange( settings, $(this).val() );\n\t\t\t\t_fnDraw( settings );\n\t\t\t} );\n\t\n\t\t// Update node value whenever anything changes the table's length\n\t\t$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t$('select', div).val( len );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn div[0];\n\t}\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Note that most of the paging logic is done in\n\t * DataTable.ext.pager\n\t */\n\t\n\t/**\n\t * Generate the node required for default pagination\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Pagination feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlPaginate ( settings )\n\t{\n\t\tvar\n\t\t\ttype   = settings.sPaginationType,\n\t\t\tplugin = DataTable.ext.pager[ type ],\n\t\t\tmodern = typeof plugin === 'function',\n\t\t\tredraw = function( settings ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t},\n\t\t\tnode = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],\n\t\t\tfeatures = settings.aanFeatures;\n\t\n\t\tif ( ! modern ) {\n\t\t\tplugin.fnInit( settings, node, redraw );\n\t\t}\n\t\n\t\t/* Add a draw callback for the pagination on first instance, to update the paging display */\n\t\tif ( ! features.p )\n\t\t{\n\t\t\tnode.id = settings.sTableId+'_paginate';\n\t\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": function( settings ) {\n\t\t\t\t\tif ( modern ) {\n\t\t\t\t\t\tvar\n\t\t\t\t\t\t\tstart      = settings._iDisplayStart,\n\t\t\t\t\t\t\tlen        = settings._iDisplayLength,\n\t\t\t\t\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\t\t\t\t\tall        = len === -1,\n\t\t\t\t\t\t\tpage = all ? 0 : Math.ceil( start / len ),\n\t\t\t\t\t\t\tpages = all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\t\t\t\tbuttons = plugin(page, pages),\n\t\t\t\t\t\t\ti, ien;\n\t\n\t\t\t\t\t\tfor ( i=0, ien=features.p.length ; i<ien ; i++ ) {\n\t\t\t\t\t\t\t_fnRenderer( settings, 'pageButton' )(\n\t\t\t\t\t\t\t\tsettings, features.p[i], i, buttons, page, pages\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tplugin.fnUpdate( settings, redraw );\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"sName\": \"pagination\"\n\t\t\t} );\n\t\t}\n\t\n\t\treturn node;\n\t}\n\t\n\t\n\t/**\n\t * Alter the display settings to change the page\n\t *  @param {object} settings DataTables settings object\n\t *  @param {string|int} action Paging action to take: \"first\", \"previous\",\n\t *    \"next\" or \"last\" or page number to jump to (integer)\n\t *  @param [bool] redraw Automatically draw the update or not\n\t *  @returns {bool} true page has changed, false - no change\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnPageChange ( settings, action, redraw )\n\t{\n\t\tvar\n\t\t\tstart     = settings._iDisplayStart,\n\t\t\tlen       = settings._iDisplayLength,\n\t\t\trecords   = settings.fnRecordsDisplay();\n\t\n\t\tif ( records === 0 || len === -1 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( typeof action === \"number\" )\n\t\t{\n\t\t\tstart = action * len;\n\t\n\t\t\tif ( start > records )\n\t\t\t{\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"first\" )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( action == \"previous\" )\n\t\t{\n\t\t\tstart = len >= 0 ?\n\t\t\t\tstart - len :\n\t\t\t\t0;\n\t\n\t\t\tif ( start < 0 )\n\t\t\t{\n\t\t\t  start = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"next\" )\n\t\t{\n\t\t\tif ( start + len < records )\n\t\t\t{\n\t\t\t\tstart += len;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"last\" )\n\t\t{\n\t\t\tstart = Math.floor( (records-1) / len) * len;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_fnLog( settings, 0, \"Unknown paging action: \"+action, 5 );\n\t\t}\n\t\n\t\tvar changed = settings._iDisplayStart !== start;\n\t\tsettings._iDisplayStart = start;\n\t\n\t\tif ( changed ) {\n\t\t\t_fnCallbackFire( settings, null, 'page', [settings] );\n\t\n\t\t\tif ( redraw ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t}\n\t\n\t\treturn changed;\n\t}\n\t\n\t\n\t\n\t/**\n\t * Generate the node required for the processing node\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Processing element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlProcessing ( settings )\n\t{\n\t\treturn $('<div/>', {\n\t\t\t\t'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,\n\t\t\t\t'class': settings.oClasses.sProcessing\n\t\t\t} )\n\t\t\t.html( settings.oLanguage.sProcessing )\n\t\t\t.insertBefore( settings.nTable )[0];\n\t}\n\t\n\t\n\t/**\n\t * Display or hide the processing indicator\n\t *  @param {object} settings dataTables settings object\n\t *  @param {bool} show Show the processing indicator (true) or not (false)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnProcessingDisplay ( settings, show )\n\t{\n\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t$(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'processing', [settings, show] );\n\t}\n\t\n\t/**\n\t * Add any control elements for the table - specifically scrolling\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Node to add to the DOM\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlTable ( settings )\n\t{\n\t\tvar table = $(settings.nTable);\n\t\n\t\t// Add the ARIA grid role to the table\n\t\ttable.attr( 'role', 'grid' );\n\t\n\t\t// Scrolling from here on in\n\t\tvar scroll = settings.oScroll;\n\t\n\t\tif ( scroll.sX === '' && scroll.sY === '' ) {\n\t\t\treturn settings.nTable;\n\t\t}\n\t\n\t\tvar scrollX = scroll.sX;\n\t\tvar scrollY = scroll.sY;\n\t\tvar classes = settings.oClasses;\n\t\tvar caption = table.children('caption');\n\t\tvar captionSide = caption.length ? caption[0]._captionSide : null;\n\t\tvar headerClone = $( table[0].cloneNode(false) );\n\t\tvar footerClone = $( table[0].cloneNode(false) );\n\t\tvar footer = table.children('tfoot');\n\t\tvar _div = '<div/>';\n\t\tvar size = function ( s ) {\n\t\t\treturn !s ? null : _fnStringToCss( s );\n\t\t};\n\t\n\t\tif ( ! footer.length ) {\n\t\t\tfooter = null;\n\t\t}\n\t\n\t\t/*\n\t\t * The HTML structure that we want to generate in this function is:\n\t\t *  div - scroller\n\t\t *    div - scroll head\n\t\t *      div - scroll head inner\n\t\t *        table - scroll head table\n\t\t *          thead - thead\n\t\t *    div - scroll body\n\t\t *      table - table (master table)\n\t\t *        thead - thead clone for sizing\n\t\t *        tbody - tbody\n\t\t *    div - scroll foot\n\t\t *      div - scroll foot inner\n\t\t *        table - scroll foot table\n\t\t *          tfoot - tfoot\n\t\t */\n\t\tvar scroller = $( _div, { 'class': classes.sScrollWrapper } )\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollHead } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollHeadInner } )\n\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t'box-sizing': 'content-box',\n\t\t\t\t\t\t\t\twidth: scroll.sXInner || '100%'\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\theaderClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'top' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('thead')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t)\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollBody } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\toverflow: 'auto',\n\t\t\t\t\t\twidth: size( scrollX )\n\t\t\t\t\t} )\n\t\t\t\t\t.append( table )\n\t\t\t);\n\t\n\t\tif ( footer ) {\n\t\t\tscroller.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollFoot } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollFootInner } )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\tfooterClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'bottom' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('tfoot')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\n\t\tvar children = scroller.children();\n\t\tvar scrollHead = children[0];\n\t\tvar scrollBody = children[1];\n\t\tvar scrollFoot = footer ? children[2] : null;\n\t\n\t\t// When the body is scrolled, then we also want to scroll the headers\n\t\tif ( scrollX ) {\n\t\t\t$(scrollBody).on( 'scroll.DT', function (e) {\n\t\t\t\tvar scrollLeft = this.scrollLeft;\n\t\n\t\t\t\tscrollHead.scrollLeft = scrollLeft;\n\t\n\t\t\t\tif ( footer ) {\n\t\t\t\t\tscrollFoot.scrollLeft = scrollLeft;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\n\t\t$(scrollBody).css(\n\t\t\tscrollY && scroll.bCollapse ? 'max-height' : 'height', \n\t\t\tscrollY\n\t\t);\n\t\n\t\tsettings.nScrollHead = scrollHead;\n\t\tsettings.nScrollBody = scrollBody;\n\t\tsettings.nScrollFoot = scrollFoot;\n\t\n\t\t// On redraw - align columns\n\t\tsettings.aoDrawCallback.push( {\n\t\t\t\"fn\": _fnScrollDraw,\n\t\t\t\"sName\": \"scrolling\"\n\t\t} );\n\t\n\t\treturn scroller[0];\n\t}\n\t\n\t\n\t\n\t/**\n\t * Update the header, footer and body tables for resizing - i.e. column\n\t * alignment.\n\t *\n\t * Welcome to the most horrible function DataTables. The process that this\n\t * function follows is basically:\n\t *   1. Re-create the table inside the scrolling div\n\t *   2. Take live measurements from the DOM\n\t *   3. Apply the measurements to align the columns\n\t *   4. Clean up\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnScrollDraw ( settings )\n\t{\n\t\t// Given that this is such a monster function, a lot of variables are use\n\t\t// to try and keep the minimised size as small as possible\n\t\tvar\n\t\t\tscroll         = settings.oScroll,\n\t\t\tscrollX        = scroll.sX,\n\t\t\tscrollXInner   = scroll.sXInner,\n\t\t\tscrollY        = scroll.sY,\n\t\t\tbarWidth       = scroll.iBarWidth,\n\t\t\tdivHeader      = $(settings.nScrollHead),\n\t\t\tdivHeaderStyle = divHeader[0].style,\n\t\t\tdivHeaderInner = divHeader.children('div'),\n\t\t\tdivHeaderInnerStyle = divHeaderInner[0].style,\n\t\t\tdivHeaderTable = divHeaderInner.children('table'),\n\t\t\tdivBodyEl      = settings.nScrollBody,\n\t\t\tdivBody        = $(divBodyEl),\n\t\t\tdivBodyStyle   = divBodyEl.style,\n\t\t\tdivFooter      = $(settings.nScrollFoot),\n\t\t\tdivFooterInner = divFooter.children('div'),\n\t\t\tdivFooterTable = divFooterInner.children('table'),\n\t\t\theader         = $(settings.nTHead),\n\t\t\ttable          = $(settings.nTable),\n\t\t\ttableEl        = table[0],\n\t\t\ttableStyle     = tableEl.style,\n\t\t\tfooter         = settings.nTFoot ? $(settings.nTFoot) : null,\n\t\t\tbrowser        = settings.oBrowser,\n\t\t\tie67           = browser.bScrollOversize,\n\t\t\tdtHeaderCells  = _pluck( settings.aoColumns, 'nTh' ),\n\t\t\theaderTrgEls, footerTrgEls,\n\t\t\theaderSrcEls, footerSrcEls,\n\t\t\theaderCopy, footerCopy,\n\t\t\theaderWidths=[], footerWidths=[],\n\t\t\theaderContent=[], footerContent=[],\n\t\t\tidx, correction, sanityWidth,\n\t\t\tzeroOut = function(nSizer) {\n\t\t\t\tvar style = nSizer.style;\n\t\t\t\tstyle.paddingTop = \"0\";\n\t\t\t\tstyle.paddingBottom = \"0\";\n\t\t\t\tstyle.borderTopWidth = \"0\";\n\t\t\t\tstyle.borderBottomWidth = \"0\";\n\t\t\t\tstyle.height = 0;\n\t\t\t};\n\t\n\t\t// If the scrollbar visibility has changed from the last draw, we need to\n\t\t// adjust the column sizes as the table width will have changed to account\n\t\t// for the scrollbar\n\t\tvar scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;\n\t\t\n\t\tif ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t\treturn; // adjust column sizing will call this function again\n\t\t}\n\t\telse {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t}\n\t\n\t\t/*\n\t\t * 1. Re-create the table inside the scrolling div\n\t\t */\n\t\n\t\t// Remove the old minimised thead and tfoot elements in the inner table\n\t\ttable.children('thead, tfoot').remove();\n\t\n\t\tif ( footer ) {\n\t\t\tfooterCopy = footer.clone().prependTo( table );\n\t\t\tfooterTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized\n\t\t\tfooterSrcEls = footerCopy.find('tr');\n\t\t}\n\t\n\t\t// Clone the current header and footer elements and then place it into the inner table\n\t\theaderCopy = header.clone().prependTo( table );\n\t\theaderTrgEls = header.find('tr'); // original header is in its own table\n\t\theaderSrcEls = headerCopy.find('tr');\n\t\theaderCopy.find('th, td').removeAttr('tabindex');\n\t\n\t\n\t\t/*\n\t\t * 2. Take live measurements from the DOM - do not alter the DOM itself!\n\t\t */\n\t\n\t\t// Remove old sizing and apply the calculated column widths\n\t\t// Get the unique column headers in the newly created (cloned) header. We want to apply the\n\t\t// calculated sizes to this header\n\t\tif ( ! scrollX )\n\t\t{\n\t\t\tdivBodyStyle.width = '100%';\n\t\t\tdivHeader[0].style.width = '100%';\n\t\t}\n\t\n\t\t$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {\n\t\t\tidx = _fnVisibleToColumnIndex( settings, i );\n\t\t\tel.style.width = settings.aoColumns[idx].sWidth;\n\t\t} );\n\t\n\t\tif ( footer ) {\n\t\t\t_fnApplyToChildren( function(n) {\n\t\t\t\tn.style.width = \"\";\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Size the table as a whole\n\t\tsanityWidth = table.outerWidth();\n\t\tif ( scrollX === \"\" ) {\n\t\t\t// No x scrolling\n\t\t\ttableStyle.width = \"100%\";\n\t\n\t\t\t// IE7 will make the width of the table when 100% include the scrollbar\n\t\t\t// - which is shouldn't. When there is a scrollbar we need to take this\n\t\t\t// into account.\n\t\t\tif ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);\n\t\t\t}\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\telse if ( scrollXInner !== \"\" ) {\n\t\t\t// legacy x scroll inner has been given - use it\n\t\t\ttableStyle.width = _fnStringToCss(scrollXInner);\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\n\t\t// Hidden header should have zero height, so remove padding and borders. Then\n\t\t// set the width based on the real headers\n\t\n\t\t// Apply all styles in one pass\n\t\t_fnApplyToChildren( zeroOut, headerSrcEls );\n\t\n\t\t// Read all widths in next pass\n\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\theaderContent.push( nSizer.innerHTML );\n\t\t\theaderWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t}, headerSrcEls );\n\t\n\t\t// Apply all widths in final pass\n\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t// Only apply widths to the DataTables detected header cells - this\n\t\t\t// prevents complex headers from having contradictory sizes applied\n\t\t\tif ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {\n\t\t\t\tnToSize.style.width = headerWidths[i];\n\t\t\t}\n\t\t}, headerTrgEls );\n\t\n\t\t$(headerSrcEls).height(0);\n\t\n\t\t/* Same again with the footer if we have one */\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( zeroOut, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\t\tfooterContent.push( nSizer.innerHTML );\n\t\t\t\tfooterWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t\t}, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t\tnToSize.style.width = footerWidths[i];\n\t\t\t}, footerTrgEls );\n\t\n\t\t\t$(footerSrcEls).height(0);\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 3. Apply the measurements\n\t\t */\n\t\n\t\t// \"Hide\" the header and footer that we used for the sizing. We need to keep\n\t\t// the content of the cell so that the width applied to the header and body\n\t\t// both match, but we want to hide it completely. We want to also fix their\n\t\t// width to what they currently are\n\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\" style=\"height:0;overflow:hidden;\">'+headerContent[i]+'</div>';\n\t\t\tnSizer.style.width = headerWidths[i];\n\t\t}, headerSrcEls );\n\t\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\" style=\"height:0;overflow:hidden;\">'+footerContent[i]+'</div>';\n\t\t\t\tnSizer.style.width = footerWidths[i];\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Sanity check that the table is of a sensible width. If not then we are going to get\n\t\t// misalignment - try to prevent this by not allowing the table to shrink below its min width\n\t\tif ( table.outerWidth() < sanityWidth )\n\t\t{\n\t\t\t// The min width depends upon if we have a vertical scrollbar visible or not */\n\t\t\tcorrection = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")) ?\n\t\t\t\t\tsanityWidth+barWidth :\n\t\t\t\t\tsanityWidth;\n\t\n\t\t\t// IE6/7 are a law unto themselves...\n\t\t\tif ( ie67 && (divBodyEl.scrollHeight >\n\t\t\t\tdivBodyEl.offsetHeight || divBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( correction-barWidth );\n\t\t\t}\n\t\n\t\t\t// And give the user a warning that we've stopped the table getting too small\n\t\t\tif ( scrollX === \"\" || scrollXInner !== \"\" ) {\n\t\t\t\t_fnLog( settings, 1, 'Possible column misalignment', 6 );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcorrection = '100%';\n\t\t}\n\t\n\t\t// Apply to the container elements\n\t\tdivBodyStyle.width = _fnStringToCss( correction );\n\t\tdivHeaderStyle.width = _fnStringToCss( correction );\n\t\n\t\tif ( footer ) {\n\t\t\tsettings.nScrollFoot.style.width = _fnStringToCss( correction );\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 4. Clean up\n\t\t */\n\t\tif ( ! scrollY ) {\n\t\t\t/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting\n\t\t\t * the scrollbar height from the visible display, rather than adding it on. We need to\n\t\t\t * set the height in order to sort this. Don't want to do it in any other browsers.\n\t\t\t */\n\t\t\tif ( ie67 ) {\n\t\t\t\tdivBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Finally set the width's of the header and footer tables */\n\t\tvar iOuterWidth = table.outerWidth();\n\t\tdivHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\tdivHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );\n\t\n\t\t// Figure out if there are scrollbar present - if so then we need a the header and footer to\n\t\t// provide a bit more space to allow \"overflow\" scrolling (i.e. past the scrollbar)\n\t\tvar bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == \"scroll\";\n\t\tvar padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );\n\t\tdivHeaderInnerStyle[ padding ] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\n\t\tif ( footer ) {\n\t\t\tdivFooterTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style[padding] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\t}\n\t\n\t\t// Correct DOM ordering for colgroup - comes before the thead\n\t\ttable.children('colgroup').insertBefore( table.children('thead') );\n\t\n\t\t/* Adjust the position of the header in case we loose the y-scrollbar */\n\t\tdivBody.scroll();\n\t\n\t\t// If sorting or filtering has occurred, jump the scrolling back to the top\n\t\t// only if we aren't holding the position\n\t\tif ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {\n\t\t\tdivBodyEl.scrollTop = 0;\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Apply a given function to the display child nodes of an element array (typically\n\t * TD children of TR rows\n\t *  @param {function} fn Method to apply to the objects\n\t *  @param array {nodes} an1 List of elements to look through for display children\n\t *  @param array {nodes} an2 Another list (identical structure to the first) - optional\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyToChildren( fn, an1, an2 )\n\t{\n\t\tvar index=0, i=0, iLen=an1.length;\n\t\tvar nNode1, nNode2;\n\t\n\t\twhile ( i < iLen ) {\n\t\t\tnNode1 = an1[i].firstChild;\n\t\t\tnNode2 = an2 ? an2[i].firstChild : null;\n\t\n\t\t\twhile ( nNode1 ) {\n\t\t\t\tif ( nNode1.nodeType === 1 ) {\n\t\t\t\t\tif ( an2 ) {\n\t\t\t\t\t\tfn( nNode1, nNode2, index );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfn( nNode1, index );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\n\t\t\t\tnNode1 = nNode1.nextSibling;\n\t\t\t\tnNode2 = an2 ? nNode2.nextSibling : null;\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t}\n\t}\n\t\n\t\n\t\n\tvar __re_html_remove = /<.*?>/g;\n\t\n\t\n\t/**\n\t * Calculate the width of columns for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCalculateColumnWidths ( oSettings )\n\t{\n\t\tvar\n\t\t\ttable = oSettings.nTable,\n\t\t\tcolumns = oSettings.aoColumns,\n\t\t\tscroll = oSettings.oScroll,\n\t\t\tscrollY = scroll.sY,\n\t\t\tscrollX = scroll.sX,\n\t\t\tscrollXInner = scroll.sXInner,\n\t\t\tcolumnCount = columns.length,\n\t\t\tvisibleColumns = _fnGetColumns( oSettings, 'bVisible' ),\n\t\t\theaderCells = $('th', oSettings.nTHead),\n\t\t\ttableWidthAttr = table.getAttribute('width'), // from DOM element\n\t\t\ttableContainer = table.parentNode,\n\t\t\tuserInputs = false,\n\t\t\ti, column, columnIdx, width, outerWidth,\n\t\t\tbrowser = oSettings.oBrowser,\n\t\t\tie67 = browser.bScrollOversize;\n\t\n\t\tvar styleWidth = table.style.width;\n\t\tif ( styleWidth && styleWidth.indexOf('%') !== -1 ) {\n\t\t\ttableWidthAttr = styleWidth;\n\t\t}\n\t\n\t\t/* Convert any user input sizes into pixel sizes */\n\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\tif ( column.sWidth !== null ) {\n\t\t\t\tcolumn.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );\n\t\n\t\t\t\tuserInputs = true;\n\t\t\t}\n\t\t}\n\t\n\t\t/* If the number of columns in the DOM equals the number that we have to\n\t\t * process in DataTables, then we can use the offsets that are created by\n\t\t * the web- browser. No custom sizes can be set in order for this to happen,\n\t\t * nor scrolling used\n\t\t */\n\t\tif ( ie67 || ! userInputs && ! scrollX && ! scrollY &&\n\t\t     columnCount == _fnVisbleColumns( oSettings ) &&\n\t\t     columnCount == headerCells.length\n\t\t) {\n\t\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\t\tvar colIdx = _fnVisibleToColumnIndex( oSettings, i );\n\t\n\t\t\t\tif ( colIdx !== null ) {\n\t\t\t\t\tcolumns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise construct a single row, worst case, table with the widest\n\t\t\t// node in the data, assign any user defined widths, then insert it into\n\t\t\t// the DOM and allow the browser to do all the hard work of calculating\n\t\t\t// table widths\n\t\t\tvar tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table\n\t\t\t\t.css( 'visibility', 'hidden' )\n\t\t\t\t.removeAttr( 'id' );\n\t\n\t\t\t// Clean up the table body\n\t\t\ttmpTable.find('tbody tr').remove();\n\t\t\tvar tr = $('<tr/>').appendTo( tmpTable.find('tbody') );\n\t\n\t\t\t// Clone the table header and footer - we can't use the header / footer\n\t\t\t// from the cloned table, since if scrolling is active, the table's\n\t\t\t// real header and footer are contained in different table tags\n\t\t\ttmpTable.find('thead, tfoot').remove();\n\t\t\ttmpTable\n\t\t\t\t.append( $(oSettings.nTHead).clone() )\n\t\t\t\t.append( $(oSettings.nTFoot).clone() );\n\t\n\t\t\t// Remove any assigned widths from the footer (from scrolling)\n\t\t\ttmpTable.find('tfoot th, tfoot td').css('width', '');\n\t\n\t\t\t// Apply custom sizing to the cloned header\n\t\t\theaderCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );\n\t\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\t\theaderCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?\n\t\t\t\t\t_fnStringToCss( column.sWidthOrig ) :\n\t\t\t\t\t'';\n\t\n\t\t\t\t// For scrollX we need to force the column width otherwise the\n\t\t\t\t// browser will collapse it. If this width is smaller than the\n\t\t\t\t// width the column requires, then it will have no effect\n\t\t\t\tif ( column.sWidthOrig && scrollX ) {\n\t\t\t\t\t$( headerCells[i] ).append( $('<div/>').css( {\n\t\t\t\t\t\twidth: column.sWidthOrig,\n\t\t\t\t\t\tmargin: 0,\n\t\t\t\t\t\tpadding: 0,\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\theight: 1\n\t\t\t\t\t} ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Find the widest cell for each column and put it into the table\n\t\t\tif ( oSettings.aoData.length ) {\n\t\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\t\tcolumnIdx = visibleColumns[i];\n\t\t\t\t\tcolumn = columns[ columnIdx ];\n\t\n\t\t\t\t\t$( _fnGetWidestNode( oSettings, columnIdx ) )\n\t\t\t\t\t\t.clone( false )\n\t\t\t\t\t\t.append( column.sContentPadding )\n\t\t\t\t\t\t.appendTo( tr );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Tidy the temporary table - remove name attributes so there aren't\n\t\t\t// duplicated in the dom (radio elements for example)\n\t\t\t$('[name]', tmpTable).removeAttr('name');\n\t\n\t\t\t// Table has been built, attach to the document so we can work with it.\n\t\t\t// A holding element is used, positioned at the top of the container\n\t\t\t// with minimal height, so it has no effect on if the container scrolls\n\t\t\t// or not. Otherwise it might trigger scrolling when it actually isn't\n\t\t\t// needed\n\t\t\tvar holder = $('<div/>').css( scrollX || scrollY ?\n\t\t\t\t\t{\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\theight: 1,\n\t\t\t\t\t\tright: 0,\n\t\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t\t} :\n\t\t\t\t\t{}\n\t\t\t\t)\n\t\t\t\t.append( tmpTable )\n\t\t\t\t.appendTo( tableContainer );\n\t\n\t\t\t// When scrolling (X or Y) we want to set the width of the table as \n\t\t\t// appropriate. However, when not scrolling leave the table width as it\n\t\t\t// is. This results in slightly different, but I think correct behaviour\n\t\t\tif ( scrollX && scrollXInner ) {\n\t\t\t\ttmpTable.width( scrollXInner );\n\t\t\t}\n\t\t\telse if ( scrollX ) {\n\t\t\t\ttmpTable.css( 'width', 'auto' );\n\t\t\t\ttmpTable.removeAttr('width');\n\t\n\t\t\t\t// If there is no width attribute or style, then allow the table to\n\t\t\t\t// collapse\n\t\t\t\tif ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {\n\t\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( scrollY ) {\n\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t}\n\t\t\telse if ( tableWidthAttr ) {\n\t\t\t\ttmpTable.width( tableWidthAttr );\n\t\t\t}\n\t\n\t\t\t// Get the width of each column in the constructed table - we need to\n\t\t\t// know the inner width (so it can be assigned to the other table's\n\t\t\t// cells) and the outer width so we can calculate the full width of the\n\t\t\t// table. This is safe since DataTables requires a unique cell for each\n\t\t\t// column, but if ever a header can span multiple columns, this will\n\t\t\t// need to be modified.\n\t\t\tvar total = 0;\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tvar cell = $(headerCells[i]);\n\t\t\t\tvar border = cell.outerWidth() - cell.width();\n\t\n\t\t\t\t// Use getBounding... where possible (not IE8-) because it can give\n\t\t\t\t// sub-pixel accuracy, which we then want to round up!\n\t\t\t\tvar bounding = browser.bBounding ?\n\t\t\t\t\tMath.ceil( headerCells[i].getBoundingClientRect().width ) :\n\t\t\t\t\tcell.outerWidth();\n\t\n\t\t\t\t// Total is tracked to remove any sub-pixel errors as the outerWidth\n\t\t\t\t// of the table might not equal the total given here (IE!).\n\t\t\t\ttotal += bounding;\n\t\n\t\t\t\t// Width for each column to use\n\t\t\t\tcolumns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );\n\t\t\t}\n\t\n\t\t\ttable.style.width = _fnStringToCss( total );\n\t\n\t\t\t// Finished with the table - ditch it\n\t\t\tholder.remove();\n\t\t}\n\t\n\t\t// If there is a width attr, we want to attach an event listener which\n\t\t// allows the table sizing to automatically adjust when the window is\n\t\t// resized. Use the width attr rather than CSS, since we can't know if the\n\t\t// CSS is a relative value or absolute - DOM read is always px.\n\t\tif ( tableWidthAttr ) {\n\t\t\ttable.style.width = _fnStringToCss( tableWidthAttr );\n\t\t}\n\t\n\t\tif ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {\n\t\t\tvar bindResize = function () {\n\t\t\t\t$(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {\n\t\t\t\t\t_fnAdjustColumnSizing( oSettings );\n\t\t\t\t} ) );\n\t\t\t};\n\t\n\t\t\t// IE6/7 will crash if we bind a resize event handler on page load.\n\t\t\t// To be removed in 1.11 which drops IE6/7 support\n\t\t\tif ( ie67 ) {\n\t\t\t\tsetTimeout( bindResize, 1000 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbindResize();\n\t\t\t}\n\t\n\t\t\toSettings._reszEvt = true;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Throttle the calls to a function. Arguments and context are maintained for\n\t * the throttled function\n\t *  @param {function} fn Function to be called\n\t *  @param {int} [freq=200] call frequency in mS\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnThrottle = DataTable.util.throttle;\n\t\n\t\n\t/**\n\t * Convert a CSS unit width to pixels (e.g. 2em)\n\t *  @param {string} width width to be converted\n\t *  @param {node} parent parent to get the with for (required for relative widths) - optional\n\t *  @returns {int} width in pixels\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnConvertToWidth ( width, parent )\n\t{\n\t\tif ( ! width ) {\n\t\t\treturn 0;\n\t\t}\n\t\n\t\tvar n = $('<div/>')\n\t\t\t.css( 'width', _fnStringToCss( width ) )\n\t\t\t.appendTo( parent || document.body );\n\t\n\t\tvar val = n[0].offsetWidth;\n\t\tn.remove();\n\t\n\t\treturn val;\n\t}\n\t\n\t\n\t/**\n\t * Get the widest node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {node} widest table node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetWidestNode( settings, colIdx )\n\t{\n\t\tvar idx = _fnGetMaxLenString( settings, colIdx );\n\t\tif ( idx < 0 ) {\n\t\t\treturn null;\n\t\t}\n\t\n\t\tvar data = settings.aoData[ idx ];\n\t\treturn ! data.nTr ? // Might not have been created when deferred rendering\n\t\t\t$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :\n\t\t\tdata.anCells[ colIdx ];\n\t}\n\t\n\t\n\t/**\n\t * Get the maximum strlen for each data column\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {string} max string length for each column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetMaxLenString( settings, colIdx )\n\t{\n\t\tvar s, max=-1, maxIdx = -1;\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\ts = _fnGetCellData( settings, i, colIdx, 'display' )+'';\n\t\t\ts = s.replace( __re_html_remove, '' );\n\t\t\ts = s.replace( /&nbsp;/g, ' ' );\n\t\n\t\t\tif ( s.length > max ) {\n\t\t\t\tmax = s.length;\n\t\t\t\tmaxIdx = i;\n\t\t\t}\n\t\t}\n\t\n\t\treturn maxIdx;\n\t}\n\t\n\t\n\t/**\n\t * Append a CSS unit (only if required) to a string\n\t *  @param {string} value to css-ify\n\t *  @returns {string} value with css unit\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnStringToCss( s )\n\t{\n\t\tif ( s === null ) {\n\t\t\treturn '0px';\n\t\t}\n\t\n\t\tif ( typeof s == 'number' ) {\n\t\t\treturn s < 0 ?\n\t\t\t\t'0px' :\n\t\t\t\ts+'px';\n\t\t}\n\t\n\t\t// Check it has a unit character already\n\t\treturn s.match(/\\d$/) ?\n\t\t\ts+'px' :\n\t\t\ts;\n\t}\n\t\n\t\n\t\n\tfunction _fnSortFlatten ( settings )\n\t{\n\t\tvar\n\t\t\ti, iLen, k, kLen,\n\t\t\taSort = [],\n\t\t\taiOrig = [],\n\t\t\taoColumns = settings.aoColumns,\n\t\t\taDataSort, iCol, sType, srcCol,\n\t\t\tfixed = settings.aaSortingFixed,\n\t\t\tfixedObj = $.isPlainObject( fixed ),\n\t\t\tnestedSort = [],\n\t\t\tadd = function ( a ) {\n\t\t\t\tif ( a.length && ! $.isArray( a[0] ) ) {\n\t\t\t\t\t// 1D array\n\t\t\t\t\tnestedSort.push( a );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// 2D array\n\t\t\t\t\t$.merge( nestedSort, a );\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t// Build the sort array, with pre-fix and post-fix options if they have been\n\t\t// specified\n\t\tif ( $.isArray( fixed ) ) {\n\t\t\tadd( fixed );\n\t\t}\n\t\n\t\tif ( fixedObj && fixed.pre ) {\n\t\t\tadd( fixed.pre );\n\t\t}\n\t\n\t\tadd( settings.aaSorting );\n\t\n\t\tif (fixedObj && fixed.post ) {\n\t\t\tadd( fixed.post );\n\t\t}\n\t\n\t\tfor ( i=0 ; i<nestedSort.length ; i++ )\n\t\t{\n\t\t\tsrcCol = nestedSort[i][0];\n\t\t\taDataSort = aoColumns[ srcCol ].aDataSort;\n\t\n\t\t\tfor ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )\n\t\t\t{\n\t\t\t\tiCol = aDataSort[k];\n\t\t\t\tsType = aoColumns[ iCol ].sType || 'string';\n\t\n\t\t\t\tif ( nestedSort[i]._idx === undefined ) {\n\t\t\t\t\tnestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );\n\t\t\t\t}\n\t\n\t\t\t\taSort.push( {\n\t\t\t\t\tsrc:       srcCol,\n\t\t\t\t\tcol:       iCol,\n\t\t\t\t\tdir:       nestedSort[i][1],\n\t\t\t\t\tindex:     nestedSort[i]._idx,\n\t\t\t\t\ttype:      sType,\n\t\t\t\t\tformatter: DataTable.ext.type.order[ sType+\"-pre\" ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\treturn aSort;\n\t}\n\t\n\t/**\n\t * Change the order of the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t *  @todo This really needs split up!\n\t */\n\tfunction _fnSort ( oSettings )\n\t{\n\t\tvar\n\t\t\ti, ien, iLen, j, jLen, k, kLen,\n\t\t\tsDataType, nTh,\n\t\t\taiOrig = [],\n\t\t\toExtSort = DataTable.ext.type.order,\n\t\t\taoData = oSettings.aoData,\n\t\t\taoColumns = oSettings.aoColumns,\n\t\t\taDataSort, data, iCol, sType, oSort,\n\t\t\tformatters = 0,\n\t\t\tsortCol,\n\t\t\tdisplayMaster = oSettings.aiDisplayMaster,\n\t\t\taSort;\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo Can this be moved into a 'data-ready' handler which is called when\n\t\t//   data is going to be used in the table?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\taSort = _fnSortFlatten( oSettings );\n\t\n\t\tfor ( i=0, ien=aSort.length ; i<ien ; i++ ) {\n\t\t\tsortCol = aSort[i];\n\t\n\t\t\t// Track if we can use the fast sort algorithm\n\t\t\tif ( sortCol.formatter ) {\n\t\t\t\tformatters++;\n\t\t\t}\n\t\n\t\t\t// Load the data needed for the sort, for each cell\n\t\t\t_fnSortData( oSettings, sortCol.col );\n\t\t}\n\t\n\t\t/* No sorting required if server-side or no sorting array */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )\n\t\t{\n\t\t\t// Create a value - key array of the current row positions such that we can use their\n\t\t\t// current position during the sort, if values match, in order to perform stable sorting\n\t\t\tfor ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {\n\t\t\t\taiOrig[ displayMaster[i] ] = i;\n\t\t\t}\n\t\n\t\t\t/* Do the sort - here we want multi-column sorting based on a given data source (column)\n\t\t\t * and sorting function (from oSort) in a certain direction. It's reasonably complex to\n\t\t\t * follow on it's own, but this is what we want (example two column sorting):\n\t\t\t *  fnLocalSorting = function(a,b){\n\t\t\t *    var iTest;\n\t\t\t *    iTest = oSort['string-asc']('data11', 'data12');\n\t\t\t *      if (iTest !== 0)\n\t\t\t *        return iTest;\n\t\t\t *    iTest = oSort['numeric-desc']('data21', 'data22');\n\t\t\t *    if (iTest !== 0)\n\t\t\t *      return iTest;\n\t\t\t *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );\n\t\t\t *  }\n\t\t\t * Basically we have a test for each sorting column, if the data in that column is equal,\n\t\t\t * test the next column. If all columns match, then we use a numeric sort on the row\n\t\t\t * positions in the original data array to provide a stable sort.\n\t\t\t *\n\t\t\t * Note - I know it seems excessive to have two sorting methods, but the first is around\n\t\t\t * 15% faster, so the second is only maintained for backwards compatibility with sorting\n\t\t\t * methods which do not have a pre-sort formatting function.\n\t\t\t */\n\t\t\tif ( formatters === aSort.length ) {\n\t\t\t\t// All sort types have formatting functions\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, test, sort,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\ttest = x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn sort.dir === 'asc' ? test : -test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Depreciated - remove in 1.11 (providing a plug-in option)\n\t\t\t\t// Not all sort types have formatting methods, so we have to call their sorting\n\t\t\t\t// methods.\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, l, test, sort, fn,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\tfn = oExtSort[ sort.type+\"-\"+sort.dir ] || oExtSort[ \"string-\"+sort.dir ];\n\t\t\t\t\t\ttest = fn( x, y );\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Tell the draw function that we have sorted the data */\n\t\toSettings.bSorted = true;\n\t}\n\t\n\t\n\tfunction _fnSortAria ( settings )\n\t{\n\t\tvar label;\n\t\tvar nextSort;\n\t\tvar columns = settings.aoColumns;\n\t\tvar aSort = _fnSortFlatten( settings );\n\t\tvar oAria = settings.oLanguage.oAria;\n\t\n\t\t// ARIA attributes - need to loop all columns, to update all (removing old\n\t\t// attributes as needed)\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar col = columns[i];\n\t\t\tvar asSorting = col.asSorting;\n\t\t\tvar sTitle = col.sTitle.replace( /<.*?>/g, \"\" );\n\t\t\tvar th = col.nTh;\n\t\n\t\t\t// IE7 is throwing an error when setting these properties with jQuery's\n\t\t\t// attr() and removeAttr() methods...\n\t\t\tth.removeAttribute('aria-sort');\n\t\n\t\t\t/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */\n\t\t\tif ( col.bSortable ) {\n\t\t\t\tif ( aSort.length > 0 && aSort[0].col == i ) {\n\t\t\t\t\tth.setAttribute('aria-sort', aSort[0].dir==\"asc\" ? \"ascending\" : \"descending\" );\n\t\t\t\t\tnextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnextSort = asSorting[0];\n\t\t\t\t}\n\t\n\t\t\t\tlabel = sTitle + ( nextSort === \"asc\" ?\n\t\t\t\t\toAria.sSortAscending :\n\t\t\t\t\toAria.sSortDescending\n\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlabel = sTitle;\n\t\t\t}\n\t\n\t\t\tth.setAttribute('aria-label', label);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Function to run on user sort request\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {boolean} [append=false] Append the requested sort to the existing\n\t *    sort if true (i.e. multi-column sort)\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortListener ( settings, colIdx, append, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\tvar sorting = settings.aaSorting;\n\t\tvar asSorting = col.asSorting;\n\t\tvar nextSortIdx;\n\t\tvar next = function ( a, overflow ) {\n\t\t\tvar idx = a._idx;\n\t\t\tif ( idx === undefined ) {\n\t\t\t\tidx = $.inArray( a[1], asSorting );\n\t\t\t}\n\t\n\t\t\treturn idx+1 < asSorting.length ?\n\t\t\t\tidx+1 :\n\t\t\t\toverflow ?\n\t\t\t\t\tnull :\n\t\t\t\t\t0;\n\t\t};\n\t\n\t\t// Convert to 2D array if needed\n\t\tif ( typeof sorting[0] === 'number' ) {\n\t\t\tsorting = settings.aaSorting = [ sorting ];\n\t\t}\n\t\n\t\t// If appending the sort then we are multi-column sorting\n\t\tif ( append && settings.oFeatures.bSortMulti ) {\n\t\t\t// Are we already doing some kind of sort on this column?\n\t\t\tvar sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );\n\t\n\t\t\tif ( sortIdx !== -1 ) {\n\t\t\t\t// Yes, modify the sort\n\t\t\t\tnextSortIdx = next( sorting[sortIdx], true );\n\t\n\t\t\t\tif ( nextSortIdx === null && sorting.length === 1 ) {\n\t\t\t\t\tnextSortIdx = 0; // can't remove sorting completely\n\t\t\t\t}\n\t\n\t\t\t\tif ( nextSortIdx === null ) {\n\t\t\t\t\tsorting.splice( sortIdx, 1 );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tsorting[sortIdx][1] = asSorting[ nextSortIdx ];\n\t\t\t\t\tsorting[sortIdx]._idx = nextSortIdx;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// No sort on this column yet\n\t\t\t\tsorting.push( [ colIdx, asSorting[0], 0 ] );\n\t\t\t\tsorting[sorting.length-1]._idx = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( sorting.length && sorting[0][0] == colIdx ) {\n\t\t\t// Single column - already sorting on this column, modify the sort\n\t\t\tnextSortIdx = next( sorting[0] );\n\t\n\t\t\tsorting.length = 1;\n\t\t\tsorting[0][1] = asSorting[ nextSortIdx ];\n\t\t\tsorting[0]._idx = nextSortIdx;\n\t\t}\n\t\telse {\n\t\t\t// Single column - sort only on this column\n\t\t\tsorting.length = 0;\n\t\t\tsorting.push( [ colIdx, asSorting[0] ] );\n\t\t\tsorting[0]._idx = 0;\n\t\t}\n\t\n\t\t// Run the sort by calling a full redraw\n\t\t_fnReDraw( settings );\n\t\n\t\t// callback used for async user interaction\n\t\tif ( typeof callback == 'function' ) {\n\t\t\tcallback( settings );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Attach a sort handler (click) to a node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortAttachListener ( settings, attachTo, colIdx, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\n\t\t_fnBindAction( attachTo, {}, function (e) {\n\t\t\t/* If the column is not sortable - don't to anything */\n\t\t\tif ( col.bSortable === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If processing is enabled use a timeout to allow the processing\n\t\t\t// display to be shown - otherwise to it synchronously\n\t\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t\tsetTimeout( function() {\n\t\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\n\t\t\t\t\t// In server-side processing, the draw callback will remove the\n\t\t\t\t\t// processing display\n\t\t\t\t\tif ( _fnDataSource( settings ) !== 'ssp' ) {\n\t\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t}\n\t\t\t\t}, 0 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Set the sorting classes on table's body, Note: it is safe to call this function\n\t * when bSort and bSortClasses are false\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortingClasses( settings )\n\t{\n\t\tvar oldSort = settings.aLastSort;\n\t\tvar sortClass = settings.oClasses.sSortColumn;\n\t\tvar sort = _fnSortFlatten( settings );\n\t\tvar features = settings.oFeatures;\n\t\tvar i, ien, colIdx;\n\t\n\t\tif ( features.bSort && features.bSortClasses ) {\n\t\t\t// Remove old sorting classes\n\t\t\tfor ( i=0, ien=oldSort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = oldSort[i].src;\n\t\n\t\t\t\t// Remove column sorting\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.removeClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\n\t\t\t// Add new column sorting\n\t\t\tfor ( i=0, ien=sort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = sort[i].src;\n\t\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.addClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aLastSort = sort;\n\t}\n\t\n\t\n\t// Get the data to sort a column, be it from cache, fresh (populating the\n\t// cache), or from a sort formatter\n\tfunction _fnSortData( settings, idx )\n\t{\n\t\t// Custom sorting function - provided by the sort data type\n\t\tvar column = settings.aoColumns[ idx ];\n\t\tvar customSort = DataTable.ext.order[ column.sSortDataType ];\n\t\tvar customData;\n\t\n\t\tif ( customSort ) {\n\t\t\tcustomData = customSort.call( settings.oInstance, settings, idx,\n\t\t\t\t_fnColumnIndexToVisible( settings, idx )\n\t\t\t);\n\t\t}\n\t\n\t\t// Use / populate cache\n\t\tvar row, cellData;\n\t\tvar formatter = DataTable.ext.type.order[ column.sType+\"-pre\" ];\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aSortData ) {\n\t\t\t\trow._aSortData = [];\n\t\t\t}\n\t\n\t\t\tif ( ! row._aSortData[idx] || customSort ) {\n\t\t\t\tcellData = customSort ?\n\t\t\t\t\tcustomData[i] : // If there was a custom sort function, use data from there\n\t\t\t\t\t_fnGetCellData( settings, i, idx, 'sort' );\n\t\n\t\t\t\trow._aSortData[ idx ] = formatter ?\n\t\t\t\t\tformatter( cellData ) :\n\t\t\t\t\tcellData;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Save the state of a table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSaveState ( settings )\n\t{\n\t\tif ( !settings.oFeatures.bStateSave || settings.bDestroying )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Store the interesting variables */\n\t\tvar state = {\n\t\t\ttime:    +new Date(),\n\t\t\tstart:   settings._iDisplayStart,\n\t\t\tlength:  settings._iDisplayLength,\n\t\t\torder:   $.extend( true, [], settings.aaSorting ),\n\t\t\tsearch:  _fnSearchToCamel( settings.oPreviousSearch ),\n\t\t\tcolumns: $.map( settings.aoColumns, function ( col, i ) {\n\t\t\t\treturn {\n\t\t\t\t\tvisible: col.bVisible,\n\t\t\t\t\tsearch: _fnSearchToCamel( settings.aoPreSearchCols[i] )\n\t\t\t\t};\n\t\t\t} )\n\t\t};\n\t\n\t\t_fnCallbackFire( settings, \"aoStateSaveParams\", 'stateSaveParams', [settings, state] );\n\t\n\t\tsettings.oSavedState = state;\n\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, state );\n\t}\n\t\n\t\n\t/**\n\t * Attempt to load a saved table state\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oInit DataTables init object so we can override settings\n\t *  @param {function} callback Callback to execute when the state has been loaded\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLoadState ( settings, oInit, callback )\n\t{\n\t\tvar i, ien;\n\t\tvar columns = settings.aoColumns;\n\t\tvar loaded = function ( s ) {\n\t\t\tif ( ! s || ! s.time ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Allow custom and plug-in manipulation functions to alter the saved data set and\n\t\t\t// cancelling of loading by returning false\n\t\t\tvar abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );\n\t\t\tif ( $.inArray( false, abStateLoad ) !== -1 ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Reject old data\n\t\t\tvar duration = settings.iStateDuration;\n\t\t\tif ( duration > 0 && s.time < +new Date() - (duration*1000) ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Number of columns have changed - all bets are off, no restore of settings\n\t\t\tif ( s.columns && columns.length !== s.columns.length ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Store the saved state so it might be accessed at any time\n\t\t\tsettings.oLoadedState = $.extend( true, {}, state );\n\t\n\t\t\t// Restore key features - todo - for 1.11 this needs to be done by\n\t\t\t// subscribed events\n\t\t\tif ( s.start !== undefined ) {\n\t\t\t\tsettings._iDisplayStart    = s.start;\n\t\t\t\tsettings.iInitDisplayStart = s.start;\n\t\t\t}\n\t\t\tif ( s.length !== undefined ) {\n\t\t\t\tsettings._iDisplayLength   = s.length;\n\t\t\t}\n\t\n\t\t\t// Order\n\t\t\tif ( s.order !== undefined ) {\n\t\t\t\tsettings.aaSorting = [];\n\t\t\t\t$.each( s.order, function ( i, col ) {\n\t\t\t\t\tsettings.aaSorting.push( col[0] >= columns.length ?\n\t\t\t\t\t\t[ 0, col[1] ] :\n\t\t\t\t\t\tcol\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Search\n\t\t\tif ( s.search !== undefined ) {\n\t\t\t\t$.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );\n\t\t\t}\n\t\n\t\t\t// Columns\n\t\t\t// \n\t\t\tif ( s.columns ) {\n\t\t\t\tfor ( i=0, ien=s.columns.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar col = s.columns[i];\n\t\n\t\t\t\t\t// Visibility\n\t\t\t\t\tif ( col.visible !== undefined ) {\n\t\t\t\t\t\tcolumns[i].bVisible = col.visible;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Search\n\t\t\t\t\tif ( col.search !== undefined ) {\n\t\t\t\t\t\t$.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );\n\t\t\tcallback();\n\t\t}\n\t\n\t\tif ( ! settings.oFeatures.bStateSave ) {\n\t\t\tcallback();\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );\n\t\n\t\tif ( state !== undefined ) {\n\t\t\tloaded( state );\n\t\t}\n\t\t// otherwise, wait for the loaded callback to be executed\n\t}\n\t\n\t\n\t/**\n\t * Return the settings object for a particular table\n\t *  @param {node} table table we are using as a dataTable\n\t *  @returns {object} Settings object - or null if not found\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSettingsFromNode ( table )\n\t{\n\t\tvar settings = DataTable.settings;\n\t\tvar idx = $.inArray( table, _pluck( settings, 'nTable' ) );\n\t\n\t\treturn idx !== -1 ?\n\t\t\tsettings[ idx ] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Log an error message\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} level log error messages, or display them to the user\n\t *  @param {string} msg error message\n\t *  @param {int} tn Technical note id to get more information about the error.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLog( settings, level, msg, tn )\n\t{\n\t\tmsg = 'DataTables warning: '+\n\t\t\t(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;\n\t\n\t\tif ( tn ) {\n\t\t\tmsg += '. For more information about this error, please see '+\n\t\t\t'http://datatables.net/tn/'+tn;\n\t\t}\n\t\n\t\tif ( ! level  ) {\n\t\t\t// Backwards compatibility pre 1.10\n\t\t\tvar ext = DataTable.ext;\n\t\t\tvar type = ext.sErrMode || ext.errMode;\n\t\n\t\t\tif ( settings ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );\n\t\t\t}\n\t\n\t\t\tif ( type == 'alert' ) {\n\t\t\t\talert( msg );\n\t\t\t}\n\t\t\telse if ( type == 'throw' ) {\n\t\t\t\tthrow new Error(msg);\n\t\t\t}\n\t\t\telse if ( typeof type == 'function' ) {\n\t\t\t\ttype( settings, tn, msg );\n\t\t\t}\n\t\t}\n\t\telse if ( window.console && console.log ) {\n\t\t\tconsole.log( msg );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * See if a property is defined on one object, if so assign it to the other object\n\t *  @param {object} ret target object\n\t *  @param {object} src source object\n\t *  @param {string} name property\n\t *  @param {string} [mappedName] name to map too - optional, name used if not given\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnMap( ret, src, name, mappedName )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\t$.each( name, function (i, val) {\n\t\t\t\tif ( $.isArray( val ) ) {\n\t\t\t\t\t_fnMap( ret, src, val[0], val[1] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_fnMap( ret, src, val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( mappedName === undefined ) {\n\t\t\tmappedName = name;\n\t\t}\n\t\n\t\tif ( src[name] !== undefined ) {\n\t\t\tret[mappedName] = src[name];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Extend objects - very similar to jQuery.extend, but deep copy objects, and\n\t * shallow copy arrays. The reason we need to do this, is that we don't want to\n\t * deep copy array init values (such as aaSorting) since the dev wouldn't be\n\t * able to override them, but we do want to deep copy arrays.\n\t *  @param {object} out Object to extend\n\t *  @param {object} extender Object from which the properties will be applied to\n\t *      out\n\t *  @param {boolean} breakRefs If true, then arrays will be sliced to take an\n\t *      independent copy with the exception of the `data` or `aaData` parameters\n\t *      if they are present. This is so you can pass in a collection to\n\t *      DataTables and have that used as your data source without breaking the\n\t *      references\n\t *  @returns {object} out Reference, just for convenience - out === the return.\n\t *  @memberof DataTable#oApi\n\t *  @todo This doesn't take account of arrays inside the deep copied objects.\n\t */\n\tfunction _fnExtend( out, extender, breakRefs )\n\t{\n\t\tvar val;\n\t\n\t\tfor ( var prop in extender ) {\n\t\t\tif ( extender.hasOwnProperty(prop) ) {\n\t\t\t\tval = extender[prop];\n\t\n\t\t\t\tif ( $.isPlainObject( val ) ) {\n\t\t\t\t\tif ( ! $.isPlainObject( out[prop] ) ) {\n\t\t\t\t\t\tout[prop] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, out[prop], val );\n\t\t\t\t}\n\t\t\t\telse if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {\n\t\t\t\t\tout[prop] = val.slice();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tout[prop] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t}\n\t\n\t\n\t/**\n\t * Bind an event handers to allow a click or return key to activate the callback.\n\t * This is good for accessibility since a return on the keyboard will have the\n\t * same effect as a click, if the element has focus.\n\t *  @param {element} n Element to bind the action to\n\t *  @param {object} oData Data object to pass to the triggered function\n\t *  @param {function} fn Callback function for when the event is triggered\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBindAction( n, oData, fn )\n\t{\n\t\t$(n)\n\t\t\t.on( 'click.DT', oData, function (e) {\n\t\t\t\t\tn.blur(); // Remove focus outline for mouse users\n\t\t\t\t\tfn(e);\n\t\t\t\t} )\n\t\t\t.on( 'keypress.DT', oData, function (e){\n\t\t\t\t\tif ( e.which === 13 ) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tfn(e);\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t.on( 'selectstart.DT', function () {\n\t\t\t\t\t/* Take the brutal approach to cancelling text selection */\n\t\t\t\t\treturn false;\n\t\t\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Register a callback function. Easily allows a callback function to be added to\n\t * an array store of callback functions that can then all be called together.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sStore Name of the array storage for the callbacks in oSettings\n\t *  @param {function} fn Function to be called back\n\t *  @param {string} sName Identifying name for the callback (i.e. a label)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackReg( oSettings, sStore, fn, sName )\n\t{\n\t\tif ( fn )\n\t\t{\n\t\t\toSettings[sStore].push( {\n\t\t\t\t\"fn\": fn,\n\t\t\t\t\"sName\": sName\n\t\t\t} );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Fire callback functions and trigger events. Note that the loop over the\n\t * callback array store is done backwards! Further note that you do not want to\n\t * fire off triggers in time sensitive applications (for example cell creation)\n\t * as its slow.\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} callbackArr Name of the array storage for the callbacks in\n\t *      oSettings\n\t *  @param {string} eventName Name of the jQuery custom event to trigger. If\n\t *      null no trigger is fired\n\t *  @param {array} args Array of arguments to pass to the callback function /\n\t *      trigger\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackFire( settings, callbackArr, eventName, args )\n\t{\n\t\tvar ret = [];\n\t\n\t\tif ( callbackArr ) {\n\t\t\tret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {\n\t\t\t\treturn val.fn.apply( settings.oInstance, args );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( eventName !== null ) {\n\t\t\tvar e = $.Event( eventName+'.dt' );\n\t\n\t\t\t$(settings.nTable).trigger( e, args );\n\t\n\t\t\tret.push( e.result );\n\t\t}\n\t\n\t\treturn ret;\n\t}\n\t\n\t\n\tfunction _fnLengthOverflow ( settings )\n\t{\n\t\tvar\n\t\t\tstart = settings._iDisplayStart,\n\t\t\tend = settings.fnDisplayEnd(),\n\t\t\tlen = settings._iDisplayLength;\n\t\n\t\t/* If we have space to show extra rows (backing up from the end point - then do so */\n\t\tif ( start >= end )\n\t\t{\n\t\t\tstart = end - len;\n\t\t}\n\t\n\t\t// Keep the start record on the current page\n\t\tstart -= (start % len);\n\t\n\t\tif ( len === -1 || start < 0 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\n\t\tsettings._iDisplayStart = start;\n\t}\n\t\n\t\n\tfunction _fnRenderer( settings, type )\n\t{\n\t\tvar renderer = settings.renderer;\n\t\tvar host = DataTable.ext.renderer[type];\n\t\n\t\tif ( $.isPlainObject( renderer ) && renderer[type] ) {\n\t\t\t// Specific renderer for this type. If available use it, otherwise use\n\t\t\t// the default.\n\t\t\treturn host[renderer[type]] || host._;\n\t\t}\n\t\telse if ( typeof renderer === 'string' ) {\n\t\t\t// Common renderer - if there is one available for this type use it,\n\t\t\t// otherwise use the default\n\t\t\treturn host[renderer] || host._;\n\t\t}\n\t\n\t\t// Use the default\n\t\treturn host._;\n\t}\n\t\n\t\n\t/**\n\t * Detect the data source being used for the table. Used to simplify the code\n\t * a little (ajax) and to make it compress a little smaller.\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {string} Data source\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDataSource ( settings )\n\t{\n\t\tif ( settings.oFeatures.bServerSide ) {\n\t\t\treturn 'ssp';\n\t\t}\n\t\telse if ( settings.ajax || settings.sAjaxSource ) {\n\t\t\treturn 'ajax';\n\t\t}\n\t\treturn 'dom';\n\t}\n\t\n\n\t\n\t\n\t/**\n\t * Computed structure of the DataTables API, defined by the options passed to\n\t * `DataTable.Api.register()` when building the API.\n\t *\n\t * The structure is built in order to speed creation and extension of the Api\n\t * objects since the extensions are effectively pre-parsed.\n\t *\n\t * The array is an array of objects with the following structure, where this\n\t * base array represents the Api prototype base:\n\t *\n\t *     [\n\t *       {\n\t *         name:      'data'                -- string   - Property name\n\t *         val:       function () {},       -- function - Api method (or undefined if just an object\n\t *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t *       },\n\t *       {\n\t *         name:     'row'\n\t *         val:       {},\n\t *         methodExt: [ ... ],\n\t *         propExt:   [\n\t *           {\n\t *             name:      'data'\n\t *             val:       function () {},\n\t *             methodExt: [ ... ],\n\t *             propExt:   [ ... ]\n\t *           },\n\t *           ...\n\t *         ]\n\t *       }\n\t *     ]\n\t *\n\t * @type {Array}\n\t * @ignore\n\t */\n\tvar __apiStruct = [];\n\t\n\t\n\t/**\n\t * `Array.prototype` reference.\n\t *\n\t * @type object\n\t * @ignore\n\t */\n\tvar __arrayProto = Array.prototype;\n\t\n\t\n\t/**\n\t * Abstraction for `context` parameter of the `Api` constructor to allow it to\n\t * take several different forms for ease of use.\n\t *\n\t * Each of the input parameter types will be converted to a DataTables settings\n\t * object where possible.\n\t *\n\t * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one\n\t *   of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t *   * `DataTables.Api` - API instance\n\t * @return {array|null} Matching DataTables settings objects. `null` or\n\t *   `undefined` is returned if no matching DataTable is found.\n\t * @ignore\n\t */\n\tvar _toSettings = function ( mixed )\n\t{\n\t\tvar idx, jq;\n\t\tvar settings = DataTable.settings;\n\t\tvar tables = $.map( settings, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\tif ( ! mixed ) {\n\t\t\treturn [];\n\t\t}\n\t\telse if ( mixed.nTable && mixed.oApi ) {\n\t\t\t// DataTables settings object\n\t\t\treturn [ mixed ];\n\t\t}\n\t\telse if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {\n\t\t\t// Table node\n\t\t\tidx = $.inArray( mixed, tables );\n\t\t\treturn idx !== -1 ? [ settings[idx] ] : null;\n\t\t}\n\t\telse if ( mixed && typeof mixed.settings === 'function' ) {\n\t\t\treturn mixed.settings().toArray();\n\t\t}\n\t\telse if ( typeof mixed === 'string' ) {\n\t\t\t// jQuery selector\n\t\t\tjq = $(mixed);\n\t\t}\n\t\telse if ( mixed instanceof $ ) {\n\t\t\t// jQuery object (also DataTables instance)\n\t\t\tjq = mixed;\n\t\t}\n\t\n\t\tif ( jq ) {\n\t\t\treturn jq.map( function(i) {\n\t\t\t\tidx = $.inArray( this, tables );\n\t\t\t\treturn idx !== -1 ? settings[idx] : null;\n\t\t\t} ).toArray();\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * DataTables API class - used to control and interface with  one or more\n\t * DataTables enhanced tables.\n\t *\n\t * The API class is heavily based on jQuery, presenting a chainable interface\n\t * that you can use to interact with tables. Each instance of the API class has\n\t * a \"context\" - i.e. the tables that it will operate on. This could be a single\n\t * table, all tables on a page or a sub-set thereof.\n\t *\n\t * Additionally the API is designed to allow you to easily work with the data in\n\t * the tables, retrieving and manipulating it as required. This is done by\n\t * presenting the API class as an array like interface. The contents of the\n\t * array depend upon the actions requested by each method (for example\n\t * `rows().nodes()` will return an array of nodes, while `rows().data()` will\n\t * return an array of objects or arrays depending upon your table's\n\t * configuration). The API object has a number of array like methods (`push`,\n\t * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,\n\t * `unique` etc) to assist your working with the data held in a table.\n\t *\n\t * Most methods (those which return an Api instance) are chainable, which means\n\t * the return from a method call also has all of the methods available that the\n\t * top level object had. For example, these two calls are equivalent:\n\t *\n\t *     // Not chained\n\t *     api.row.add( {...} );\n\t *     api.draw();\n\t *\n\t *     // Chained\n\t *     api.row.add( {...} ).draw();\n\t *\n\t * @class DataTable.Api\n\t * @param {array|object|string|jQuery} context DataTable identifier. This is\n\t *   used to define which DataTables enhanced tables this API will operate on.\n\t *   Can be one of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t * @param {array} [data] Data to initialise the Api instance with.\n\t *\n\t * @example\n\t *   // Direct initialisation during DataTables construction\n\t *   var api = $('#example').DataTable();\n\t *\n\t * @example\n\t *   // Initialisation using a DataTables jQuery object\n\t *   var api = $('#example').dataTable().api();\n\t *\n\t * @example\n\t *   // Initialisation as a constructor\n\t *   var api = new $.fn.DataTable.Api( 'table.dataTable' );\n\t */\n\t_Api = function ( context, data )\n\t{\n\t\tif ( ! (this instanceof _Api) ) {\n\t\t\treturn new _Api( context, data );\n\t\t}\n\t\n\t\tvar settings = [];\n\t\tvar ctxSettings = function ( o ) {\n\t\t\tvar a = _toSettings( o );\n\t\t\tif ( a ) {\n\t\t\t\tsettings = settings.concat( a );\n\t\t\t}\n\t\t};\n\t\n\t\tif ( $.isArray( context ) ) {\n\t\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tctxSettings( context[i] );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tctxSettings( context );\n\t\t}\n\t\n\t\t// Remove duplicates\n\t\tthis.context = _unique( settings );\n\t\n\t\t// Initial data\n\t\tif ( data ) {\n\t\t\t$.merge( this, data );\n\t\t}\n\t\n\t\t// selector\n\t\tthis.selector = {\n\t\t\trows: null,\n\t\t\tcols: null,\n\t\t\topts: null\n\t\t};\n\t\n\t\t_Api.extend( this, this, __apiStruct );\n\t};\n\t\n\tDataTable.Api = _Api;\n\t\n\t// Don't destroy the existing prototype, just extend it. Required for jQuery 2's\n\t// isPlainObject.\n\t$.extend( _Api.prototype, {\n\t\tany: function ()\n\t\t{\n\t\t\treturn this.count() !== 0;\n\t\t},\n\t\n\t\n\t\tconcat:  __arrayProto.concat,\n\t\n\t\n\t\tcontext: [], // array of table settings objects\n\t\n\t\n\t\tcount: function ()\n\t\t{\n\t\t\treturn this.flatten().length;\n\t\t},\n\t\n\t\n\t\teach: function ( fn )\n\t\t{\n\t\t\tfor ( var i=0, ien=this.length ; i<ien; i++ ) {\n\t\t\t\tfn.call( this, this[i], i, this );\n\t\t\t}\n\t\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\teq: function ( idx )\n\t\t{\n\t\t\tvar ctx = this.context;\n\t\n\t\t\treturn ctx.length > idx ?\n\t\t\t\tnew _Api( ctx[idx], this[idx] ) :\n\t\t\t\tnull;\n\t\t},\n\t\n\t\n\t\tfilter: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.filter ) {\n\t\t\t\ta = __arrayProto.filter.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( fn.call( this, this[i], i, this ) ) {\n\t\t\t\t\t\ta.push( this[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tflatten: function ()\n\t\t{\n\t\t\tvar a = [];\n\t\t\treturn new _Api( this.context, a.concat.apply( a, this.toArray() ) );\n\t\t},\n\t\n\t\n\t\tjoin:    __arrayProto.join,\n\t\n\t\n\t\tindexOf: __arrayProto.indexOf || function (obj, start)\n\t\t{\n\t\t\tfor ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {\n\t\t\t\tif ( this[i] === obj ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1;\n\t\t},\n\t\n\t\titerator: function ( flatten, type, fn, alwaysNew ) {\n\t\t\tvar\n\t\t\t\ta = [], ret,\n\t\t\t\ti, ien, j, jen,\n\t\t\t\tcontext = this.context,\n\t\t\t\trows, items, item,\n\t\t\t\tselector = this.selector;\n\t\n\t\t\t// Argument shifting\n\t\t\tif ( typeof flatten === 'string' ) {\n\t\t\t\talwaysNew = fn;\n\t\t\t\tfn = type;\n\t\t\t\ttype = flatten;\n\t\t\t\tflatten = false;\n\t\t\t}\n\t\n\t\t\tfor ( i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tvar apiInst = new _Api( context[i] );\n\t\n\t\t\t\tif ( type === 'table' ) {\n\t\t\t\t\tret = fn.call( apiInst, context[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'columns' || type === 'rows' ) {\n\t\t\t\t\t// this has same length as context - one entry for each table\n\t\t\t\t\tret = fn.call( apiInst, context[i], this[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {\n\t\t\t\t\t// columns and rows share the same structure.\n\t\t\t\t\t// 'this' is an array of column indexes for each context\n\t\t\t\t\titems = this[i];\n\t\n\t\t\t\t\tif ( type === 'column-rows' ) {\n\t\t\t\t\t\trows = _selector_row_indexes( context[i], selector.opts );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfor ( j=0, jen=items.length ; j<jen ; j++ ) {\n\t\t\t\t\t\titem = items[j];\n\t\n\t\t\t\t\t\tif ( type === 'cell' ) {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item.row, item.column, i, j );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item, i, j, rows );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( a.length || alwaysNew ) {\n\t\t\t\tvar api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );\n\t\t\t\tvar apiSelector = api.selector;\n\t\t\t\tapiSelector.rows = selector.rows;\n\t\t\t\tapiSelector.cols = selector.cols;\n\t\t\t\tapiSelector.opts = selector.opts;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\tlastIndexOf: __arrayProto.lastIndexOf || function (obj, start)\n\t\t{\n\t\t\t// Bit cheeky...\n\t\t\treturn this.indexOf.apply( this.toArray.reverse(), arguments );\n\t\t},\n\t\n\t\n\t\tlength:  0,\n\t\n\t\n\t\tmap: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.map ) {\n\t\t\t\ta = __arrayProto.map.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\ta.push( fn.call( this, this[i], i ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tpluck: function ( prop )\n\t\t{\n\t\t\treturn this.map( function ( el ) {\n\t\t\t\treturn el[ prop ];\n\t\t\t} );\n\t\t},\n\t\n\t\tpop:     __arrayProto.pop,\n\t\n\t\n\t\tpush:    __arrayProto.push,\n\t\n\t\n\t\t// Does not return an API instance\n\t\treduce: __arrayProto.reduce || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, 0, this.length, 1 );\n\t\t},\n\t\n\t\n\t\treduceRight: __arrayProto.reduceRight || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, this.length-1, -1, -1 );\n\t\t},\n\t\n\t\n\t\treverse: __arrayProto.reverse,\n\t\n\t\n\t\t// Object with rows, columns and opts\n\t\tselector: null,\n\t\n\t\n\t\tshift:   __arrayProto.shift,\n\t\n\t\n\t\tsort:    __arrayProto.sort, // ? name - order?\n\t\n\t\n\t\tsplice:  __arrayProto.splice,\n\t\n\t\n\t\ttoArray: function ()\n\t\t{\n\t\t\treturn __arrayProto.slice.call( this );\n\t\t},\n\t\n\t\n\t\tto$: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\ttoJQuery: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\tunique: function ()\n\t\t{\n\t\t\treturn new _Api( this.context, _unique(this) );\n\t\t},\n\t\n\t\n\t\tunshift: __arrayProto.unshift\n\t} );\n\t\n\t\n\t_Api.extend = function ( scope, obj, ext )\n\t{\n\t\t// Only extend API instances and static properties of the API\n\t\tif ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\tj, jen,\n\t\t\tstruct, inner,\n\t\t\tmethodScoping = function ( scope, fn, struc ) {\n\t\t\t\treturn function () {\n\t\t\t\t\tvar ret = fn.apply( scope, arguments );\n\t\n\t\t\t\t\t// Method extension\n\t\t\t\t\t_Api.extend( ret, ret, struc.methodExt );\n\t\t\t\t\treturn ret;\n\t\t\t\t};\n\t\t\t};\n\t\n\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\tstruct = ext[i];\n\t\n\t\t\t// Value\n\t\t\tobj[ struct.name ] = typeof struct.val === 'function' ?\n\t\t\t\tmethodScoping( scope, struct.val, struct ) :\n\t\t\t\t$.isPlainObject( struct.val ) ?\n\t\t\t\t\t{} :\n\t\t\t\t\tstruct.val;\n\t\n\t\t\tobj[ struct.name ].__dt_wrapper = true;\n\t\n\t\t\t// Property extension\n\t\t\t_Api.extend( scope, obj[ struct.name ], struct.propExt );\n\t\t}\n\t};\n\t\n\t\n\t// @todo - Is there need for an augment function?\n\t// _Api.augment = function ( inst, name )\n\t// {\n\t// \t// Find src object in the structure from the name\n\t// \tvar parts = name.split('.');\n\t\n\t// \t_Api.extend( inst, obj );\n\t// };\n\t\n\t\n\t//     [\n\t//       {\n\t//         name:      'data'                -- string   - Property name\n\t//         val:       function () {},       -- function - Api method (or undefined if just an object\n\t//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t//       },\n\t//       {\n\t//         name:     'row'\n\t//         val:       {},\n\t//         methodExt: [ ... ],\n\t//         propExt:   [\n\t//           {\n\t//             name:      'data'\n\t//             val:       function () {},\n\t//             methodExt: [ ... ],\n\t//             propExt:   [ ... ]\n\t//           },\n\t//           ...\n\t//         ]\n\t//       }\n\t//     ]\n\t\n\t_Api.register = _api_register = function ( name, val )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\tfor ( var j=0, jen=name.length ; j<jen ; j++ ) {\n\t\t\t\t_Api.register( name[j], val );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\their = name.split('.'),\n\t\t\tstruct = __apiStruct,\n\t\t\tkey, method;\n\t\n\t\tvar find = function ( src, name ) {\n\t\t\tfor ( var i=0, ien=src.length ; i<ien ; i++ ) {\n\t\t\t\tif ( src[i].name === name ) {\n\t\t\t\t\treturn src[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\n\t\tfor ( i=0, ien=heir.length ; i<ien ; i++ ) {\n\t\t\tmethod = heir[i].indexOf('()') !== -1;\n\t\t\tkey = method ?\n\t\t\t\their[i].replace('()', '') :\n\t\t\t\their[i];\n\t\n\t\t\tvar src = find( struct, key );\n\t\t\tif ( ! src ) {\n\t\t\t\tsrc = {\n\t\t\t\t\tname:      key,\n\t\t\t\t\tval:       {},\n\t\t\t\t\tmethodExt: [],\n\t\t\t\t\tpropExt:   []\n\t\t\t\t};\n\t\t\t\tstruct.push( src );\n\t\t\t}\n\t\n\t\t\tif ( i === ien-1 ) {\n\t\t\t\tsrc.val = val;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstruct = method ?\n\t\t\t\t\tsrc.methodExt :\n\t\t\t\t\tsrc.propExt;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\t_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {\n\t\t_Api.register( pluralName, val );\n\t\n\t\t_Api.register( singularName, function () {\n\t\t\tvar ret = val.apply( this, arguments );\n\t\n\t\t\tif ( ret === this ) {\n\t\t\t\t// Returned item is the API instance that was passed in, return it\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\telse if ( ret instanceof _Api ) {\n\t\t\t\t// New API instance returned, want the value from the first item\n\t\t\t\t// in the returned array for the singular result.\n\t\t\t\treturn ret.length ?\n\t\t\t\t\t$.isArray( ret[0] ) ?\n\t\t\t\t\t\tnew _Api( ret.context, ret[0] ) : // Array results are 'enhanced'\n\t\t\t\t\t\tret[0] :\n\t\t\t\t\tundefined;\n\t\t\t}\n\t\n\t\t\t// Non-API return - just fire it back\n\t\t\treturn ret;\n\t\t} );\n\t};\n\t\n\t\n\t/**\n\t * Selector for HTML tables. Apply the given selector to the give array of\n\t * DataTables settings objects.\n\t *\n\t * @param {string|integer} [selector] jQuery selector string or integer\n\t * @param  {array} Array of DataTables settings objects to be filtered\n\t * @return {array}\n\t * @ignore\n\t */\n\tvar __table_selector = function ( selector, a )\n\t{\n\t\t// Integer is used to pick out a table by index\n\t\tif ( typeof selector === 'number' ) {\n\t\t\treturn [ a[ selector ] ];\n\t\t}\n\t\n\t\t// Perform a jQuery selector on the table nodes\n\t\tvar nodes = $.map( a, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\treturn $(nodes)\n\t\t\t.filter( selector )\n\t\t\t.map( function (i) {\n\t\t\t\t// Need to translate back from the table node to the settings\n\t\t\t\tvar idx = $.inArray( this, nodes );\n\t\t\t\treturn a[ idx ];\n\t\t\t} )\n\t\t\t.toArray();\n\t};\n\t\n\t\n\t\n\t/**\n\t * Context selector for the API's context (i.e. the tables the API instance\n\t * refers to.\n\t *\n\t * @name    DataTable.Api#tables\n\t * @param {string|integer} [selector] Selector to pick which tables the iterator\n\t *   should operate on. If not given, all tables in the current context are\n\t *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to\n\t *   select multiple tables or as an integer to select a single table.\n\t * @returns {DataTable.Api} Returns a new API instance if a selector is given.\n\t */\n\t_api_register( 'tables()', function ( selector ) {\n\t\t// A new instance is created if there was a selector specified\n\t\treturn selector ?\n\t\t\tnew _Api( __table_selector( selector, this.context ) ) :\n\t\t\tthis;\n\t} );\n\t\n\t\n\t_api_register( 'table()', function ( selector ) {\n\t\tvar tables = this.tables( selector );\n\t\tvar ctx = tables.context;\n\t\n\t\t// Truncate to the first matched table\n\t\treturn ctx.length ?\n\t\t\tnew _Api( ctx[0] ) :\n\t\t\ttables;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTable;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().body()', 'table().body()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTBody;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().header()', 'table().header()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTHead;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTFoot;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().containers()', 'table().container()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTableWrapper;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Redraw the tables in the current context.\n\t */\n\t_api_register( 'draw()', function ( paging ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( paging === 'page' ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ( typeof paging === 'string' ) {\n\t\t\t\t\tpaging = paging === 'full-hold' ?\n\t\t\t\t\t\tfalse :\n\t\t\t\t\t\ttrue;\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, paging===false );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get the current page index.\n\t *\n\t * @return {integer} Current page index (zero based)\n\t *//**\n\t * Set the current page.\n\t *\n\t * Note that if you attempt to show a page which does not exist, DataTables will\n\t * not throw an error, but rather reset the paging.\n\t *\n\t * @param {integer|string} action The paging action to take. This can be one of:\n\t *  * `integer` - The page index to jump to\n\t *  * `string` - An action to take:\n\t *    * `first` - Jump to first page.\n\t *    * `next` - Jump to the next page\n\t *    * `previous` - Jump to previous page\n\t *    * `last` - Jump to the last page.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page()', function ( action ) {\n\t\tif ( action === undefined ) {\n\t\t\treturn this.page.info().page; // not an expensive call\n\t\t}\n\t\n\t\t// else, have an action to take on all tables\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnPageChange( settings, action );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Paging information for the first table in the current context.\n\t *\n\t * If you require paging information for another table, use the `table()` method\n\t * with a suitable selector.\n\t *\n\t * @return {object} Object with the following properties set:\n\t *  * `page` - Current page index (zero based - i.e. the first page is `0`)\n\t *  * `pages` - Total number of pages\n\t *  * `start` - Display index for the first record shown on the current page\n\t *  * `end` - Display index for the last record shown on the current page\n\t *  * `length` - Display length (number of records). Note that generally `start\n\t *    + length = end`, but this is not always true, for example if there are\n\t *    only 2 records to show on the final page, with a length of 10.\n\t *  * `recordsTotal` - Full data set length\n\t *  * `recordsDisplay` - Data set length once the current filtering criterion\n\t *    are applied.\n\t */\n\t_api_register( 'page.info()', function ( action ) {\n\t\tif ( this.context.length === 0 ) {\n\t\t\treturn undefined;\n\t\t}\n\t\n\t\tvar\n\t\t\tsettings   = this.context[0],\n\t\t\tstart      = settings._iDisplayStart,\n\t\t\tlen        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,\n\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn {\n\t\t\t\"page\":           all ? 0 : Math.floor( start / len ),\n\t\t\t\"pages\":          all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\"start\":          start,\n\t\t\t\"end\":            settings.fnDisplayEnd(),\n\t\t\t\"length\":         len,\n\t\t\t\"recordsTotal\":   settings.fnRecordsTotal(),\n\t\t\t\"recordsDisplay\": visRecords,\n\t\t\t\"serverSide\":     _fnDataSource( settings ) === 'ssp'\n\t\t};\n\t} );\n\t\n\t\n\t/**\n\t * Get the current page length.\n\t *\n\t * @return {integer} Current page length. Note `-1` indicates that all records\n\t *   are to be shown.\n\t *//**\n\t * Set the current page length.\n\t *\n\t * @param {integer} Page length to set. Use `-1` to show all records.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page.len()', function ( len ) {\n\t\t// Note that we can't call this function 'length()' because `length`\n\t\t// is a Javascript property of functions which defines how many arguments\n\t\t// the function expects.\n\t\tif ( len === undefined ) {\n\t\t\treturn this.context.length !== 0 ?\n\t\t\t\tthis.context[0]._iDisplayLength :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// else, set the page length\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnLengthChange( settings, len );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\tvar __reload = function ( settings, holdPosition, callback ) {\n\t\t// Use the draw event to trigger a callback\n\t\tif ( callback ) {\n\t\t\tvar api = new _Api( settings );\n\t\n\t\t\tapi.one( 'draw', function () {\n\t\t\t\tcallback( api.ajax.json() );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t_fnReDraw( settings, holdPosition );\n\t\t}\n\t\telse {\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t// Cancel an existing request\n\t\t\tvar xhr = settings.jqXHR;\n\t\t\tif ( xhr && xhr.readyState !== 4 ) {\n\t\t\t\txhr.abort();\n\t\t\t}\n\t\n\t\t\t// Trigger xhr\n\t\t\t_fnBuildAjax( settings, [], function( json ) {\n\t\t\t\t_fnClearTable( settings );\n\t\n\t\t\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\t_fnAddData( settings, data[i] );\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, holdPosition );\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Get the JSON response from the last Ajax request that DataTables made to the\n\t * server. Note that this returns the JSON from the first table in the current\n\t * context.\n\t *\n\t * @return {object} JSON received from the server.\n\t */\n\t_api_register( 'ajax.json()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].json;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Get the data submitted in the last Ajax request\n\t */\n\t_api_register( 'ajax.params()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].oAjaxData;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Reload tables from the Ajax data source. Note that this function will\n\t * automatically re-draw the table when the remote data has been loaded.\n\t *\n\t * @param {boolean} [reset=true] Reset (default) or hold the current paging\n\t *   position. A full re-sort and re-filter is performed when this method is\n\t *   called, which is why the pagination reset is the default action.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.reload()', function ( callback, resetPaging ) {\n\t\treturn this.iterator( 'table', function (settings) {\n\t\t\t__reload( settings, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Get the current Ajax URL. Note that this returns the URL from the first\n\t * table in the current context.\n\t *\n\t * @return {string} Current Ajax source URL\n\t *//**\n\t * Set the Ajax URL. Note that this will set the URL for all tables in the\n\t * current context.\n\t *\n\t * @param {string} url URL to set.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url()', function ( url ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( url === undefined ) {\n\t\t\t// get\n\t\t\tif ( ctx.length === 0 ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tctx = ctx[0];\n\t\n\t\t\treturn ctx.ajax ?\n\t\t\t\t$.isPlainObject( ctx.ajax ) ?\n\t\t\t\t\tctx.ajax.url :\n\t\t\t\t\tctx.ajax :\n\t\t\t\tctx.sAjaxSource;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( $.isPlainObject( settings.ajax ) ) {\n\t\t\t\tsettings.ajax.url = url;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsettings.ajax = url;\n\t\t\t}\n\t\t\t// No need to consider sAjaxSource here since DataTables gives priority\n\t\t\t// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any\n\t\t\t// value of `sAjaxSource` redundant.\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Load data from the newly set Ajax URL. Note that this method is only\n\t * available when `ajax.url()` is used to set a URL. Additionally, this method\n\t * has the same effect as calling `ajax.reload()` but is provided for\n\t * convenience when setting a new URL. Like `ajax.reload()` it will\n\t * automatically redraw the table once the remote data has been loaded.\n\t *\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {\n\t\t// Same as a reload, but makes sense to present it for easy access after a\n\t\t// url change\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\t__reload( ctx, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t\n\tvar _selector_run = function ( type, selector, selectFn, settings, opts )\n\t{\n\t\tvar\n\t\t\tout = [], res,\n\t\t\ta, i, ien, j, jen,\n\t\t\tselectorType = typeof selector;\n\t\n\t\t// Can't just check for isArray here, as an API or jQuery instance might be\n\t\t// given with their array like look\n\t\tif ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {\n\t\t\tselector = [ selector ];\n\t\t}\n\t\n\t\tfor ( i=0, ien=selector.length ; i<ien ; i++ ) {\n\t\t\t// Only split on simple strings - complex expressions will be jQuery selectors\n\t\t\ta = selector[i] && selector[i].split && ! selector[i].match(/[\\[\\(:]/) ?\n\t\t\t\tselector[i].split(',') :\n\t\t\t\t[ selector[i] ];\n\t\n\t\t\tfor ( j=0, jen=a.length ; j<jen ; j++ ) {\n\t\t\t\tres = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );\n\t\n\t\t\t\tif ( res && res.length ) {\n\t\t\t\t\tout = out.concat( res );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// selector extensions\n\t\tvar ext = _ext.selector[ type ];\n\t\tif ( ext.length ) {\n\t\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\t\tout = ext[i]( settings, opts, out );\n\t\t\t}\n\t\t}\n\t\n\t\treturn _unique( out );\n\t};\n\t\n\t\n\tvar _selector_opts = function ( opts )\n\t{\n\t\tif ( ! opts ) {\n\t\t\topts = {};\n\t\t}\n\t\n\t\t// Backwards compatibility for 1.9- which used the terminology filter rather\n\t\t// than search\n\t\tif ( opts.filter && opts.search === undefined ) {\n\t\t\topts.search = opts.filter;\n\t\t}\n\t\n\t\treturn $.extend( {\n\t\t\tsearch: 'none',\n\t\t\torder: 'current',\n\t\t\tpage: 'all'\n\t\t}, opts );\n\t};\n\t\n\t\n\tvar _selector_first = function ( inst )\n\t{\n\t\t// Reduce the API instance to the first item found\n\t\tfor ( var i=0, ien=inst.length ; i<ien ; i++ ) {\n\t\t\tif ( inst[i].length > 0 ) {\n\t\t\t\t// Assign the first element to the first item in the instance\n\t\t\t\t// and truncate the instance and context\n\t\t\t\tinst[0] = inst[i];\n\t\t\t\tinst[0].length = 1;\n\t\t\t\tinst.length = 1;\n\t\t\t\tinst.context = [ inst.context[i] ];\n\t\n\t\t\t\treturn inst;\n\t\t\t}\n\t\t}\n\t\n\t\t// Not found - return an empty instance\n\t\tinst.length = 0;\n\t\treturn inst;\n\t};\n\t\n\t\n\tvar _selector_row_indexes = function ( settings, opts )\n\t{\n\t\tvar\n\t\t\ti, ien, tmp, a=[],\n\t\t\tdisplayFiltered = settings.aiDisplay,\n\t\t\tdisplayMaster = settings.aiDisplayMaster;\n\t\n\t\tvar\n\t\t\tsearch = opts.search,  // none, applied, removed\n\t\t\torder  = opts.order,   // applied, current, index (original - compatibility with 1.9)\n\t\t\tpage   = opts.page;    // all, current\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t// In server-side processing mode, most options are irrelevant since\n\t\t\t// rows not shown don't exist and the index order is the applied order\n\t\t\t// Removed is a special case - for consistency just return an empty\n\t\t\t// array\n\t\t\treturn search === 'removed' ?\n\t\t\t\t[] :\n\t\t\t\t_range( 0, displayMaster.length );\n\t\t}\n\t\telse if ( page == 'current' ) {\n\t\t\t// Current page implies that order=current and fitler=applied, since it is\n\t\t\t// fairly senseless otherwise, regardless of what order and search actually\n\t\t\t// are\n\t\t\tfor ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {\n\t\t\t\ta.push( displayFiltered[i] );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'current' || order == 'applied' ) {\n\t\t\ta = search == 'none' ?\n\t\t\t\tdisplayMaster.slice() :                      // no search\n\t\t\t\tsearch == 'applied' ?\n\t\t\t\t\tdisplayFiltered.slice() :                // applied search\n\t\t\t\t\t$.map( displayMaster, function (el, i) { // removed search\n\t\t\t\t\t\treturn $.inArray( el, displayFiltered ) === -1 ? el : null;\n\t\t\t\t\t} );\n\t\t}\n\t\telse if ( order == 'index' || order == 'original' ) {\n\t\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tif ( search == 'none' ) {\n\t\t\t\t\ta.push( i );\n\t\t\t\t}\n\t\t\t\telse { // applied | removed\n\t\t\t\t\ttmp = $.inArray( i, displayFiltered );\n\t\n\t\t\t\t\tif ((tmp === -1 && search == 'removed') ||\n\t\t\t\t\t\t(tmp >= 0   && search == 'applied') )\n\t\t\t\t\t{\n\t\t\t\t\t\ta.push( i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn a;\n\t};\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Rows\n\t *\n\t * {}          - no selector - use all available rows\n\t * {integer}   - row aoData index\n\t * {node}      - TR node\n\t * {string}    - jQuery selector to apply to the TR elements\n\t * {array}     - jQuery array of nodes, or simply an array of TR nodes\n\t *\n\t */\n\t\n\t\n\tvar __row_selector = function ( settings, selector, opts )\n\t{\n\t\tvar rows;\n\t\tvar run = function ( sel ) {\n\t\t\tvar selInt = _intVal( sel );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Short cut - selector is a number and no options provided (default is\n\t\t\t// all records, so no need to check if the index is in there, since it\n\t\t\t// must be - dev error if the index doesn't exist).\n\t\t\tif ( selInt !== null && ! opts ) {\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\n\t\t\tif ( ! rows ) {\n\t\t\t\trows = _selector_row_indexes( settings, opts );\n\t\t\t}\n\t\n\t\t\tif ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {\n\t\t\t\t// Selector - integer\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\t\telse if ( sel === null || sel === undefined || sel === '' ) {\n\t\t\t\t// Selector - none\n\t\t\t\treturn rows;\n\t\t\t}\n\t\n\t\t\t// Selector - function\n\t\t\tif ( typeof sel === 'function' ) {\n\t\t\t\treturn $.map( rows, function (idx) {\n\t\t\t\t\tvar row = settings.aoData[ idx ];\n\t\t\t\t\treturn sel( idx, row._aData, row.nTr ) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Get nodes in the order from the `rows` array with null values removed\n\t\t\tvar nodes = _removeEmpty(\n\t\t\t\t_pluck_order( settings.aoData, rows, 'nTr' )\n\t\t\t);\n\t\n\t\t\t// Selector - node\n\t\t\tif ( sel.nodeName ) {\n\t\t\t\tif ( sel._DT_RowIndex !== undefined ) {\n\t\t\t\t\treturn [ sel._DT_RowIndex ]; // Property added by DT for fast lookup\n\t\t\t\t}\n\t\t\t\telse if ( sel._DT_CellIndex ) {\n\t\t\t\t\treturn [ sel._DT_CellIndex.row ];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tvar host = $(sel).closest('*[data-dt-row]');\n\t\t\t\t\treturn host.length ?\n\t\t\t\t\t\t[ host.data('dt-row') ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// ID selector. Want to always be able to select rows by id, regardless\n\t\t\t// of if the tr element has been created or not, so can't rely upon\n\t\t\t// jQuery here - hence a custom implementation. This does not match\n\t\t\t// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,\n\t\t\t// but to select it using a CSS selector engine (like Sizzle or\n\t\t\t// querySelect) it would need to need to be escaped for some characters.\n\t\t\t// DataTables simplifies this for row selectors since you can select\n\t\t\t// only a row. A # indicates an id any anything that follows is the id -\n\t\t\t// unescaped.\n\t\t\tif ( typeof sel === 'string' && sel.charAt(0) === '#' ) {\n\t\t\t\t// get row index from id\n\t\t\t\tvar rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];\n\t\t\t\tif ( rowObj !== undefined ) {\n\t\t\t\t\treturn [ rowObj.idx ];\n\t\t\t\t}\n\t\n\t\t\t\t// need to fall through to jQuery in case there is DOM id that\n\t\t\t\t// matches\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery selector string, array of nodes or jQuery object/\n\t\t\t// As jQuery's .filter() allows jQuery objects to be passed in filter,\n\t\t\t// it also allows arrays, so this will cope with all three options\n\t\t\treturn $(nodes)\n\t\t\t\t.filter( sel )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn this._DT_RowIndex;\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\t};\n\t\n\t\treturn _selector_run( 'row', selector, run, settings, opts );\n\t};\n\t\n\t\n\t_api_register( 'rows()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __row_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in __row_selector?\n\t\tinst.selector.rows = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_register( 'rows().nodes()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn settings.aoData[ row ].nTr || undefined;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'rows().data()', function () {\n\t\treturn this.iterator( true, 'rows', function ( settings, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, '_aData' );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\tvar r = settings.aoData[ row ];\n\t\t\treturn type === 'search' ? r._aFilterData : r._aSortData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\t_fnInvalidate( settings, row, src );\n\t\t} );\n\t} );\n\t\n\t_api_registerPlural( 'rows().indexes()', 'row().index()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn row;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {\n\t\tvar a = [];\n\t\tvar context = this.context;\n\t\n\t\t// `iterator` will drop undefined values, but in this case we want them\n\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\tfor ( var j=0, jen=this[i].length ; j<jen ; j++ ) {\n\t\t\t\tvar id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );\n\t\t\t\ta.push( (hash === true ? '#' : '' )+ id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn new _Api( context, a );\n\t} );\n\t\n\t_api_registerPlural( 'rows().remove()', 'row().remove()', function () {\n\t\tvar that = this;\n\t\n\t\tthis.iterator( 'row', function ( settings, row, thatIdx ) {\n\t\t\tvar data = settings.aoData;\n\t\t\tvar rowData = data[ row ];\n\t\t\tvar i, ien, j, jen;\n\t\t\tvar loopRow, loopCells;\n\t\n\t\t\tdata.splice( row, 1 );\n\t\n\t\t\t// Update the cached indexes\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\tloopRow = data[i];\n\t\t\t\tloopCells = loopRow.anCells;\n\t\n\t\t\t\t// Rows\n\t\t\t\tif ( loopRow.nTr !== null ) {\n\t\t\t\t\tloopRow.nTr._DT_RowIndex = i;\n\t\t\t\t}\n\t\n\t\t\t\t// Cells\n\t\t\t\tif ( loopCells !== null ) {\n\t\t\t\t\tfor ( j=0, jen=loopCells.length ; j<jen ; j++ ) {\n\t\t\t\t\t\tloopCells[j]._DT_CellIndex.row = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Delete from the display arrays\n\t\t\t_fnDeleteIndex( settings.aiDisplayMaster, row );\n\t\t\t_fnDeleteIndex( settings.aiDisplay, row );\n\t\t\t_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes\n\t\n\t\t\t// Check for an 'overflow' they case for displaying the table\n\t\t\t_fnLengthOverflow( settings );\n\t\n\t\t\t// Remove the row's ID reference if there is one\n\t\t\tvar id = settings.rowIdFn( rowData._aData );\n\t\t\tif ( id !== undefined ) {\n\t\t\t\tdelete settings.aIds[ id ];\n\t\t\t}\n\t\t} );\n\t\n\t\tthis.iterator( 'table', function ( settings ) {\n\t\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tsettings.aoData[i].idx = i;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'rows.add()', function ( rows ) {\n\t\tvar newRows = this.iterator( 'table', function ( settings ) {\n\t\t\t\tvar row, i, ien;\n\t\t\t\tvar out = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\t\t\tout.push( _fnAddTr( settings, row )[0] );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tout.push( _fnAddData( settings, row ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn out;\n\t\t\t}, 1 );\n\t\n\t\t// Return an Api.rows() extended instance, so rows().nodes() etc can be used\n\t\tvar modRows = this.rows( -1 );\n\t\tmodRows.pop();\n\t\t$.merge( modRows, newRows );\n\t\n\t\treturn modRows;\n\t} );\n\t\n\t\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( 'row()', function ( selector, opts ) {\n\t\treturn _selector_first( this.rows( selector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'row().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._aData :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\tctx[0].aoData[ this[0] ]._aData = data;\n\t\n\t\t// Automatically invalidate\n\t\t_fnInvalidate( ctx[0], this[0], 'data' );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'row().node()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\treturn ctx.length && this.length ?\n\t\t\tctx[0].aoData[ this[0] ].nTr || null :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'row.add()', function ( row ) {\n\t\t// Allow a jQuery object to be passed in - only a single row is added from\n\t\t// it though - the first element in the set\n\t\tif ( row instanceof $ && row.length ) {\n\t\t\trow = row[0];\n\t\t}\n\t\n\t\tvar rows = this.iterator( 'table', function ( settings ) {\n\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\treturn _fnAddTr( settings, row )[0];\n\t\t\t}\n\t\t\treturn _fnAddData( settings, row );\n\t\t} );\n\t\n\t\t// Return an Api.rows() extended instance, with the newly added row selected\n\t\treturn this.row( rows[0] );\n\t} );\n\t\n\t\n\t\n\tvar __details_add = function ( ctx, row, data, klass )\n\t{\n\t\t// Convert to array of TR elements\n\t\tvar rows = [];\n\t\tvar addRow = function ( r, k ) {\n\t\t\t// Recursion to allow for arrays of jQuery objects\n\t\t\tif ( $.isArray( r ) || r instanceof $ ) {\n\t\t\t\tfor ( var i=0, ien=r.length ; i<ien ; i++ ) {\n\t\t\t\t\taddRow( r[i], k );\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If we get a TR element, then just add it directly - up to the dev\n\t\t\t// to add the correct number of columns etc\n\t\t\tif ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {\n\t\t\t\trows.push( r );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Otherwise create a row with a wrapper\n\t\t\t\tvar created = $('<tr><td/></tr>').addClass( k );\n\t\t\t\t$('td', created)\n\t\t\t\t\t.addClass( k )\n\t\t\t\t\t.html( r )\n\t\t\t\t\t[0].colSpan = _fnVisbleColumns( ctx );\n\t\n\t\t\t\trows.push( created[0] );\n\t\t\t}\n\t\t};\n\t\n\t\taddRow( data, klass );\n\t\n\t\tif ( row._details ) {\n\t\t\trow._details.detach();\n\t\t}\n\t\n\t\trow._details = $(rows);\n\t\n\t\t// If the children were already shown, that state should be retained\n\t\tif ( row._detailsShow ) {\n\t\t\trow._details.insertAfter( row.nTr );\n\t\t}\n\t};\n\t\n\t\n\tvar __details_remove = function ( api, idx )\n\t{\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length ) {\n\t\t\tvar row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];\n\t\n\t\t\tif ( row && row._details ) {\n\t\t\t\trow._details.remove();\n\t\n\t\t\t\trow._detailsShow = undefined;\n\t\t\t\trow._details = undefined;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_display = function ( api, show ) {\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length && api.length ) {\n\t\t\tvar row = ctx[0].aoData[ api[0] ];\n\t\n\t\t\tif ( row._details ) {\n\t\t\t\trow._detailsShow = show;\n\t\n\t\t\t\tif ( show ) {\n\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\trow._details.detach();\n\t\t\t\t}\n\t\n\t\t\t\t__details_events( ctx[0] );\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_events = function ( settings )\n\t{\n\t\tvar api = new _Api( settings );\n\t\tvar namespace = '.dt.DT_details';\n\t\tvar drawEvent = 'draw'+namespace;\n\t\tvar colvisEvent = 'column-visibility'+namespace;\n\t\tvar destroyEvent = 'destroy'+namespace;\n\t\tvar data = settings.aoData;\n\t\n\t\tapi.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );\n\t\n\t\tif ( _pluck( data, '_details' ).length > 0 ) {\n\t\t\t// On each draw, insert the required elements into the document\n\t\t\tapi.on( drawEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tapi.rows( {page:'current'} ).eq(0).each( function (idx) {\n\t\t\t\t\t// Internal data grab\n\t\t\t\t\tvar row = data[ idx ];\n\t\n\t\t\t\t\tif ( row._detailsShow ) {\n\t\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\n\t\t\t// Column visibility change - update the colspan\n\t\t\tapi.on( colvisEvent, function ( e, ctx, idx, vis ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t// Update the colspan for the details rows (note, only if it already has\n\t\t\t\t// a colspan)\n\t\t\t\tvar row, visible = _fnVisbleColumns( ctx );\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = data[i];\n\t\n\t\t\t\t\tif ( row._details ) {\n\t\t\t\t\t\trow._details.children('td[colspan]').attr('colspan', visible );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\t// Table destroyed - nuke any child rows\n\t\t\tapi.on( destroyEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( data[i]._details ) {\n\t\t\t\t\t\t__details_remove( api, i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t// Strings for the method names to help minification\n\tvar _emp = '';\n\tvar _child_obj = _emp+'row().child';\n\tvar _child_mth = _child_obj+'()';\n\t\n\t// data can be:\n\t//  tr\n\t//  string\n\t//  jQuery or array of any of the above\n\t_api_register( _child_mth, function ( data, klass ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._details :\n\t\t\t\tundefined;\n\t\t}\n\t\telse if ( data === true ) {\n\t\t\t// show\n\t\t\tthis.child.show();\n\t\t}\n\t\telse if ( data === false ) {\n\t\t\t// remove\n\t\t\t__details_remove( this );\n\t\t}\n\t\telse if ( ctx.length && this.length ) {\n\t\t\t// set\n\t\t\t__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );\n\t\t}\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.show()',\n\t\t_child_mth+'.show()' // only when `child()` was called with parameters (without\n\t], function ( show ) {   // it returns an object and this method is not executed)\n\t\t__details_display( this, true );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.hide()',\n\t\t_child_mth+'.hide()' // only when `child()` was called with parameters (without\n\t], function () {         // it returns an object and this method is not executed)\n\t\t__details_display( this, false );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.remove()',\n\t\t_child_mth+'.remove()' // only when `child()` was called with parameters (without\n\t], function () {           // it returns an object and this method is not executed)\n\t\t__details_remove( this );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( _child_obj+'.isShown()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length && this.length ) {\n\t\t\t// _detailsShown as false or undefined will fall through to return false\n\t\t\treturn ctx[0].aoData[ this[0] ]._detailsShow || false;\n\t\t}\n\t\treturn false;\n\t} );\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Columns\n\t *\n\t * {integer}           - column index (>=0 count from left, <0 count from right)\n\t * \"{integer}:visIdx\"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)\n\t * \"{integer}:visible\" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)\n\t * \"{string}:name\"     - column name\n\t * \"{string}\"          - jQuery selector on column header nodes\n\t *\n\t */\n\t\n\t// can be an array of these items, comma separated list, or an array of comma\n\t// separated lists\n\t\n\tvar __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;\n\t\n\t\n\t// r1 and r2 are redundant - but it means that the parameters match for the\n\t// iterator callback in columns().data()\n\tvar __columnData = function ( settings, column, r1, r2, rows ) {\n\t\tvar a = [];\n\t\tfor ( var row=0, ien=rows.length ; row<ien ; row++ ) {\n\t\t\ta.push( _fnGetCellData( settings, rows[row], column ) );\n\t\t}\n\t\treturn a;\n\t};\n\t\n\t\n\tvar __column_selector = function ( settings, selector, opts )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tnames = _pluck( columns, 'sName' ),\n\t\t\tnodes = _pluck( columns, 'nTh' );\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar selInt = _intVal( s );\n\t\n\t\t\t// Selector - all\n\t\t\tif ( s === '' ) {\n\t\t\t\treturn _range( columns.length );\n\t\t\t}\n\t\n\t\t\t// Selector - index\n\t\t\tif ( selInt !== null ) {\n\t\t\t\treturn [ selInt >= 0 ?\n\t\t\t\t\tselInt : // Count from left\n\t\t\t\t\tcolumns.length + selInt // Count from right (+ because its a negative value)\n\t\t\t\t];\n\t\t\t}\n\t\n\t\t\t// Selector = function\n\t\t\tif ( typeof s === 'function' ) {\n\t\t\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\n\t\t\t\treturn $.map( columns, function (col, idx) {\n\t\t\t\t\treturn s(\n\t\t\t\t\t\t\tidx,\n\t\t\t\t\t\t\t__columnData( settings, idx, 0, 0, rows ),\n\t\t\t\t\t\t\tnodes[ idx ]\n\t\t\t\t\t\t) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// jQuery or string selector\n\t\t\tvar match = typeof s === 'string' ?\n\t\t\t\ts.match( __re_column_selector ) :\n\t\t\t\t'';\n\t\n\t\t\tif ( match ) {\n\t\t\t\tswitch( match[2] ) {\n\t\t\t\t\tcase 'visIdx':\n\t\t\t\t\tcase 'visible':\n\t\t\t\t\t\tvar idx = parseInt( match[1], 10 );\n\t\t\t\t\t\t// Visible index given, convert to column index\n\t\t\t\t\t\tif ( idx < 0 ) {\n\t\t\t\t\t\t\t// Counting from the right\n\t\t\t\t\t\t\tvar visColumns = $.map( columns, function (col,i) {\n\t\t\t\t\t\t\t\treturn col.bVisible ? i : null;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\treturn [ visColumns[ visColumns.length + idx ] ];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Counting from the left\n\t\t\t\t\t\treturn [ _fnVisibleToColumnIndex( settings, idx ) ];\n\t\n\t\t\t\t\tcase 'name':\n\t\t\t\t\t\t// match by name. `names` is column index complete and in order\n\t\t\t\t\t\treturn $.map( names, function (name, i) {\n\t\t\t\t\t\t\treturn name === match[1] ? i : null;\n\t\t\t\t\t\t} );\n\t\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Cell in the table body\n\t\t\tif ( s.nodeName && s._DT_CellIndex ) {\n\t\t\t\treturn [ s._DT_CellIndex.column ];\n\t\t\t}\n\t\n\t\t\t// jQuery selector on the TH elements for the columns\n\t\t\tvar jqResult = $( nodes )\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn $.inArray( this, nodes ); // `nodes` is column index complete and in order\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise a node which might have a `dt-column` data attribute, or be\n\t\t\t// a child or such an element\n\t\t\tvar host = $(s).closest('*[data-dt-column]');\n\t\t\treturn host.length ?\n\t\t\t\t[ host.data('dt-column') ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'column', selector, run, settings, opts );\n\t};\n\t\n\t\n\tvar __setColumnVis = function ( settings, column, vis ) {\n\t\tvar\n\t\t\tcols = settings.aoColumns,\n\t\t\tcol  = cols[ column ],\n\t\t\tdata = settings.aoData,\n\t\t\trow, cells, i, ien, tr;\n\t\n\t\t// Get\n\t\tif ( vis === undefined ) {\n\t\t\treturn col.bVisible;\n\t\t}\n\t\n\t\t// Set\n\t\t// No change\n\t\tif ( col.bVisible === vis ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( vis ) {\n\t\t\t// Insert column\n\t\t\t// Need to decide if we should use appendChild or insertBefore\n\t\t\tvar insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );\n\t\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\ttr = data[i].nTr;\n\t\t\t\tcells = data[i].anCells;\n\t\n\t\t\t\tif ( tr ) {\n\t\t\t\t\t// insertBefore can act like appendChild if 2nd arg is null\n\t\t\t\t\ttr.insertBefore( cells[ column ], cells[ insertBefore ] || null );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Remove column\n\t\t\t$( _pluck( settings.aoData, 'anCells', column ) ).detach();\n\t\t}\n\t\n\t\t// Common actions\n\t\tcol.bVisible = vis;\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t_fnSaveState( settings );\n\t};\n\t\n\t\n\t_api_register( 'columns()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __column_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in _row_selector?\n\t\tinst.selector.cols = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTh;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTf;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().data()', 'column().data()', function () {\n\t\treturn this.iterator( 'column-rows', __columnData, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].mData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows,\n\t\t\t\ttype === 'search' ? '_aFilterData' : '_aSortData', column\n\t\t\t);\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, 'anCells', column ) ;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {\n\t\tvar ret = this.iterator( 'column', function ( settings, column ) {\n\t\t\tif ( vis === undefined ) {\n\t\t\t\treturn settings.aoColumns[ column ].bVisible;\n\t\t\t} // else\n\t\t\t__setColumnVis( settings, column, vis );\n\t\t} );\n\t\n\t\t// Group the column visibility changes\n\t\tif ( vis !== undefined ) {\n\t\t\t// Second loop once the first is done for events\n\t\t\tthis.iterator( 'column', function ( settings, column ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );\n\t\t\t} );\n\t\n\t\t\tif ( calc === undefined || calc ) {\n\t\t\t\tthis.columns.adjust();\n\t\t\t}\n\t\t}\n\t\n\t\treturn ret;\n\t} );\n\t\n\t_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn type === 'visible' ?\n\t\t\t\t_fnColumnIndexToVisible( settings, column ) :\n\t\t\t\tcolumn;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'columns.adjust()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'column.index()', function ( type, idx ) {\n\t\tif ( this.context.length !== 0 ) {\n\t\t\tvar ctx = this.context[0];\n\t\n\t\t\tif ( type === 'fromVisible' || type === 'toData' ) {\n\t\t\t\treturn _fnVisibleToColumnIndex( ctx, idx );\n\t\t\t}\n\t\t\telse if ( type === 'fromData' || type === 'toVisible' ) {\n\t\t\t\treturn _fnColumnIndexToVisible( ctx, idx );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t_api_register( 'column()', function ( selector, opts ) {\n\t\treturn _selector_first( this.columns( selector, opts ) );\n\t} );\n\t\n\t\n\t\n\tvar __cell_selector = function ( settings, selector, opts )\n\t{\n\t\tvar data = settings.aoData;\n\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\tvar cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );\n\t\tvar allCells = $( [].concat.apply([], cells) );\n\t\tvar row;\n\t\tvar columns = settings.aoColumns.length;\n\t\tvar a, i, ien, j, o, host;\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar fnSelector = typeof s === 'function';\n\t\n\t\t\tif ( s === null || s === undefined || fnSelector ) {\n\t\t\t\t// All cells and function selectors\n\t\t\t\ta = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tfor ( j=0 ; j<columns ; j++ ) {\n\t\t\t\t\t\to = {\n\t\t\t\t\t\t\trow: row,\n\t\t\t\t\t\t\tcolumn: j\n\t\t\t\t\t\t};\n\t\n\t\t\t\t\t\tif ( fnSelector ) {\n\t\t\t\t\t\t\t// Selector - function\n\t\t\t\t\t\t\thost = data[ row ];\n\t\n\t\t\t\t\t\t\tif ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {\n\t\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Selector - all\n\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn a;\n\t\t\t}\n\t\t\t\n\t\t\t// Selector - index\n\t\t\tif ( $.isPlainObject( s ) ) {\n\t\t\t\treturn [s];\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery filtered cells\n\t\t\tvar jqResult = allCells\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function (i, el) {\n\t\t\t\t\treturn { // use a new object, in case someone changes the values\n\t\t\t\t\t\trow:    el._DT_CellIndex.row,\n\t\t\t\t\t\tcolumn: el._DT_CellIndex.column\n\t \t\t\t\t};\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise the selector is a node, and there is one last option - the\n\t\t\t// element might be a child of an element which has dt-row and dt-column\n\t\t\t// data attributes\n\t\t\thost = $(s).closest('*[data-dt-row]');\n\t\t\treturn host.length ?\n\t\t\t\t[ {\n\t\t\t\t\trow: host.data('dt-row'),\n\t\t\t\t\tcolumn: host.data('dt-column')\n\t\t\t\t} ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'cell', selector, run, settings, opts );\n\t};\n\t\n\t\n\t\n\t\n\t_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {\n\t\t// Argument shifting\n\t\tif ( $.isPlainObject( rowSelector ) ) {\n\t\t\t// Indexes\n\t\t\tif ( rowSelector.row === undefined ) {\n\t\t\t\t// Selector options in first parameter\n\t\t\t\topts = rowSelector;\n\t\t\t\trowSelector = null;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Cell index objects in first parameter\n\t\t\t\topts = columnSelector;\n\t\t\t\tcolumnSelector = null;\n\t\t\t}\n\t\t}\n\t\tif ( $.isPlainObject( columnSelector ) ) {\n\t\t\topts = columnSelector;\n\t\t\tcolumnSelector = null;\n\t\t}\n\t\n\t\t// Cell selector\n\t\tif ( columnSelector === null || columnSelector === undefined ) {\n\t\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t\treturn __cell_selector( settings, rowSelector, _selector_opts( opts ) );\n\t\t\t} );\n\t\t}\n\t\n\t\t// Row + column selector\n\t\tvar columns = this.columns( columnSelector, opts );\n\t\tvar rows = this.rows( rowSelector, opts );\n\t\tvar a, i, ien, j, jen;\n\t\n\t\tvar cells = this.iterator( 'table', function ( settings, idx ) {\n\t\t\ta = [];\n\t\n\t\t\tfor ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {\n\t\t\t\tfor ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {\n\t\t\t\t\ta.push( {\n\t\t\t\t\t\trow:    rows[idx][i],\n\t\t\t\t\t\tcolumn: columns[idx][j]\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn a;\n\t\t}, 1 );\n\t\n\t\t$.extend( cells.selector, {\n\t\t\tcols: columnSelector,\n\t\t\trows: rowSelector,\n\t\t\topts: opts\n\t\t} );\n\t\n\t\treturn cells;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\tvar data = settings.aoData[ row ];\n\t\n\t\t\treturn data && data.anCells ?\n\t\t\t\tdata.anCells[ column ] :\n\t\t\t\tundefined;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_register( 'cells().data()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {\n\t\ttype = type === 'search' ? '_aFilterData' : '_aSortData';\n\t\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn settings.aoData[ row ][ type ][ column ];\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column, type );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn {\n\t\t\t\trow: row,\n\t\t\t\tcolumn: column,\n\t\t\t\tcolumnVisible: _fnColumnIndexToVisible( settings, column )\n\t\t\t};\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\t_fnInvalidate( settings, row, src, column );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {\n\t\treturn _selector_first( this.cells( rowSelector, columnSelector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'cell().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\tvar cell = this[0];\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && cell.length ?\n\t\t\t\t_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\t_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );\n\t\t_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get current ordering (sorting) that has been applied to the table.\n\t *\n\t * @returns {array} 2D array containing the sorting information for the first\n\t *   table in the current context. Each element in the parent array represents\n\t *   a column being sorted upon (i.e. multi-sorting with two columns would have\n\t *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is\n\t *   the column index that the sorting condition applies to, the second is the\n\t *   direction of the sort (`desc` or `asc`) and, optionally, the third is the\n\t *   index of the sorting order from the `column.sorting` initialisation array.\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {integer} order Column index to sort upon.\n\t * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 1D array of sorting information to be applied.\n\t * @param {array} [...] Optional additional sorting conditions\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 2D array of sorting information to be applied.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order()', function ( order, dir ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( order === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].aaSorting :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\tif ( typeof order === 'number' ) {\n\t\t\t// Simple column / direction passed in\n\t\t\torder = [ [ order, dir ] ];\n\t\t}\n\t\telse if ( order.length && ! $.isArray( order[0] ) ) {\n\t\t\t// Arguments passed in (list of 1D arrays)\n\t\t\torder = Array.prototype.slice.call( arguments );\n\t\t}\n\t\t// otherwise a 2D array was passed in\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSorting = order.slice();\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Attach a sort listener to an element for a given column\n\t *\n\t * @param {node|jQuery|string} node Identifier for the element(s) to attach the\n\t *   listener to. This can take the form of a single DOM node, a jQuery\n\t *   collection of nodes or a jQuery selector which will identify the node(s).\n\t * @param {integer} column the column that a click on this node will sort on\n\t * @param {function} [callback] callback function when sort is run\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order.listener()', function ( node, column, callback ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSortAttachListener( settings, node, column, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'order.fixed()', function ( set ) {\n\t\tif ( ! set ) {\n\t\t\tvar ctx = this.context;\n\t\t\tvar fixed = ctx.length ?\n\t\t\t\tctx[0].aaSortingFixed :\n\t\t\t\tundefined;\n\t\n\t\t\treturn $.isArray( fixed ) ?\n\t\t\t\t{ pre: fixed } :\n\t\t\t\tfixed;\n\t\t}\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSortingFixed = $.extend( true, {}, set );\n\t\t} );\n\t} );\n\t\n\t\n\t// Order by the selected column(s)\n\t_api_register( [\n\t\t'columns().order()',\n\t\t'column().order()'\n\t], function ( dir ) {\n\t\tvar that = this;\n\t\n\t\treturn this.iterator( 'table', function ( settings, i ) {\n\t\t\tvar sort = [];\n\t\n\t\t\t$.each( that[i], function (j, col) {\n\t\t\t\tsort.push( [ col, dir ] );\n\t\t\t} );\n\t\n\t\t\tsettings.aaSorting = sort;\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'search()', function ( input, regex, smart, caseInsen ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( input === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].oPreviousSearch.sSearch :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {\n\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t} ), 1 );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural(\n\t\t'columns().search()',\n\t\t'column().search()',\n\t\tfunction ( input, regex, smart, caseInsen ) {\n\t\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\t\tvar preSearch = settings.aoPreSearchCols;\n\t\n\t\t\t\tif ( input === undefined ) {\n\t\t\t\t\t// get\n\t\t\t\t\treturn preSearch[ column ].sSearch;\n\t\t\t\t}\n\t\n\t\t\t\t// set\n\t\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t$.extend( preSearch[ column ], {\n\t\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t\t} );\n\t\n\t\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch, 1 );\n\t\t\t} );\n\t\t}\n\t);\n\t\n\t/*\n\t * State API methods\n\t */\n\t\n\t_api_register( 'state()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oSavedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t// Save an empty object\n\t\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, {} );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'state.loaded()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oLoadedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.save()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSaveState( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Provide a common method for plug-ins to check the version of DataTables being\n\t * used, in order to ensure compatibility.\n\t *\n\t *  @param {string} version Version string to check for, in the format \"X.Y.Z\".\n\t *    Note that the formats \"X\" and \"X.Y\" are also acceptable.\n\t *  @returns {boolean} true if this version of DataTables is greater or equal to\n\t *    the required version, or false if this version of DataTales is not\n\t *    suitable\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );\n\t */\n\tDataTable.versionCheck = DataTable.fnVersionCheck = function( version )\n\t{\n\t\tvar aThis = DataTable.version.split('.');\n\t\tvar aThat = version.split('.');\n\t\tvar iThis, iThat;\n\t\n\t\tfor ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {\n\t\t\tiThis = parseInt( aThis[i], 10 ) || 0;\n\t\t\tiThat = parseInt( aThat[i], 10 ) || 0;\n\t\n\t\t\t// Parts are the same, keep comparing\n\t\t\tif (iThis === iThat) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\t// Parts are different, return immediately\n\t\t\treturn iThis > iThat;\n\t\t}\n\t\n\t\treturn true;\n\t};\n\t\n\t\n\t/**\n\t * Check if a `<table>` node is a DataTable table already or not.\n\t *\n\t *  @param {node|jquery|string} table Table node, jQuery object or jQuery\n\t *      selector for the table to test. Note that if more than more than one\n\t *      table is passed on, only the first will be checked\n\t *  @returns {boolean} true the table given is a DataTable, or false otherwise\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {\n\t *      $('#example').dataTable();\n\t *    }\n\t */\n\tDataTable.isDataTable = DataTable.fnIsDataTable = function ( table )\n\t{\n\t\tvar t = $(table).get(0);\n\t\tvar is = false;\n\t\n\t\tif ( table instanceof DataTable.Api ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\t$.each( DataTable.settings, function (i, o) {\n\t\t\tvar head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;\n\t\t\tvar foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;\n\t\n\t\t\tif ( o.nTable === t || head === t || foot === t ) {\n\t\t\t\tis = true;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn is;\n\t};\n\t\n\t\n\t/**\n\t * Get all DataTable tables that have been initialised - optionally you can\n\t * select to get only currently visible tables.\n\t *\n\t *  @param {boolean} [visible=false] Flag to indicate if you want all (default)\n\t *    or visible tables only.\n\t *  @returns {array} Array of `table` nodes (not DataTable instances) which are\n\t *    DataTables\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    $.each( $.fn.dataTable.tables(true), function () {\n\t *      $(table).DataTable().columns.adjust();\n\t *    } );\n\t */\n\tDataTable.tables = DataTable.fnTables = function ( visible )\n\t{\n\t\tvar api = false;\n\t\n\t\tif ( $.isPlainObject( visible ) ) {\n\t\t\tapi = visible.api;\n\t\t\tvisible = visible.visible;\n\t\t}\n\t\n\t\tvar a = $.map( DataTable.settings, function (o) {\n\t\t\tif ( !visible || (visible && $(o.nTable).is(':visible')) ) {\n\t\t\t\treturn o.nTable;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn api ?\n\t\t\tnew _Api( a ) :\n\t\t\ta;\n\t};\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian notation. This is made public\n\t * for the extensions to provide the same ability as DataTables core to accept\n\t * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase\n\t * parameters.\n\t *\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t */\n\tDataTable.camelToHungarian = _fnCamelToHungarian;\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( '$()', function ( selector, opts ) {\n\t\tvar\n\t\t\trows   = this.rows( opts ).nodes(), // Get all rows\n\t\t\tjqRows = $(rows);\n\t\n\t\treturn $( [].concat(\n\t\t\tjqRows.filter( selector ).toArray(),\n\t\t\tjqRows.find( selector ).toArray()\n\t\t) );\n\t} );\n\t\n\t\n\t// jQuery functions to operate on the tables\n\t$.each( [ 'on', 'one', 'off' ], function (i, key) {\n\t\t_api_register( key+'()', function ( /* event, handler */ ) {\n\t\t\tvar args = Array.prototype.slice.call(arguments);\n\t\n\t\t\t// Add the `dt` namespace automatically if it isn't already present\n\t\t\targs[0] = $.map( args[0].split( /\\s/ ), function ( e ) {\n\t\t\t\treturn ! e.match(/\\.dt\\b/) ?\n\t\t\t\t\te+'.dt' :\n\t\t\t\t\te;\n\t\t\t\t} ).join( ' ' );\n\t\n\t\t\tvar inst = $( this.tables().nodes() );\n\t\t\tinst[key].apply( inst, args );\n\t\t\treturn this;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnClearTable( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'settings()', function () {\n\t\treturn new _Api( this.context, this.context );\n\t} );\n\t\n\t\n\t_api_register( 'init()', function () {\n\t\tvar ctx = this.context;\n\t\treturn ctx.length ? ctx[0].oInit : null;\n\t} );\n\t\n\t\n\t_api_register( 'data()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\treturn _pluck( settings.aoData, '_aData' );\n\t\t} ).flatten();\n\t} );\n\t\n\t\n\t_api_register( 'destroy()', function ( remove ) {\n\t\tremove = remove || false;\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tvar orig      = settings.nTableWrapper.parentNode;\n\t\t\tvar classes   = settings.oClasses;\n\t\t\tvar table     = settings.nTable;\n\t\t\tvar tbody     = settings.nTBody;\n\t\t\tvar thead     = settings.nTHead;\n\t\t\tvar tfoot     = settings.nTFoot;\n\t\t\tvar jqTable   = $(table);\n\t\t\tvar jqTbody   = $(tbody);\n\t\t\tvar jqWrapper = $(settings.nTableWrapper);\n\t\t\tvar rows      = $.map( settings.aoData, function (r) { return r.nTr; } );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Flag to note that the table is currently being destroyed - no action\n\t\t\t// should be taken\n\t\t\tsettings.bDestroying = true;\n\t\n\t\t\t// Fire off the destroy callbacks for plug-ins etc\n\t\t\t_fnCallbackFire( settings, \"aoDestroyCallback\", \"destroy\", [settings] );\n\t\n\t\t\t// If not being removed from the document, make all columns visible\n\t\t\tif ( ! remove ) {\n\t\t\t\tnew _Api( settings ).columns().visible( true );\n\t\t\t}\n\t\n\t\t\t// Blitz all `DT` namespaced events (these are internal events, the\n\t\t\t// lowercase, `dt` events are user subscribed and they are responsible\n\t\t\t// for removing them\n\t\t\tjqWrapper.off('.DT').find(':not(tbody *)').off('.DT');\n\t\t\t$(window).off('.DT-'+settings.sInstance);\n\t\n\t\t\t// When scrolling we had to break the table up - restore it\n\t\t\tif ( table != thead.parentNode ) {\n\t\t\t\tjqTable.children('thead').detach();\n\t\t\t\tjqTable.append( thead );\n\t\t\t}\n\t\n\t\t\tif ( tfoot && table != tfoot.parentNode ) {\n\t\t\t\tjqTable.children('tfoot').detach();\n\t\t\t\tjqTable.append( tfoot );\n\t\t\t}\n\t\n\t\t\tsettings.aaSorting = [];\n\t\t\tsettings.aaSortingFixed = [];\n\t\t\t_fnSortingClasses( settings );\n\t\n\t\t\t$( rows ).removeClass( settings.asStripeClasses.join(' ') );\n\t\n\t\t\t$('th, td', thead).removeClass( classes.sSortable+' '+\n\t\t\t\tclasses.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone\n\t\t\t);\n\t\n\t\t\tif ( settings.bJUI ) {\n\t\t\t\t$('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();\n\t\t\t\t$('th, td', thead).each( function () {\n\t\t\t\t\tvar wrapper = $('div.'+classes.sSortJUIWrapper, this);\n\t\t\t\t\t$(this).append( wrapper.contents() );\n\t\t\t\t\twrapper.detach();\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Add the TR elements back into the table in their original order\n\t\t\tjqTbody.children().detach();\n\t\t\tjqTbody.append( rows );\n\t\n\t\t\t// Remove the DataTables generated nodes, events and classes\n\t\t\tvar removedMethod = remove ? 'remove' : 'detach';\n\t\t\tjqTable[ removedMethod ]();\n\t\t\tjqWrapper[ removedMethod ]();\n\t\n\t\t\t// If we need to reattach the table to the document\n\t\t\tif ( ! remove && orig ) {\n\t\t\t\t// insertBefore acts like appendChild if !arg[1]\n\t\t\t\torig.insertBefore( table, settings.nTableReinsertBefore );\n\t\n\t\t\t\t// Restore the width of the original table - was read from the style property,\n\t\t\t\t// so we can restore directly to that\n\t\t\t\tjqTable\n\t\t\t\t\t.css( 'width', settings.sDestroyWidth )\n\t\t\t\t\t.removeClass( classes.sTable );\n\t\n\t\t\t\t// If the were originally stripe classes - then we add them back here.\n\t\t\t\t// Note this is not fool proof (for example if not all rows had stripe\n\t\t\t\t// classes - but it's a good effort without getting carried away\n\t\t\t\tien = settings.asDestroyStripes.length;\n\t\n\t\t\t\tif ( ien ) {\n\t\t\t\t\tjqTbody.children().each( function (i) {\n\t\t\t\t\t\t$(this).addClass( settings.asDestroyStripes[i % ien] );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Remove the settings object from the settings array */\n\t\t\tvar idx = $.inArray( settings, DataTable.settings );\n\t\t\tif ( idx !== -1 ) {\n\t\t\t\tDataTable.settings.splice( idx, 1 );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t// Add the `every()` method for rows, columns and cells in a compact form\n\t$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {\n\t\t_api_register( type+'s().every()', function ( fn ) {\n\t\t\tvar opts = this.selector.opts;\n\t\t\tvar api = this;\n\t\n\t\t\treturn this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {\n\t\t\t\t// Rows and columns:\n\t\t\t\t//  arg1 - index\n\t\t\t\t//  arg2 - table counter\n\t\t\t\t//  arg3 - loop counter\n\t\t\t\t//  arg4 - undefined\n\t\t\t\t// Cells:\n\t\t\t\t//  arg1 - row index\n\t\t\t\t//  arg2 - column index\n\t\t\t\t//  arg3 - table counter\n\t\t\t\t//  arg4 - loop counter\n\t\t\t\tfn.call(\n\t\t\t\t\tapi[ type ](\n\t\t\t\t\t\targ1,\n\t\t\t\t\t\ttype==='cell' ? arg2 : opts,\n\t\t\t\t\t\ttype==='cell' ? opts : undefined\n\t\t\t\t\t),\n\t\t\t\t\targ1, arg2, arg3, arg4\n\t\t\t\t);\n\t\t\t} );\n\t\t} );\n\t} );\n\t\n\t\n\t// i18n method for extensions to be able to use the language object from the\n\t// DataTable\n\t_api_register( 'i18n()', function ( token, def, plural ) {\n\t\tvar ctx = this.context[0];\n\t\tvar resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );\n\t\n\t\tif ( resolved === undefined ) {\n\t\t\tresolved = def;\n\t\t}\n\t\n\t\tif ( plural !== undefined && $.isPlainObject( resolved ) ) {\n\t\t\tresolved = resolved[ plural ] !== undefined ?\n\t\t\t\tresolved[ plural ] :\n\t\t\t\tresolved._;\n\t\t}\n\t\n\t\treturn resolved.replace( '%d', plural ); // nb: plural might be undefined,\n\t} );\n\n\t/**\n\t * Version string for plug-ins to check compatibility. Allowed format is\n\t * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used\n\t * only for non-release builds. See http://semver.org/ for more information.\n\t *  @member\n\t *  @type string\n\t *  @default Version number\n\t */\n\tDataTable.version = \"1.10.13\";\n\n\t/**\n\t * Private data store, containing all of the settings objects that are\n\t * created for the tables on a given page.\n\t *\n\t * Note that the `DataTable.settings` object is aliased to\n\t * `jQuery.fn.dataTableExt` through which it may be accessed and\n\t * manipulated, or `jQuery.fn.dataTable.settings`.\n\t *  @member\n\t *  @type array\n\t *  @default []\n\t *  @private\n\t */\n\tDataTable.settings = [];\n\n\t/**\n\t * Object models container, for the various models that DataTables has\n\t * available to it. These models define the objects that are used to hold\n\t * the active state and configuration of the table.\n\t *  @namespace\n\t */\n\tDataTable.models = {};\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * search information for the global filter and individual column filters.\n\t *  @namespace\n\t */\n\tDataTable.models.oSearch = {\n\t\t/**\n\t\t * Flag to indicate if the filtering should be case insensitive or not\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bCaseInsensitive\": true,\n\t\n\t\t/**\n\t\t * Applied search term\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sSearch\": \"\",\n\t\n\t\t/**\n\t\t * Flag to indicate if the search term should be interpreted as a\n\t\t * regular expression (true) or not (false) and therefore and special\n\t\t * regex characters escaped.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bRegex\": false,\n\t\n\t\t/**\n\t\t * Flag to indicate if DataTables is to use its smart filtering or not.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bSmart\": true\n\t};\n\t\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * each individual row. This is the object format used for the settings\n\t * aoData array.\n\t *  @namespace\n\t */\n\tDataTable.models.oRow = {\n\t\t/**\n\t\t * TR element for the row\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTr\": null,\n\t\n\t\t/**\n\t\t * Array of TD elements for each row. This is null until the row has been\n\t\t * created.\n\t\t *  @type array nodes\n\t\t *  @default []\n\t\t */\n\t\t\"anCells\": null,\n\t\n\t\t/**\n\t\t * Data object from the original data source for the row. This is either\n\t\t * an array if using the traditional form of DataTables, or an object if\n\t\t * using mData options. The exact type will depend on the passed in\n\t\t * data from the data source, or will be an array if using DOM a data\n\t\t * source.\n\t\t *  @type array|object\n\t\t *  @default []\n\t\t */\n\t\t\"_aData\": [],\n\t\n\t\t/**\n\t\t * Sorting data cache - this array is ostensibly the same length as the\n\t\t * number of columns (although each index is generated only as it is\n\t\t * needed), and holds the data that is used for sorting each column in the\n\t\t * row. We do this cache generation at the start of the sort in order that\n\t\t * the formatting of the sort data need be done only once for each cell\n\t\t * per sort. This array should not be read from or written to by anything\n\t\t * other than the master sorting methods.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aSortData\": null,\n\t\n\t\t/**\n\t\t * Per cell filtering data cache. As per the sort data cache, used to\n\t\t * increase the performance of the filtering in DataTables\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aFilterData\": null,\n\t\n\t\t/**\n\t\t * Filtering data cache. This is the same as the cell filtering cache, but\n\t\t * in this case a string rather than an array. This is easily computed with\n\t\t * a join on `_aFilterData`, but is provided as a cache so the join isn't\n\t\t * needed on every search (memory traded for performance)\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sFilterRow\": null,\n\t\n\t\t/**\n\t\t * Cache of the class name that DataTables has applied to the row, so we\n\t\t * can quickly look at this variable rather than needing to do a DOM check\n\t\t * on className for the nTr property.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *  @private\n\t\t */\n\t\t\"_sRowStripe\": \"\",\n\t\n\t\t/**\n\t\t * Denote if the original data source was from the DOM, or the data source\n\t\t * object. This is used for invalidating data, so DataTables can\n\t\t * automatically read data from the original source, unless uninstructed\n\t\t * otherwise.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"src\": null,\n\t\n\t\t/**\n\t\t * Index in the aoData array. This saves an indexOf lookup when we have the\n\t\t * object, but want to know the index\n\t\t *  @type integer\n\t\t *  @default -1\n\t\t *  @private\n\t\t */\n\t\t\"idx\": -1\n\t};\n\t\n\t\n\t/**\n\t * Template object for the column information object in DataTables. This object\n\t * is held in the settings aoColumns array and contains all the information that\n\t * DataTables needs about each individual column.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults.column}\n\t * but this one is the internal data store for DataTables's cache of columns.\n\t * It should NOT be manipulated outside of DataTables. Any configuration should\n\t * be done through the initialisation options.\n\t *  @namespace\n\t */\n\tDataTable.models.oColumn = {\n\t\t/**\n\t\t * Column index. This could be worked out on-the-fly with $.inArray, but it\n\t\t * is faster to just hold it as a variable\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"idx\": null,\n\t\n\t\t/**\n\t\t * A list of the columns that sorting should occur on when this column\n\t\t * is sorted. That this property is an array allows multi-column sorting\n\t\t * to be defined for a column (for example first name / last name columns\n\t\t * would benefit from this). The values are integers pointing to the\n\t\t * columns to be sorted on (typically it will be a single integer pointing\n\t\t * at itself, but that doesn't need to be the case).\n\t\t *  @type array\n\t\t */\n\t\t\"aDataSort\": null,\n\t\n\t\t/**\n\t\t * Define the sorting directions that are applied to the column, in sequence\n\t\t * as the column is repeatedly sorted upon - i.e. the first value is used\n\t\t * as the sorting direction when the column if first sorted (clicked on).\n\t\t * Sort it again (click again) and it will move on to the next index.\n\t\t * Repeat until loop.\n\t\t *  @type array\n\t\t */\n\t\t\"asSorting\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is searchable, and thus should be included\n\t\t * in the filtering or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSearchable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is sortable or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is currently visible in the table or not\n\t\t *  @type boolean\n\t\t */\n\t\t\"bVisible\": null,\n\t\n\t\t/**\n\t\t * Store for manual type assignment using the `column.type` option. This\n\t\t * is held in store so we can manipulate the column's `sType` property.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sManualType\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if HTML5 data attributes should be used as the data\n\t\t * source for filtering or sorting. True is either are.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @private\n\t\t */\n\t\t\"_bAttrSrc\": false,\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} nTd The TD node that has been created\n\t\t *  @param {*} sData The Data for the cell\n\t\t *  @param {array|object} oData The data for the whole row\n\t\t *  @param {int} iRow The row index for the aoData data store\n\t\t *  @default null\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\t/**\n\t\t * Function to get data from a cell in a column. You should <b>never</b>\n\t\t * access data directly through _aData internally in DataTables - always use\n\t\t * the method attached to this property. It allows mData to function as\n\t\t * required. This function is automatically assigned by the column\n\t\t * initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {string} sSpecific The specific data type you want to get -\n\t\t *    'display', 'type' 'filter' 'sort'\n\t\t *  @returns {*} The data for the cell from the given row's data\n\t\t *  @default null\n\t\t */\n\t\t\"fnGetData\": null,\n\t\n\t\t/**\n\t\t * Function to set data for a cell in the column. You should <b>never</b>\n\t\t * set the data directly to _aData internally in DataTables - always use\n\t\t * this method. It allows mData to function as required. This function\n\t\t * is automatically assigned by the column initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {*} sValue Value to set\n\t\t *  @default null\n\t\t */\n\t\t\"fnSetData\": null,\n\t\n\t\t/**\n\t\t * Property to read the value for the cells in the column from the data\n\t\t * source array / object. If null, then the default content is used, if a\n\t\t * function is given then the return from the function is used.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\t/**\n\t\t * Partner property to mData which is used (only when defined) to get\n\t\t * the data - i.e. it is basically the same as mData, but without the\n\t\t * 'set' option, and also the data fed to it is the result from mData.\n\t\t * This is the rendering method to match the data method of mData.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\t/**\n\t\t * Unique header TH/TD element for this column - this is what the sorting\n\t\t * listener is attached to (if sorting is enabled.)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTh\": null,\n\t\n\t\t/**\n\t\t * Unique footer TH/TD element for this column (if there is one). Not used\n\t\t * in DataTables as such, but can be used for plug-ins to reference the\n\t\t * footer for each column.\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTf\": null,\n\t\n\t\t/**\n\t\t * The class to apply to all TD elements in the table's TBODY for the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sClass\": null,\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t *  @type string\n\t\t */\n\t\t\"sContentPadding\": null,\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because mData\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\t/**\n\t\t * Name for the column, allowing reference to the column by name as well as\n\t\t * by index (needs a lookup to work by name).\n\t\t *  @type string\n\t\t */\n\t\t\"sName\": null,\n\t\n\t\t/**\n\t\t * Custom sorting data type - defines which of the available plug-ins in\n\t\t * afnSortData the custom sorting will use - if any is defined.\n\t\t *  @type string\n\t\t *  @default std\n\t\t */\n\t\t\"sSortDataType\": 'std',\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClass\": null,\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column -\n\t\t * when jQuery UI theming is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClassJUI\": null,\n\t\n\t\t/**\n\t\t * Title of the column - what is seen in the TH element (nTh).\n\t\t *  @type string\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\t/**\n\t\t * Column sorting and filtering type\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\t/**\n\t\t * Width of the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidth\": null,\n\t\n\t\t/**\n\t\t * Width of the column when it was first \"encountered\"\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidthOrig\": null\n\t};\n\t\n\t\n\t/*\n\t * Developer note: The properties of the object below are given in Hungarian\n\t * notation, that was used as the interface for DataTables prior to v1.10, however\n\t * from v1.10 onwards the primary interface is camel case. In order to avoid\n\t * breaking backwards compatibility utterly with this change, the Hungarian\n\t * version is still, internally the primary interface, but is is not documented\n\t * - hence the @name tags in each doc comment. This allows a Javascript function\n\t * to create a map from Hungarian notation to camel case (going the other direction\n\t * would require each property to be listed, which would at around 3K to the size\n\t * of DataTables, while this method is about a 0.5K hit.\n\t *\n\t * Ultimately this does pave the way for Hungarian notation to be dropped\n\t * completely, but that is a massive amount of work and will break current\n\t * installs (therefore is on-hold until v2).\n\t */\n\t\n\t/**\n\t * Initialisation options that can be given to DataTables at initialisation\n\t * time.\n\t *  @namespace\n\t */\n\tDataTable.defaults = {\n\t\t/**\n\t\t * An array of data to use for the table, passed in at initialisation which\n\t\t * will be used in preference to any data which is already in the DOM. This is\n\t\t * particularly useful for constructing tables purely in Javascript, for\n\t\t * example with a custom Ajax call.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.data\n\t\t *\n\t\t *  @example\n\t\t *    // Using a 2D array data source\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],\n\t\t *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\" },\n\t\t *          { \"title\": \"Browser\" },\n\t\t *          { \"title\": \"Platform\" },\n\t\t *          { \"title\": \"Version\" },\n\t\t *          { \"title\": \"Grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using an array of objects as a data source (`data`)\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 4.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  4,\n\t\t *            \"grade\":    \"X\"\n\t\t *          },\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 5.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  5,\n\t\t *            \"grade\":    \"C\"\n\t\t *          }\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\",   \"data\": \"engine\" },\n\t\t *          { \"title\": \"Browser\",  \"data\": \"browser\" },\n\t\t *          { \"title\": \"Platform\", \"data\": \"platform\" },\n\t\t *          { \"title\": \"Version\",  \"data\": \"version\" },\n\t\t *          { \"title\": \"Grade\",    \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaData\": null,\n\t\n\t\n\t\t/**\n\t\t * If ordering is enabled, then DataTables will perform a first pass sort on\n\t\t * initialisation. You can define which column(s) the sort is performed\n\t\t * upon, and the sorting direction, with this variable. The `sorting` array\n\t\t * should contain an array for each column to be sorted initially containing\n\t\t * the column's index and a direction string ('asc' or 'desc').\n\t\t *  @type array\n\t\t *  @default [[0,'asc']]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.order\n\t\t *\n\t\t *  @example\n\t\t *    // Sort by 3rd column first, and then 4th column\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": [[2,'asc'], [3,'desc']]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *    // No initial sorting\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": []\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaSorting\": [[0,'asc']],\n\t\n\t\n\t\t/**\n\t\t * This parameter is basically identical to the `sorting` parameter, but\n\t\t * cannot be overridden by user interaction with the table. What this means\n\t\t * is that you could have a column (visible or hidden) which the sorting\n\t\t * will always be forced on first - any sorting after that (from the user)\n\t\t * will then be performed as required. This can be useful for grouping rows\n\t\t * together.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.orderFixed\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderFixed\": [[0,'asc']]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\n\t\t/**\n\t\t * DataTables can be instructed to load data to display in the table from a\n\t\t * Ajax source. This option defines how that Ajax call is made and where to.\n\t\t *\n\t\t * The `ajax` property has three different modes of operation, depending on\n\t\t * how it is defined. These are:\n\t\t *\n\t\t * * `string` - Set the URL from where the data should be loaded from.\n\t\t * * `object` - Define properties for `jQuery.ajax`.\n\t\t * * `function` - Custom data get function\n\t\t *\n\t\t * `string`\n\t\t * --------\n\t\t *\n\t\t * As a string, the `ajax` property simply defines the URL from which\n\t\t * DataTables will load data.\n\t\t *\n\t\t * `object`\n\t\t * --------\n\t\t *\n\t\t * As an object, the parameters in the object are passed to\n\t\t * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control\n\t\t * of the Ajax request. DataTables has a number of default parameters which\n\t\t * you can override using this option. Please refer to the jQuery\n\t\t * documentation for a full description of the options available, although\n\t\t * the following parameters provide additional options in DataTables or\n\t\t * require special consideration:\n\t\t *\n\t\t * * `data` - As with jQuery, `data` can be provided as an object, but it\n\t\t *   can also be used as a function to manipulate the data DataTables sends\n\t\t *   to the server. The function takes a single parameter, an object of\n\t\t *   parameters with the values that DataTables has readied for sending. An\n\t\t *   object may be returned which will be merged into the DataTables\n\t\t *   defaults, or you can add the items to the object that was passed in and\n\t\t *   not return anything from the function. This supersedes `fnServerParams`\n\t\t *   from DataTables 1.9-.\n\t\t *\n\t\t * * `dataSrc` - By default DataTables will look for the property `data` (or\n\t\t *   `aaData` for compatibility with DataTables 1.9-) when obtaining data\n\t\t *   from an Ajax source or for server-side processing - this parameter\n\t\t *   allows that property to be changed. You can use Javascript dotted\n\t\t *   object notation to get a data source for multiple levels of nesting, or\n\t\t *   it my be used as a function. As a function it takes a single parameter,\n\t\t *   the JSON returned from the server, which can be manipulated as\n\t\t *   required, with the returned value being that used by DataTables as the\n\t\t *   data source for the table. This supersedes `sAjaxDataProp` from\n\t\t *   DataTables 1.9-.\n\t\t *\n\t\t * * `success` - Should not be overridden it is used internally in\n\t\t *   DataTables. To manipulate / transform the data returned by the server\n\t\t *   use `ajax.dataSrc`, or use `ajax` as a function (see below).\n\t\t *\n\t\t * `function`\n\t\t * ----------\n\t\t *\n\t\t * As a function, making the Ajax call is left up to yourself allowing\n\t\t * complete control of the Ajax request. Indeed, if desired, a method other\n\t\t * than Ajax could be used to obtain the required data, such as Web storage\n\t\t * or an AIR database.\n\t\t *\n\t\t * The function is given four parameters and no return is required. The\n\t\t * parameters are:\n\t\t *\n\t\t * 1. _object_ - Data to send to the server\n\t\t * 2. _function_ - Callback function that must be executed when the required\n\t\t *    data has been obtained. That data should be passed into the callback\n\t\t *    as the only parameter\n\t\t * 3. _object_ - DataTables settings object for the table\n\t\t *\n\t\t * Note that this supersedes `fnServerData` from DataTables 1.9-.\n\t\t *\n\t\t *  @type string|object|function\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.ajax\n\t\t *  @since 1.10.0\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax.\n\t\t *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": \"data.json\"\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to change\n\t\t *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"tableData\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to read data\n\t\t *   // from a plain array rather than an array in an object\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Manipulate the data returned from the server - add a link to data\n\t\t *   // (note this can, should, be done using `render` for the column - this\n\t\t *   // is just a simple example of how the data can be manipulated).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": function ( json ) {\n\t\t *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {\n\t\t *           json[i][0] = '<a href=\"/message/'+json[i][0]+'>View message</a>';\n\t\t *         }\n\t\t *         return json;\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Add data to the request\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"data\": function ( d ) {\n\t\t *         return {\n\t\t *           \"extra_search\": $('#extra').val()\n\t\t *         };\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Send request as POST\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"type\": \"POST\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get the data from localStorage (could interface with a form for\n\t\t *   // adding, editing and removing rows).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": function (data, callback, settings) {\n\t\t *       callback(\n\t\t *         JSON.parse( localStorage.getItem('dataTablesData') )\n\t\t *       );\n\t\t *     }\n\t\t *   } );\n\t\t */\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to readily specify the entries in the length drop\n\t\t * down menu that DataTables shows when pagination is enabled. It can be\n\t\t * either a 1D array of options which will be used for both the displayed\n\t\t * option and the value, or a 2D array which will use the array in the first\n\t\t * position as the value, and the array in the second position as the\n\t\t * displayed options (useful for language strings such as 'All').\n\t\t *\n\t\t * Note that the `pageLength` property will be automatically set to the\n\t\t * first value given in this array, unless `pageLength` is also provided.\n\t\t *  @type array\n\t\t *  @default [ 10, 25, 50, 100 ]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.lengthMenu\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthMenu\": [[10, 25, 50, -1], [10, 25, 50, \"All\"]]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aLengthMenu\": [ 10, 25, 50, 100 ],\n\t\n\t\n\t\t/**\n\t\t * The `columns` option in the initialisation parameter allows you to define\n\t\t * details about the way individual columns behave. For a full list of\n\t\t * column options that can be set, please see\n\t\t * {@link DataTable.defaults.column}. Note that if you use `columns` to\n\t\t * define your columns, you must have an entry in the array for every single\n\t\t * column that you have in your table (these can be null if you don't which\n\t\t * to specify any options).\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.column\n\t\t */\n\t\t\"aoColumns\": null,\n\t\n\t\t/**\n\t\t * Very similar to `columns`, `columnDefs` allows you to target a specific\n\t\t * column, multiple columns, or all columns, using the `targets` property of\n\t\t * each object in the array. This allows great flexibility when creating\n\t\t * tables, as the `columnDefs` arrays can be of any length, targeting the\n\t\t * columns you specifically want. `columnDefs` may use any of the column\n\t\t * options available: {@link DataTable.defaults.column}, but it _must_\n\t\t * have `targets` defined in each object in the array. Values in the `targets`\n\t\t * array may be:\n\t\t *   <ul>\n\t\t *     <li>a string - class name will be matched on the TH for the column</li>\n\t\t *     <li>0 or a positive integer - column index counting from the left</li>\n\t\t *     <li>a negative integer - column index counting from the right</li>\n\t\t *     <li>the string \"_all\" - all columns (i.e. assign a default)</li>\n\t\t *   </ul>\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.columnDefs\n\t\t */\n\t\t\"aoColumnDefs\": null,\n\t\n\t\n\t\t/**\n\t\t * Basically the same as `search`, this parameter defines the individual column\n\t\t * filtering state at initialisation time. The array must be of the same size\n\t\t * as the number of columns, and each element be an object with the parameters\n\t\t * `search` and `escapeRegex` (the latter is optional). 'null' is also\n\t\t * accepted and the default will be used.\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.searchCols\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchCols\": [\n\t\t *          null,\n\t\t *          { \"search\": \"My filter\" },\n\t\t *          null,\n\t\t *          { \"search\": \"^[0-9]\", \"escapeRegex\": false }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aoSearchCols\": [],\n\t\n\t\n\t\t/**\n\t\t * An array of CSS classes that should be applied to displayed rows. This\n\t\t * array may be of any length, and DataTables will apply each class\n\t\t * sequentially, looping when required.\n\t\t *  @type array\n\t\t *  @default null <i>Will take the values determined by the `oClasses.stripe*`\n\t\t *    options</i>\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.stripeClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stripeClasses\": [ 'strip1', 'strip2', 'strip3' ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable automatic column width calculation. This can be disabled\n\t\t * as an optimisation (it takes some time to calculate the widths) if the\n\t\t * tables widths are passed in using `columns`.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.autoWidth\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"autoWidth\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bAutoWidth\": true,\n\t\n\t\n\t\t/**\n\t\t * Deferred rendering can provide DataTables with a huge speed boost when you\n\t\t * are using an Ajax or JS data source for the table. This option, when set to\n\t\t * true, will cause DataTables to defer the creation of the table elements for\n\t\t * each row until they are needed for a draw - saving a significant amount of\n\t\t * time.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.deferRender\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajax\": \"sources/arrays.txt\",\n\t\t *        \"deferRender\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDeferRender\": false,\n\t\n\t\n\t\t/**\n\t\t * Replace a DataTable which matches the given selector and replace it with\n\t\t * one which has the properties of the new initialisation object passed. If no\n\t\t * table matches the selector, then the new DataTable will be constructed as\n\t\t * per normal.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.destroy\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"srollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      // Some time later....\n\t\t *      $('#example').dataTable( {\n\t\t *        \"filter\": false,\n\t\t *        \"destroy\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDestroy\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering of data. Filtering in DataTables is \"smart\" in\n\t\t * that it allows the end user to input multiple words (space separated) and\n\t\t * will match a row containing those words, even if not in the order that was\n\t\t * specified (this allow matching across multiple columns). Note that if you\n\t\t * wish to use filtering in DataTables this must remain 'true' - to remove the\n\t\t * default filtering input box and retain filtering abilities, please use\n\t\t * {@link DataTable.defaults.dom}.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.searching\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searching\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bFilter\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the table information display. This shows information\n\t\t * about the data that is currently visible on the page, including information\n\t\t * about filtered data if that action is being performed.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.info\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"info\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bInfo\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some\n\t\t * slightly different and additional mark-up from what DataTables has\n\t\t * traditionally used).\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.jQueryUI\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"jQueryUI\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bJQueryUI\": false,\n\t\n\t\n\t\t/**\n\t\t * Allows the end user to select the size of a formatted page from a select\n\t\t * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.lengthChange\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthChange\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bLengthChange\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable pagination.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.paging\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"paging\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bPaginate\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of a 'processing' indicator when the table is\n\t\t * being processed (e.g. a sort). This is particularly useful for tables with\n\t\t * large amounts of data where it can take a noticeable amount of time to sort\n\t\t * the entries.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.processing\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"processing\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bProcessing\": false,\n\t\n\t\n\t\t/**\n\t\t * Retrieve the DataTables object for the given selector. Note that if the\n\t\t * table has already been initialised, this parameter will cause DataTables\n\t\t * to simply return the object that has already been set up - it will not take\n\t\t * account of any changes you might have made to the initialisation object\n\t\t * passed to DataTables (setting this parameter to true is an acknowledgement\n\t\t * that you understand this). `destroy` can be used to reinitialise a table if\n\t\t * you need.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.retrieve\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      initTable();\n\t\t *      tableActions();\n\t\t *    } );\n\t\t *\n\t\t *    function initTable ()\n\t\t *    {\n\t\t *      return $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false,\n\t\t *        \"retrieve\": true\n\t\t *      } );\n\t\t *    }\n\t\t *\n\t\t *    function tableActions ()\n\t\t *    {\n\t\t *      var table = initTable();\n\t\t *      // perform API operations with oTable\n\t\t *    }\n\t\t */\n\t\t\"bRetrieve\": false,\n\t\n\t\n\t\t/**\n\t\t * When vertical (y) scrolling is enabled, DataTables will force the height of\n\t\t * the table's viewport to the given height at all times (useful for layout).\n\t\t * However, this can look odd when filtering data down to a small data set,\n\t\t * and the footer is left \"floating\" further down. This parameter (when\n\t\t * enabled) will cause DataTables to collapse the table's viewport down when\n\t\t * the result set will fit within the given Y height.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollCollapse\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200\",\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bScrollCollapse\": false,\n\t\n\t\n\t\t/**\n\t\t * Configure DataTables to use server-side processing. Note that the\n\t\t * `ajax` parameter must also be given in order to give DataTables a\n\t\t * source to obtain the required data for each draw.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverSide\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"xhr.php\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bServerSide\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable sorting of columns. Sorting of individual columns can be\n\t\t * disabled by the `sortable` option for each column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.ordering\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ordering\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSort\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or display DataTables' ability to sort multiple columns at the\n\t\t * same time (activated by shift-click by the user).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderMulti\n\t\t *\n\t\t *  @example\n\t\t *    // Disable multiple column sorting ability\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderMulti\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortMulti\": true,\n\t\n\t\n\t\t/**\n\t\t * Allows control over whether DataTables should use the top (true) unique\n\t\t * cell that is found for a single column, or the bottom (false - default).\n\t\t * This is useful when using complex headers.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderCellsTop\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderCellsTop\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortCellsTop\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the addition of the classes `sorting\\_1`, `sorting\\_2` and\n\t\t * `sorting\\_3` to the columns which are currently being sorted on. This is\n\t\t * presented as a feature switch as it can increase processing time (while\n\t\t * classes are removed and added) so for large data sets you might want to\n\t\t * turn this off.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.orderClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderClasses\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortClasses\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable state saving. When enabled HTML5 `localStorage` will be\n\t\t * used to save table display information such as pagination information,\n\t\t * display length, filtering and sorting. As such when the end user reloads\n\t\t * the page the display display will match what thy had previously set up.\n\t\t *\n\t\t * Due to the use of `localStorage` the default state saving is not supported\n\t\t * in IE6 or 7. If state saving is required in those browsers, use\n\t\t * `stateSaveCallback` to provide a storage solution such as cookies.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.stateSave\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bStateSave\": false,\n\t\n\t\n\t\t/**\n\t\t * This function is called when a TR element is created (and all TD child\n\t\t * elements have been inserted), or registered if using a DOM source, allowing\n\t\t * manipulation of the TR element (adding classes etc).\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} dataIndex The index of this row in the internal aoData array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.createdRow\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"createdRow\": function( row, data, dataIndex ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" )\n\t\t *          {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedRow\": null,\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify any aspect you want about the created DOM.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.drawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"drawCallback\": function( settings ) {\n\t\t *          alert( 'DataTables has redrawn the table' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Identical to fnHeaderCallback() but for the table footer this function\n\t\t * allows you to modify the table footer on every 'draw' event.\n\t\t *  @type function\n\t\t *  @param {node} foot \"TR\" element for the footer\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.footerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"footerCallback\": function( tfoot, data, start, end, display ) {\n\t\t *          tfoot.getElementsByTagName('th')[0].innerHTML = \"Starting index is \"+start;\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnFooterCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * When rendering large numbers in the information element for the table\n\t\t * (i.e. \"Showing 1 to 10 of 57 entries\") DataTables will render large numbers\n\t\t * to have a comma separator for the 'thousands' units (e.g. 1 million is\n\t\t * rendered as \"1,000,000\") to help readability for the end user. This\n\t\t * function will override the default method DataTables uses.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {int} toFormat number to be formatted\n\t\t *  @returns {string} formatted string for DataTables to show the number\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.formatNumber\n\t\t *\n\t\t *  @example\n\t\t *    // Format a number using a single quote for the separator (note that\n\t\t *    // this can also be done with the language.thousands option)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"formatNumber\": function ( toFormat ) {\n\t\t *          return toFormat.toString().replace(\n\t\t *            /\\B(?=(\\d{3})+(?!\\d))/g, \"'\"\n\t\t *          );\n\t\t *        };\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnFormatNumber\": function ( toFormat ) {\n\t\t\treturn toFormat.toString().replace(\n\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g,\n\t\t\t\tthis.oLanguage.sThousands\n\t\t\t);\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify the header row. This can be used to calculate and\n\t\t * display useful information about the table.\n\t\t *  @type function\n\t\t *  @param {node} head \"TR\" element for the header\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.headerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"fheaderCallback\": function( head, data, start, end, display ) {\n\t\t *          head.getElementsByTagName('th')[0].innerHTML = \"Displaying \"+(end-start)+\" records\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnHeaderCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * The information element can be used to convey information about the current\n\t\t * state of the table. Although the internationalisation options presented by\n\t\t * DataTables are quite capable of dealing with most customisations, there may\n\t\t * be times where you wish to customise the string further. This callback\n\t\t * allows you to do exactly that.\n\t\t *  @type function\n\t\t *  @param {object} oSettings DataTables settings object\n\t\t *  @param {int} start Starting position in data for the draw\n\t\t *  @param {int} end End position in data for the draw\n\t\t *  @param {int} max Total number of rows in the table (regardless of\n\t\t *    filtering)\n\t\t *  @param {int} total Total number of rows in the data set, after filtering\n\t\t *  @param {string} pre The string that DataTables has formatted using it's\n\t\t *    own rules\n\t\t *  @returns {string} The string to be displayed in the information element.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.infoCallback\n\t\t *\n\t\t *  @example\n\t\t *    $('#example').dataTable( {\n\t\t *      \"infoCallback\": function( settings, start, end, max, total, pre ) {\n\t\t *        return start +\" to \"+ end;\n\t\t *      }\n\t\t *    } );\n\t\t */\n\t\t\"fnInfoCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Called when the table has been initialised. Normally DataTables will\n\t\t * initialise sequentially and there will be no need for this function,\n\t\t * however, this does not hold true when using external language information\n\t\t * since that is obtained using an async XHR call.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} json The JSON object request from the server - only\n\t\t *    present if client-side Ajax sourced data is used\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.initComplete\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"initComplete\": function(settings, json) {\n\t\t *          alert( 'DataTables has finished its initialisation.' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnInitComplete\": null,\n\t\n\t\n\t\t/**\n\t\t * Called at the very start of each table draw and can be used to cancel the\n\t\t * draw by returning false, any other return (including undefined) results in\n\t\t * the full draw occurring).\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @returns {boolean} False will cancel the draw, anything else (including no\n\t\t *    return) will allow it to complete.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.preDrawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"preDrawCallback\": function( settings ) {\n\t\t *          if ( $('#test').val() == 1 ) {\n\t\t *            return false;\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnPreDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * This function allows you to 'post process' each row after it have been\n\t\t * generated for each table draw, but before it is rendered on screen. This\n\t\t * function might be used for setting the row class name etc.\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} displayIndex The display index for the current table draw\n\t\t *  @param {int} displayIndexFull The index of the data in the full list of\n\t\t *    rows (after filtering)\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.rowCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"rowCallback\": function( row, data, displayIndex, displayIndexFull ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" ) {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnRowCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * This parameter allows you to override the default function which obtains\n\t\t * the data from the server so something more suitable for your application.\n\t\t * For example you could use POST data, or pull information from a Gears or\n\t\t * AIR database.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {string} source HTTP source to obtain the data from (`ajax`)\n\t\t *  @param {array} data A key/value pair object containing the data to send\n\t\t *    to the server\n\t\t *  @param {function} callback to be called on completion of the data get\n\t\t *    process that will draw the data on the page.\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverData\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t *  It is often useful to send extra data to the server when making an Ajax\n\t\t * request - for example custom filtering information, and this callback\n\t\t * function makes it trivial to send extra information to the server. The\n\t\t * passed in parameter is the data set that has been constructed by\n\t\t * DataTables, and you can add to this or modify it as you require.\n\t\t *  @type function\n\t\t *  @param {array} data Data array (array of objects which are name/value\n\t\t *    pairs) that has been constructed by DataTables and will be sent to the\n\t\t *    server. In the case of Ajax sourced data with server-side processing\n\t\t *    this will be an empty array, for server-side processing there will be a\n\t\t *    significant number of parameters!\n\t\t *  @returns {undefined} Ensure that you modify the data array passed in,\n\t\t *    as this is passed by reference.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverParams\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Load the table state. With this function you can define from where, and how, the\n\t\t * state of a table is loaded. By default DataTables will load from `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} callback Callback that can be executed when done. It\n\t\t *    should be passed the loaded state object.\n\t\t *  @return {object} The DataTables state object to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadCallback\": function (settings, callback) {\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_load\",\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"success\": function (json) {\n\t\t *              callback( json );\n\t\t *            }\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadCallback\": function ( settings ) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(\n\t\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(\n\t\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the saved state prior to loading that state.\n\t\t * This callback is called when the table is loading state from the stored data, but\n\t\t * prior to the settings object being modified by the saved state. Note that for\n\t\t * plug-in authors, you should use the `stateLoadParams` event to load parameters for\n\t\t * a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that is to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never loaded\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Disallow state loading by returning false\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          return false;\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Callback that is called when the state has been loaded from the state saving method\n\t\t * and the DataTables settings object has been modified as a result of the loaded state.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that was loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoaded\n\t\t *\n\t\t *  @example\n\t\t *    // Show an alert with the filtering value that was saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoaded\": function (settings, data) {\n\t\t *          alert( 'Saved filter was: '+data.oSearch.sSearch );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoaded\": null,\n\t\n\t\n\t\t/**\n\t\t * Save the table state. This function allows you to define where and how the state\n\t\t * information for the table is stored By default DataTables will use `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveCallback\": function (settings, data) {\n\t\t *          // Send an Ajax request to the server with the state object\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_save\",\n\t\t *            \"data\": data,\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"method\": \"POST\"\n\t\t *            \"success\": function () {}\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveCallback\": function ( settings, data ) {\n\t\t\ttry {\n\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(\n\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname,\n\t\t\t\t\tJSON.stringify( data )\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the state to be saved. Called when the table\n\t\t * has changed state a new state save is required. This method allows modification of\n\t\t * the state saving object prior to actually doing the save, including addition or\n\t\t * other state properties or modification. Note that for plug-in authors, you should\n\t\t * use the `stateSaveParams` event to save parameters for a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Duration for which the saved state information is considered valid. After this period\n\t\t * has elapsed the state will be returned to the default.\n\t\t * Value is given in seconds.\n\t\t *  @type int\n\t\t *  @default 7200 <i>(2 hours)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.stateDuration\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateDuration\": 60*60*24; // 1 day\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iStateDuration\": 7200,\n\t\n\t\n\t\t/**\n\t\t * When enabled DataTables will not make a request to the server for the first\n\t\t * page draw - rather it will use the data already on the page (no sorting etc\n\t\t * will be applied to it), thus saving on an XHR at load time. `deferLoading`\n\t\t * is used to indicate that deferred loading is required, but it is also used\n\t\t * to tell DataTables how many records there are in the full table (allowing\n\t\t * the information element and pagination to be displayed correctly). In the case\n\t\t * where a filtering is applied to the table on initial load, this can be\n\t\t * indicated by giving the parameter as an array, where the first element is\n\t\t * the number of records available after filtering and the second element is the\n\t\t * number of records without filtering (allowing the table information element\n\t\t * to be shown correctly).\n\t\t *  @type int | array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.deferLoading\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records available in the table, no filtering applied\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": 57\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records after filtering, 100 without filtering (an initial filter applied)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": [ 57, 100 ],\n\t\t *        \"search\": {\n\t\t *          \"search\": \"my_filter\"\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iDeferLoading\": null,\n\t\n\t\n\t\t/**\n\t\t * Number of rows to display on a single page when using pagination. If\n\t\t * feature enabled (`lengthChange`) then the end user will be able to override\n\t\t * this to a custom setting using a pop-up menu.\n\t\t *  @type int\n\t\t *  @default 10\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pageLength\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pageLength\": 50\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayLength\": 10,\n\t\n\t\n\t\t/**\n\t\t * Define the starting point for data display when using DataTables with\n\t\t * pagination. Note that this parameter is the number of records, rather than\n\t\t * the page number, so if you have 10 records per page and want to start on\n\t\t * the third page, it should be \"20\".\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.displayStart\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"displayStart\": 20\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayStart\": 0,\n\t\n\t\n\t\t/**\n\t\t * By default DataTables allows keyboard navigation of the table (sorting, paging,\n\t\t * and filtering) by adding a `tabindex` attribute to the required elements. This\n\t\t * allows you to tab through the controls and press the enter key to activate them.\n\t\t * The tabindex is default 0, meaning that the tab follows the flow of the document.\n\t\t * You can overrule this using this parameter if you wish. Use a value of -1 to\n\t\t * disable built-in keyboard navigation.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.tabIndex\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"tabIndex\": 1\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\n\t\t/**\n\t\t * Classes that DataTables assigns to the various components and features\n\t\t * that it adds to the HTML table. This allows classes to be configured\n\t\t * during initialisation in addition to through the static\n\t\t * {@link DataTable.ext.oStdClasses} object).\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.classes\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\n\t\t/**\n\t\t * All strings that DataTables uses in the user interface that it creates\n\t\t * are defined in this object, allowing you to modified them individually or\n\t\t * completely replace them all as required.\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.language\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Strings that are used for WAI-ARIA labels and controls only (these are not\n\t\t\t * actually visible on the page, but will be read by screenreaders, and thus\n\t\t\t * must be internationalised as well).\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.aria\n\t\t\t */\n\t\t\t\"oAria\": {\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted ascending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortAscending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortAscending\": \" - click/return to sort ascending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortAscending\": \": activate to sort column ascending\",\n\t\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted descending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortDescending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortDescending\": \" - click/return to sort descending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortDescending\": \": activate to sort column descending\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * Pagination string used by DataTables for the built-in pagination\n\t\t\t * control types.\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.paginate\n\t\t\t */\n\t\t\t\"oPaginate\": {\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the first page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default First\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.first\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"first\": \"First page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sFirst\": \"First\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the last page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Last\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.last\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"last\": \"Last page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sLast\": \"Last\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'next' pagination button (to take the user to the\n\t\t\t\t * next page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Next\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.next\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"next\": \"Next page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sNext\": \"Next\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'previous' pagination button (to take the user to\n\t\t\t\t * the previous page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Previous\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.previous\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"previous\": \"Previous page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sPrevious\": \"Previous\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * This string is shown in preference to `zeroRecords` when the table is\n\t\t\t * empty of data (regardless of filtering). Note that this is an optional\n\t\t\t * parameter - if it is not given, the value of `zeroRecords` will be used\n\t\t\t * instead (either the default or given value).\n\t\t\t *  @type string\n\t\t\t *  @default No data available in table\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.emptyTable\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"emptyTable\": \"No data available in table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sEmptyTable\": \"No data available in table\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This string gives information to the end user about the information\n\t\t\t * that is current on display on the page. The following tokens can be\n\t\t\t * used in the string and will be dynamically replaced as the table\n\t\t\t * display updates. This tokens can be placed anywhere in the string, or\n\t\t\t * removed as needed by the language requires:\n\t\t\t *\n\t\t\t * * `\\_START\\_` - Display index of the first record on the current page\n\t\t\t * * `\\_END\\_` - Display index of the last record on the current page\n\t\t\t * * `\\_TOTAL\\_` - Number of records in the table after filtering\n\t\t\t * * `\\_MAX\\_` - Number of records in the table without filtering\n\t\t\t * * `\\_PAGE\\_` - Current page number\n\t\t\t * * `\\_PAGES\\_` - Total number of pages of data in the table\n\t\t\t *\n\t\t\t *  @type string\n\t\t\t *  @default Showing _START_ to _END_ of _TOTAL_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.info\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"info\": \"Showing page _PAGE_ of _PAGES_\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfo\": \"Showing _START_ to _END_ of _TOTAL_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Display information string for when the table is empty. Typically the\n\t\t\t * format of this string should match `info`.\n\t\t\t *  @type string\n\t\t\t *  @default Showing 0 to 0 of 0 entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoEmpty\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoEmpty\": \"No entries to show\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoEmpty\": \"Showing 0 to 0 of 0 entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When a user filters the information in a table, this string is appended\n\t\t\t * to the information (`info`) to give an idea of how strong the filtering\n\t\t\t * is. The variable _MAX_ is dynamically updated.\n\t\t\t *  @type string\n\t\t\t *  @default (filtered from _MAX_ total entries)\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoFiltered\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoFiltered\": \" - filtering from _MAX_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoFiltered\": \"(filtered from _MAX_ total entries)\",\n\t\n\t\n\t\t\t/**\n\t\t\t * If can be useful to append extra information to the info string at times,\n\t\t\t * and this variable does exactly that. This information will be appended to\n\t\t\t * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are\n\t\t\t * being used) at all times.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoPostFix\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoPostFix\": \"All records shown are derived from real information.\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoPostFix\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This decimal place operator is a little different from the other\n\t\t\t * language options since DataTables doesn't output floating point\n\t\t\t * numbers, so it won't ever use this for display of a number. Rather,\n\t\t\t * what this parameter does is modify the sort methods of the table so\n\t\t\t * that numbers which are in a format which has a character other than\n\t\t\t * a period (`.`) as a decimal place will be sorted numerically.\n\t\t\t *\n\t\t\t * Note that numbers with different decimal places cannot be shown in\n\t\t\t * the same table and still be sortable, the table must be consistent.\n\t\t\t * However, multiple different tables on the page can use different\n\t\t\t * decimal place characters.\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.decimal\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"decimal\": \",\"\n\t\t\t *          \"thousands\": \".\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sDecimal\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * DataTables has a build in number formatter (`formatNumber`) which is\n\t\t\t * used to format large numbers that are used in the table information.\n\t\t\t * By default a comma is used, but this can be trivially changed to any\n\t\t\t * character you wish with this parameter.\n\t\t\t *  @type string\n\t\t\t *  @default ,\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.thousands\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"thousands\": \"'\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sThousands\": \",\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Detail the action that will be taken when the drop down menu for the\n\t\t\t * pagination length option is changed. The '_MENU_' variable is replaced\n\t\t\t * with a default select list of 10, 25, 50 and 100, and can be replaced\n\t\t\t * with a custom select box if required.\n\t\t\t *  @type string\n\t\t\t *  @default Show _MENU_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.lengthMenu\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language change only\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": \"Display _MENU_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language and options change\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": 'Display <select>'+\n\t\t\t *            '<option value=\"10\">10</option>'+\n\t\t\t *            '<option value=\"20\">20</option>'+\n\t\t\t *            '<option value=\"30\">30</option>'+\n\t\t\t *            '<option value=\"40\">40</option>'+\n\t\t\t *            '<option value=\"50\">50</option>'+\n\t\t\t *            '<option value=\"-1\">All</option>'+\n\t\t\t *            '</select> records'\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLengthMenu\": \"Show _MENU_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When using Ajax sourced data and during the first draw when DataTables is\n\t\t\t * gathering the data, this message is shown in an empty row in the table to\n\t\t\t * indicate to the end user the the data is being loaded. Note that this\n\t\t\t * parameter is not used when loading data by server-side processing, just\n\t\t\t * Ajax sourced data with client-side processing.\n\t\t\t *  @type string\n\t\t\t *  @default Loading...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.loadingRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"loadingRecords\": \"Please wait - loading...\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLoadingRecords\": \"Loading...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text which is displayed when the table is processing a user action\n\t\t\t * (usually a sort command or similar).\n\t\t\t *  @type string\n\t\t\t *  @default Processing...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.processing\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"processing\": \"DataTables is currently busy\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sProcessing\": \"Processing...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Details the actions that will be taken when the user types into the\n\t\t\t * filtering input text box. The variable \"_INPUT_\", if used in the string,\n\t\t\t * is replaced with the HTML text box for the filtering input allowing\n\t\t\t * control over where it appears in the string. If \"_INPUT_\" is not given\n\t\t\t * then the input box is appended to the string automatically.\n\t\t\t *  @type string\n\t\t\t *  @default Search:\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.search\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Input text box will be appended at the end automatically\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Filter records:\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Specify where the filter should appear\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Apply filter _INPUT_ to table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sSearch\": \"Search:\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Assign a `placeholder` attribute to the search `input` element\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.searchPlaceholder\n\t\t\t */\n\t\t\t\"sSearchPlaceholder\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * All of the language information can be stored in a file on the\n\t\t\t * server-side, which DataTables will look up if this parameter is passed.\n\t\t\t * It must store the URL of the language file, which is in a JSON format,\n\t\t\t * and the object has the same properties as the oLanguage object in the\n\t\t\t * initialiser object (i.e. the above parameters). Please refer to one of\n\t\t\t * the example language files to see how this works in action.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string - i.e. disabled</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.url\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"url\": \"http://www.sprymedia.co.uk/dataTables/lang.txt\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sUrl\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text shown inside the table records when the is no information to be\n\t\t\t * displayed after filtering. `emptyTable` is shown when there is simply no\n\t\t\t * information in the table at all (regardless of filtering).\n\t\t\t *  @type string\n\t\t\t *  @default No matching records found\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.zeroRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"zeroRecords\": \"No records to display\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sZeroRecords\": \"No matching records found\"\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to have define the global filtering state at\n\t\t * initialisation time. As an object the `search` parameter must be\n\t\t * defined, but all other parameters are optional. When `regex` is true,\n\t\t * the search string will be treated as a regular expression, when false\n\t\t * (default) it will be treated as a straight string. When `smart`\n\t\t * DataTables will use it's smart filtering methods (to word match at\n\t\t * any point in the data), when false this will not be done.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.search\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"search\": {\"search\": \"Initial search\"}\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"oSearch\": $.extend( {}, DataTable.models.oSearch ),\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * By default DataTables will look for the property `data` (or `aaData` for\n\t\t * compatibility with DataTables 1.9-) when obtaining data from an Ajax\n\t\t * source or for server-side processing - this parameter allows that\n\t\t * property to be changed. You can use Javascript dotted object notation to\n\t\t * get a data source for multiple levels of nesting.\n\t\t *  @type string\n\t\t *  @default data\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxDataProp\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxDataProp\": \"data\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * You can instruct DataTables to load data from an external\n\t\t * source using this parameter (use aData if you want to pass data in you\n\t\t * already have). Simply provide a url a JSON object can be obtained from.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxSource\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\n\t\t/**\n\t\t * This initialisation variable allows you to specify exactly where in the\n\t\t * DOM you want DataTables to inject the various controls it adds to the page\n\t\t * (for example you might want the pagination controls at the top of the\n\t\t * table). DIV elements (with or without a custom class) can also be added to\n\t\t * aid styling. The follow syntax is used:\n\t\t *   <ul>\n\t\t *     <li>The following options are allowed:\n\t\t *       <ul>\n\t\t *         <li>'l' - Length changing</li>\n\t\t *         <li>'f' - Filtering input</li>\n\t\t *         <li>'t' - The table!</li>\n\t\t *         <li>'i' - Information</li>\n\t\t *         <li>'p' - Pagination</li>\n\t\t *         <li>'r' - pRocessing</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following constants are allowed:\n\t\t *       <ul>\n\t\t *         <li>'H' - jQueryUI theme \"header\" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>\n\t\t *         <li>'F' - jQueryUI theme \"footer\" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following syntax is expected:\n\t\t *       <ul>\n\t\t *         <li>'&lt;' and '&gt;' - div elements</li>\n\t\t *         <li>'&lt;\"class\" and '&gt;' - div with a class</li>\n\t\t *         <li>'&lt;\"#id\" and '&gt;' - div with an ID</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>Examples:\n\t\t *       <ul>\n\t\t *         <li>'&lt;\"wrapper\"flipt&gt;'</li>\n\t\t *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *   </ul>\n\t\t *  @type string\n\t\t *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>\n\t\t *    <\"H\"lfr>t<\"F\"ip> <i>(when `jQueryUI` is true)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.dom\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"dom\": '&lt;\"top\"i&gt;rt&lt;\"bottom\"flp&gt;&lt;\"clear\"&gt;'\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDom\": \"lfrtip\",\n\t\n\t\n\t\t/**\n\t\t * Search delay option. This will throttle full table searches that use the\n\t\t * DataTables provided search input element (it does not effect calls to\n\t\t * `dt-api search()`, providing a delay before the search is made.\n\t\t *  @type integer\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.searchDelay\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchDelay\": 200\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\n\t\t/**\n\t\t * DataTables features six different built-in options for the buttons to\n\t\t * display for pagination control:\n\t\t *\n\t\t * * `numbers` - Page number buttons only\n\t\t * * `simple` - 'Previous' and 'Next' buttons only\n\t\t * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers\n\t\t * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons\n\t\t * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers\n\t\t * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers\n\t\t *  \n\t\t * Further methods can be added using {@link DataTable.ext.oPagination}.\n\t\t *  @type string\n\t\t *  @default simple_numbers\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pagingType\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pagingType\": \"full_numbers\"\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"sPaginationType\": \"simple_numbers\",\n\t\n\t\n\t\t/**\n\t\t * Enable horizontal scrolling. When a table is too wide to fit into a\n\t\t * certain layout, or you have a large number of columns in the table, you\n\t\t * can enable x-scrolling to show the table in a viewport, which can be\n\t\t * scrolled. This property can be `true` which will allow the table to\n\t\t * scroll horizontally when needed, or any CSS unit, or a number (in which\n\t\t * case it will be treated as a pixel measurement). Setting as simply `true`\n\t\t * is recommended.\n\t\t *  @type boolean|string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollX\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": true,\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollX\": \"\",\n\t\n\t\n\t\t/**\n\t\t * This property can be used to force a DataTable to use more width than it\n\t\t * might otherwise do when x-scrolling is enabled. For example if you have a\n\t\t * table which requires to be well spaced, this parameter is useful for\n\t\t * \"over-sizing\" the table, and thus forcing scrolling. This property can by\n\t\t * any CSS unit, or a number (in which case it will be treated as a pixel\n\t\t * measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollXInner\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": \"100%\",\n\t\t *        \"scrollXInner\": \"110%\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollXInner\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Enable vertical scrolling. Vertical scrolling will constrain the DataTable\n\t\t * to the given height, and enable scrolling for any data which overflows the\n\t\t * current viewport. This can be used as an alternative to paging to display\n\t\t * a lot of data in a small area (although paging and scrolling can both be\n\t\t * enabled at the same time). This property can be any CSS unit, or a number\n\t\t * (in which case it will be treated as a pixel measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollY\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollY\": \"\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * Set the HTTP method that is used to make the Ajax call for server-side\n\t\t * processing or Ajax sourced data.\n\t\t *  @type string\n\t\t *  @default GET\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverMethod\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sServerMethod\": \"GET\",\n\t\n\t\n\t\t/**\n\t\t * DataTables makes use of renderers when displaying HTML elements for\n\t\t * a table. These renderers can be added or modified by plug-ins to\n\t\t * generate suitable mark-up for a site. For example the Bootstrap\n\t\t * integration plug-in for DataTables uses a paging button renderer to\n\t\t * display pagination buttons in the mark-up required by Bootstrap.\n\t\t *\n\t\t * For further information about the renderers available see\n\t\t * DataTable.ext.renderer\n\t\t *  @type string|object\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.renderer\n\t\t *\n\t\t */\n\t\t\"renderer\": null,\n\t\n\t\n\t\t/**\n\t\t * Set the data property name that DataTables should use to get a row's id\n\t\t * to set as the `id` property in the node.\n\t\t *  @type string\n\t\t *  @default DT_RowId\n\t\t *\n\t\t *  @name DataTable.defaults.rowId\n\t\t */\n\t\t\"rowId\": \"DT_RowId\"\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults );\n\t\n\t\n\t\n\t/*\n\t * Developer note - See note in model.defaults.js about the use of Hungarian\n\t * notation and camel case.\n\t */\n\t\n\t/**\n\t * Column options that can be given to DataTables at initialisation time.\n\t *  @namespace\n\t */\n\tDataTable.defaults.column = {\n\t\t/**\n\t\t * Define which column(s) an order will occur on for this column. This\n\t\t * allows a column's ordering to take multiple columns into account when\n\t\t * doing a sort or use the data from a different column. For example first\n\t\t * name / last name columns make sense to do a multi-column sort over the\n\t\t * two columns.\n\t\t *  @type array|int\n\t\t *  @default null <i>Takes the value of the column index automatically</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderData\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderData\": [ 0, 1 ], \"targets\": [ 0 ] },\n\t\t *          { \"orderData\": [ 1, 0 ], \"targets\": [ 1 ] },\n\t\t *          { \"orderData\": 2, \"targets\": [ 2 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderData\": [ 0, 1 ] },\n\t\t *          { \"orderData\": [ 1, 0 ] },\n\t\t *          { \"orderData\": 2 },\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aDataSort\": null,\n\t\t\"iDataSort\": -1,\n\t\n\t\n\t\t/**\n\t\t * You can control the default ordering direction, and even alter the\n\t\t * behaviour of the sort handler (i.e. only allow ascending ordering etc)\n\t\t * using this parameter.\n\t\t *  @type array\n\t\t *  @default [ 'asc', 'desc' ]\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderSequence\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderSequence\": [ \"asc\" ], \"targets\": [ 1 ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ], \"targets\": [ 2 ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ], \"targets\": [ 3 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          { \"orderSequence\": [ \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ] },\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"asSorting\": [ 'asc', 'desc' ],\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering on the data in this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.searchable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"searchable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"searchable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSearchable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable ordering on this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.visible\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"visible\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"visible\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bVisible\": true,\n\t\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} td The TD node that has been created\n\t\t *  @param {*} cellData The Data for the cell\n\t\t *  @param {array|object} rowData The data for the whole row\n\t\t *  @param {int} row The row index for the aoData data store\n\t\t *  @param {int} col The column index for aoColumns\n\t\t *\n\t\t *  @name DataTable.defaults.column.createdCell\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [3],\n\t\t *          \"createdCell\": function (td, cellData, rowData, row, col) {\n\t\t *            if ( cellData == \"1.7\" ) {\n\t\t *              $(td).css('color', 'blue')\n\t\t *            }\n\t\t *          }\n\t\t *        } ]\n\t\t *      });\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter has been replaced by `data` in DataTables to ensure naming\n\t\t * consistency. `dataProp` can still be used, as there is backwards\n\t\t * compatibility in DataTables for this option, but it is strongly\n\t\t * recommended that you use `data` in preference to `dataProp`.\n\t\t *  @name DataTable.defaults.column.dataProp\n\t\t */\n\t\n\t\n\t\t/**\n\t\t * This property can be used to read data from any data source property,\n\t\t * including deeply nested objects / properties. `data` can be given in a\n\t\t * number of different ways which effect its behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object. Note that\n\t\t *      function notation is recommended for use in `render` rather than\n\t\t *      `data` as it is much simpler to use as a renderer.\n\t\t * * `null` - use the original data source for the row rather than plucking\n\t\t *   data directly from it. This action has effects on two other\n\t\t *   initialisation options:\n\t\t *    * `defaultContent` - When null is given as the `data` option and\n\t\t *      `defaultContent` is specified for the column, the value defined by\n\t\t *      `defaultContent` will be used for the cell.\n\t\t *    * `render` - When null is used for the `data` option and the `render`\n\t\t *      option is specified for the column, the whole data source for the\n\t\t *      row is used for the renderer.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * `{array|object}` The data source for the row\n\t\t *      * `{string}` The type call data requested - this will be 'set' when\n\t\t *        setting data or 'filter', 'display', 'type', 'sort' or undefined\n\t\t *        when gathering data. Note that when `undefined` is given for the\n\t\t *        type DataTables expects to get the raw data for the object back<\n\t\t *      * `{*}` Data to set when the second parameter is 'set'.\n\t\t *    * Return:\n\t\t *      * The return value from the function is not required when 'set' is\n\t\t *        the type of call, but otherwise the return is what will be used\n\t\t *        for the data requested.\n\t\t *\n\t\t * Note that `data` is a getter and setter option. If you just require\n\t\t * formatting of data for output, you will likely want to use `render` which\n\t\t * is simply a getter and thus simpler to use.\n\t\t *\n\t\t * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The\n\t\t * name change reflects the flexibility of this property and is consistent\n\t\t * with the naming of mRender. If 'mDataProp' is given, then it will still\n\t\t * be used by DataTables, as it automatically maps the old name to the new\n\t\t * if required.\n\t\t *\n\t\t *  @type string|int|function|null\n\t\t *  @default null <i>Use automatically calculated column index</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.data\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Read table data from objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {value},\n\t\t *    //      \"version\": {value},\n\t\t *    //      \"grade\": {value}\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/objects.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform\" },\n\t\t *          { \"data\": \"version\" },\n\t\t *          { \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Read information from deeply nested objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {\n\t\t *    //         \"inner\": {value}\n\t\t *    //      },\n\t\t *    //      \"details\": [\n\t\t *    //         {value}, {value}\n\t\t *    //      ]\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform.inner\" },\n\t\t *          { \"data\": \"platform.details.0\" },\n\t\t *          { \"data\": \"platform.details.1\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `data` as a function to provide different information for\n\t\t *    // sorting, filtering and display. In this case, currency (price)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": function ( source, type, val ) {\n\t\t *            if (type === 'set') {\n\t\t *              source.price = val;\n\t\t *              // Store the computed dislay and filter values for efficiency\n\t\t *              source.price_display = val==\"\" ? \"\" : \"$\"+numberFormat(val);\n\t\t *              source.price_filter  = val==\"\" ? \"\" : \"$\"+numberFormat(val)+\" \"+val;\n\t\t *              return;\n\t\t *            }\n\t\t *            else if (type === 'display') {\n\t\t *              return source.price_display;\n\t\t *            }\n\t\t *            else if (type === 'filter') {\n\t\t *              return source.price_filter;\n\t\t *            }\n\t\t *            // 'sort', 'type' and undefined all just use the integer\n\t\t *            return source.price;\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using default content\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null,\n\t\t *          \"defaultContent\": \"Click to edit\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using array notation - outputting a list from an array\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"name[, ]\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\n\t\t/**\n\t\t * This property is the rendering partner to `data` and it is suggested that\n\t\t * when you want to manipulate data for display (including filtering,\n\t\t * sorting etc) without altering the underlying data for the table, use this\n\t\t * property. `render` can be considered to be the the read only companion to\n\t\t * `data` which is read / write (then as such more complex). Like `data`\n\t\t * this option can be given in a number of different ways to effect its\n\t\t * behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object.\n\t\t * * `object` - use different data for the different data types requested by\n\t\t *   DataTables ('filter', 'display', 'type' or 'sort'). The property names\n\t\t *   of the object is the data type the property refers to and the value can\n\t\t *   defined using an integer, string or function using the same rules as\n\t\t *   `render` normally does. Note that an `_` option _must_ be specified.\n\t\t *   This is the default value to use if you haven't specified a value for\n\t\t *   the data type requested by DataTables.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * {array|object} The data source for the row (based on `data`)\n\t\t *      * {string} The type call data requested - this will be 'filter',\n\t\t *        'display', 'type' or 'sort'.\n\t\t *      * {array|object} The full data source for the row (not based on\n\t\t *        `data`)\n\t\t *    * Return:\n\t\t *      * The return value from the function is what will be used for the\n\t\t *        data requested.\n\t\t *\n\t\t *  @type string|int|function|object|null\n\t\t *  @default null Use the data source value.\n\t\t *\n\t\t *  @name DataTable.defaults.column.render\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Create a comma separated list from an array of objects\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          {\n\t\t *            \"data\": \"platform\",\n\t\t *            \"render\": \"[, ].name\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Execute a function to obtain data\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": \"browserName()\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // As an object, extracting different data for the different types\n\t\t *    // This would be used with a data source such as:\n\t\t *    //   { \"phone\": 5552368, \"phone_filter\": \"5552368 555-2368\", \"phone_display\": \"555-2368\" }\n\t\t *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`\n\t\t *    // (which has both forms) is used for filtering for if a user inputs either format, while\n\t\t *    // the formatted phone number is the one that is shown in the table.\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": {\n\t\t *            \"_\": \"phone\",\n\t\t *            \"filter\": \"phone_filter\",\n\t\t *            \"display\": \"phone_display\"\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Use as a function to create a link from the data source\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"download_link\",\n\t\t *          \"render\": function ( data, type, full ) {\n\t\t *            return '<a href=\"'+data+'\">Download</a>';\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\n\t\t/**\n\t\t * Change the cell type created for the column - either TD cells or TH cells. This\n\t\t * can be useful as TH cells have semantic meaning in the table body, allowing them\n\t\t * to act as a header for a row (you may wish to add scope='row' to the TH elements).\n\t\t *  @type string\n\t\t *  @default td\n\t\t *\n\t\t *  @name DataTable.defaults.column.cellType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Make the first column use TH cells\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"cellType\": \"th\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sCellType\": \"td\",\n\t\n\t\n\t\t/**\n\t\t * Class to give to each cell in this column.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.class\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"class\": \"my_class\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"class\": \"my_class\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sClass\": \"\",\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t * Generally you shouldn't need this!\n\t\t *  @type string\n\t\t *  @default <i>Empty string<i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.contentPadding\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"contentPadding\": \"mmm\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sContentPadding\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because `data`\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.column.defaultContent\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\",\n\t\t *            \"targets\": [ -1 ]\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter is only used in DataTables' server-side processing. It can\n\t\t * be exceptionally useful to know what columns are being displayed on the\n\t\t * client side, and to map these to database fields. When defined, the names\n\t\t * also allow DataTables to reorder information from the server if it comes\n\t\t * back in an unexpected order (i.e. if you switch your columns around on the\n\t\t * client-side, your server-side code does not also need updating).\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.name\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"name\": \"engine\", \"targets\": [ 0 ] },\n\t\t *          { \"name\": \"browser\", \"targets\": [ 1 ] },\n\t\t *          { \"name\": \"platform\", \"targets\": [ 2 ] },\n\t\t *          { \"name\": \"version\", \"targets\": [ 3 ] },\n\t\t *          { \"name\": \"grade\", \"targets\": [ 4 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"name\": \"engine\" },\n\t\t *          { \"name\": \"browser\" },\n\t\t *          { \"name\": \"platform\" },\n\t\t *          { \"name\": \"version\" },\n\t\t *          { \"name\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sName\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Defines a data source type for the ordering which can be used to read\n\t\t * real-time information from the table (updating the internally cached\n\t\t * version) prior to ordering. This allows ordering to occur on user\n\t\t * editable elements such as form inputs.\n\t\t *  @type string\n\t\t *  @default std\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderDataType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderDataType\": \"dom-text\", \"targets\": [ 2, 3 ] },\n\t\t *          { \"type\": \"numeric\", \"targets\": [ 3 ] },\n\t\t *          { \"orderDataType\": \"dom-select\", \"targets\": [ 4 ] },\n\t\t *          { \"orderDataType\": \"dom-checkbox\", \"targets\": [ 5 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          { \"orderDataType\": \"dom-text\" },\n\t\t *          { \"orderDataType\": \"dom-text\", \"type\": \"numeric\" },\n\t\t *          { \"orderDataType\": \"dom-select\" },\n\t\t *          { \"orderDataType\": \"dom-checkbox\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sSortDataType\": \"std\",\n\t\n\t\n\t\t/**\n\t\t * The title of this column.\n\t\t *  @type string\n\t\t *  @default null <i>Derived from the 'TH' value for this column in the\n\t\t *    original HTML table.</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.title\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"title\": \"My column title\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"My column title\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\n\t\t/**\n\t\t * The type allows you to specify how the data for this column will be\n\t\t * ordered. Four types (string, numeric, date and html (which will strip\n\t\t * HTML tags before ordering)) are currently available. Note that only date\n\t\t * formats understood by Javascript's Date() object will be accepted as type\n\t\t * date. For example: \"Mar 26, 2008 5:03 PM\". May take the values: 'string',\n\t\t * 'numeric', 'date' or 'html' (by default). Further types can be adding\n\t\t * through plug-ins.\n\t\t *  @type string\n\t\t *  @default null <i>Auto-detected from raw data</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.type\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"type\": \"html\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"type\": \"html\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\n\t\t/**\n\t\t * Defining the width of the column, this parameter may take any CSS value\n\t\t * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not\n\t\t * been given a specific width through this interface ensuring that the table\n\t\t * remains readable.\n\t\t *  @type string\n\t\t *  @default null <i>Automatic</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.width\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"width\": \"20%\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"width\": \"20%\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sWidth\": null\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults.column );\n\t\n\t\n\t\n\t/**\n\t * DataTables settings object - this holds all the information needed for a\n\t * given table, including configuration, data and current application of the\n\t * table options. DataTables does not have a single instance for each DataTable\n\t * with the settings attached to that instance, but rather instances of the\n\t * DataTable \"class\" are created on-the-fly as needed (typically by a\n\t * $().dataTable() call) and the settings object is then applied to that\n\t * instance.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults} but this\n\t * one is the internal data store for DataTables's cache of columns. It should\n\t * NOT be manipulated outside of DataTables. Any configuration should be done\n\t * through the initialisation options.\n\t *  @namespace\n\t *  @todo Really should attach the settings object to individual instances so we\n\t *    don't need to create new instances on each $().dataTable() call (if the\n\t *    table already exists). It would also save passing oSettings around and\n\t *    into every single function. However, this is a very significant\n\t *    architecture change for DataTables and will almost certainly break\n\t *    backwards compatibility with older installations. This is something that\n\t *    will be done in 2.0.\n\t */\n\tDataTable.models.oSettings = {\n\t\t/**\n\t\t * Primary features of DataTables and their enablement state.\n\t\t *  @namespace\n\t\t */\n\t\t\"oFeatures\": {\n\t\n\t\t\t/**\n\t\t\t * Flag to say if DataTables should automatically try to calculate the\n\t\t\t * optimum table and columns widths (true) or not (false).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bAutoWidth\": null,\n\t\n\t\t\t/**\n\t\t\t * Delay the creation of TR and TD elements until they are actually\n\t\t\t * needed by a driven page draw. This can give a significant speed\n\t\t\t * increase for Ajax source and Javascript source data, but makes no\n\t\t\t * difference at all fro DOM and server-side processing tables.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bDeferRender\": null,\n\t\n\t\t\t/**\n\t\t\t * Enable filtering on the table or not. Note that if this is disabled\n\t\t\t * then there is no filtering at all on the table, including fnFilter.\n\t\t\t * To just remove the filtering input use sDom and remove the 'f' option.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bFilter\": null,\n\t\n\t\t\t/**\n\t\t\t * Table information element (the 'Showing x of y records' div) enable\n\t\t\t * flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bInfo\": null,\n\t\n\t\t\t/**\n\t\t\t * Present a user control allowing the end user to change the page size\n\t\t\t * when pagination is enabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bLengthChange\": null,\n\t\n\t\t\t/**\n\t\t\t * Pagination enabled or not. Note that if this is disabled then length\n\t\t\t * changing must also be disabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bPaginate\": null,\n\t\n\t\t\t/**\n\t\t\t * Processing indicator enable flag whenever DataTables is enacting a\n\t\t\t * user request - typically an Ajax request for server-side processing.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bProcessing\": null,\n\t\n\t\t\t/**\n\t\t\t * Server-side processing enabled flag - when enabled DataTables will\n\t\t\t * get all data from the server for every draw - there is no filtering,\n\t\t\t * sorting or paging done on the client-side.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bServerSide\": null,\n\t\n\t\t\t/**\n\t\t\t * Sorting enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSort\": null,\n\t\n\t\t\t/**\n\t\t\t * Multi-column sorting\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortMulti\": null,\n\t\n\t\t\t/**\n\t\t\t * Apply a class to the columns which are being sorted to provide a\n\t\t\t * visual highlight or not. This can slow things down when enabled since\n\t\t\t * there is a lot of DOM interaction.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortClasses\": null,\n\t\n\t\t\t/**\n\t\t\t * State saving enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bStateSave\": null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Scrolling settings for a table.\n\t\t *  @namespace\n\t\t */\n\t\t\"oScroll\": {\n\t\t\t/**\n\t\t\t * When the table is shorter in height than sScrollY, collapse the\n\t\t\t * table container down to the height of the table (when true).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bCollapse\": null,\n\t\n\t\t\t/**\n\t\t\t * Width of the scrollbar for the web-browser's platform. Calculated\n\t\t\t * during table initialisation.\n\t\t\t *  @type int\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"iBarWidth\": 0,\n\t\n\t\t\t/**\n\t\t\t * Viewport width for horizontal scrolling. Horizontal scrolling is\n\t\t\t * disabled if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sX\": null,\n\t\n\t\t\t/**\n\t\t\t * Width to expand the table to when using x-scrolling. Typically you\n\t\t\t * should not need to use this.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t *  @deprecated\n\t\t\t */\n\t\t\t\"sXInner\": null,\n\t\n\t\t\t/**\n\t\t\t * Viewport height for vertical scrolling. Vertical scrolling is disabled\n\t\t\t * if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sY\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Language information for the table.\n\t\t *  @namespace\n\t\t *  @extends DataTable.defaults.oLanguage\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Information callback function. See\n\t\t\t * {@link DataTable.defaults.fnInfoCallback}\n\t\t\t *  @type function\n\t\t\t *  @default null\n\t\t\t */\n\t\t\t\"fnInfoCallback\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Browser support parameters\n\t\t *  @namespace\n\t\t */\n\t\t\"oBrowser\": {\n\t\t\t/**\n\t\t\t * Indicate if the browser incorrectly calculates width:100% inside a\n\t\t\t * scrolling element (IE6/7)\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollOversize\": false,\n\t\n\t\t\t/**\n\t\t\t * Determine if the vertical scrollbar is on the right or left of the\n\t\t\t * scrolling container - needed for rtl language layout, although not\n\t\t\t * all browsers move the scrollbar (Safari).\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollbarLeft\": false,\n\t\n\t\t\t/**\n\t\t\t * Flag for if `getBoundingClientRect` is fully supported or not\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bBounding\": false,\n\t\n\t\t\t/**\n\t\t\t * Browser scrollbar width\n\t\t\t *  @type integer\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"barWidth\": 0\n\t\t},\n\t\n\t\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * Array referencing the nodes which are used for the features. The\n\t\t * parameters of this object match what is allowed by sDom - i.e.\n\t\t *   <ul>\n\t\t *     <li>'l' - Length changing</li>\n\t\t *     <li>'f' - Filtering input</li>\n\t\t *     <li>'t' - The table!</li>\n\t\t *     <li>'i' - Information</li>\n\t\t *     <li>'p' - Pagination</li>\n\t\t *     <li>'r' - pRocessing</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aanFeatures\": [],\n\t\n\t\t/**\n\t\t * Store data information - see {@link DataTable.models.oRow} for detailed\n\t\t * information.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoData\": [],\n\t\n\t\t/**\n\t\t * Array of indexes which are in the current display (after filtering etc)\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplay\": [],\n\t\n\t\t/**\n\t\t * Array of indexes for display - no filtering\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplayMaster\": [],\n\t\n\t\t/**\n\t\t * Map of row ids to data indexes\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"aIds\": {},\n\t\n\t\t/**\n\t\t * Store information about each column that is in use\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoColumns\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's header\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeader\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's footer\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooter\": [],\n\t\n\t\t/**\n\t\t * Store the applied global search information in case we want to force a\n\t\t * research or compare the old search to a new one.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t */\n\t\t\"oPreviousSearch\": {},\n\t\n\t\t/**\n\t\t * Store the applied search for each column - see\n\t\t * {@link DataTable.models.oSearch} for the format that is used for the\n\t\t * filtering information for each column.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreSearchCols\": [],\n\t\n\t\t/**\n\t\t * Sorting that is applied to the table. Note that the inner arrays are\n\t\t * used in the following manner:\n\t\t * <ul>\n\t\t *   <li>Index 0 - column number</li>\n\t\t *   <li>Index 1 - current sorting direction</li>\n\t\t * </ul>\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @todo These inner arrays should really be objects\n\t\t */\n\t\t\"aaSorting\": null,\n\t\n\t\t/**\n\t\t * Sorting that is always applied to the table (i.e. prefixed in front of\n\t\t * aaSorting).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\t/**\n\t\t * Classes to use for the striping of a table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its striping classes as well\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asDestroyStripes\": [],\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its width\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"sDestroyWidth\": 0,\n\t\n\t\t/**\n\t\t * Callback functions array for every time a row is inserted (i.e. on a draw).\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for the header on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeaderCallback\": [],\n\t\n\t\t/**\n\t\t * Callback function for the footer on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooterCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for draw callback functions\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for row created function\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCreatedCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for just before the table is redrawn. A return of\n\t\t * false will be used to cancel the draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for when the table has been initialised.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoInitComplete\": [],\n\t\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings to be stored for state saving, prior to\n\t\t * saving state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSaveParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings that have been stored for state saving\n\t\t * prior to using the stored values to restore the state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoadParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for operating on the settings object once the saved state has been\n\t\t * loaded\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoaded\": [],\n\t\n\t\t/**\n\t\t * Cache the table ID for quick access\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sTableId\": \"\",\n\t\n\t\t/**\n\t\t * The TABLE node for the main table\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTable\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the thead element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTHead\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tfoot element - if it exists\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTFoot\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tbody element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTBody\": null,\n\t\n\t\t/**\n\t\t * Cache the wrapper node (contains all DataTables controlled elements)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTableWrapper\": null,\n\t\n\t\t/**\n\t\t * Indicate if when using server-side processing the loading of data\n\t\t * should be deferred until the second draw.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDeferLoading\": false,\n\t\n\t\t/**\n\t\t * Indicate if all required information has been read in\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bInitialised\": false,\n\t\n\t\t/**\n\t\t * Information about open rows. Each object in the array has the parameters\n\t\t * 'nTr' and 'nParent'\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoOpenRows\": [],\n\t\n\t\t/**\n\t\t * Dictate the positioning of DataTables' control elements - see\n\t\t * {@link DataTable.model.oInit.sDom}.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDom\": null,\n\t\n\t\t/**\n\t\t * Search delay (in mS)\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\t/**\n\t\t * Which type of pagination should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default two_button\n\t\t */\n\t\t\"sPaginationType\": \"two_button\",\n\t\n\t\t/**\n\t\t * The state duration (for `stateSave`) in seconds.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iStateDuration\": 0,\n\t\n\t\t/**\n\t\t * Array of callback functions for state saving. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the JSON string to save that has been thus far created. Returns\n\t\t *       a JSON string to be inserted into a json object\n\t\t *       (i.e. '\"param\": [ 0, 1, 2]')</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSave\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for state loading. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the object stored. May return false to cancel state loading</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoad\": [],\n\t\n\t\t/**\n\t\t * State that was saved. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oSavedState\": null,\n\t\n\t\t/**\n\t\t * State that was loaded. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oLoadedState\": null,\n\t\n\t\t/**\n\t\t * Source url for AJAX data for the table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\t/**\n\t\t * Property from a given object from which to read the table data from. This\n\t\t * can be an empty string (when not server-side processing), in which case\n\t\t * it is  assumed an an array is given directly.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sAjaxDataProp\": null,\n\t\n\t\t/**\n\t\t * Note if draw should be blocked while getting data\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bAjaxDataGet\": true,\n\t\n\t\t/**\n\t\t * The last jQuery XHR object that was used for server-side data gathering.\n\t\t * This can be used for working with the XHR information in one of the\n\t\t * callbacks\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"jqXHR\": null,\n\t\n\t\t/**\n\t\t * JSON returned from the server in the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"json\": undefined,\n\t\n\t\t/**\n\t\t * Data submitted as part of the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"oAjaxData\": undefined,\n\t\n\t\t/**\n\t\t * Function to get the server-side data.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\t/**\n\t\t * Functions which are called prior to sending an Ajax request so extra\n\t\t * parameters can easily be sent to the server\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoServerParams\": [],\n\t\n\t\t/**\n\t\t * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if\n\t\t * required).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sServerMethod\": null,\n\t\n\t\t/**\n\t\t * Format numbers for display.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnFormatNumber\": null,\n\t\n\t\t/**\n\t\t * List of options that can be used for the user selectable length menu.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLengthMenu\": null,\n\t\n\t\t/**\n\t\t * Counter for the draws that the table does. Also used as a tracker for\n\t\t * server-side processing\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iDraw\": 0,\n\t\n\t\t/**\n\t\t * Indicate if a redraw is being done - useful for Ajax\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDrawing\": false,\n\t\n\t\t/**\n\t\t * Draw index (iDraw) of the last error when parsing the returned data\n\t\t *  @type int\n\t\t *  @default -1\n\t\t */\n\t\t\"iDrawError\": -1,\n\t\n\t\t/**\n\t\t * Paging display length\n\t\t *  @type int\n\t\t *  @default 10\n\t\t */\n\t\t\"_iDisplayLength\": 10,\n\t\n\t\t/**\n\t\t * Paging start point - aiDisplay index\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"_iDisplayStart\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the result set\n\t\t * (i.e. before filtering), Use fnRecordsTotal rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsTotal\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the current display set\n\t\t * (i.e. after filtering). Use fnRecordsDisplay rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type boolean\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsDisplay\": 0,\n\t\n\t\t/**\n\t\t * Flag to indicate if jQuery UI marking and classes should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bJUI\": null,\n\t\n\t\t/**\n\t\t * The classes to use for the table\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if filtering has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bFiltered\": false,\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if sorting has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bSorted\": false,\n\t\n\t\t/**\n\t\t * Indicate that if multiple rows are in the header and there is more than\n\t\t * one unique cell per column, if the top one (true) or bottom one (false)\n\t\t * should be used for sorting / title by DataTables.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortCellsTop\": null,\n\t\n\t\t/**\n\t\t * Initialisation object that is used for the table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInit\": null,\n\t\n\t\t/**\n\t\t * Destroy callback functions - for plug-ins to attach themselves to the\n\t\t * destroy so they can clean up markup and events.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDestroyCallback\": [],\n\t\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, before filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsTotal\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsTotal * 1 :\n\t\t\t\tthis.aiDisplayMaster.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, after filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsDisplay\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsDisplay * 1 :\n\t\t\t\tthis.aiDisplay.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the display end point - aiDisplay index\n\t\t *  @type function\n\t\t */\n\t\t\"fnDisplayEnd\": function ()\n\t\t{\n\t\t\tvar\n\t\t\t\tlen      = this._iDisplayLength,\n\t\t\t\tstart    = this._iDisplayStart,\n\t\t\t\tcalc     = start + len,\n\t\t\t\trecords  = this.aiDisplay.length,\n\t\t\t\tfeatures = this.oFeatures,\n\t\t\t\tpaginate = features.bPaginate;\n\t\n\t\t\tif ( features.bServerSide ) {\n\t\t\t\treturn paginate === false || len === -1 ?\n\t\t\t\t\tstart + records :\n\t\t\t\t\tMath.min( start+len, this._iRecordsDisplay );\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn ! paginate || calc>records || len===-1 ?\n\t\t\t\t\trecords :\n\t\t\t\t\tcalc;\n\t\t\t}\n\t\t},\n\t\n\t\t/**\n\t\t * The DataTables object for this table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInstance\": null,\n\t\n\t\t/**\n\t\t * Unique identifier for each instance of the DataTables object. If there\n\t\t * is an ID on the table node, then it takes that value, otherwise an\n\t\t * incrementing internal counter is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sInstance\": null,\n\t\n\t\t/**\n\t\t * tabindex attribute value that is added to DataTables control elements, allowing\n\t\t * keyboard navigation of the table and its controls.\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollHead\": null,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollFoot\": null,\n\t\n\t\t/**\n\t\t * Last applied sort\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLastSort\": [],\n\t\n\t\t/**\n\t\t * Stored plug-in instances\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oPlugins\": {},\n\t\n\t\t/**\n\t\t * Function used to get a row's id from the row's data\n\t\t *  @type function\n\t\t *  @default null\n\t\t */\n\t\t\"rowIdFn\": null,\n\t\n\t\t/**\n\t\t * Data location where to store a row's id\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"rowId\": null\n\t};\n\n\t/**\n\t * Extension object for DataTables that is used to provide all extension\n\t * options.\n\t *\n\t * Note that the `DataTable.ext` object is available through\n\t * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is\n\t * also aliased to `jQuery.fn.dataTableExt` for historic reasons.\n\t *  @namespace\n\t *  @extends DataTable.models.ext\n\t */\n\t\n\t\n\t/**\n\t * DataTables extensions\n\t * \n\t * This namespace acts as a collection area for plug-ins that can be used to\n\t * extend DataTables capabilities. Indeed many of the build in methods\n\t * use this method to provide their own capabilities (sorting methods for\n\t * example).\n\t *\n\t * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy\n\t * reasons\n\t *\n\t *  @namespace\n\t */\n\tDataTable.ext = _ext = {\n\t\t/**\n\t\t * Buttons. For use with the Buttons extension for DataTables. This is\n\t\t * defined here so other extensions can define buttons regardless of load\n\t\t * order. It is _not_ used by DataTables core.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tbuttons: {},\n\t\n\t\n\t\t/**\n\t\t * Element class names\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tclasses: {},\n\t\n\t\n\t\t/**\n\t\t * DataTables build type (expanded by the download builder)\n\t\t *\n\t\t *  @type string\n\t\t */\n\t\tbuilder: \"-source-\",\n\t\n\t\n\t\t/**\n\t\t * Error reporting.\n\t\t * \n\t\t * How should DataTables report an error. Can take the value 'alert',\n\t\t * 'throw', 'none' or a function.\n\t\t *\n\t\t *  @type string|function\n\t\t *  @default alert\n\t\t */\n\t\terrMode: \"alert\",\n\t\n\t\n\t\t/**\n\t\t * Feature plug-ins.\n\t\t * \n\t\t * This is an array of objects which describe the feature plug-ins that are\n\t\t * available to DataTables. These feature plug-ins are then available for\n\t\t * use through the `dom` initialisation option.\n\t\t * \n\t\t * Each feature plug-in is described by an object which must have the\n\t\t * following properties:\n\t\t * \n\t\t * * `fnInit` - function that is used to initialise the plug-in,\n\t\t * * `cFeature` - a character so the feature can be enabled by the `dom`\n\t\t *   instillation option. This is case sensitive.\n\t\t *\n\t\t * The `fnInit` function has the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *\n\t\t * And the following return is expected:\n\t\t * \n\t\t * * {node|null} The element which contains your feature. Note that the\n\t\t *   return may also be void if your plug-in does not require to inject any\n\t\t *   DOM elements into DataTables control (`dom`) - for example this might\n\t\t *   be useful when developing a plug-in which allows table control via\n\t\t *   keyboard entry\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    $.fn.dataTable.ext.features.push( {\n\t\t *      \"fnInit\": function( oSettings ) {\n\t\t *        return new TableTools( { \"oDTSettings\": oSettings } );\n\t\t *      },\n\t\t *      \"cFeature\": \"T\"\n\t\t *    } );\n\t\t */\n\t\tfeature: [],\n\t\n\t\n\t\t/**\n\t\t * Row searching.\n\t\t * \n\t\t * This method of searching is complimentary to the default type based\n\t\t * searching, and a lot more comprehensive as it allows you complete control\n\t\t * over the searching logic. Each element in this array is a function\n\t\t * (parameters described below) that is called for every row in the table,\n\t\t * and your logic decides if it should be included in the searching data set\n\t\t * or not.\n\t\t *\n\t\t * Searching functions have the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{array|object}` Data for the row to be processed (same as the\n\t\t *    original format that was passed in as the data source, or an array\n\t\t *    from a DOM data source\n\t\t * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which\n\t\t *    can be useful to retrieve the `TR` element if you need DOM interaction.\n\t\t *\n\t\t * And the following return is expected:\n\t\t *\n\t\t * * {boolean} Include the row in the searched result set (true) or not\n\t\t *   (false)\n\t\t *\n\t\t * Note that as with the main search ability in DataTables, technically this\n\t\t * is \"filtering\", since it is subtractive. However, for consistency in\n\t\t * naming we call it searching here.\n\t\t *\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @example\n\t\t *    // The following example shows custom search being applied to the\n\t\t *    // fourth column (i.e. the data[3] index) based on two input values\n\t\t *    // from the end-user, matching the data in a certain range.\n\t\t *    $.fn.dataTable.ext.search.push(\n\t\t *      function( settings, data, dataIndex ) {\n\t\t *        var min = document.getElementById('min').value * 1;\n\t\t *        var max = document.getElementById('max').value * 1;\n\t\t *        var version = data[3] == \"-\" ? 0 : data[3]*1;\n\t\t *\n\t\t *        if ( min == \"\" && max == \"\" ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min == \"\" && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && \"\" == max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        return false;\n\t\t *      }\n\t\t *    );\n\t\t */\n\t\tsearch: [],\n\t\n\t\n\t\t/**\n\t\t * Selector extensions\n\t\t *\n\t\t * The `selector` option can be used to extend the options available for the\n\t\t * selector modifier options (`selector-modifier` object data type) that\n\t\t * each of the three built in selector types offer (row, column and cell +\n\t\t * their plural counterparts). For example the Select extension uses this\n\t\t * mechanism to provide an option to select only rows, columns and cells\n\t\t * that have been marked as selected by the end user (`{selected: true}`),\n\t\t * which can be used in conjunction with the existing built in selector\n\t\t * options.\n\t\t *\n\t\t * Each property is an array to which functions can be pushed. The functions\n\t\t * take three attributes:\n\t\t *\n\t\t * * Settings object for the host table\n\t\t * * Options object (`selector-modifier` object type)\n\t\t * * Array of selected item indexes\n\t\t *\n\t\t * The return is an array of the resulting item indexes after the custom\n\t\t * selector has been applied.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tselector: {\n\t\t\tcell: [],\n\t\t\tcolumn: [],\n\t\t\trow: []\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Internal functions, exposed for used in plug-ins.\n\t\t * \n\t\t * Please note that you should not need to use the internal methods for\n\t\t * anything other than a plug-in (and even then, try to avoid if possible).\n\t\t * The internal function may change between releases.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tinternal: {},\n\t\n\t\n\t\t/**\n\t\t * Legacy configuration options. Enable and disable legacy options that\n\t\t * are available in DataTables.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tlegacy: {\n\t\t\t/**\n\t\t\t * Enable / disable DataTables 1.9 compatible server-side processing\n\t\t\t * requests\n\t\t\t *\n\t\t\t *  @type boolean\n\t\t\t *  @default null\n\t\t\t */\n\t\t\tajax: null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Pagination plug-in methods.\n\t\t * \n\t\t * Each entry in this object is a function and defines which buttons should\n\t\t * be shown by the pagination rendering method that is used for the table:\n\t\t * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the\n\t\t * buttons are displayed in the document, while the functions here tell it\n\t\t * what buttons to display. This is done by returning an array of button\n\t\t * descriptions (what each button will do).\n\t\t *\n\t\t * Pagination types (the four built in options and any additional plug-in\n\t\t * options defined here) can be used through the `paginationType`\n\t\t * initialisation parameter.\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{int} page` The current page index\n\t\t * 2. `{int} pages` The number of pages in the table\n\t\t *\n\t\t * Each function is expected to return an array where each element of the\n\t\t * array can be one of:\n\t\t *\n\t\t * * `first` - Jump to first page when activated\n\t\t * * `last` - Jump to last page when activated\n\t\t * * `previous` - Show previous page when activated\n\t\t * * `next` - Show next page when activated\n\t\t * * `{int}` - Show page of the index given\n\t\t * * `{array}` - A nested array containing the above elements to add a\n\t\t *   containing 'DIV' element (might be useful for styling).\n\t\t *\n\t\t * Note that DataTables v1.9- used this object slightly differently whereby\n\t\t * an object with two functions would be defined for each plug-in. That\n\t\t * ability is still supported by DataTables 1.10+ to provide backwards\n\t\t * compatibility, but this option of use is now decremented and no longer\n\t\t * documented in DataTables 1.10+.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t *\n\t\t *  @example\n\t\t *    // Show previous, next and current page buttons only\n\t\t *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {\n\t\t *      return [ 'previous', page, 'next' ];\n\t\t *    };\n\t\t */\n\t\tpager: {},\n\t\n\t\n\t\trenderer: {\n\t\t\tpageButton: {},\n\t\t\theader: {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Ordering plug-ins - custom data source\n\t\t * \n\t\t * The extension options for ordering of data available here is complimentary\n\t\t * to the default type based ordering that DataTables typically uses. It\n\t\t * allows much greater control over the the data that is being used to\n\t\t * order a column, but is necessarily therefore more complex.\n\t\t * \n\t\t * This type of ordering is useful if you want to do ordering based on data\n\t\t * live from the DOM (for example the contents of an 'input' element) rather\n\t\t * than just the static string that DataTables knows of.\n\t\t * \n\t\t * The way these plug-ins work is that you create an array of the values you\n\t\t * wish to be ordering for the column in question and then return that\n\t\t * array. The data in the array much be in the index order of the rows in\n\t\t * the table (not the currently ordering order!). Which order data gathering\n\t\t * function is run here depends on the `dt-init columns.orderDataType`\n\t\t * parameter that is used for the column (if any).\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{int}` Target column index\n\t\t *\n\t\t * Each function is expected to return an array:\n\t\t *\n\t\t * * `{array}` Data for the column to be ordering upon\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    // Ordering using `input` node values\n\t\t *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )\n\t\t *    {\n\t\t *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {\n\t\t *        return $('input', td).val();\n\t\t *      } );\n\t\t *    }\n\t\t */\n\t\torder: {},\n\t\n\t\n\t\t/**\n\t\t * Type based plug-ins.\n\t\t *\n\t\t * Each column in DataTables has a type assigned to it, either by automatic\n\t\t * detection or by direct assignment using the `type` option for the column.\n\t\t * The type of a column will effect how it is ordering and search (plug-ins\n\t\t * can also make use of the column type if required).\n\t\t *\n\t\t * @namespace\n\t\t */\n\t\ttype: {\n\t\t\t/**\n\t\t\t * Type detection functions.\n\t\t\t *\n\t\t\t * The functions defined in this object are used to automatically detect\n\t\t\t * a column's type, making initialisation of DataTables super easy, even\n\t\t\t * when complex data is in the table.\n\t\t\t *\n\t\t\t * The functions defined take two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be analysed\n\t\t     *  2. `{settings}` DataTables settings object. This can be used to\n\t\t     *     perform context specific type detection - for example detection\n\t\t     *     based on language settings such as using a comma for a decimal\n\t\t     *     place. Generally speaking the options from the settings will not\n\t\t     *     be required\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Data type detected, or null if unknown (and thus\n\t\t\t *   pass it on to the other type detection functions.\n\t\t\t *\n\t\t\t *  @type array\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Currency type detection plug-in:\n\t\t\t *    $.fn.dataTable.ext.type.detect.push(\n\t\t\t *      function ( data, settings ) {\n\t\t\t *        // Check the numeric part\n\t\t\t *        if ( ! $.isNumeric( data.substring(1) ) ) {\n\t\t\t *          return null;\n\t\t\t *        }\n\t\t\t *\n\t\t\t *        // Check prefixed by currency\n\t\t\t *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {\n\t\t\t *          return 'currency';\n\t\t\t *        }\n\t\t\t *        return null;\n\t\t\t *      }\n\t\t\t *    );\n\t\t\t */\n\t\t\tdetect: [],\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based search formatting.\n\t\t\t *\n\t\t\t * The type based searching functions can be used to pre-format the\n\t\t\t * data to be search on. For example, it can be used to strip HTML\n\t\t\t * tags or to de-format telephone numbers for numeric only searching.\n\t\t\t *\n\t\t\t * Note that is a search is not defined for a column of a given type,\n\t\t\t * no search formatting will be performed.\n\t\t\t * \n\t\t\t * Pre-processing of searching data plug-ins - When you assign the sType\n\t\t\t * for a column (or have it automatically detected for you by DataTables\n\t\t\t * or a type detection plug-in), you will typically be using this for\n\t\t\t * custom sorting, but it can also be used to provide custom searching\n\t\t\t * by allowing you to pre-processing the data and returning the data in\n\t\t\t * the format that should be searched upon. This is done by adding\n\t\t\t * functions this object with a parameter name which matches the sType\n\t\t\t * for that target column. This is the corollary of <i>afnSortData</i>\n\t\t\t * for searching data.\n\t\t\t *\n\t\t\t * The functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for searching\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Formatted string that will be used for the searching.\n\t\t\t *\n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {\n\t\t\t *      return d.replace(/\\n/g,\" \").replace( /<.*?>/g, \"\" );\n\t\t\t *    }\n\t\t\t */\n\t\t\tsearch: {},\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based ordering.\n\t\t\t *\n\t\t\t * The column type tells DataTables what ordering to apply to the table\n\t\t\t * when a column is sorted upon. The order for each type that is defined,\n\t\t\t * is defined by the functions available in this object.\n\t\t\t *\n\t\t\t * Each ordering option can be described by three properties added to\n\t\t\t * this object:\n\t\t\t *\n\t\t\t * * `{type}-pre` - Pre-formatting function\n\t\t\t * * `{type}-asc` - Ascending order function\n\t\t\t * * `{type}-desc` - Descending order function\n\t\t\t *\n\t\t\t * All three can be used together, only `{type}-pre` or only\n\t\t\t * `{type}-asc` and `{type}-desc` together. It is generally recommended\n\t\t\t * that only `{type}-pre` is used, as this provides the optimal\n\t\t\t * implementation in terms of speed, although the others are provided\n\t\t\t * for compatibility with existing Javascript sort functions.\n\t\t\t *\n\t\t\t * `{type}-pre`: Functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for ordering\n\t\t\t *\n\t\t\t * And return:\n\t\t\t *\n\t\t\t * * `{*}` Data to be sorted upon\n\t\t\t *\n\t\t\t * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort\n\t\t\t * functions, taking two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data to compare to the second parameter\n\t\t     *  2. `{*}` Data to compare to the first parameter\n\t\t\t *\n\t\t\t * And returning:\n\t\t\t *\n\t\t\t * * `{*}` Ordering match: <0 if first parameter should be sorted lower\n\t\t\t *   than the second parameter, ===0 if the two parameters are equal and\n\t\t\t *   >0 if the first parameter should be sorted height than the second\n\t\t\t *   parameter.\n\t\t\t * \n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Numeric ordering of formatted numbers with a pre-formatter\n\t\t\t *    $.extend( $.fn.dataTable.ext.type.order, {\n\t\t\t *      \"string-pre\": function(x) {\n\t\t\t *        a = (a === \"-\" || a === \"\") ? 0 : a.replace( /[^\\d\\-\\.]/g, \"\" );\n\t\t\t *        return parseFloat( a );\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Case-sensitive string ordering, with no pre-formatting method\n\t\t\t *    $.extend( $.fn.dataTable.ext.order, {\n\t\t\t *      \"string-case-asc\": function(x,y) {\n\t\t\t *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t\t *      },\n\t\t\t *      \"string-case-desc\": function(x,y) {\n\t\t\t *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t */\n\t\t\torder: {}\n\t\t},\n\t\n\t\t/**\n\t\t * Unique DataTables instance counter\n\t\t *\n\t\t * @type int\n\t\t * @private\n\t\t */\n\t\t_unique: 0,\n\t\n\t\n\t\t//\n\t\t// Depreciated\n\t\t// The following properties are retained for backwards compatiblity only.\n\t\t// The should not be used in new projects and will be removed in a future\n\t\t// version\n\t\t//\n\t\n\t\t/**\n\t\t * Version check function.\n\t\t *  @type function\n\t\t *  @depreciated Since 1.10\n\t\t */\n\t\tfnVersionCheck: DataTable.fnVersionCheck,\n\t\n\t\n\t\t/**\n\t\t * Index for what 'this' index API functions should use\n\t\t *  @type int\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tiApiIndex: 0,\n\t\n\t\n\t\t/**\n\t\t * jQuery UI class container\n\t\t *  @type object\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\toJUIClasses: {},\n\t\n\t\n\t\t/**\n\t\t * Software version\n\t\t *  @type string\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tsVersion: DataTable.version\n\t};\n\t\n\t\n\t//\n\t// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts\n\t//\n\t$.extend( _ext, {\n\t\tafnFiltering: _ext.search,\n\t\taTypes:       _ext.type.detect,\n\t\tofnSearch:    _ext.type.search,\n\t\toSort:        _ext.type.order,\n\t\tafnSortData:  _ext.order,\n\t\taoFeatures:   _ext.feature,\n\t\toApi:         _ext.internal,\n\t\toStdClasses:  _ext.classes,\n\t\toPagination:  _ext.pager\n\t} );\n\t\n\t\n\t$.extend( DataTable.ext.classes, {\n\t\t\"sTable\": \"dataTable\",\n\t\t\"sNoFooter\": \"no-footer\",\n\t\n\t\t/* Paging buttons */\n\t\t\"sPageButton\": \"paginate_button\",\n\t\t\"sPageButtonActive\": \"current\",\n\t\t\"sPageButtonDisabled\": \"disabled\",\n\t\n\t\t/* Striping classes */\n\t\t\"sStripeOdd\": \"odd\",\n\t\t\"sStripeEven\": \"even\",\n\t\n\t\t/* Empty row */\n\t\t\"sRowEmpty\": \"dataTables_empty\",\n\t\n\t\t/* Features */\n\t\t\"sWrapper\": \"dataTables_wrapper\",\n\t\t\"sFilter\": \"dataTables_filter\",\n\t\t\"sInfo\": \"dataTables_info\",\n\t\t\"sPaging\": \"dataTables_paginate paging_\", /* Note that the type is postfixed */\n\t\t\"sLength\": \"dataTables_length\",\n\t\t\"sProcessing\": \"dataTables_processing\",\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\": \"sorting_asc\",\n\t\t\"sSortDesc\": \"sorting_desc\",\n\t\t\"sSortable\": \"sorting\", /* Sortable in both directions */\n\t\t\"sSortableAsc\": \"sorting_asc_disabled\",\n\t\t\"sSortableDesc\": \"sorting_desc_disabled\",\n\t\t\"sSortableNone\": \"sorting_disabled\",\n\t\t\"sSortColumn\": \"sorting_\", /* Note that an int is postfixed for the sorting order */\n\t\n\t\t/* Filtering */\n\t\t\"sFilterInput\": \"\",\n\t\n\t\t/* Page length */\n\t\t\"sLengthSelect\": \"\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollWrapper\": \"dataTables_scroll\",\n\t\t\"sScrollHead\": \"dataTables_scrollHead\",\n\t\t\"sScrollHeadInner\": \"dataTables_scrollHeadInner\",\n\t\t\"sScrollBody\": \"dataTables_scrollBody\",\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot\",\n\t\t\"sScrollFootInner\": \"dataTables_scrollFootInner\",\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\": \"\",\n\t\t\"sFooterTH\": \"\",\n\t\n\t\t// Deprecated\n\t\t\"sSortJUIAsc\": \"\",\n\t\t\"sSortJUIDesc\": \"\",\n\t\t\"sSortJUI\": \"\",\n\t\t\"sSortJUIAscAllowed\": \"\",\n\t\t\"sSortJUIDescAllowed\": \"\",\n\t\t\"sSortJUIWrapper\": \"\",\n\t\t\"sSortIcon\": \"\",\n\t\t\"sJUIHeader\": \"\",\n\t\t\"sJUIFooter\": \"\"\n\t} );\n\t\n\t\n\t(function() {\n\t\n\t// Reused strings for better compression. Closure compiler appears to have a\n\t// weird edge case where it is trying to expand strings rather than use the\n\t// variable version. This results in about 200 bytes being added, for very\n\t// little preference benefit since it this run on script load only.\n\tvar _empty = '';\n\t_empty = '';\n\t\n\tvar _stateDefault = _empty + 'ui-state-default';\n\tvar _sortIcon     = _empty + 'css_right ui-icon ui-icon-';\n\tvar _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';\n\t\n\t$.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {\n\t\t/* Full numbers paging buttons */\n\t\t\"sPageButton\":         \"fg-button ui-button \"+_stateDefault,\n\t\t\"sPageButtonActive\":   \"ui-state-disabled\",\n\t\t\"sPageButtonDisabled\": \"ui-state-disabled\",\n\t\n\t\t/* Features */\n\t\t\"sPaging\": \"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi \"+\n\t\t\t\"ui-buttonset-multi paging_\", /* Note that the type is postfixed */\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\":            _stateDefault+\" sorting_asc\",\n\t\t\"sSortDesc\":           _stateDefault+\" sorting_desc\",\n\t\t\"sSortable\":           _stateDefault+\" sorting\",\n\t\t\"sSortableAsc\":        _stateDefault+\" sorting_asc_disabled\",\n\t\t\"sSortableDesc\":       _stateDefault+\" sorting_desc_disabled\",\n\t\t\"sSortableNone\":       _stateDefault+\" sorting_disabled\",\n\t\t\"sSortJUIAsc\":         _sortIcon+\"triangle-1-n\",\n\t\t\"sSortJUIDesc\":        _sortIcon+\"triangle-1-s\",\n\t\t\"sSortJUI\":            _sortIcon+\"carat-2-n-s\",\n\t\t\"sSortJUIAscAllowed\":  _sortIcon+\"carat-1-n\",\n\t\t\"sSortJUIDescAllowed\": _sortIcon+\"carat-1-s\",\n\t\t\"sSortJUIWrapper\":     \"DataTables_sort_wrapper\",\n\t\t\"sSortIcon\":           \"DataTables_sort_icon\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollHead\": \"dataTables_scrollHead \"+_stateDefault,\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot \"+_stateDefault,\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\":  _stateDefault,\n\t\t\"sFooterTH\":  _stateDefault,\n\t\t\"sJUIHeader\": _headerFooter+\" ui-corner-tl ui-corner-tr\",\n\t\t\"sJUIFooter\": _headerFooter+\" ui-corner-bl ui-corner-br\"\n\t} );\n\t\n\t}());\n\t\n\t\n\t\n\tvar extPagination = DataTable.ext.pager;\n\t\n\tfunction _numbers ( page, pages ) {\n\t\tvar\n\t\t\tnumbers = [],\n\t\t\tbuttons = extPagination.numbers_length,\n\t\t\thalf = Math.floor( buttons / 2 ),\n\t\t\ti = 1;\n\t\n\t\tif ( pages <= buttons ) {\n\t\t\tnumbers = _range( 0, pages );\n\t\t}\n\t\telse if ( page <= half ) {\n\t\t\tnumbers = _range( 0, buttons-2 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t}\n\t\telse if ( page >= pages - 1 - half ) {\n\t\t\tnumbers = _range( pages-(buttons-2), pages );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\telse {\n\t\t\tnumbers = _range( page-half+2, page+half-1 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' );\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\n\t\tnumbers.DT_el = 'span';\n\t\treturn numbers;\n\t}\n\t\n\t\n\t$.extend( extPagination, {\n\t\tsimple: function ( page, pages ) {\n\t\t\treturn [ 'previous', 'next' ];\n\t\t},\n\t\n\t\tfull: function ( page, pages ) {\n\t\t\treturn [  'first', 'previous', 'next', 'last' ];\n\t\t},\n\t\n\t\tnumbers: function ( page, pages ) {\n\t\t\treturn [ _numbers(page, pages) ];\n\t\t},\n\t\n\t\tsimple_numbers: function ( page, pages ) {\n\t\t\treturn [ 'previous', _numbers(page, pages), 'next' ];\n\t\t},\n\t\n\t\tfull_numbers: function ( page, pages ) {\n\t\t\treturn [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];\n\t\t},\n\t\t\n\t\tfirst_last_numbers: function (page, pages) {\n\t \t\treturn ['first', _numbers(page, pages), 'last'];\n\t \t},\n\t\n\t\t// For testing and plug-ins to use\n\t\t_numbers: _numbers,\n\t\n\t\t// Number of number buttons (including ellipsis) to show. _Must be odd!_\n\t\tnumbers_length: 7\n\t} );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\tpageButton: {\n\t\t\t_: function ( settings, host, idx, buttons, page, pages ) {\n\t\t\t\tvar classes = settings.oClasses;\n\t\t\t\tvar lang = settings.oLanguage.oPaginate;\n\t\t\t\tvar aria = settings.oLanguage.oAria.paginate || {};\n\t\t\t\tvar btnDisplay, btnClass, counter=0;\n\t\n\t\t\t\tvar attach = function( container, buttons ) {\n\t\t\t\t\tvar i, ien, node, button;\n\t\t\t\t\tvar clickHandler = function ( e ) {\n\t\t\t\t\t\t_fnPageChange( settings, e.data.action, true );\n\t\t\t\t\t};\n\t\n\t\t\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tbutton = buttons[i];\n\t\n\t\t\t\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\t\t\t\tvar inner = $( '<'+(button.DT_el || 'div')+'/>' )\n\t\t\t\t\t\t\t\t.appendTo( container );\n\t\t\t\t\t\t\tattach( inner, button );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tbtnDisplay = null;\n\t\t\t\t\t\t\tbtnClass = '';\n\t\n\t\t\t\t\t\t\tswitch ( button ) {\n\t\t\t\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\t\t\t\tcontainer.append('<span class=\"ellipsis\">&#x2026;</span>');\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'first':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'next':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'last':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t\t\t\tclasses.sPageButtonActive : '';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\tif ( btnDisplay !== null ) {\n\t\t\t\t\t\t\t\tnode = $('<a>', {\n\t\t\t\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t\t\t\t.appendTo( container );\n\t\n\t\t\t\t\t\t\t\t_fnBindAction(\n\t\t\t\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t\t\t\t);\n\t\n\t\t\t\t\t\t\t\tcounter++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame. Try / catch the error. Not good for\n\t\t\t\t// accessibility, but neither are frames.\n\t\t\t\tvar activeEl;\n\t\n\t\t\t\ttry {\n\t\t\t\t\t// Because this approach is destroying and recreating the paging\n\t\t\t\t\t// elements, focus is lost on the select button which is bad for\n\t\t\t\t\t// accessibility. So we want to restore focus once the draw has\n\t\t\t\t\t// completed\n\t\t\t\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t\t\t\t}\n\t\t\t\tcatch (e) {}\n\t\n\t\t\t\tattach( $(host).empty(), buttons );\n\t\n\t\t\t\tif ( activeEl !== undefined ) {\n\t\t\t\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t\n\t\n\t// Built in type detection. See model.ext.aTypes for information about\n\t// what is required from this methods.\n\t$.extend( DataTable.ext.type.detect, [\n\t\t// Plain numbers - first since V8 detects some plain numbers as dates\n\t\t// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal ) ? 'num'+decimal : null;\n\t\t},\n\t\n\t\t// Dates (only those recognised by the browser's Date.parse)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\t// V8 tries _very_ hard to make a string passed into `Date.parse()`\n\t\t\t// valid, so we need to use a regex to restrict date formats. Use a\n\t\t\t// plug-in for anything other than ISO8601 style strings\n\t\t\tif ( d && !(d instanceof Date) && ! _re_date.test(d) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tvar parsed = Date.parse(d);\n\t\t\treturn (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;\n\t\t},\n\t\n\t\t// Formatted numbers\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric, formatted\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML (this is strict checking - there must be html)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\treturn _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?\n\t\t\t\t'html' : null;\n\t\t}\n\t] );\n\t\n\t\n\t\n\t// Filter formatting functions. See model.ext.ofnSearch for information about\n\t// what is required from these methods.\n\t// \n\t// Note that additional search methods are added for the html numbers and\n\t// html formatted numbers by `_addNumericSort()` when we know what the decimal\n\t// place is\n\t\n\t\n\t$.extend( DataTable.ext.type.search, {\n\t\thtml: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata\n\t\t\t\t\t\t.replace( _re_new_lines, \" \" )\n\t\t\t\t\t\t.replace( _re_html, \"\" ) :\n\t\t\t\t\t'';\n\t\t},\n\t\n\t\tstring: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata.replace( _re_new_lines, \" \" ) :\n\t\t\t\t\tdata;\n\t\t}\n\t} );\n\t\n\t\n\t\n\tvar __numericReplace = function ( d, decimalPlace, re1, re2 ) {\n\t\tif ( d !== 0 && (!d || d === '-') ) {\n\t\t\treturn -Infinity;\n\t\t}\n\t\n\t\t// If a decimal place other than `.` is used, it needs to be given to the\n\t\t// function so we can detect it and replace with a `.` which is the only\n\t\t// decimal place Javascript recognises - it is not locale aware.\n\t\tif ( decimalPlace ) {\n\t\t\td = _numToDecimal( d, decimalPlace );\n\t\t}\n\t\n\t\tif ( d.replace ) {\n\t\t\tif ( re1 ) {\n\t\t\t\td = d.replace( re1, '' );\n\t\t\t}\n\t\n\t\t\tif ( re2 ) {\n\t\t\t\td = d.replace( re2, '' );\n\t\t\t}\n\t\t}\n\t\n\t\treturn d * 1;\n\t};\n\t\n\t\n\t// Add the numeric 'deformatting' functions for sorting and search. This is done\n\t// in a function to provide an easy ability for the language options to add\n\t// additional methods if a non-period decimal place is used.\n\tfunction _addNumericSort ( decimalPlace ) {\n\t\t$.each(\n\t\t\t{\n\t\t\t\t// Plain numbers\n\t\t\t\t\"num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace );\n\t\t\t\t},\n\t\n\t\t\t\t// Formatted numbers\n\t\t\t\t\"num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_formatted_numeric );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric\n\t\t\t\t\"html-num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric, formatted\n\t\t\t\t\"html-num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );\n\t\t\t\t}\n\t\t\t},\n\t\t\tfunction ( key, fn ) {\n\t\t\t\t// Add the ordering method\n\t\t\t\t_ext.type.order[ key+decimalPlace+'-pre' ] = fn;\n\t\n\t\t\t\t// For HTML types add a search formatter that will strip the HTML\n\t\t\t\tif ( key.match(/^html\\-/) ) {\n\t\t\t\t\t_ext.type.search[ key+decimalPlace ] = _ext.type.search.html;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\t\n\t\n\t// Default sort methods\n\t$.extend( _ext.type.order, {\n\t\t// Dates\n\t\t\"date-pre\": function ( d ) {\n\t\t\treturn Date.parse( d ) || -Infinity;\n\t\t},\n\t\n\t\t// html\n\t\t\"html-pre\": function ( a ) {\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ta.replace ?\n\t\t\t\t\ta.replace( /<.*?>/g, \"\" ).toLowerCase() :\n\t\t\t\t\ta+'';\n\t\t},\n\t\n\t\t// string\n\t\t\"string-pre\": function ( a ) {\n\t\t\t// This is a little complex, but faster than always calling toString,\n\t\t\t// http://jsperf.com/tostring-v-check\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ttypeof a === 'string' ?\n\t\t\t\t\ta.toLowerCase() :\n\t\t\t\t\t! a.toString ?\n\t\t\t\t\t\t'' :\n\t\t\t\t\t\ta.toString();\n\t\t},\n\t\n\t\t// string-asc and -desc are retained only for compatibility with the old\n\t\t// sort methods\n\t\t\"string-asc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t},\n\t\n\t\t\"string-desc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t}\n\t} );\n\t\n\t\n\t// Numeric sorting types - order doesn't matter here\n\t_addNumericSort( '' );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\theader: {\n\t\t\t_: function ( settings, cell, column, classes ) {\n\t\t\t\t// No additional mark-up required\n\t\t\t\t// Attach a sort listener to update on sort - note that using the\n\t\t\t\t// `DT` namespace will allow the event to be removed automatically\n\t\t\t\t// on destroy, while the `dt` namespaced event is the one we are\n\t\t\t\t// listening for\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) { // need to check this this is the host\n\t\t\t\t\t\treturn;               // table, not a nested one\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tcolumn.sSortingClass +' '+\n\t\t\t\t\t\t\tclasses.sSortAsc +' '+\n\t\t\t\t\t\t\tclasses.sSortDesc\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t},\n\t\n\t\t\tjqueryui: function ( settings, cell, column, classes ) {\n\t\t\t\t$('<div/>')\n\t\t\t\t\t.addClass( classes.sSortJUIWrapper )\n\t\t\t\t\t.append( cell.contents() )\n\t\t\t\t\t.append( $('<span/>')\n\t\t\t\t\t\t.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo( cell );\n\t\n\t\t\t\t// Attach a sort listener to update on sort\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.find( 'span.'+classes.sSortIcon )\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tclasses.sSortJUIAsc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDesc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUI +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIAscAllowed +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDescAllowed\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortJUIAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortJUIDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClassJUI\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t/*\n\t * Public helper functions. These aren't used internally by DataTables, or\n\t * called by any of the options passed into DataTables, but they can be used\n\t * externally by developers working with DataTables. They are helper functions\n\t * to make working with DataTables a little bit easier.\n\t */\n\t\n\tvar __htmlEscapeEntities = function ( d ) {\n\t\treturn typeof d === 'string' ?\n\t\t\td.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;') :\n\t\t\td;\n\t};\n\t\n\t/**\n\t * Helpers for `columns.render`.\n\t *\n\t * The options defined here can be used with the `columns.render` initialisation\n\t * option to provide a display renderer. The following functions are defined:\n\t *\n\t * * `number` - Will format numeric data (defined by `columns.data`) for\n\t *   display, retaining the original unformatted data for sorting and filtering.\n\t *   It takes 5 parameters:\n\t *   * `string` - Thousands grouping separator\n\t *   * `string` - Decimal point indicator\n\t *   * `integer` - Number of decimal points to show\n\t *   * `string` (optional) - Prefix.\n\t *   * `string` (optional) - Postfix (/suffix).\n\t * * `text` - Escape HTML to help prevent XSS attacks. It has no optional\n\t *   parameters.\n\t *\n\t * @example\n\t *   // Column definition using the number renderer\n\t *   {\n\t *     data: \"salary\",\n\t *     render: $.fn.dataTable.render.number( '\\'', '.', 0, '$' )\n\t *   }\n\t *\n\t * @namespace\n\t */\n\tDataTable.render = {\n\t\tnumber: function ( thousands, decimal, precision, prefix, postfix ) {\n\t\t\treturn {\n\t\t\t\tdisplay: function ( d ) {\n\t\t\t\t\tif ( typeof d !== 'number' && typeof d !== 'string' ) {\n\t\t\t\t\t\treturn d;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar negative = d < 0 ? '-' : '';\n\t\t\t\t\tvar flo = parseFloat( d );\n\t\n\t\t\t\t\t// If NaN then there isn't much formatting that we can do - just\n\t\t\t\t\t// return immediately, escaping any HTML (this was supposed to\n\t\t\t\t\t// be a number after all)\n\t\t\t\t\tif ( isNaN( flo ) ) {\n\t\t\t\t\t\treturn __htmlEscapeEntities( d );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tflo = flo.toFixed( precision );\n\t\t\t\t\td = Math.abs( flo );\n\t\n\t\t\t\t\tvar intPart = parseInt( d, 10 );\n\t\t\t\t\tvar floatPart = precision ?\n\t\t\t\t\t\tdecimal+(d - intPart).toFixed( precision ).substring( 2 ):\n\t\t\t\t\t\t'';\n\t\n\t\t\t\t\treturn negative + (prefix||'') +\n\t\t\t\t\t\tintPart.toString().replace(\n\t\t\t\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g, thousands\n\t\t\t\t\t\t) +\n\t\t\t\t\t\tfloatPart +\n\t\t\t\t\t\t(postfix||'');\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\ttext: function () {\n\t\t\treturn {\n\t\t\t\tdisplay: __htmlEscapeEntities\n\t\t\t};\n\t\t}\n\t};\n\t\n\t\n\t/*\n\t * This is really a good bit rubbish this method of exposing the internal methods\n\t * publicly... - To be fixed in 2.0 using methods on the prototype\n\t */\n\t\n\t\n\t/**\n\t * Create a wrapper function for exporting an internal functions to an external API.\n\t *  @param {string} fn API function name\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#internal\n\t */\n\tfunction _fnExternApiFunc (fn)\n\t{\n\t\treturn function() {\n\t\t\tvar args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(\n\t\t\t\tArray.prototype.slice.call(arguments)\n\t\t\t);\n\t\t\treturn DataTable.ext.internal[fn].apply( this, args );\n\t\t};\n\t}\n\t\n\t\n\t/**\n\t * Reference to internal functions for use by plug-in developers. Note that\n\t * these methods are references to internal functions and are considered to be\n\t * private. If you use these methods, be aware that they are liable to change\n\t * between versions.\n\t *  @namespace\n\t */\n\t$.extend( DataTable.ext.internal, {\n\t\t_fnExternApiFunc: _fnExternApiFunc,\n\t\t_fnBuildAjax: _fnBuildAjax,\n\t\t_fnAjaxUpdate: _fnAjaxUpdate,\n\t\t_fnAjaxParameters: _fnAjaxParameters,\n\t\t_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,\n\t\t_fnAjaxDataSrc: _fnAjaxDataSrc,\n\t\t_fnAddColumn: _fnAddColumn,\n\t\t_fnColumnOptions: _fnColumnOptions,\n\t\t_fnAdjustColumnSizing: _fnAdjustColumnSizing,\n\t\t_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,\n\t\t_fnColumnIndexToVisible: _fnColumnIndexToVisible,\n\t\t_fnVisbleColumns: _fnVisbleColumns,\n\t\t_fnGetColumns: _fnGetColumns,\n\t\t_fnColumnTypes: _fnColumnTypes,\n\t\t_fnApplyColumnDefs: _fnApplyColumnDefs,\n\t\t_fnHungarianMap: _fnHungarianMap,\n\t\t_fnCamelToHungarian: _fnCamelToHungarian,\n\t\t_fnLanguageCompat: _fnLanguageCompat,\n\t\t_fnBrowserDetect: _fnBrowserDetect,\n\t\t_fnAddData: _fnAddData,\n\t\t_fnAddTr: _fnAddTr,\n\t\t_fnNodeToDataIndex: _fnNodeToDataIndex,\n\t\t_fnNodeToColumnIndex: _fnNodeToColumnIndex,\n\t\t_fnGetCellData: _fnGetCellData,\n\t\t_fnSetCellData: _fnSetCellData,\n\t\t_fnSplitObjNotation: _fnSplitObjNotation,\n\t\t_fnGetObjectDataFn: _fnGetObjectDataFn,\n\t\t_fnSetObjectDataFn: _fnSetObjectDataFn,\n\t\t_fnGetDataMaster: _fnGetDataMaster,\n\t\t_fnClearTable: _fnClearTable,\n\t\t_fnDeleteIndex: _fnDeleteIndex,\n\t\t_fnInvalidate: _fnInvalidate,\n\t\t_fnGetRowElements: _fnGetRowElements,\n\t\t_fnCreateTr: _fnCreateTr,\n\t\t_fnBuildHead: _fnBuildHead,\n\t\t_fnDrawHead: _fnDrawHead,\n\t\t_fnDraw: _fnDraw,\n\t\t_fnReDraw: _fnReDraw,\n\t\t_fnAddOptionsHtml: _fnAddOptionsHtml,\n\t\t_fnDetectHeader: _fnDetectHeader,\n\t\t_fnGetUniqueThs: _fnGetUniqueThs,\n\t\t_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,\n\t\t_fnFilterComplete: _fnFilterComplete,\n\t\t_fnFilterCustom: _fnFilterCustom,\n\t\t_fnFilterColumn: _fnFilterColumn,\n\t\t_fnFilter: _fnFilter,\n\t\t_fnFilterCreateSearch: _fnFilterCreateSearch,\n\t\t_fnEscapeRegex: _fnEscapeRegex,\n\t\t_fnFilterData: _fnFilterData,\n\t\t_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,\n\t\t_fnUpdateInfo: _fnUpdateInfo,\n\t\t_fnInfoMacros: _fnInfoMacros,\n\t\t_fnInitialise: _fnInitialise,\n\t\t_fnInitComplete: _fnInitComplete,\n\t\t_fnLengthChange: _fnLengthChange,\n\t\t_fnFeatureHtmlLength: _fnFeatureHtmlLength,\n\t\t_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,\n\t\t_fnPageChange: _fnPageChange,\n\t\t_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,\n\t\t_fnProcessingDisplay: _fnProcessingDisplay,\n\t\t_fnFeatureHtmlTable: _fnFeatureHtmlTable,\n\t\t_fnScrollDraw: _fnScrollDraw,\n\t\t_fnApplyToChildren: _fnApplyToChildren,\n\t\t_fnCalculateColumnWidths: _fnCalculateColumnWidths,\n\t\t_fnThrottle: _fnThrottle,\n\t\t_fnConvertToWidth: _fnConvertToWidth,\n\t\t_fnGetWidestNode: _fnGetWidestNode,\n\t\t_fnGetMaxLenString: _fnGetMaxLenString,\n\t\t_fnStringToCss: _fnStringToCss,\n\t\t_fnSortFlatten: _fnSortFlatten,\n\t\t_fnSort: _fnSort,\n\t\t_fnSortAria: _fnSortAria,\n\t\t_fnSortListener: _fnSortListener,\n\t\t_fnSortAttachListener: _fnSortAttachListener,\n\t\t_fnSortingClasses: _fnSortingClasses,\n\t\t_fnSortData: _fnSortData,\n\t\t_fnSaveState: _fnSaveState,\n\t\t_fnLoadState: _fnLoadState,\n\t\t_fnSettingsFromNode: _fnSettingsFromNode,\n\t\t_fnLog: _fnLog,\n\t\t_fnMap: _fnMap,\n\t\t_fnBindAction: _fnBindAction,\n\t\t_fnCallbackReg: _fnCallbackReg,\n\t\t_fnCallbackFire: _fnCallbackFire,\n\t\t_fnLengthOverflow: _fnLengthOverflow,\n\t\t_fnRenderer: _fnRenderer,\n\t\t_fnDataSource: _fnDataSource,\n\t\t_fnRowAttributes: _fnRowAttributes,\n\t\t_fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant\n\t\t                                // in 1.10, so this dead-end function is\n\t\t                                // added to prevent errors\n\t} );\n\t\n\n\t// jQuery access\n\t$.fn.dataTable = DataTable;\n\n\t// Provide access to the host jQuery object (circular reference)\n\tDataTable.$ = $;\n\n\t// Legacy aliases\n\t$.fn.dataTableSettings = DataTable.settings;\n\t$.fn.dataTableExt = DataTable.ext;\n\n\t// With a capital `D` we return a DataTables API instance rather than a\n\t// jQuery object\n\t$.fn.DataTable = function ( opts ) {\n\t\treturn $(this).dataTable( opts ).api();\n\t};\n\n\t// All properties that are available to $.fn.dataTable should also be\n\t// available on $.fn.DataTable\n\t$.each( DataTable, function ( prop, val ) {\n\t\t$.fn.DataTable[ prop ] = val;\n\t} );\n\n\n\t// Information about events fired by DataTables - for documentation.\n\t/**\n\t * Draw event, fired whenever the table is redrawn on the page, at the same\n\t * point as fnDrawCallback. This may be useful for binding events or\n\t * performing calculations when the table is altered at all.\n\t *  @name DataTable#draw.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Search event, fired when the searching applied to the table (using the\n\t * built-in global search, or column filters) is altered.\n\t *  @name DataTable#search.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page change event, fired when the paging of the table is altered.\n\t *  @name DataTable#page.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Order event, fired when the ordering applied to the table is altered.\n\t *  @name DataTable#order.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * DataTables initialisation complete event, fired when the table is fully\n\t * drawn, including Ajax data loaded, if Ajax data is required.\n\t *  @name DataTable#init.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The JSON object request from the server - only\n\t *    present if client-side Ajax sourced data is used</li></ol>\n\t */\n\n\t/**\n\t * State save event, fired when the table has changed state a new state save\n\t * is required. This event allows modification of the state saving object\n\t * prior to actually doing the save, including addition or other state\n\t * properties (for plug-ins) or modification of a DataTables core property.\n\t *  @name DataTable#stateSaveParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The state information to be saved\n\t */\n\n\t/**\n\t * State load event, fired when the table is loading state from the stored\n\t * data, but prior to the settings object being modified by the saved state\n\t * - allowing modification of the saved state is required or loading of\n\t * state for a plug-in.\n\t *  @name DataTable#stateLoadParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * State loaded event, fired when state has been loaded from stored data and\n\t * the settings object has been modified by the loaded data.\n\t *  @name DataTable#stateLoaded.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * Processing event, fired when DataTables is doing some kind of processing\n\t * (be it, order, searcg or anything else). It can be used to indicate to\n\t * the end user that there is something happening, or that something has\n\t * finished.\n\t *  @name DataTable#processing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {boolean} bShow Flag for if DataTables is doing processing or not\n\t */\n\n\t/**\n\t * Ajax (XHR) event, fired whenever an Ajax request is completed from a\n\t * request to made to the server for new data. This event is called before\n\t * DataTables processed the returned data, so it can also be used to pre-\n\t * process the data returned from the server, if needed.\n\t *\n\t * Note that this trigger is called in `fnServerData`, if you override\n\t * `fnServerData` and which to use this event, you need to trigger it in you\n\t * success function.\n\t *  @name DataTable#xhr.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {object} json JSON returned from the server\n\t *\n\t *  @example\n\t *     // Use a custom property returned from the server in another DOM element\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       $('#status').html( json.status );\n\t *     } );\n\t *\n\t *  @example\n\t *     // Pre-process the data returned from the server\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {\n\t *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;\n\t *       }\n\t *       // Note no return - manipulate the data directly in the JSON object.\n\t *     } );\n\t */\n\n\t/**\n\t * Destroy event, fired when the DataTable is destroyed by calling fnDestroy\n\t * or passing the bDestroy:true parameter in the initialisation object. This\n\t * can be used to remove bound events, added DOM nodes, etc.\n\t *  @name DataTable#destroy.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page length change event, fired when number of records to show on each\n\t * page (the length) is changed.\n\t *  @name DataTable#length.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {integer} len New length\n\t */\n\n\t/**\n\t * Column sizing has changed.\n\t *  @name DataTable#column-sizing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Column visibility has changed.\n\t *  @name DataTable#column-visibility.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {int} column Column index\n\t *  @param {bool} vis `false` if column now hidden, or `true` if visible\n\t */\n\n\treturn $.fn.dataTable;\n}));\n"
  },
  {
    "path": "platforms/browser/www/lib/DataTables/datatables.css",
    "content": "/*\n * This combined file was created by the DataTables downloader builder:\n *   https://datatables.net/download\n *\n * To rebuild or modify this file with the latest versions of the included\n * software please visit:\n *   https://datatables.net/download/#dt/dt-1.10.13\n *\n * Included libraries:\n *   DataTables 1.10.13\n */\n\n/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px;\n  border-bottom: 1px solid #111;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n  border-top: 1px solid #111;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc {\n  cursor: pointer;\n  *cursor: hand;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"DataTables-1.10.13/images/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"DataTables-1.10.13/images/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"DataTables-1.10.13/images/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"DataTables-1.10.13/images/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"DataTables-1.10.13/images/sort_desc_disabled.png\");\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: #f6f6f6;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #fafafa;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #fafafa;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fcfcfc;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fefefe;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ececec;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #efefef;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em 1em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #979797;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  color: white !important;\n  border: 1px solid #111;\n  background-color: #585858;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #585858 0%, #111 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #585858 0%, #111 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #585858 0%, #111 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #585858 0%, #111 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  background-color: #2b2b2b;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);\n  /* W3C */\n  box-shadow: inset 0 0 3px #111;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td {\n  vertical-align: middle;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}\n\n\n"
  },
  {
    "path": "platforms/browser/www/lib/DataTables/datatables.js",
    "content": "/*\n * This combined file was created by the DataTables downloader builder:\n *   https://datatables.net/download\n *\n * To rebuild or modify this file with the latest versions of the included\n * software please visit:\n *   https://datatables.net/download/#dt/dt-1.10.13\n *\n * Included libraries:\n *   DataTables 1.10.13\n */\n\n/*! DataTables 1.10.13\n * ©2008-2016 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     DataTables\n * @description Paginate, search and order HTML tables\n * @version     1.10.13\n * @file        jquery.dataTables.js\n * @author      SpryMedia Ltd\n * @contact     www.datatables.net\n * @copyright   Copyright 2008-2016 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n/*jslint evil: true, undef: true, browser: true */\n/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/\n\n(function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\t// CommonJS environments without a window global must pass a\n\t\t\t\t// root. This will give an error otherwise\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ ) {\n\t\t\t\t$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window\n\t\t\t\t\trequire('jquery') :\n\t\t\t\t\trequire('jquery')( root );\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}\n(function( $, window, document, undefined ) {\n\t\"use strict\";\n\n\t/**\n\t * DataTables is a plug-in for the jQuery Javascript library. It is a highly\n\t * flexible tool, based upon the foundations of progressive enhancement,\n\t * which will add advanced interaction controls to any HTML table. For a\n\t * full list of features please refer to\n\t * [DataTables.net](href=\"http://datatables.net).\n\t *\n\t * Note that the `DataTable` object is not a global variable but is aliased\n\t * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may\n\t * be  accessed.\n\t *\n\t *  @class\n\t *  @param {object} [init={}] Configuration object for DataTables. Options\n\t *    are defined by {@link DataTable.defaults}\n\t *  @requires jQuery 1.7+\n\t *\n\t *  @example\n\t *    // Basic initialisation\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable();\n\t *    } );\n\t *\n\t *  @example\n\t *    // Initialisation with configuration options - in this case, disable\n\t *    // pagination and sorting.\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable( {\n\t *        \"paginate\": false,\n\t *        \"sort\": false\n\t *      } );\n\t *    } );\n\t */\n\tvar DataTable = function ( options )\n\t{\n\t\t/**\n\t\t * Perform a jQuery selector action on the table's TR elements (from the tbody) and\n\t\t * return the resulting jQuery object.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter\n\t\t *    criterion (\"applied\") or all TR elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {object} jQuery object, filtered by the given selector.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Highlight every second row\n\t\t *      oTable.$('tr:odd').css('backgroundColor', 'blue');\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to rows with 'Webkit' in them, add a background colour and then\n\t\t *      // remove the filter, thus highlighting the 'Webkit' rows only.\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      oTable.$('tr', {\"search\": \"applied\"}).css('backgroundColor', 'blue');\n\t\t *      oTable.fnFilter('');\n\t\t *    } );\n\t\t */\n\t\tthis.$ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).$( sSelector, oOpts );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Almost identical to $ in operation, but in this case returns the data for the matched\n\t\t * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes\n\t\t * rather than any descendants, so the data can be obtained for the row/cell. If matching\n\t\t * rows are found, the data returned is the original data array/object that was used to\n\t\t * create the row (or a generated array if from a DOM source).\n\t\t *\n\t\t * This method is often useful in-combination with $ where both functions are given the\n\t\t * same parameters and the array indexes will match identically.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select elements that meet the current filter\n\t\t *    criterion (\"applied\") or all elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the data in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {array} Data for the matched elements. If any elements, as a result of the\n\t\t *    selector, were not TR, TD or TH elements in the DataTable, they will have a null\n\t\t *    entry in the array.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the data from the first row in the table\n\t\t *      var data = oTable._('tr:first');\n\t\t *\n\t\t *      // Do something useful with the data\n\t\t *      alert( \"First cell is: \"+data[0] );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to 'Webkit' and get all data for\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      var data = oTable._('tr', {\"search\": \"applied\"});\n\t\t *\n\t\t *      // Do something with the data\n\t\t *      alert( data.length+\" rows matched the search\" );\n\t\t *    } );\n\t\t */\n\t\tthis._ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).rows( sSelector, oOpts ).data();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Create a DataTables Api instance, with the currently selected tables for\n\t\t * the Api's context.\n\t\t * @param {boolean} [traditional=false] Set the API instance's context to be\n\t\t *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was\n\t\t *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),\n\t\t *   or if all tables captured in the jQuery object should be used.\n\t\t * @return {DataTables.Api}\n\t\t */\n\t\tthis.api = function ( traditional )\n\t\t{\n\t\t\treturn traditional ?\n\t\t\t\tnew _Api(\n\t\t\t\t\t_fnSettingsFromNode( this[ _ext.iApiIndex ] )\n\t\t\t\t) :\n\t\t\t\tnew _Api( this );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Add a single new row or multiple rows of data to the table. Please note\n\t\t * that this is suitable for client-side processing only - if you are using\n\t\t * server-side processing (i.e. \"bServerSide\": true), then to add data, you\n\t\t * must add it to the data source, i.e. the server-side, through an Ajax call.\n\t\t *  @param {array|object} data The data to be added to the table. This can be:\n\t\t *    <ul>\n\t\t *      <li>1D array of data - add a single row with the data provided</li>\n\t\t *      <li>2D array of arrays - add multiple rows in a single call</li>\n\t\t *      <li>object - data object when using <i>mData</i></li>\n\t\t *      <li>array of objects - multiple data objects when using <i>mData</i></li>\n\t\t *    </ul>\n\t\t *  @param {bool} [redraw=true] redraw the table or not\n\t\t *  @returns {array} An array of integers, representing the list of indexes in\n\t\t *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to\n\t\t *    the table.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Global var for counter\n\t\t *    var giCount = 2;\n\t\t *\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example').dataTable();\n\t\t *    } );\n\t\t *\n\t\t *    function fnClickAddRow() {\n\t\t *      $('#example').dataTable().fnAddData( [\n\t\t *        giCount+\".1\",\n\t\t *        giCount+\".2\",\n\t\t *        giCount+\".3\",\n\t\t *        giCount+\".4\" ]\n\t\t *      );\n\t\t *\n\t\t *      giCount++;\n\t\t *    }\n\t\t */\n\t\tthis.fnAddData = function( data, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\t/* Check if we want to add multiple rows or not */\n\t\t\tvar rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?\n\t\t\t\tapi.rows.add( data ) :\n\t\t\t\tapi.row.add( data );\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn rows.flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will make DataTables recalculate the column sizes, based on the data\n\t\t * contained in the table and the sizes applied to the columns (in the DOM, CSS or\n\t\t * through the sWidth parameter). This can be useful when the width of the table's\n\t\t * parent element changes (for example a window resize).\n\t\t *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable( {\n\t\t *        \"sScrollY\": \"200px\",\n\t\t *        \"bPaginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      $(window).on('resize', function () {\n\t\t *        oTable.fnAdjustColumnSizing();\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnAdjustColumnSizing = function ( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).columns.adjust();\n\t\t\tvar settings = api.settings()[0];\n\t\t\tvar scroll = settings.oScroll;\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw( false );\n\t\t\t}\n\t\t\telse if ( scroll.sX !== \"\" || scroll.sY !== \"\" ) {\n\t\t\t\t/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */\n\t\t\t\t_fnScrollDraw( settings );\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Quickly and simply clear a table\n\t\t *  @param {bool} [bRedraw=true] redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)\n\t\t *      oTable.fnClearTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClearTable = function( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).clear();\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * The exact opposite of 'opening' a row, this function will close any rows which\n\t\t * are currently 'open'.\n\t\t *  @param {node} nTr the table row to 'close'\n\t\t *  @returns {int} 0 on success, or 1 if failed (can't find the row)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClose = function( nTr )\n\t\t{\n\t\t\tthis.api( true ).row( nTr ).child.hide();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Remove a row for the table\n\t\t *  @param {mixed} target The index of the row from aoData to be deleted, or\n\t\t *    the TR element you want to delete\n\t\t *  @param {function|null} [callBack] Callback function\n\t\t *  @param {bool} [redraw=true] Redraw the table or not\n\t\t *  @returns {array} The row that was deleted\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately remove the first row\n\t\t *      oTable.fnDeleteRow( 0 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnDeleteRow = function( target, callback, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar rows = api.rows( target );\n\t\t\tvar settings = rows.settings()[0];\n\t\t\tvar data = settings.aoData[ rows[0][0] ];\n\t\t\n\t\t\trows.remove();\n\t\t\n\t\t\tif ( callback ) {\n\t\t\t\tcallback.call( this, settings, data );\n\t\t\t}\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn data;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Restore the table to it's original state in the DOM by removing all of DataTables\n\t\t * enhancements, alterations to the DOM structure of the table and event listeners.\n\t\t *  @param {boolean} [remove=false] Completely remove the table from the DOM\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      // This example is fairly pointless in reality, but shows how fnDestroy can be used\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnDestroy();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDestroy = function ( remove )\n\t\t{\n\t\t\tthis.api( true ).destroy( remove );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Redraw the table\n\t\t *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)\n\t\t *      oTable.fnDraw();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDraw = function( complete )\n\t\t{\n\t\t\t// Note that this isn't an exact match to the old call to _fnDraw - it takes\n\t\t\t// into account the new data, but can hold position.\n\t\t\tthis.api( true ).draw( complete );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Filter the input based on data\n\t\t *  @param {string} sInput String to filter the table on\n\t\t *  @param {int|null} [iColumn] Column to limit filtering to\n\t\t *  @param {bool} [bRegex=false] Treat as regular expression or not\n\t\t *  @param {bool} [bSmart=true] Perform smart filtering or not\n\t\t *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)\n\t\t *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sometime later - filter...\n\t\t *      oTable.fnFilter( 'test string' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === null || iColumn === undefined ) {\n\t\t\t\tapi.search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\n\t\t\tapi.draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the data for the whole table, an individual row or an individual cell based on the\n\t\t * provided parameters.\n\t\t *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as\n\t\t *    a TR node then the data source for the whole row will be returned. If given as a\n\t\t *    TD/TH cell node then iCol will be automatically calculated and the data for the\n\t\t *    cell returned. If given as an integer, then this is treated as the aoData internal\n\t\t *    data index for the row (see fnGetPosition) and the data for that row used.\n\t\t *  @param {int} [col] Optional column index that you want the data of.\n\t\t *  @returns {array|object|string} If mRow is undefined, then the data for all rows is\n\t\t *    returned. If mRow is defined, just data for that row, and is iCol is\n\t\t *    defined, only data for the designated cell is returned.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Row data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('tr').click( function () {\n\t\t *        var data = oTable.fnGetData( this );\n\t\t *        // ... do something with the array / object of data for the row\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Individual cell data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('td').click( function () {\n\t\t *        var sData = oTable.fnGetData( this );\n\t\t *        alert( 'The cell clicked on had the value of '+sData );\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetData = function( src, col )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( src !== undefined ) {\n\t\t\t\tvar type = src.nodeName ? src.nodeName.toLowerCase() : '';\n\t\t\n\t\t\t\treturn col !== undefined || type == 'td' || type == 'th' ?\n\t\t\t\t\tapi.cell( src, col ).data() :\n\t\t\t\t\tapi.row( src ).data() || null;\n\t\t\t}\n\t\t\n\t\t\treturn api.data().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get an array of the TR nodes that are used in the table's body. Note that you will\n\t\t * typically want to use the '$' API method in preference to this as it is more\n\t\t * flexible.\n\t\t *  @param {int} [iRow] Optional row index for the TR element you want\n\t\t *  @returns {array|node} If iRow is undefined, returns an array of all TR elements\n\t\t *    in the table's body, or iRow is defined, just the TR element requested.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the nodes from the table\n\t\t *      var nNodes = oTable.fnGetNodes( );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetNodes = function( iRow )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\treturn iRow !== undefined ?\n\t\t\t\tapi.row( iRow ).node() :\n\t\t\t\tapi.rows().nodes().flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the array indexes of a particular cell from it's DOM element\n\t\t * and column index including hidden columns\n\t\t *  @param {node} node this can either be a TR, TD or TH in the table's body\n\t\t *  @returns {int} If nNode is given as a TR, then a single index is returned, or\n\t\t *    if given as a cell, an array of [row index, column index (visible),\n\t\t *    column index (all)] is given.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example tbody td').click( function () {\n\t\t *        // Get the position of the current data from the node\n\t\t *        var aPos = oTable.fnGetPosition( this );\n\t\t *\n\t\t *        // Get the data array for this row\n\t\t *        var aData = oTable.fnGetData( aPos[0] );\n\t\t *\n\t\t *        // Update the data array and return the value\n\t\t *        aData[ aPos[1] ] = 'clicked';\n\t\t *        this.innerHTML = 'clicked';\n\t\t *      } );\n\t\t *\n\t\t *      // Init DataTables\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetPosition = function( node )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar nodeName = node.nodeName.toUpperCase();\n\t\t\n\t\t\tif ( nodeName == 'TR' ) {\n\t\t\t\treturn api.row( node ).index();\n\t\t\t}\n\t\t\telse if ( nodeName == 'TD' || nodeName == 'TH' ) {\n\t\t\t\tvar cell = api.cell( node ).index();\n\t\t\n\t\t\t\treturn [\n\t\t\t\t\tcell.row,\n\t\t\t\t\tcell.columnVisible,\n\t\t\t\t\tcell.column\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Check to see if a row is 'open' or not.\n\t\t *  @param {node} nTr the table row to check\n\t\t *  @returns {boolean} true if the row is currently open, false otherwise\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnIsOpen = function( nTr )\n\t\t{\n\t\t\treturn this.api( true ).row( nTr ).child.isShown();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will place a new row directly after a row which is currently\n\t\t * on display on the page, with the HTML contents that is passed into the\n\t\t * function. This can be used, for example, to ask for confirmation that a\n\t\t * particular record should be deleted.\n\t\t *  @param {node} nTr The table row to 'open'\n\t\t *  @param {string|node|jQuery} mHtml The HTML to put into the row\n\t\t *  @param {string} sClass Class to give the new TD cell\n\t\t *  @returns {node} The row opened. Note that if the table row passed in as the\n\t\t *    first parameter, is not found in the table, this method will silently\n\t\t *    return.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnOpen = function( nTr, mHtml, sClass )\n\t\t{\n\t\t\treturn this.api( true )\n\t\t\t\t.row( nTr )\n\t\t\t\t.child( mHtml, sClass )\n\t\t\t\t.show()\n\t\t\t\t.child()[0];\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Change the pagination - provides the internal logic for pagination in a simple API\n\t\t * function. With this function you can have a DataTables table go to the next,\n\t\t * previous, first or last pages.\n\t\t *  @param {string|int} mAction Paging action to take: \"first\", \"previous\", \"next\" or \"last\"\n\t\t *    or page number to jump to (integer), note that page 0 is the first page.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnPageChange( 'next' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnPageChange = function ( mAction, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).page( mAction );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw(false);\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Show a particular column\n\t\t *  @param {int} iCol The column whose display should be changed\n\t\t *  @param {bool} bShow Show (true) or hide (false) the column\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Hide the second column after initialisation\n\t\t *      oTable.fnSetColumnVis( 1, false );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSetColumnVis = function ( iCol, bShow, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).column( iCol ).visible( bShow );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.columns.adjust().draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the settings for a particular table for external manipulation\n\t\t *  @returns {object} DataTables settings object. See\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      var oSettings = oTable.fnSettings();\n\t\t *\n\t\t *      // Show an example parameter from the settings\n\t\t *      alert( oSettings._iDisplayStart );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSettings = function()\n\t\t{\n\t\t\treturn _fnSettingsFromNode( this[_ext.iApiIndex] );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Sort the table by a particular column\n\t\t *  @param {int} iCol the data index to sort on. Note that this will not match the\n\t\t *    'display index' if you have hidden data entries\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort immediately with columns 0 and 1\n\t\t *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSort = function( aaSort )\n\t\t{\n\t\t\tthis.api( true ).order( aaSort ).draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Attach a sort listener to an element for a given column\n\t\t *  @param {node} nNode the element to attach the sort listener to\n\t\t *  @param {int} iColumn the column that a click on this node will sort on\n\t\t *  @param {function} [fnCallback] callback function when sort is run\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort on column 1, when 'sorter' is clicked on\n\t\t *      oTable.fnSortListener( document.getElementById('sorter'), 1 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSortListener = function( nNode, iColumn, fnCallback )\n\t\t{\n\t\t\tthis.api( true ).order.listener( nNode, iColumn, fnCallback );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Update a table cell or row - this method will accept either a single value to\n\t\t * update the cell with, an array of values with one element for each column or\n\t\t * an object in the same format as the original data source. The function is\n\t\t * self-referencing in order to make the multi column updates easier.\n\t\t *  @param {object|array|string} mData Data to update the cell/row with\n\t\t *  @param {node|int} mRow TR element you want to update or the aoData index\n\t\t *  @param {int} [iColumn] The column to update, give as null or undefined to\n\t\t *    update a whole row.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @param {bool} [bAction=true] Perform pre-draw actions or not\n\t\t *  @returns {int} 0 on success, 1 on error\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell\n\t\t *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row\n\t\t *    } );\n\t\t */\n\t\tthis.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === undefined || iColumn === null ) {\n\t\t\t\tapi.row( mRow ).data( mData );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.cell( mRow, iColumn ).data( mData );\n\t\t\t}\n\t\t\n\t\t\tif ( bAction === undefined || bAction ) {\n\t\t\t\tapi.columns.adjust();\n\t\t\t}\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Provide a common method for plug-ins to check the version of DataTables being used, in order\n\t\t * to ensure compatibility.\n\t\t *  @param {string} sVersion Version string to check for, in the format \"X.Y.Z\". Note that the\n\t\t *    formats \"X\" and \"X.Y\" are also acceptable.\n\t\t *  @returns {boolean} true if this version of DataTables is greater or equal to the required\n\t\t *    version, or false if this version of DataTales is not suitable\n\t\t *  @method\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      alert( oTable.fnVersionCheck( '1.9.0' ) );\n\t\t *    } );\n\t\t */\n\t\tthis.fnVersionCheck = _ext.fnVersionCheck;\n\t\t\n\n\t\tvar _that = this;\n\t\tvar emptyInit = options === undefined;\n\t\tvar len = this.length;\n\n\t\tif ( emptyInit ) {\n\t\t\toptions = {};\n\t\t}\n\n\t\tthis.oApi = this.internal = _ext.internal;\n\n\t\t// Extend with old style plug-in API methods\n\t\tfor ( var fn in DataTable.ext.internal ) {\n\t\t\tif ( fn ) {\n\t\t\t\tthis[fn] = _fnExternApiFunc(fn);\n\t\t\t}\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\t// For each initialisation we want to give it a clean initialisation\n\t\t\t// object that can be bashed around\n\t\t\tvar o = {};\n\t\t\tvar oInit = len > 1 ? // optimisation for single table case\n\t\t\t\t_fnExtend( o, options, true ) :\n\t\t\t\toptions;\n\n\t\t\t/*global oInit,_that,emptyInit*/\n\t\t\tvar i=0, iLen, j, jLen, k, kLen;\n\t\t\tvar sId = this.getAttribute( 'id' );\n\t\t\tvar bInitHandedOff = false;\n\t\t\tvar defaults = DataTable.defaults;\n\t\t\tvar $this = $(this);\n\t\t\t\n\t\t\t\n\t\t\t/* Sanity check */\n\t\t\tif ( this.nodeName.toLowerCase() != 'table' )\n\t\t\t{\n\t\t\t\t_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/* Backwards compatibility for the defaults */\n\t\t\t_fnCompatOpts( defaults );\n\t\t\t_fnCompatCols( defaults.column );\n\t\t\t\n\t\t\t/* Convert the camel-case defaults to Hungarian */\n\t\t\t_fnCamelToHungarian( defaults, defaults, true );\n\t\t\t_fnCamelToHungarian( defaults.column, defaults.column, true );\n\t\t\t\n\t\t\t/* Setting up the initialisation object */\n\t\t\t_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/* Check to see if we are re-initialising a table */\n\t\t\tvar allSettings = DataTable.settings;\n\t\t\tfor ( i=0, iLen=allSettings.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tvar s = allSettings[i];\n\t\t\t\n\t\t\t\t/* Base check on table node */\n\t\t\t\tif ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )\n\t\t\t\t{\n\t\t\t\t\tvar bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;\n\t\t\t\t\tvar bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;\n\t\t\t\n\t\t\t\t\tif ( emptyInit || bRetrieve )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn s.oInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( bDestroy )\n\t\t\t\t\t{\n\t\t\t\t\t\ts.oInstance.fnDestroy();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* If the element we are initialising has the same ID as a table which was previously\n\t\t\t\t * initialised, but the table nodes don't match (from before) then we destroy the old\n\t\t\t\t * instance by simply deleting it. This is under the assumption that the table has been\n\t\t\t\t * destroyed by other methods. Anyone using non-id selectors will need to do this manually\n\t\t\t\t */\n\t\t\t\tif ( s.sTableId == this.id )\n\t\t\t\t{\n\t\t\t\t\tallSettings.splice( i, 1 );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Ensure the table has an ID - required for accessibility */\n\t\t\tif ( sId === null || sId === \"\" )\n\t\t\t{\n\t\t\t\tsId = \"DataTables_Table_\"+(DataTable.ext._unique++);\n\t\t\t\tthis.id = sId;\n\t\t\t}\n\t\t\t\n\t\t\t/* Create the settings object for this table and set some of the default parameters */\n\t\t\tvar oSettings = $.extend( true, {}, DataTable.models.oSettings, {\n\t\t\t\t\"sDestroyWidth\": $this[0].style.width,\n\t\t\t\t\"sInstance\":     sId,\n\t\t\t\t\"sTableId\":      sId\n\t\t\t} );\n\t\t\toSettings.nTable = this;\n\t\t\toSettings.oApi   = _that.internal;\n\t\t\toSettings.oInit  = oInit;\n\t\t\t\n\t\t\tallSettings.push( oSettings );\n\t\t\t\n\t\t\t// Need to add the instance after the instance after the settings object has been added\n\t\t\t// to the settings array, so we can self reference the table instance if more than one\n\t\t\toSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();\n\t\t\t\n\t\t\t// Backwards compatibility, before we apply all the defaults\n\t\t\t_fnCompatOpts( oInit );\n\t\t\t\n\t\t\tif ( oInit.oLanguage )\n\t\t\t{\n\t\t\t\t_fnLanguageCompat( oInit.oLanguage );\n\t\t\t}\n\t\t\t\n\t\t\t// If the length menu is given, but the init display length is not, use the length menu\n\t\t\tif ( oInit.aLengthMenu && ! oInit.iDisplayLength )\n\t\t\t{\n\t\t\t\toInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?\n\t\t\t\t\toInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];\n\t\t\t}\n\t\t\t\n\t\t\t// Apply the defaults and init options to make a single init object will all\n\t\t\t// options defined from defaults and instance options.\n\t\t\toInit = _fnExtend( $.extend( true, {}, defaults ), oInit );\n\t\t\t\n\t\t\t\n\t\t\t// Map the initialisation options onto the settings object\n\t\t\t_fnMap( oSettings.oFeatures, oInit, [\n\t\t\t\t\"bPaginate\",\n\t\t\t\t\"bLengthChange\",\n\t\t\t\t\"bFilter\",\n\t\t\t\t\"bSort\",\n\t\t\t\t\"bSortMulti\",\n\t\t\t\t\"bInfo\",\n\t\t\t\t\"bProcessing\",\n\t\t\t\t\"bAutoWidth\",\n\t\t\t\t\"bSortClasses\",\n\t\t\t\t\"bServerSide\",\n\t\t\t\t\"bDeferRender\"\n\t\t\t] );\n\t\t\t_fnMap( oSettings, oInit, [\n\t\t\t\t\"asStripeClasses\",\n\t\t\t\t\"ajax\",\n\t\t\t\t\"fnServerData\",\n\t\t\t\t\"fnFormatNumber\",\n\t\t\t\t\"sServerMethod\",\n\t\t\t\t\"aaSorting\",\n\t\t\t\t\"aaSortingFixed\",\n\t\t\t\t\"aLengthMenu\",\n\t\t\t\t\"sPaginationType\",\n\t\t\t\t\"sAjaxSource\",\n\t\t\t\t\"sAjaxDataProp\",\n\t\t\t\t\"iStateDuration\",\n\t\t\t\t\"sDom\",\n\t\t\t\t\"bSortCellsTop\",\n\t\t\t\t\"iTabIndex\",\n\t\t\t\t\"fnStateLoadCallback\",\n\t\t\t\t\"fnStateSaveCallback\",\n\t\t\t\t\"renderer\",\n\t\t\t\t\"searchDelay\",\n\t\t\t\t\"rowId\",\n\t\t\t\t[ \"iCookieDuration\", \"iStateDuration\" ], // backwards compat\n\t\t\t\t[ \"oSearch\", \"oPreviousSearch\" ],\n\t\t\t\t[ \"aoSearchCols\", \"aoPreSearchCols\" ],\n\t\t\t\t[ \"iDisplayLength\", \"_iDisplayLength\" ],\n\t\t\t\t[ \"bJQueryUI\", \"bJUI\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oScroll, oInit, [\n\t\t\t\t[ \"sScrollX\", \"sX\" ],\n\t\t\t\t[ \"sScrollXInner\", \"sXInner\" ],\n\t\t\t\t[ \"sScrollY\", \"sY\" ],\n\t\t\t\t[ \"bScrollCollapse\", \"bCollapse\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oLanguage, oInit, \"fnInfoCallback\" );\n\t\t\t\n\t\t\t/* Callback functions which are array driven */\n\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );\n\t\t\t\n\t\t\toSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );\n\t\t\t\n\t\t\t/* Browser support detection */\n\t\t\t_fnBrowserDetect( oSettings );\n\t\t\t\n\t\t\tvar oClasses = oSettings.oClasses;\n\t\t\t\n\t\t\t// @todo Remove in 1.11\n\t\t\tif ( oInit.bJQueryUI )\n\t\t\t{\n\t\t\t\t/* Use the JUI classes object for display. You could clone the oStdClasses object if\n\t\t\t\t * you want to have multiple tables with multiple independent classes\n\t\t\t\t */\n\t\t\t\t$.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );\n\t\t\t\n\t\t\t\tif ( oInit.sDom === defaults.sDom && defaults.sDom === \"lfrtip\" )\n\t\t\t\t{\n\t\t\t\t\t/* Set the DOM to use a layout suitable for jQuery UI's theming */\n\t\t\t\t\toSettings.sDom = '<\"H\"lfr>t<\"F\"ip>';\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( ! oSettings.renderer ) {\n\t\t\t\t\toSettings.renderer = 'jqueryui';\n\t\t\t\t}\n\t\t\t\telse if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {\n\t\t\t\t\toSettings.renderer.header = 'jqueryui';\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );\n\t\t\t}\n\t\t\t$this.addClass( oClasses.sTable );\n\t\t\t\n\t\t\t\n\t\t\tif ( oSettings.iInitDisplayStart === undefined )\n\t\t\t{\n\t\t\t\t/* Display start point, taking into account the save saving */\n\t\t\t\toSettings.iInitDisplayStart = oInit.iDisplayStart;\n\t\t\t\toSettings._iDisplayStart = oInit.iDisplayStart;\n\t\t\t}\n\t\t\t\n\t\t\tif ( oInit.iDeferLoading !== null )\n\t\t\t{\n\t\t\t\toSettings.bDeferLoading = true;\n\t\t\t\tvar tmp = $.isArray( oInit.iDeferLoading );\n\t\t\t\toSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;\n\t\t\t\toSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;\n\t\t\t}\n\t\t\t\n\t\t\t/* Language definitions */\n\t\t\tvar oLanguage = oSettings.oLanguage;\n\t\t\t$.extend( true, oLanguage, oInit.oLanguage );\n\t\t\t\n\t\t\tif ( oLanguage.sUrl )\n\t\t\t{\n\t\t\t\t/* Get the language definitions from a file - because this Ajax call makes the language\n\t\t\t\t * get async to the remainder of this function we use bInitHandedOff to indicate that\n\t\t\t\t * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor\n\t\t\t\t */\n\t\t\t\t$.ajax( {\n\t\t\t\t\tdataType: 'json',\n\t\t\t\t\turl: oLanguage.sUrl,\n\t\t\t\t\tsuccess: function ( json ) {\n\t\t\t\t\t\t_fnLanguageCompat( json );\n\t\t\t\t\t\t_fnCamelToHungarian( defaults.oLanguage, json );\n\t\t\t\t\t\t$.extend( true, oLanguage, json );\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t},\n\t\t\t\t\terror: function () {\n\t\t\t\t\t\t// Error occurred loading language file, continue on as best we can\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tbInitHandedOff = true;\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Stripes\n\t\t\t */\n\t\t\tif ( oInit.asStripeClasses === null )\n\t\t\t{\n\t\t\t\toSettings.asStripeClasses =[\n\t\t\t\t\toClasses.sStripeOdd,\n\t\t\t\t\toClasses.sStripeEven\n\t\t\t\t];\n\t\t\t}\n\t\t\t\n\t\t\t/* Remove row stripe classes if they are already on the table row */\n\t\t\tvar stripeClasses = oSettings.asStripeClasses;\n\t\t\tvar rowOne = $this.children('tbody').find('tr').eq(0);\n\t\t\tif ( $.inArray( true, $.map( stripeClasses, function(el, i) {\n\t\t\t\treturn rowOne.hasClass(el);\n\t\t\t} ) ) !== -1 ) {\n\t\t\t\t$('tbody tr', this).removeClass( stripeClasses.join(' ') );\n\t\t\t\toSettings.asDestroyStripes = stripeClasses.slice();\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Columns\n\t\t\t * See if we should load columns automatically or use defined ones\n\t\t\t */\n\t\t\tvar anThs = [];\n\t\t\tvar aoColumnsInit;\n\t\t\tvar nThead = this.getElementsByTagName('thead');\n\t\t\tif ( nThead.length !== 0 )\n\t\t\t{\n\t\t\t\t_fnDetectHeader( oSettings.aoHeader, nThead[0] );\n\t\t\t\tanThs = _fnGetUniqueThs( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* If not given a column array, generate one with nulls */\n\t\t\tif ( oInit.aoColumns === null )\n\t\t\t{\n\t\t\t\taoColumnsInit = [];\n\t\t\t\tfor ( i=0, iLen=anThs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\taoColumnsInit.push( null );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoColumnsInit = oInit.aoColumns;\n\t\t\t}\n\t\t\t\n\t\t\t/* Add the columns */\n\t\t\tfor ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t_fnAddColumn( oSettings, anThs ? anThs[i] : null );\n\t\t\t}\n\t\t\t\n\t\t\t/* Apply the column definitions */\n\t\t\t_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {\n\t\t\t\t_fnColumnOptions( oSettings, iCol, oDef );\n\t\t\t} );\n\t\t\t\n\t\t\t/* HTML5 attribute detection - build an mData object automatically if the\n\t\t\t * attributes are found\n\t\t\t */\n\t\t\tif ( rowOne.length ) {\n\t\t\t\tvar a = function ( cell, name ) {\n\t\t\t\t\treturn cell.getAttribute( 'data-'+name ) !== null ? name : null;\n\t\t\t\t};\n\t\t\t\n\t\t\t\t$( rowOne[0] ).children('th, td').each( function (i, cell) {\n\t\t\t\t\tvar col = oSettings.aoColumns[i];\n\t\t\t\n\t\t\t\t\tif ( col.mData === i ) {\n\t\t\t\t\t\tvar sort = a( cell, 'sort' ) || a( cell, 'order' );\n\t\t\t\t\t\tvar filter = a( cell, 'filter' ) || a( cell, 'search' );\n\t\t\t\n\t\t\t\t\t\tif ( sort !== null || filter !== null ) {\n\t\t\t\t\t\t\tcol.mData = {\n\t\t\t\t\t\t\t\t_:      i+'.display',\n\t\t\t\t\t\t\t\tsort:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\ttype:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\tfilter: filter !== null ? i+'.@data-'+filter : undefined\n\t\t\t\t\t\t\t};\n\t\t\t\n\t\t\t\t\t\t\t_fnColumnOptions( oSettings, i );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\t\n\t\t\tvar features = oSettings.oFeatures;\n\t\t\tvar loadedInit = function () {\n\t\t\t\t/*\n\t\t\t\t * Sorting\n\t\t\t\t * @todo For modularisation (1.11) this needs to do into a sort start up handler\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// If aaSorting is not defined, then we use the first indicator in asSorting\n\t\t\t\t// in case that has been altered, so the default sort reflects that option\n\t\t\t\tif ( oInit.aaSorting === undefined ) {\n\t\t\t\t\tvar sorting = oSettings.aaSorting;\n\t\t\t\t\tfor ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {\n\t\t\t\t\t\tsorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Do a first pass on the sorting classes (allows any size changes to be taken into\n\t\t\t\t * account, and also will apply sorting disabled classes if disabled\n\t\t\t\t */\n\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\n\t\t\t\tif ( features.bSort ) {\n\t\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\t\tif ( oSettings.bSorted ) {\n\t\t\t\t\t\t\tvar aSort = _fnSortFlatten( oSettings );\n\t\t\t\t\t\t\tvar sortedColumns = {};\n\t\t\t\n\t\t\t\t\t\t\t$.each( aSort, function (i, val) {\n\t\t\t\t\t\t\t\tsortedColumns[ val.src ] = val.dir;\n\t\t\t\t\t\t\t} );\n\t\t\t\n\t\t\t\t\t\t\t_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );\n\t\t\t\t\t\t\t_fnSortAria( oSettings );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\tif ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {\n\t\t\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\t\t}\n\t\t\t\t}, 'sc' );\n\t\t\t\n\t\t\t\n\t\t\t\t/*\n\t\t\t\t * Final init\n\t\t\t\t * Cache the header, body and footer as required, creating them if needed\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// Work around for Webkit bug 83867 - store the caption-side before removing from doc\n\t\t\t\tvar captions = $this.children('caption').each( function () {\n\t\t\t\t\tthis._captionSide = $(this).css('caption-side');\n\t\t\t\t} );\n\t\t\t\n\t\t\t\tvar thead = $this.children('thead');\n\t\t\t\tif ( thead.length === 0 ) {\n\t\t\t\t\tthead = $('<thead/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTHead = thead[0];\n\t\t\t\n\t\t\t\tvar tbody = $this.children('tbody');\n\t\t\t\tif ( tbody.length === 0 ) {\n\t\t\t\t\ttbody = $('<tbody/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTBody = tbody[0];\n\t\t\t\n\t\t\t\tvar tfoot = $this.children('tfoot');\n\t\t\t\tif ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\") ) {\n\t\t\t\t\t// If we are a scrolling table, and no footer has been given, then we need to create\n\t\t\t\t\t// a tfoot element for the caption element to be appended to\n\t\t\t\t\ttfoot = $('<tfoot/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( tfoot.length === 0 || tfoot.children().length === 0 ) {\n\t\t\t\t\t$this.addClass( oClasses.sNoFooter );\n\t\t\t\t}\n\t\t\t\telse if ( tfoot.length > 0 ) {\n\t\t\t\t\toSettings.nTFoot = tfoot[0];\n\t\t\t\t\t_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Check if there is data passing into the constructor */\n\t\t\t\tif ( oInit.aaData ) {\n\t\t\t\t\tfor ( i=0 ; i<oInit.aaData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( oSettings, oInit.aaData[ i ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {\n\t\t\t\t\t/* Grab the data from the page - only do this when deferred loading or no Ajax\n\t\t\t\t\t * source since there is no point in reading the DOM data if we are then going\n\t\t\t\t\t * to replace it with Ajax data\n\t\t\t\t\t */\n\t\t\t\t\t_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Copy the data index array */\n\t\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\n\t\t\t\t/* Initialisation complete - table can be drawn */\n\t\t\t\toSettings.bInitialised = true;\n\t\t\t\n\t\t\t\t/* Check if we need to initialise the table (it might not have been handed off to the\n\t\t\t\t * language processor)\n\t\t\t\t */\n\t\t\t\tif ( bInitHandedOff === false ) {\n\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\t/* Must be done after everything which can be overridden by the state saving! */\n\t\t\tif ( oInit.bStateSave )\n\t\t\t{\n\t\t\t\tfeatures.bStateSave = true;\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );\n\t\t\t\t_fnLoadState( oSettings, oInit, loadedInit );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadedInit();\n\t\t\t}\n\t\t\t\n\t\t} );\n\t\t_that = null;\n\t\treturn this;\n\t};\n\n\t\n\t/*\n\t * It is useful to have variables which are scoped locally so only the\n\t * DataTables functions can access them and they don't leak into global space.\n\t * At the same time these functions are often useful over multiple files in the\n\t * core and API, so we list, or at least document, all variables which are used\n\t * by DataTables as private variables here. This also ensures that there is no\n\t * clashing of variable names and that they can easily referenced for reuse.\n\t */\n\t\n\t\n\t// Defined else where\n\t//  _selector_run\n\t//  _selector_opts\n\t//  _selector_first\n\t//  _selector_row_indexes\n\t\n\tvar _ext; // DataTable.ext\n\tvar _Api; // DataTable.Api\n\tvar _api_register; // DataTable.Api.register\n\tvar _api_registerPlural; // DataTable.Api.registerPlural\n\t\n\tvar _re_dic = {};\n\tvar _re_new_lines = /[\\r\\n]/g;\n\tvar _re_html = /<.*?>/g;\n\t\n\t// This is not strict ISO8601 - Date.parse() is quite lax, although\n\t// implementations differ between browsers.\n\tvar _re_date = /^\\d{2,4}[\\.\\/\\-]\\d{1,2}[\\.\\/\\-]\\d{1,2}([T ]{1}\\d{1,2}[:\\.]\\d{2}([\\.:]\\d{2})?)?$/;\n\t\n\t// Escape regular expression special characters\n\tvar _re_escape_regex = new RegExp( '(\\\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\\\', '$', '^', '-' ].join('|\\\\') + ')', 'g' );\n\t\n\t// http://en.wikipedia.org/wiki/Foreign_exchange_market\n\t// - \\u20BD - Russian ruble.\n\t// - \\u20a9 - South Korean Won\n\t// - \\u20BA - Turkish Lira\n\t// - \\u20B9 - Indian Rupee\n\t// - R - Brazil (R$) and South Africa\n\t// - fr - Swiss Franc\n\t// - kr - Swedish krona, Norwegian krone and Danish krone\n\t// - \\u2009 is thin space and \\u202F is narrow no-break space, both used in many\n\t//   standards as thousands separators.\n\tvar _re_formatted_numeric = /[',$£€¥%\\u2009\\u202F\\u20BD\\u20a9\\u20BArfk]/gi;\n\t\n\t\n\tvar _empty = function ( d ) {\n\t\treturn !d || d === true || d === '-' ? true : false;\n\t};\n\t\n\t\n\tvar _intVal = function ( s ) {\n\t\tvar integer = parseInt( s, 10 );\n\t\treturn !isNaN(integer) && isFinite(s) ? integer : null;\n\t};\n\t\n\t// Convert from a formatted number with characters other than `.` as the\n\t// decimal place, to a Javascript number\n\tvar _numToDecimal = function ( num, decimalPoint ) {\n\t\t// Cache created regular expressions for speed as this function is called often\n\t\tif ( ! _re_dic[ decimalPoint ] ) {\n\t\t\t_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );\n\t\t}\n\t\treturn typeof num === 'string' && decimalPoint !== '.' ?\n\t\t\tnum.replace( /\\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :\n\t\t\tnum;\n\t};\n\t\n\t\n\tvar _isNumber = function ( d, decimalPoint, formatted ) {\n\t\tvar strType = typeof d === 'string';\n\t\n\t\t// If empty return immediately so there must be a number if it is a\n\t\t// formatted string (this stops the string \"k\", or \"kr\", etc being detected\n\t\t// as a formatted number for currency\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tif ( decimalPoint && strType ) {\n\t\t\td = _numToDecimal( d, decimalPoint );\n\t\t}\n\t\n\t\tif ( formatted && strType ) {\n\t\t\td = d.replace( _re_formatted_numeric, '' );\n\t\t}\n\t\n\t\treturn !isNaN( parseFloat(d) ) && isFinite( d );\n\t};\n\t\n\t\n\t// A string without HTML in it can be considered to be HTML still\n\tvar _isHtml = function ( d ) {\n\t\treturn _empty( d ) || typeof d === 'string';\n\t};\n\t\n\t\n\tvar _htmlNumeric = function ( d, decimalPoint, formatted ) {\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tvar html = _isHtml( d );\n\t\treturn ! html ?\n\t\t\tnull :\n\t\t\t_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?\n\t\t\t\ttrue :\n\t\t\t\tnull;\n\t};\n\t\n\t\n\tvar _pluck = function ( a, prop, prop2 ) {\n\t\tvar out = [];\n\t\tvar i=0, ien=a.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] && a[i][ prop ] ) {\n\t\t\t\t\tout.push( a[i][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] ) {\n\t\t\t\t\tout.push( a[i][ prop ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t// Basically the same as _pluck, but rather than looping over `a` we use `order`\n\t// as the indexes to pick from `a`\n\tvar _pluck_order = function ( a, order, prop, prop2 )\n\t{\n\t\tvar out = [];\n\t\tvar i=0, ien=order.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[ order[i] ][ prop ] ) {\n\t\t\t\t\tout.push( a[ order[i] ][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tout.push( a[ order[i] ][ prop ] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _range = function ( len, start )\n\t{\n\t\tvar out = [];\n\t\tvar end;\n\t\n\t\tif ( start === undefined ) {\n\t\t\tstart = 0;\n\t\t\tend = len;\n\t\t}\n\t\telse {\n\t\t\tend = start;\n\t\t\tstart = len;\n\t\t}\n\t\n\t\tfor ( var i=start ; i<end ; i++ ) {\n\t\t\tout.push( i );\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _removeEmpty = function ( a )\n\t{\n\t\tvar out = [];\n\t\n\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\tif ( a[i] ) { // careful - will remove all falsy values!\n\t\t\t\tout.push( a[i] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _stripHtml = function ( d ) {\n\t\treturn d.replace( _re_html, '' );\n\t};\n\t\n\t\n\t/**\n\t * Find the unique elements in a source array.\n\t *\n\t * @param  {array} src Source array\n\t * @return {array} Array of unique items\n\t * @ignore\n\t */\n\tvar _unique = function ( src )\n\t{\n\t\t// A faster unique method is to use object keys to identify used values,\n\t\t// but this doesn't work with arrays or objects, which we must also\n\t\t// consider. See jsperf.com/compare-array-unique-versions/4 for more\n\t\t// information.\n\t\tvar\n\t\t\tout = [],\n\t\t\tval,\n\t\t\ti, ien=src.length,\n\t\t\tj, k=0;\n\t\n\t\tagain: for ( i=0 ; i<ien ; i++ ) {\n\t\t\tval = src[i];\n\t\n\t\t\tfor ( j=0 ; j<k ; j++ ) {\n\t\t\t\tif ( out[j] === val ) {\n\t\t\t\t\tcontinue again;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tout.push( val );\n\t\t\tk++;\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t/**\n\t * DataTables utility methods\n\t * \n\t * This namespace provides helper methods that DataTables uses internally to\n\t * create a DataTable, but which are not exclusively used only for DataTables.\n\t * These methods can be used by extension authors to save the duplication of\n\t * code.\n\t *\n\t *  @namespace\n\t */\n\tDataTable.util = {\n\t\t/**\n\t\t * Throttle the calls to a function. Arguments and context are maintained\n\t\t * for the throttled function.\n\t\t *\n\t\t * @param {function} fn Function to be called\n\t\t * @param {integer} freq Call frequency in mS\n\t\t * @return {function} Wrapped function\n\t\t */\n\t\tthrottle: function ( fn, freq ) {\n\t\t\tvar\n\t\t\t\tfrequency = freq !== undefined ? freq : 200,\n\t\t\t\tlast,\n\t\t\t\ttimer;\n\t\n\t\t\treturn function () {\n\t\t\t\tvar\n\t\t\t\t\tthat = this,\n\t\t\t\t\tnow  = +new Date(),\n\t\t\t\t\targs = arguments;\n\t\n\t\t\t\tif ( last && now < last + frequency ) {\n\t\t\t\t\tclearTimeout( timer );\n\t\n\t\t\t\t\ttimer = setTimeout( function () {\n\t\t\t\t\t\tlast = undefined;\n\t\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t\t}, frequency );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlast = now;\n\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Escape a string such that it can be used in a regular expression\n\t\t *\n\t\t *  @param {string} val string to escape\n\t\t *  @returns {string} escaped string\n\t\t */\n\t\tescapeRegex: function ( val ) {\n\t\t\treturn val.replace( _re_escape_regex, '\\\\$1' );\n\t\t}\n\t};\n\t\n\t\n\t\n\t/**\n\t * Create a mapping object that allows camel case parameters to be looked up\n\t * for their Hungarian counterparts. The mapping is stored in a private\n\t * parameter called `_hungarianMap` which can be accessed on the source object.\n\t *  @param {object} o\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnHungarianMap ( o )\n\t{\n\t\tvar\n\t\t\thungarian = 'a aa ai ao as b fn i m o s ',\n\t\t\tmatch,\n\t\t\tnewKey,\n\t\t\tmap = {};\n\t\n\t\t$.each( o, function (key, val) {\n\t\t\tmatch = key.match(/^([^A-Z]+?)([A-Z])/);\n\t\n\t\t\tif ( match && hungarian.indexOf(match[1]+' ') !== -1 )\n\t\t\t{\n\t\t\t\tnewKey = key.replace( match[0], match[2].toLowerCase() );\n\t\t\t\tmap[ newKey ] = key;\n\t\n\t\t\t\tif ( match[1] === 'o' )\n\t\t\t\t{\n\t\t\t\t\t_fnHungarianMap( o[key] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\n\t\to._hungarianMap = map;\n\t}\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian, based on a Hungarian map\n\t * created by _fnHungarianMap.\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCamelToHungarian ( src, user, force )\n\t{\n\t\tif ( ! src._hungarianMap ) {\n\t\t\t_fnHungarianMap( src );\n\t\t}\n\t\n\t\tvar hungarianKey;\n\t\n\t\t$.each( user, function (key, val) {\n\t\t\thungarianKey = src._hungarianMap[ key ];\n\t\n\t\t\tif ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )\n\t\t\t{\n\t\t\t\t// For objects, we need to buzz down into the object to copy parameters\n\t\t\t\tif ( hungarianKey.charAt(0) === 'o' )\n\t\t\t\t{\n\t\t\t\t\t// Copy the camelCase options over to the hungarian\n\t\t\t\t\tif ( ! user[ hungarianKey ] ) {\n\t\t\t\t\t\tuser[ hungarianKey ] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, user[hungarianKey], user[key] );\n\t\n\t\t\t\t\t_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tuser[hungarianKey] = user[ key ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Language compatibility - when certain options are given, and others aren't, we\n\t * need to duplicate the values over, in order to provide backwards compatibility\n\t * with older language files.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLanguageCompat( lang )\n\t{\n\t\tvar defaults = DataTable.defaults.oLanguage;\n\t\tvar zeroRecords = lang.sZeroRecords;\n\t\n\t\t/* Backwards compatibility - if there is no sEmptyTable given, then use the same as\n\t\t * sZeroRecords - assuming that is given.\n\t\t */\n\t\tif ( ! lang.sEmptyTable && zeroRecords &&\n\t\t\tdefaults.sEmptyTable === \"No data available in table\" )\n\t\t{\n\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );\n\t\t}\n\t\n\t\t/* Likewise with loading records */\n\t\tif ( ! lang.sLoadingRecords && zeroRecords &&\n\t\t\tdefaults.sLoadingRecords === \"Loading...\" )\n\t\t{\n\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );\n\t\t}\n\t\n\t\t// Old parameter name of the thousands separator mapped onto the new\n\t\tif ( lang.sInfoThousands ) {\n\t\t\tlang.sThousands = lang.sInfoThousands;\n\t\t}\n\t\n\t\tvar decimal = lang.sDecimal;\n\t\tif ( decimal ) {\n\t\t\t_addNumericSort( decimal );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Map one parameter onto another\n\t *  @param {object} o Object to map\n\t *  @param {*} knew The new parameter name\n\t *  @param {*} old The old parameter name\n\t */\n\tvar _fnCompatMap = function ( o, knew, old ) {\n\t\tif ( o[ knew ] !== undefined ) {\n\t\t\to[ old ] = o[ knew ];\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for the main DT options. Note that the new\n\t * options are mapped onto the old parameters, so this is an external interface\n\t * change only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatOpts ( init )\n\t{\n\t\t_fnCompatMap( init, 'ordering',      'bSort' );\n\t\t_fnCompatMap( init, 'orderMulti',    'bSortMulti' );\n\t\t_fnCompatMap( init, 'orderClasses',  'bSortClasses' );\n\t\t_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );\n\t\t_fnCompatMap( init, 'order',         'aaSorting' );\n\t\t_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );\n\t\t_fnCompatMap( init, 'paging',        'bPaginate' );\n\t\t_fnCompatMap( init, 'pagingType',    'sPaginationType' );\n\t\t_fnCompatMap( init, 'pageLength',    'iDisplayLength' );\n\t\t_fnCompatMap( init, 'searching',     'bFilter' );\n\t\n\t\t// Boolean initialisation of x-scrolling\n\t\tif ( typeof init.sScrollX === 'boolean' ) {\n\t\t\tinit.sScrollX = init.sScrollX ? '100%' : '';\n\t\t}\n\t\tif ( typeof init.scrollX === 'boolean' ) {\n\t\t\tinit.scrollX = init.scrollX ? '100%' : '';\n\t\t}\n\t\n\t\t// Column search objects are in an array, so it needs to be converted\n\t\t// element by element\n\t\tvar searchCols = init.aoSearchCols;\n\t\n\t\tif ( searchCols ) {\n\t\t\tfor ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {\n\t\t\t\tif ( searchCols[i] ) {\n\t\t\t\t\t_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for column options. Note that the new options\n\t * are mapped onto the old parameters, so this is an external interface change\n\t * only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatCols ( init )\n\t{\n\t\t_fnCompatMap( init, 'orderable',     'bSortable' );\n\t\t_fnCompatMap( init, 'orderData',     'aDataSort' );\n\t\t_fnCompatMap( init, 'orderSequence', 'asSorting' );\n\t\t_fnCompatMap( init, 'orderDataType', 'sortDataType' );\n\t\n\t\t// orderData can be given as an integer\n\t\tvar dataSort = init.aDataSort;\n\t\tif ( dataSort && ! $.isArray( dataSort ) ) {\n\t\t\tinit.aDataSort = [ dataSort ];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Browser feature detection for capabilities, quirks\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBrowserDetect( settings )\n\t{\n\t\t// We don't need to do this every time DataTables is constructed, the values\n\t\t// calculated are specific to the browser and OS configuration which we\n\t\t// don't expect to change between initialisations\n\t\tif ( ! DataTable.__browser ) {\n\t\t\tvar browser = {};\n\t\t\tDataTable.__browser = browser;\n\t\n\t\t\t// Scrolling feature / quirks detection\n\t\t\tvar n = $('<div/>')\n\t\t\t\t.css( {\n\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: $(window).scrollLeft()*-1, // allow for scrolling\n\t\t\t\t\theight: 1,\n\t\t\t\t\twidth: 1,\n\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t} )\n\t\t\t\t.append(\n\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\ttop: 1,\n\t\t\t\t\t\t\tleft: 1,\n\t\t\t\t\t\t\twidth: 100,\n\t\t\t\t\t\t\toverflow: 'scroll'\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t\t\t\theight: 10\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t.appendTo( 'body' );\n\t\n\t\t\tvar outer = n.children();\n\t\t\tvar inner = outer.children();\n\t\n\t\t\t// Numbers below, in order, are:\n\t\t\t// inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth\n\t\t\t//\n\t\t\t// IE6 XP:                           100 100 100  83\n\t\t\t// IE7 Vista:                        100 100 100  83\n\t\t\t// IE 8+ Windows:                     83  83 100  83\n\t\t\t// Evergreen Windows:                 83  83 100  83\n\t\t\t// Evergreen Mac with scrollbars:     85  85 100  85\n\t\t\t// Evergreen Mac without scrollbars: 100 100 100 100\n\t\n\t\t\t// Get scrollbar width\n\t\t\tbrowser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;\n\t\n\t\t\t// IE6/7 will oversize a width 100% element inside a scrolling element, to\n\t\t\t// include the width of the scrollbar, while other browsers ensure the inner\n\t\t\t// element is contained without forcing scrolling\n\t\t\tbrowser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;\n\t\n\t\t\t// In rtl text layout, some browsers (most, but not all) will place the\n\t\t\t// scrollbar on the left, rather than the right.\n\t\t\tbrowser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;\n\t\n\t\t\t// IE8- don't provide height and width for getBoundingClientRect\n\t\t\tbrowser.bBounding = n[0].getBoundingClientRect().width ? true : false;\n\t\n\t\t\tn.remove();\n\t\t}\n\t\n\t\t$.extend( settings.oBrowser, DataTable.__browser );\n\t\tsettings.oScroll.iBarWidth = DataTable.__browser.barWidth;\n\t}\n\t\n\t\n\t/**\n\t * Array.prototype reduce[Right] method, used for browsers which don't support\n\t * JS 1.6. Done this way to reduce code size, since we iterate either way\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReduce ( that, fn, init, start, end, inc )\n\t{\n\t\tvar\n\t\t\ti = start,\n\t\t\tvalue,\n\t\t\tisSet = false;\n\t\n\t\tif ( init !== undefined ) {\n\t\t\tvalue = init;\n\t\t\tisSet = true;\n\t\t}\n\t\n\t\twhile ( i !== end ) {\n\t\t\tif ( ! that.hasOwnProperty(i) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\tvalue = isSet ?\n\t\t\t\tfn( value, that[i], i, that ) :\n\t\t\t\tthat[i];\n\t\n\t\t\tisSet = true;\n\t\t\ti += inc;\n\t\t}\n\t\n\t\treturn value;\n\t}\n\t\n\t/**\n\t * Add a column to the list used for the table with default values\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nTh The th element for this column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddColumn( oSettings, nTh )\n\t{\n\t\t// Add column to aoColumns array\n\t\tvar oDefaults = DataTable.defaults.column;\n\t\tvar iCol = oSettings.aoColumns.length;\n\t\tvar oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {\n\t\t\t\"nTh\": nTh ? nTh : document.createElement('th'),\n\t\t\t\"sTitle\":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',\n\t\t\t\"aDataSort\": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],\n\t\t\t\"mData\": oDefaults.mData ? oDefaults.mData : iCol,\n\t\t\tidx: iCol\n\t\t} );\n\t\toSettings.aoColumns.push( oCol );\n\t\n\t\t// Add search object for column specific search. Note that the `searchCols[ iCol ]`\n\t\t// passed into extend can be undefined. This allows the user to give a default\n\t\t// with only some of the parameters defined, and also not give a default\n\t\tvar searchCols = oSettings.aoPreSearchCols;\n\t\tsearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );\n\t\n\t\t// Use the default column options function to initialise classes etc\n\t\t_fnColumnOptions( oSettings, iCol, $(nTh).data() );\n\t}\n\t\n\t\n\t/**\n\t * Apply options for a column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iCol column index to consider\n\t *  @param {object} oOptions object with sType, bVisible and bSearchable etc\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnOptions( oSettings, iCol, oOptions )\n\t{\n\t\tvar oCol = oSettings.aoColumns[ iCol ];\n\t\tvar oClasses = oSettings.oClasses;\n\t\tvar th = $(oCol.nTh);\n\t\n\t\t// Try to get width information from the DOM. We can't get it from CSS\n\t\t// as we'd need to parse the CSS stylesheet. `width` option can override\n\t\tif ( ! oCol.sWidthOrig ) {\n\t\t\t// Width attribute\n\t\t\toCol.sWidthOrig = th.attr('width') || null;\n\t\n\t\t\t// Style attribute\n\t\t\tvar t = (th.attr('style') || '').match(/width:\\s*(\\d+[pxem%]+)/);\n\t\t\tif ( t ) {\n\t\t\t\toCol.sWidthOrig = t[1];\n\t\t\t}\n\t\t}\n\t\n\t\t/* User specified column options */\n\t\tif ( oOptions !== undefined && oOptions !== null )\n\t\t{\n\t\t\t// Backwards compatibility\n\t\t\t_fnCompatCols( oOptions );\n\t\n\t\t\t// Map camel case parameters to their Hungarian counterparts\n\t\t\t_fnCamelToHungarian( DataTable.defaults.column, oOptions );\n\t\n\t\t\t/* Backwards compatibility for mDataProp */\n\t\t\tif ( oOptions.mDataProp !== undefined && !oOptions.mData )\n\t\t\t{\n\t\t\t\toOptions.mData = oOptions.mDataProp;\n\t\t\t}\n\t\n\t\t\tif ( oOptions.sType )\n\t\t\t{\n\t\t\t\toCol._sManualType = oOptions.sType;\n\t\t\t}\n\t\n\t\t\t// `class` is a reserved word in Javascript, so we need to provide\n\t\t\t// the ability to use a valid name for the camel case input\n\t\t\tif ( oOptions.className && ! oOptions.sClass )\n\t\t\t{\n\t\t\t\toOptions.sClass = oOptions.className;\n\t\t\t}\n\t\n\t\t\t$.extend( oCol, oOptions );\n\t\t\t_fnMap( oCol, oOptions, \"sWidth\", \"sWidthOrig\" );\n\t\n\t\t\t/* iDataSort to be applied (backwards compatibility), but aDataSort will take\n\t\t\t * priority if defined\n\t\t\t */\n\t\t\tif ( oOptions.iDataSort !== undefined )\n\t\t\t{\n\t\t\t\toCol.aDataSort = [ oOptions.iDataSort ];\n\t\t\t}\n\t\t\t_fnMap( oCol, oOptions, \"aDataSort\" );\n\t\t}\n\t\n\t\t/* Cache the data get and set functions for speed */\n\t\tvar mDataSrc = oCol.mData;\n\t\tvar mData = _fnGetObjectDataFn( mDataSrc );\n\t\tvar mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;\n\t\n\t\tvar attrTest = function( src ) {\n\t\t\treturn typeof src === 'string' && src.indexOf('@') !== -1;\n\t\t};\n\t\toCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (\n\t\t\tattrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)\n\t\t);\n\t\toCol._setter = null;\n\t\n\t\toCol.fnGetData = function (rowData, type, meta) {\n\t\t\tvar innerData = mData( rowData, type, undefined, meta );\n\t\n\t\t\treturn mRender && type ?\n\t\t\t\tmRender( innerData, type, rowData, meta ) :\n\t\t\t\tinnerData;\n\t\t};\n\t\toCol.fnSetData = function ( rowData, val, meta ) {\n\t\t\treturn _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );\n\t\t};\n\t\n\t\t// Indicate if DataTables should read DOM data as an object or array\n\t\t// Used in _fnGetRowElements\n\t\tif ( typeof mDataSrc !== 'number' ) {\n\t\t\toSettings._rowReadObject = true;\n\t\t}\n\t\n\t\t/* Feature sorting overrides column specific when off */\n\t\tif ( !oSettings.oFeatures.bSort )\n\t\t{\n\t\t\toCol.bSortable = false;\n\t\t\tth.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called\n\t\t}\n\t\n\t\t/* Check that the class assignment is correct for sorting */\n\t\tvar bAsc = $.inArray('asc', oCol.asSorting) !== -1;\n\t\tvar bDesc = $.inArray('desc', oCol.asSorting) !== -1;\n\t\tif ( !oCol.bSortable || (!bAsc && !bDesc) )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableNone;\n\t\t\toCol.sSortingClassJUI = \"\";\n\t\t}\n\t\telse if ( bAsc && !bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableAsc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;\n\t\t}\n\t\telse if ( !bAsc && bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableDesc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;\n\t\t}\n\t\telse\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortable;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUI;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Adjust the table column widths for new data. Note: you would probably want to\n\t * do a redraw after calling this function!\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAdjustColumnSizing ( settings )\n\t{\n\t\t/* Not interested in doing column width calculation if auto-width is disabled */\n\t\tif ( settings.oFeatures.bAutoWidth !== false )\n\t\t{\n\t\t\tvar columns = settings.aoColumns;\n\t\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t\tfor ( var i=0 , iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tcolumns[i].nTh.style.width = columns[i].sWidth;\n\t\t\t}\n\t\t}\n\t\n\t\tvar scroll = settings.oScroll;\n\t\tif ( scroll.sY !== '' || scroll.sX !== '')\n\t\t{\n\t\t\t_fnScrollDraw( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'column-sizing', [settings] );\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of a visible column to the index in the data array (take account\n\t * of hidden columns)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iMatch Visible column index to lookup\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisibleToColumnIndex( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\n\t\treturn typeof aiVis[iMatch] === 'number' ?\n\t\t\taiVis[iMatch] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of an index in the data array and convert it to the visible\n\t *   column index (take account of hidden columns)\n\t *  @param {int} iMatch Column index to lookup\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnIndexToVisible( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\tvar iPos = $.inArray( iMatch, aiVis );\n\t\n\t\treturn iPos !== -1 ? iPos : null;\n\t}\n\t\n\t\n\t/**\n\t * Get the number of visible columns\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the number of visible columns\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisbleColumns( oSettings )\n\t{\n\t\tvar vis = 0;\n\t\n\t\t// No reduce in IE8, use a loop for now\n\t\t$.each( oSettings.aoColumns, function ( i, col ) {\n\t\t\tif ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {\n\t\t\t\tvis++;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn vis;\n\t}\n\t\n\t\n\t/**\n\t * Get an array of column indexes that match a given property\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sParam Parameter in aoColumns to look for - typically\n\t *    bVisible or bSearchable\n\t *  @returns {array} Array of indexes with matched properties\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetColumns( oSettings, sParam )\n\t{\n\t\tvar a = [];\n\t\n\t\t$.map( oSettings.aoColumns, function(val, i) {\n\t\t\tif ( val[sParam] ) {\n\t\t\t\ta.push( i );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn a;\n\t}\n\t\n\t\n\t/**\n\t * Calculate the 'type' of a column\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnTypes ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar data = settings.aoData;\n\t\tvar types = DataTable.ext.type.detect;\n\t\tvar i, ien, j, jen, k, ken;\n\t\tvar col, cell, detectedType, cache;\n\t\n\t\t// For each column, spin over the \n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcol = columns[i];\n\t\t\tcache = [];\n\t\n\t\t\tif ( ! col.sType && col._sManualType ) {\n\t\t\t\tcol.sType = col._sManualType;\n\t\t\t}\n\t\t\telse if ( ! col.sType ) {\n\t\t\t\tfor ( j=0, jen=types.length ; j<jen ; j++ ) {\n\t\t\t\t\tfor ( k=0, ken=data.length ; k<ken ; k++ ) {\n\t\t\t\t\t\t// Use a cache array so we only need to get the type data\n\t\t\t\t\t\t// from the formatter once (when using multiple detectors)\n\t\t\t\t\t\tif ( cache[k] === undefined ) {\n\t\t\t\t\t\t\tcache[k] = _fnGetCellData( settings, k, i, 'type' );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tdetectedType = types[j]( cache[k], settings );\n\t\n\t\t\t\t\t\t// If null, then this type can't apply to this column, so\n\t\t\t\t\t\t// rather than testing all cells, break out. There is an\n\t\t\t\t\t\t// exception for the last type which is `html`. We need to\n\t\t\t\t\t\t// scan all rows since it is possible to mix string and HTML\n\t\t\t\t\t\t// types\n\t\t\t\t\t\tif ( ! detectedType && j !== types.length-1 ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Only a single match is needed for html type since it is\n\t\t\t\t\t\t// bottom of the pile and very similar to string\n\t\t\t\t\t\tif ( detectedType === 'html' ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Type is valid for all data points in the column - use this\n\t\t\t\t\t// type\n\t\t\t\t\tif ( detectedType ) {\n\t\t\t\t\t\tcol.sType = detectedType;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Fall back - if no type was detected, always use string\n\t\t\t\tif ( ! col.sType ) {\n\t\t\t\t\tcol.sType = 'string';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Take the column definitions and static columns arrays and calculate how\n\t * they relate to column indexes. The callback function will then apply the\n\t * definition found for a column to a suitable configuration object.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aoColDefs The aoColumnDefs array that is to be applied\n\t *  @param {array} aoCols The aoColumns array that defines columns individually\n\t *  @param {function} fn Callback function - takes two parameters, the calculated\n\t *    column index and the definition for that column.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, def;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Column definitions with aTargets\n\t\tif ( aoColDefs )\n\t\t{\n\t\t\t/* Loop over the definitions array - loop in reverse so first instance has priority */\n\t\t\tfor ( i=aoColDefs.length-1 ; i>=0 ; i-- )\n\t\t\t{\n\t\t\t\tdef = aoColDefs[i];\n\t\n\t\t\t\t/* Each definition can target multiple columns, as it is an array */\n\t\t\t\tvar aTargets = def.targets !== undefined ?\n\t\t\t\t\tdef.targets :\n\t\t\t\t\tdef.aTargets;\n\t\n\t\t\t\tif ( ! $.isArray( aTargets ) )\n\t\t\t\t{\n\t\t\t\t\taTargets = [ aTargets ];\n\t\t\t\t}\n\t\n\t\t\t\tfor ( j=0, jLen=aTargets.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Add columns that we don't yet know about */\n\t\t\t\t\t\twhile( columns.length <= aTargets[j] )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_fnAddColumn( oSettings );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t/* Integer, basic index */\n\t\t\t\t\t\tfn( aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Negative integer, right to left column counting */\n\t\t\t\t\t\tfn( columns.length+aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'string' )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Class name matching on TH element */\n\t\t\t\t\t\tfor ( k=0, kLen=columns.length ; k<kLen ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( aTargets[j] == \"_all\" ||\n\t\t\t\t\t\t\t     $(columns[k].nTh).hasClass( aTargets[j] ) )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfn( k, def );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// Statically defined columns array\n\t\tif ( aoCols )\n\t\t{\n\t\t\tfor ( i=0, iLen=aoCols.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfn( i, aoCols[i] );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * Add a data array to the table, creating DOM node etc. This is the parallel to\n\t * _fnGatherData, but for adding rows from a Javascript source, rather than a\n\t * DOM source.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aData data array to be added\n\t *  @param {node} [nTr] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddData ( oSettings, aDataIn, nTr, anTds )\n\t{\n\t\t/* Create the object for storing information about this new row */\n\t\tvar iRow = oSettings.aoData.length;\n\t\tvar oData = $.extend( true, {}, DataTable.models.oRow, {\n\t\t\tsrc: nTr ? 'dom' : 'data',\n\t\t\tidx: iRow\n\t\t} );\n\t\n\t\toData._aData = aDataIn;\n\t\toSettings.aoData.push( oData );\n\t\n\t\t/* Create the cells */\n\t\tvar nTd, sThisType;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Invalidate the column types as the new data needs to be revalidated\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tcolumns[i].sType = null;\n\t\t}\n\t\n\t\t/* Add to the display array */\n\t\toSettings.aiDisplayMaster.push( iRow );\n\t\n\t\tvar id = oSettings.rowIdFn( aDataIn );\n\t\tif ( id !== undefined ) {\n\t\t\toSettings.aIds[ id ] = oData;\n\t\t}\n\t\n\t\t/* Create the DOM information, or register it if already present */\n\t\tif ( nTr || ! oSettings.oFeatures.bDeferRender )\n\t\t{\n\t\t\t_fnCreateTr( oSettings, iRow, nTr, anTds );\n\t\t}\n\t\n\t\treturn iRow;\n\t}\n\t\n\t\n\t/**\n\t * Add one or more TR elements to the table. Generally we'd expect to\n\t * use this for reading data from a DOM sourced table, but it could be\n\t * used for an TR element. Note that if a TR is given, it is used (i.e.\n\t * it is not cloned).\n\t *  @param {object} settings dataTables settings object\n\t *  @param {array|node|jQuery} trs The TR element(s) to add to the table\n\t *  @returns {array} Array of indexes for the added rows\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddTr( settings, trs )\n\t{\n\t\tvar row;\n\t\n\t\t// Allow an individual node to be passed in\n\t\tif ( ! (trs instanceof $) ) {\n\t\t\ttrs = $(trs);\n\t\t}\n\t\n\t\treturn trs.map( function (i, el) {\n\t\t\trow = _fnGetRowElements( settings, el );\n\t\t\treturn _fnAddData( settings, row.data, el, row.cells );\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Take a TR element and convert it to an index in aoData\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} n the TR element to find\n\t *  @returns {int} index if the node is found, null if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToDataIndex( oSettings, n )\n\t{\n\t\treturn (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;\n\t}\n\t\n\t\n\t/**\n\t * Take a TD element and convert it into a column data index (not the visible index)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow The row number the TD/TH can be found in\n\t *  @param {node} n The TD/TH element to find\n\t *  @returns {int} index if the node is found, -1 if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToColumnIndex( oSettings, iRow, n )\n\t{\n\t\treturn $.inArray( n, oSettings.aoData[ iRow ].anCells );\n\t}\n\t\n\t\n\t/**\n\t * Get the data for a given cell from the internal cache, taking into account data mapping\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {string} type data get type ('display', 'type' 'filter' 'sort')\n\t *  @returns {*} Cell data\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetCellData( settings, rowIdx, colIdx, type )\n\t{\n\t\tvar draw           = settings.iDraw;\n\t\tvar col            = settings.aoColumns[colIdx];\n\t\tvar rowData        = settings.aoData[rowIdx]._aData;\n\t\tvar defaultContent = col.sDefaultContent;\n\t\tvar cellData       = col.fnGetData( rowData, type, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t} );\n\t\n\t\tif ( cellData === undefined ) {\n\t\t\tif ( settings.iDrawError != draw && defaultContent === null ) {\n\t\t\t\t_fnLog( settings, 0, \"Requested unknown parameter \"+\n\t\t\t\t\t(typeof col.mData=='function' ? '{function}' : \"'\"+col.mData+\"'\")+\n\t\t\t\t\t\" for row \"+rowIdx+\", column \"+colIdx, 4 );\n\t\t\t\tsettings.iDrawError = draw;\n\t\t\t}\n\t\t\treturn defaultContent;\n\t\t}\n\t\n\t\t// When the data source is null and a specific data type is requested (i.e.\n\t\t// not the original data), we can use default column data\n\t\tif ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {\n\t\t\tcellData = defaultContent;\n\t\t}\n\t\telse if ( typeof cellData === 'function' ) {\n\t\t\t// If the data source is a function, then we run it and use the return,\n\t\t\t// executing in the scope of the data object (for instances)\n\t\t\treturn cellData.call( rowData );\n\t\t}\n\t\n\t\tif ( cellData === null && type == 'display' ) {\n\t\t\treturn '';\n\t\t}\n\t\treturn cellData;\n\t}\n\t\n\t\n\t/**\n\t * Set the value for a specific cell, into the internal data cache\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {*} val Value to set\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetCellData( settings, rowIdx, colIdx, val )\n\t{\n\t\tvar col     = settings.aoColumns[colIdx];\n\t\tvar rowData = settings.aoData[rowIdx]._aData;\n\t\n\t\tcol.fnSetData( rowData, val, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t}  );\n\t}\n\t\n\t\n\t// Private variable that is used to match action syntax in the data property object\n\tvar __reArray = /\\[.*?\\]$/;\n\tvar __reFn = /\\(\\)$/;\n\t\n\t/**\n\t * Split string on periods, taking into account escaped periods\n\t * @param  {string} str String to split\n\t * @return {array} Split string\n\t */\n\tfunction _fnSplitObjNotation( str )\n\t{\n\t\treturn $.map( str.match(/(\\\\.|[^\\.])+/g) || [''], function ( s ) {\n\t\t\treturn s.replace(/\\\\\\./g, '.');\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to get data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data get function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Build an object of get functions, and wrap them in a single call */\n\t\t\tvar o = {};\n\t\t\t$.each( mSource, function (key, val) {\n\t\t\t\tif ( val ) {\n\t\t\t\t\to[key] = _fnGetObjectDataFn( val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\tvar t = o[type] || o._;\n\t\t\t\treturn t !== undefined ?\n\t\t\t\t\tt(data, type, row, meta) :\n\t\t\t\t\tdata;\n\t\t\t};\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Give an empty string for rendering / sorting etc */\n\t\t\treturn function (data) { // type, row and meta also passed, but not used\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\treturn mSource( data, type, row, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* If there is a . in the source string then the data source is in a\n\t\t\t * nested object so we loop over the data for each level to get the next\n\t\t\t * level down. On each loop we test for undefined, and if found immediately\n\t\t\t * return. This allows entire objects to be missing and sDefaultContent to\n\t\t\t * be used if defined, rather than throwing an error\n\t\t\t */\n\t\t\tvar fetchData = function (data, type, src) {\n\t\t\t\tvar arrayNotation, funcNotation, out, innerSrc;\n\t\n\t\t\t\tif ( src !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tvar a = _fnSplitObjNotation( src );\n\t\n\t\t\t\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if we are dealing with special notation\n\t\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Array notation\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\n\t\t\t\t\t\t\t// Condition allows simply [] to be passed in\n\t\t\t\t\t\t\tif ( a[i] !== \"\" ) {\n\t\t\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tout = [];\n\t\n\t\t\t\t\t\t\t// Get the remainder of the nested object to get\n\t\t\t\t\t\t\ta.splice( 0, i+1 );\n\t\t\t\t\t\t\tinnerSrc = a.join('.');\n\t\n\t\t\t\t\t\t\t// Traverse each entry in the array getting the properties requested\n\t\t\t\t\t\t\tif ( $.isArray( data ) ) {\n\t\t\t\t\t\t\t\tfor ( var j=0, jLen=data.length ; j<jLen ; j++ ) {\n\t\t\t\t\t\t\t\t\tout.push( fetchData( data[j], type, innerSrc ) );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\t// If a string is given in between the array notation indicators, that\n\t\t\t\t\t\t\t// is used to join the strings together, otherwise an array is returned\n\t\t\t\t\t\t\tvar join = arrayNotation[0].substring(1, arrayNotation[0].length-1);\n\t\t\t\t\t\t\tdata = (join===\"\") ? out : out.join(join);\n\t\n\t\t\t\t\t\t\t// The inner call to fetchData has already traversed through the remainder\n\t\t\t\t\t\t\t// of the source requested, so we exit from the loop\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Function call\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\t\tdata = data[ a[i] ]();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( data === null || data[ a[i] ] === undefined )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn data;\n\t\t\t};\n\t\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn fetchData( data, type, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn data[mSource];\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to set data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data set function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Unlike get, only the underscore (global) option is used for for\n\t\t\t * setting data since we don't know the type here. This is why an object\n\t\t\t * option is not documented for `mData` (which is read/write), but it is\n\t\t\t * for `mRender` which is read only.\n\t\t\t */\n\t\t\treturn _fnSetObjectDataFn( mSource._ );\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Nothing to do when the data source is null */\n\t\t\treturn function () {};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, val, meta) {\n\t\t\t\tmSource( data, 'set', val, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* Like the get, we need to get data from a nested object */\n\t\t\tvar setData = function (data, val, src) {\n\t\t\t\tvar a = _fnSplitObjNotation( src ), b;\n\t\t\t\tvar aLast = a[a.length-1];\n\t\t\t\tvar arrayNotation, funcNotation, o, innerSrc;\n\t\n\t\t\t\tfor ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\t// Check if we are dealing with an array notation request\n\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\t\t\t\t\tdata[ a[i] ] = [];\n\t\n\t\t\t\t\t\t// Get the remainder of the nested object to set so we can recurse\n\t\t\t\t\t\tb = a.slice();\n\t\t\t\t\t\tb.splice( 0, i+1 );\n\t\t\t\t\t\tinnerSrc = b.join('.');\n\t\n\t\t\t\t\t\t// Traverse each entry in the array setting the properties requested\n\t\t\t\t\t\tif ( $.isArray( val ) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor ( var j=0, jLen=val.length ; j<jLen ; j++ )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\to = {};\n\t\t\t\t\t\t\t\tsetData( o, val[j], innerSrc );\n\t\t\t\t\t\t\t\tdata[ a[i] ].push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We've been asked to save data to an array, but it\n\t\t\t\t\t\t\t// isn't array data to be saved. Best that can be done\n\t\t\t\t\t\t\t// is to just save the value.\n\t\t\t\t\t\t\tdata[ a[i] ] = val;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// The inner call to setData has already traversed through the remainder\n\t\t\t\t\t\t// of the source and has set the data, thus we can exit here\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Function call\n\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\tdata = data[ a[i] ]( val );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If the nested object doesn't currently exist - since we are\n\t\t\t\t\t// trying to set the value - create it\n\t\t\t\t\tif ( data[ a[i] ] === null || data[ a[i] ] === undefined )\n\t\t\t\t\t{\n\t\t\t\t\t\tdata[ a[i] ] = {};\n\t\t\t\t\t}\n\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t}\n\t\n\t\t\t\t// Last item in the input - i.e, the actual set\n\t\t\t\tif ( aLast.match(__reFn ) )\n\t\t\t\t{\n\t\t\t\t\t// Function call\n\t\t\t\t\tdata = data[ aLast.replace(__reFn, '') ]( val );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// If array notation is used, we just want to strip it and use the property name\n\t\t\t\t\t// and assign the value. If it isn't used, then we get the result we want anyway\n\t\t\t\t\tdata[ aLast.replace(__reArray, '') ] = val;\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\treturn setData( data, val, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\tdata[mSource] = val;\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return an array with the full table data\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns array {array} aData Master data array\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetDataMaster ( settings )\n\t{\n\t\treturn _pluck( settings.aoData, '_aData' );\n\t}\n\t\n\t\n\t/**\n\t * Nuke the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnClearTable( settings )\n\t{\n\t\tsettings.aoData.length = 0;\n\t\tsettings.aiDisplayMaster.length = 0;\n\t\tsettings.aiDisplay.length = 0;\n\t\tsettings.aIds = {};\n\t}\n\t\n\t\n\t /**\n\t * Take an array of integers (index array) and remove a target integer (value - not\n\t * the key!)\n\t *  @param {array} a Index array to target\n\t *  @param {int} iTarget value to find\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDeleteIndex( a, iTarget, splice )\n\t{\n\t\tvar iTargetIndex = -1;\n\t\n\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( a[i] == iTarget )\n\t\t\t{\n\t\t\t\tiTargetIndex = i;\n\t\t\t}\n\t\t\telse if ( a[i] > iTarget )\n\t\t\t{\n\t\t\t\ta[i]--;\n\t\t\t}\n\t\t}\n\t\n\t\tif ( iTargetIndex != -1 && splice === undefined )\n\t\t{\n\t\t\ta.splice( iTargetIndex, 1 );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Mark cached data as invalid such that a re-read of the data will occur when\n\t * the cached data is next requested. Also update from the data source object.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {int}    rowIdx   Row index to invalidate\n\t * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'\n\t *     or 'data'\n\t * @param {int}    [colIdx] Column index to invalidate. If undefined the whole\n\t *     row will be invalidated\n\t * @memberof DataTable#oApi\n\t *\n\t * @todo For the modularisation of v1.11 this will need to become a callback, so\n\t *   the sort and filter methods can subscribe to it. That will required\n\t *   initialisation options for sorting, which is why it is not already baked in\n\t */\n\tfunction _fnInvalidate( settings, rowIdx, src, colIdx )\n\t{\n\t\tvar row = settings.aoData[ rowIdx ];\n\t\tvar i, ien;\n\t\tvar cellWrite = function ( cell, col ) {\n\t\t\t// This is very frustrating, but in IE if you just write directly\n\t\t\t// to innerHTML, and elements that are overwritten are GC'ed,\n\t\t\t// even if there is a reference to them elsewhere\n\t\t\twhile ( cell.childNodes.length ) {\n\t\t\t\tcell.removeChild( cell.firstChild );\n\t\t\t}\n\t\n\t\t\tcell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );\n\t\t};\n\t\n\t\t// Are we reading last data from DOM or the data object?\n\t\tif ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {\n\t\t\t// Read the data from the DOM\n\t\t\trow._aData = _fnGetRowElements(\n\t\t\t\t\tsettings, row, colIdx, colIdx === undefined ? undefined : row._aData\n\t\t\t\t)\n\t\t\t\t.data;\n\t\t}\n\t\telse {\n\t\t\t// Reading from data object, update the DOM\n\t\t\tvar cells = row.anCells;\n\t\n\t\t\tif ( cells ) {\n\t\t\t\tif ( colIdx !== undefined ) {\n\t\t\t\t\tcellWrite( cells[colIdx], colIdx );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tcellWrite( cells[i], i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// For both row and cell invalidation, the cached data for sorting and\n\t\t// filtering is nulled out\n\t\trow._aSortData = null;\n\t\trow._aFilterData = null;\n\t\n\t\t// Invalidate the type for a specific column (if given) or all columns since\n\t\t// the data might have changed\n\t\tvar cols = settings.aoColumns;\n\t\tif ( colIdx !== undefined ) {\n\t\t\tcols[ colIdx ].sType = null;\n\t\t}\n\t\telse {\n\t\t\tfor ( i=0, ien=cols.length ; i<ien ; i++ ) {\n\t\t\t\tcols[i].sType = null;\n\t\t\t}\n\t\n\t\t\t// Update DataTables special `DT_*` attributes for the row\n\t\t\t_fnRowAttributes( settings, row );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a data source object from an HTML row, reading the contents of the\n\t * cells that are in the row.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {node|object} TR element from which to read data or existing row\n\t *   object from which to re-read the data from the cells\n\t * @param {int} [colIdx] Optional column index\n\t * @param {array|object} [d] Data source object. If `colIdx` is given then this\n\t *   parameter should also be given and will be used to write the data into.\n\t *   Only the column in question will be written\n\t * @returns {object} Object with two parameters: `data` the data read, in\n\t *   document order, and `cells` and array of nodes (they can be useful to the\n\t *   caller, so rather than needing a second traversal to get them, just return\n\t *   them from here).\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetRowElements( settings, row, colIdx, d )\n\t{\n\t\tvar\n\t\t\ttds = [],\n\t\t\ttd = row.firstChild,\n\t\t\tname, col, o, i=0, contents,\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tobjectRead = settings._rowReadObject;\n\t\n\t\t// Allow the data object to be passed in, or construct\n\t\td = d !== undefined ?\n\t\t\td :\n\t\t\tobjectRead ?\n\t\t\t\t{} :\n\t\t\t\t[];\n\t\n\t\tvar attr = function ( str, td  ) {\n\t\t\tif ( typeof str === 'string' ) {\n\t\t\t\tvar idx = str.indexOf('@');\n\t\n\t\t\t\tif ( idx !== -1 ) {\n\t\t\t\t\tvar attr = str.substring( idx+1 );\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( str );\n\t\t\t\t\tsetter( d, td.getAttribute( attr ) );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\n\t\t// Read data from a cell and store into the data object\n\t\tvar cellProcess = function ( cell ) {\n\t\t\tif ( colIdx === undefined || colIdx === i ) {\n\t\t\t\tcol = columns[i];\n\t\t\t\tcontents = $.trim(cell.innerHTML);\n\t\n\t\t\t\tif ( col && col._bAttrSrc ) {\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( col.mData._ );\n\t\t\t\t\tsetter( d, contents );\n\t\n\t\t\t\t\tattr( col.mData.sort, cell );\n\t\t\t\t\tattr( col.mData.type, cell );\n\t\t\t\t\tattr( col.mData.filter, cell );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Depending on the `data` option for the columns the data can\n\t\t\t\t\t// be read to either an object or an array.\n\t\t\t\t\tif ( objectRead ) {\n\t\t\t\t\t\tif ( ! col._setter ) {\n\t\t\t\t\t\t\t// Cache the setter function\n\t\t\t\t\t\t\tcol._setter = _fnSetObjectDataFn( col.mData );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcol._setter( d, contents );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\td[i] = contents;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t};\n\t\n\t\tif ( td ) {\n\t\t\t// `tr` element was passed in\n\t\t\twhile ( td ) {\n\t\t\t\tname = td.nodeName.toUpperCase();\n\t\n\t\t\t\tif ( name == \"TD\" || name == \"TH\" ) {\n\t\t\t\t\tcellProcess( td );\n\t\t\t\t\ttds.push( td );\n\t\t\t\t}\n\t\n\t\t\t\ttd = td.nextSibling;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Existing row object passed in\n\t\t\ttds = row.anCells;\n\t\n\t\t\tfor ( var j=0, jen=tds.length ; j<jen ; j++ ) {\n\t\t\t\tcellProcess( tds[j] );\n\t\t\t}\n\t\t}\n\t\n\t\t// Read the ID from the DOM if present\n\t\tvar rowNode = row.firstChild ? row : row.nTr;\n\t\n\t\tif ( rowNode ) {\n\t\t\tvar id = rowNode.getAttribute( 'id' );\n\t\n\t\t\tif ( id ) {\n\t\t\t\t_fnSetObjectDataFn( settings.rowId )( d, id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn {\n\t\t\tdata: d,\n\t\t\tcells: tds\n\t\t};\n\t}\n\t/**\n\t * Create a new TR element (and it's TD children) for a row\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow Row to consider\n\t *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCreateTr ( oSettings, iRow, nTrIn, anTds )\n\t{\n\t\tvar\n\t\t\trow = oSettings.aoData[iRow],\n\t\t\trowData = row._aData,\n\t\t\tcells = [],\n\t\t\tnTr, nTd, oCol,\n\t\t\ti, iLen;\n\t\n\t\tif ( row.nTr === null )\n\t\t{\n\t\t\tnTr = nTrIn || document.createElement('tr');\n\t\n\t\t\trow.nTr = nTr;\n\t\t\trow.anCells = cells;\n\t\n\t\t\t/* Use a private property on the node to allow reserve mapping from the node\n\t\t\t * to the aoData array for fast look up\n\t\t\t */\n\t\t\tnTr._DT_RowIndex = iRow;\n\t\n\t\t\t/* Special parameters can be given by the data source to be used on the row */\n\t\t\t_fnRowAttributes( oSettings, row );\n\t\n\t\t\t/* Process each column */\n\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toCol = oSettings.aoColumns[i];\n\t\n\t\t\t\tnTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );\n\t\t\t\tnTd._DT_CellIndex = {\n\t\t\t\t\trow: iRow,\n\t\t\t\t\tcolumn: i\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tcells.push( nTd );\n\t\n\t\t\t\t// Need to create the HTML if new, or if a rendering function is defined\n\t\t\t\tif ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&\n\t\t\t\t\t (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')\n\t\t\t\t) {\n\t\t\t\t\tnTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );\n\t\t\t\t}\n\t\n\t\t\t\t/* Add user defined class */\n\t\t\t\tif ( oCol.sClass )\n\t\t\t\t{\n\t\t\t\t\tnTd.className += ' '+oCol.sClass;\n\t\t\t\t}\n\t\n\t\t\t\t// Visibility - add or remove as required\n\t\t\t\tif ( oCol.bVisible && ! nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTr.appendChild( nTd );\n\t\t\t\t}\n\t\t\t\telse if ( ! oCol.bVisible && nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTd.parentNode.removeChild( nTd );\n\t\t\t\t}\n\t\n\t\t\t\tif ( oCol.fnCreatedCell )\n\t\t\t\t{\n\t\t\t\t\toCol.fnCreatedCell.call( oSettings.oInstance,\n\t\t\t\t\t\tnTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );\n\t\t}\n\t\n\t\t// Remove once webkit bug 131819 and Chromium bug 365619 have been resolved\n\t\t// and deployed\n\t\trow.nTr.setAttribute( 'role', 'row' );\n\t}\n\t\n\t\n\t/**\n\t * Add attributes to a row based on the special `DT_*` parameters in a data\n\t * source object.\n\t *  @param {object} settings DataTables settings object\n\t *  @param {object} DataTables row object for the row to be modified\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnRowAttributes( settings, row )\n\t{\n\t\tvar tr = row.nTr;\n\t\tvar data = row._aData;\n\t\n\t\tif ( tr ) {\n\t\t\tvar id = settings.rowIdFn( data );\n\t\n\t\t\tif ( id ) {\n\t\t\t\ttr.id = id;\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowClass ) {\n\t\t\t\t// Remove any classes added by DT_RowClass before\n\t\t\t\tvar a = data.DT_RowClass.split(' ');\n\t\t\t\trow.__rowc = row.__rowc ?\n\t\t\t\t\t_unique( row.__rowc.concat( a ) ) :\n\t\t\t\t\ta;\n\t\n\t\t\t\t$(tr)\n\t\t\t\t\t.removeClass( row.__rowc.join(' ') )\n\t\t\t\t\t.addClass( data.DT_RowClass );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowAttr ) {\n\t\t\t\t$(tr).attr( data.DT_RowAttr );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowData ) {\n\t\t\t\t$(tr).data( data.DT_RowData );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Create the HTML header for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBuildHead( oSettings )\n\t{\n\t\tvar i, ien, cell, row, column;\n\t\tvar thead = oSettings.nTHead;\n\t\tvar tfoot = oSettings.nTFoot;\n\t\tvar createHeader = $('th, td', thead).length === 0;\n\t\tvar classes = oSettings.oClasses;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\tif ( createHeader ) {\n\t\t\trow = $('<tr/>').appendTo( thead );\n\t\t}\n\t\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcell = $( column.nTh ).addClass( column.sClass );\n\t\n\t\t\tif ( createHeader ) {\n\t\t\t\tcell.appendTo( row );\n\t\t\t}\n\t\n\t\t\t// 1.11 move into sorting\n\t\t\tif ( oSettings.oFeatures.bSort ) {\n\t\t\t\tcell.addClass( column.sSortingClass );\n\t\n\t\t\t\tif ( column.bSortable !== false ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.attr( 'tabindex', oSettings.iTabIndex )\n\t\t\t\t\t\t.attr( 'aria-controls', oSettings.sTableId );\n\t\n\t\t\t\t\t_fnSortAttachListener( oSettings, column.nTh, i );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( column.sTitle != cell[0].innerHTML ) {\n\t\t\t\tcell.html( column.sTitle );\n\t\t\t}\n\t\n\t\t\t_fnRenderer( oSettings, 'header' )(\n\t\t\t\toSettings, cell, column, classes\n\t\t\t);\n\t\t}\n\t\n\t\tif ( createHeader ) {\n\t\t\t_fnDetectHeader( oSettings.aoHeader, thead );\n\t\t}\n\t\t\n\t\t/* ARIA role for the rows */\n\t \t$(thead).find('>tr').attr('role', 'row');\n\t\n\t\t/* Deal with the footer - add classes if required */\n\t\t$(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );\n\t\t$(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );\n\t\n\t\t// Cache the footer cells. Note that we only take the cells from the first\n\t\t// row in the footer. If there is more than one row the user wants to\n\t\t// interact with, they need to use the table().foot() method. Note also this\n\t\t// allows cells to be used for multiple columns using colspan\n\t\tif ( tfoot !== null ) {\n\t\t\tvar cells = oSettings.aoFooter[0];\n\t\n\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tcolumn = columns[i];\n\t\t\t\tcolumn.nTf = cells[i].cell;\n\t\n\t\t\t\tif ( column.sClass ) {\n\t\t\t\t\t$(column.nTf).addClass( column.sClass );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the header (or footer) element based on the column visibility states. The\n\t * methodology here is to use the layout array from _fnDetectHeader, modified for\n\t * the instantaneous column visibility, to construct the new layout. The grid is\n\t * traversed over cell at a time in a rows x columns grid fashion, although each\n\t * cell insert can cover multiple elements in the grid - which is tracks using the\n\t * aApplied array. Cell inserts in the grid will only occur where there isn't\n\t * already a cell in that position.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param array {objects} aoSource Layout array from _fnDetectHeader\n\t *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDrawHead( oSettings, aoSource, bIncludeHidden )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, n, nLocalTr;\n\t\tvar aoLocal = [];\n\t\tvar aApplied = [];\n\t\tvar iColumns = oSettings.aoColumns.length;\n\t\tvar iRowspan, iColspan;\n\t\n\t\tif ( ! aoSource )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif (  bIncludeHidden === undefined )\n\t\t{\n\t\t\tbIncludeHidden = false;\n\t\t}\n\t\n\t\t/* Make a copy of the master layout array, but without the visible columns in it */\n\t\tfor ( i=0, iLen=aoSource.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taoLocal[i] = aoSource[i].slice();\n\t\t\taoLocal[i].nTr = aoSource[i].nTr;\n\t\n\t\t\t/* Remove any columns which are currently hidden */\n\t\t\tfor ( j=iColumns-1 ; j>=0 ; j-- )\n\t\t\t{\n\t\t\t\tif ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )\n\t\t\t\t{\n\t\t\t\t\taoLocal[i].splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Prep the applied array - it needs an element for each row */\n\t\t\taApplied.push( [] );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnLocalTr = aoLocal[i].nTr;\n\t\n\t\t\t/* All cells are going to be replaced, so empty out the row */\n\t\t\tif ( nLocalTr )\n\t\t\t{\n\t\t\t\twhile( (n = nLocalTr.firstChild) )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.removeChild( n );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tfor ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tiRowspan = 1;\n\t\t\t\tiColspan = 1;\n\t\n\t\t\t\t/* Check to see if there is already a cell (row/colspan) covering our target\n\t\t\t\t * insert point. If there is, then there is nothing to do.\n\t\t\t\t */\n\t\t\t\tif ( aApplied[i][j] === undefined )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.appendChild( aoLocal[i][j].cell );\n\t\t\t\t\taApplied[i][j] = 1;\n\t\n\t\t\t\t\t/* Expand the cell to cover as many rows as needed */\n\t\t\t\t\twhile ( aoLocal[i+iRowspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\taApplied[i+iRowspan][j] = 1;\n\t\t\t\t\t\tiRowspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Expand the cell to cover as many columns as needed */\n\t\t\t\t\twhile ( aoLocal[i][j+iColspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Must update the applied array over the rows for the columns */\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taApplied[i+k][j+iColspan] = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiColspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Do the actual expansion in the DOM */\n\t\t\t\t\t$(aoLocal[i][j].cell)\n\t\t\t\t\t\t.attr('rowspan', iRowspan)\n\t\t\t\t\t\t.attr('colspan', iColspan);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Insert the required TR nodes into the table for display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDraw( oSettings )\n\t{\n\t\t/* Provide a pre-callback function which can be used to cancel the draw is false is returned */\n\t\tvar aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );\n\t\tif ( $.inArray( false, aPreDraw ) !== -1 )\n\t\t{\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar i, iLen, n;\n\t\tvar anRows = [];\n\t\tvar iRowCount = 0;\n\t\tvar asStripeClasses = oSettings.asStripeClasses;\n\t\tvar iStripes = asStripeClasses.length;\n\t\tvar iOpenRows = oSettings.aoOpenRows.length;\n\t\tvar oLang = oSettings.oLanguage;\n\t\tvar iInitDisplayStart = oSettings.iInitDisplayStart;\n\t\tvar bServerSide = _fnDataSource( oSettings ) == 'ssp';\n\t\tvar aiDisplay = oSettings.aiDisplay;\n\t\n\t\toSettings.bDrawing = true;\n\t\n\t\t/* Check and see if we have an initial draw position from state saving */\n\t\tif ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )\n\t\t{\n\t\t\toSettings._iDisplayStart = bServerSide ?\n\t\t\t\tiInitDisplayStart :\n\t\t\t\tiInitDisplayStart >= oSettings.fnRecordsDisplay() ?\n\t\t\t\t\t0 :\n\t\t\t\t\tiInitDisplayStart;\n\t\n\t\t\toSettings.iInitDisplayStart = -1;\n\t\t}\n\t\n\t\tvar iDisplayStart = oSettings._iDisplayStart;\n\t\tvar iDisplayEnd = oSettings.fnDisplayEnd();\n\t\n\t\t/* Server-side processing draw intercept */\n\t\tif ( oSettings.bDeferLoading )\n\t\t{\n\t\t\toSettings.bDeferLoading = false;\n\t\t\toSettings.iDraw++;\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t}\n\t\telse if ( !bServerSide )\n\t\t{\n\t\t\toSettings.iDraw++;\n\t\t}\n\t\telse if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( aiDisplay.length !== 0 )\n\t\t{\n\t\t\tvar iStart = bServerSide ? 0 : iDisplayStart;\n\t\t\tvar iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;\n\t\n\t\t\tfor ( var j=iStart ; j<iEnd ; j++ )\n\t\t\t{\n\t\t\t\tvar iDataIndex = aiDisplay[j];\n\t\t\t\tvar aoData = oSettings.aoData[ iDataIndex ];\n\t\t\t\tif ( aoData.nTr === null )\n\t\t\t\t{\n\t\t\t\t\t_fnCreateTr( oSettings, iDataIndex );\n\t\t\t\t}\n\t\n\t\t\t\tvar nRow = aoData.nTr;\n\t\n\t\t\t\t/* Remove the old striping classes and then add the new one */\n\t\t\t\tif ( iStripes !== 0 )\n\t\t\t\t{\n\t\t\t\t\tvar sStripe = asStripeClasses[ iRowCount % iStripes ];\n\t\t\t\t\tif ( aoData._sRowStripe != sStripe )\n\t\t\t\t\t{\n\t\t\t\t\t\t$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );\n\t\t\t\t\t\taoData._sRowStripe = sStripe;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Row callback functions - might want to manipulate the row\n\t\t\t\t// iRowCount and j are not currently documented. Are they at all\n\t\t\t\t// useful?\n\t\t\t\t_fnCallbackFire( oSettings, 'aoRowCallback', null,\n\t\t\t\t\t[nRow, aoData._aData, iRowCount, j] );\n\t\n\t\t\t\tanRows.push( nRow );\n\t\t\t\tiRowCount++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Table is empty - create a row with an empty message in it */\n\t\t\tvar sZero = oLang.sZeroRecords;\n\t\t\tif ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )\n\t\t\t{\n\t\t\t\tsZero = oLang.sLoadingRecords;\n\t\t\t}\n\t\t\telse if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )\n\t\t\t{\n\t\t\t\tsZero = oLang.sEmptyTable;\n\t\t\t}\n\t\n\t\t\tanRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )\n\t\t\t\t.append( $('<td />', {\n\t\t\t\t\t'valign':  'top',\n\t\t\t\t\t'colSpan': _fnVisbleColumns( oSettings ),\n\t\t\t\t\t'class':   oSettings.oClasses.sRowEmpty\n\t\t\t\t} ).html( sZero ) )[0];\n\t\t}\n\t\n\t\t/* Header and footer callbacks */\n\t\t_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\t_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\tvar body = $(oSettings.nTBody);\n\t\n\t\tbody.children().detach();\n\t\tbody.append( $(anRows) );\n\t\n\t\t/* Call all required callback functions for the end of a draw */\n\t\t_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );\n\t\n\t\t/* Draw is complete, sorting and filtering must be as well */\n\t\toSettings.bSorted = false;\n\t\toSettings.bFiltered = false;\n\t\toSettings.bDrawing = false;\n\t}\n\t\n\t\n\t/**\n\t * Redraw the table - taking account of the various features which are enabled\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {boolean} [holdPosition] Keep the current paging position. By default\n\t *    the paging is reset to the first page\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReDraw( settings, holdPosition )\n\t{\n\t\tvar\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tsort     = features.bSort,\n\t\t\tfilter   = features.bFilter;\n\t\n\t\tif ( sort ) {\n\t\t\t_fnSort( settings );\n\t\t}\n\t\n\t\tif ( filter ) {\n\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch );\n\t\t}\n\t\telse {\n\t\t\t// No filtering, so we want to just use the display master\n\t\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\t}\n\t\n\t\tif ( holdPosition !== true ) {\n\t\t\tsettings._iDisplayStart = 0;\n\t\t}\n\t\n\t\t// Let any modules know about the draw hold position state (used by\n\t\t// scrolling internally)\n\t\tsettings._drawHold = holdPosition;\n\t\n\t\t_fnDraw( settings );\n\t\n\t\tsettings._drawHold = false;\n\t}\n\t\n\t\n\t/**\n\t * Add the options to the page HTML for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddOptionsHtml ( oSettings )\n\t{\n\t\tvar classes = oSettings.oClasses;\n\t\tvar table = $(oSettings.nTable);\n\t\tvar holding = $('<div/>').insertBefore( table ); // Holding element for speed\n\t\tvar features = oSettings.oFeatures;\n\t\n\t\t// All DataTables are wrapped in a div\n\t\tvar insert = $('<div/>', {\n\t\t\tid:      oSettings.sTableId+'_wrapper',\n\t\t\t'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)\n\t\t} );\n\t\n\t\toSettings.nHolding = holding[0];\n\t\toSettings.nTableWrapper = insert[0];\n\t\toSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;\n\t\n\t\t/* Loop over the user set positioning and place the elements as needed */\n\t\tvar aDom = oSettings.sDom.split('');\n\t\tvar featureNode, cOption, nNewNode, cNext, sAttr, j;\n\t\tfor ( var i=0 ; i<aDom.length ; i++ )\n\t\t{\n\t\t\tfeatureNode = null;\n\t\t\tcOption = aDom[i];\n\t\n\t\t\tif ( cOption == '<' )\n\t\t\t{\n\t\t\t\t/* New container div */\n\t\t\t\tnNewNode = $('<div/>')[0];\n\t\n\t\t\t\t/* Check to see if we should append an id and/or a class name to the container */\n\t\t\t\tcNext = aDom[i+1];\n\t\t\t\tif ( cNext == \"'\" || cNext == '\"' )\n\t\t\t\t{\n\t\t\t\t\tsAttr = \"\";\n\t\t\t\t\tj = 2;\n\t\t\t\t\twhile ( aDom[i+j] != cNext )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr += aDom[i+j];\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Replace jQuery UI constants @todo depreciated */\n\t\t\t\t\tif ( sAttr == \"H\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIHeader;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr == \"F\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIFooter;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* The attribute can be in the format of \"#id.class\", \"#id\" or \"class\" This logic\n\t\t\t\t\t * breaks the string into parts and applies them as needed\n\t\t\t\t\t */\n\t\t\t\t\tif ( sAttr.indexOf('.') != -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar aSplit = sAttr.split('.');\n\t\t\t\t\t\tnNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);\n\t\t\t\t\t\tnNewNode.className = aSplit[1];\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr.charAt(0) == \"#\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.id = sAttr.substr(1, sAttr.length-1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.className = sAttr;\n\t\t\t\t\t}\n\t\n\t\t\t\t\ti += j; /* Move along the position array */\n\t\t\t\t}\n\t\n\t\t\t\tinsert.append( nNewNode );\n\t\t\t\tinsert = $(nNewNode);\n\t\t\t}\n\t\t\telse if ( cOption == '>' )\n\t\t\t{\n\t\t\t\t/* End container div */\n\t\t\t\tinsert = insert.parent();\n\t\t\t}\n\t\t\t// @todo Move options into their own plugins?\n\t\t\telse if ( cOption == 'l' && features.bPaginate && features.bLengthChange )\n\t\t\t{\n\t\t\t\t/* Length */\n\t\t\t\tfeatureNode = _fnFeatureHtmlLength( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'f' && features.bFilter )\n\t\t\t{\n\t\t\t\t/* Filter */\n\t\t\t\tfeatureNode = _fnFeatureHtmlFilter( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'r' && features.bProcessing )\n\t\t\t{\n\t\t\t\t/* pRocessing */\n\t\t\t\tfeatureNode = _fnFeatureHtmlProcessing( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 't' )\n\t\t\t{\n\t\t\t\t/* Table */\n\t\t\t\tfeatureNode = _fnFeatureHtmlTable( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption ==  'i' && features.bInfo )\n\t\t\t{\n\t\t\t\t/* Info */\n\t\t\t\tfeatureNode = _fnFeatureHtmlInfo( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'p' && features.bPaginate )\n\t\t\t{\n\t\t\t\t/* Pagination */\n\t\t\t\tfeatureNode = _fnFeatureHtmlPaginate( oSettings );\n\t\t\t}\n\t\t\telse if ( DataTable.ext.feature.length !== 0 )\n\t\t\t{\n\t\t\t\t/* Plug-in features */\n\t\t\t\tvar aoFeatures = DataTable.ext.feature;\n\t\t\t\tfor ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )\n\t\t\t\t{\n\t\t\t\t\tif ( cOption == aoFeatures[k].cFeature )\n\t\t\t\t\t{\n\t\t\t\t\t\tfeatureNode = aoFeatures[k].fnInit( oSettings );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Add to the 2D features array */\n\t\t\tif ( featureNode )\n\t\t\t{\n\t\t\t\tvar aanFeatures = oSettings.aanFeatures;\n\t\n\t\t\t\tif ( ! aanFeatures[cOption] )\n\t\t\t\t{\n\t\t\t\t\taanFeatures[cOption] = [];\n\t\t\t\t}\n\t\n\t\t\t\taanFeatures[cOption].push( featureNode );\n\t\t\t\tinsert.append( featureNode );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Built our DOM structure - replace the holding div with what we want */\n\t\tholding.replaceWith( insert );\n\t\toSettings.nHolding = null;\n\t}\n\t\n\t\n\t/**\n\t * Use the DOM source to create up an array of header cells. The idea here is to\n\t * create a layout grid (array) of rows x columns, which contains a reference\n\t * to the cell that that point in the grid (regardless of col/rowspan), such that\n\t * any column / row could be removed and the new grid constructed\n\t *  @param array {object} aLayout Array to store the calculated layout in\n\t *  @param {node} nThead The header/footer element for the table\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDetectHeader ( aLayout, nThead )\n\t{\n\t\tvar nTrs = $(nThead).children('tr');\n\t\tvar nTr, nCell;\n\t\tvar i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;\n\t\tvar bUnique;\n\t\tvar fnShiftCol = function ( a, i, j ) {\n\t\t\tvar k = a[i];\n\t                while ( k[j] ) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\treturn j;\n\t\t};\n\t\n\t\taLayout.splice( 0, aLayout.length );\n\t\n\t\t/* We know how many rows there are in the layout - so prep it */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taLayout.push( [] );\n\t\t}\n\t\n\t\t/* Calculate a layout array */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnTr = nTrs[i];\n\t\t\tiColumn = 0;\n\t\n\t\t\t/* For every cell in the row... */\n\t\t\tnCell = nTr.firstChild;\n\t\t\twhile ( nCell ) {\n\t\t\t\tif ( nCell.nodeName.toUpperCase() == \"TD\" ||\n\t\t\t\t     nCell.nodeName.toUpperCase() == \"TH\" )\n\t\t\t\t{\n\t\t\t\t\t/* Get the col and rowspan attributes from the DOM and sanitise them */\n\t\t\t\t\tiColspan = nCell.getAttribute('colspan') * 1;\n\t\t\t\t\tiRowspan = nCell.getAttribute('rowspan') * 1;\n\t\t\t\t\tiColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;\n\t\t\t\t\tiRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;\n\t\n\t\t\t\t\t/* There might be colspan cells already in this row, so shift our target\n\t\t\t\t\t * accordingly\n\t\t\t\t\t */\n\t\t\t\t\tiColShifted = fnShiftCol( aLayout, i, iColumn );\n\t\n\t\t\t\t\t/* Cache calculation for unique columns */\n\t\t\t\t\tbUnique = iColspan === 1 ? true : false;\n\t\n\t\t\t\t\t/* If there is col / rowspan, copy the information into the layout grid */\n\t\t\t\t\tfor ( l=0 ; l<iColspan ; l++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taLayout[i+k][iColShifted+l] = {\n\t\t\t\t\t\t\t\t\"cell\": nCell,\n\t\t\t\t\t\t\t\t\"unique\": bUnique\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\taLayout[i+k].nTr = nTr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnCell = nCell.nextSibling;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Get an array of unique th elements, one for each column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nHeader automatically detect the layout from this node - optional\n\t *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional\n\t *  @returns array {node} aReturn list of unique th's\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetUniqueThs ( oSettings, nHeader, aLayout )\n\t{\n\t\tvar aReturn = [];\n\t\tif ( !aLayout )\n\t\t{\n\t\t\taLayout = oSettings.aoHeader;\n\t\t\tif ( nHeader )\n\t\t\t{\n\t\t\t\taLayout = [];\n\t\t\t\t_fnDetectHeader( aLayout, nHeader );\n\t\t\t}\n\t\t}\n\t\n\t\tfor ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfor ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( aLayout[i][j].unique &&\n\t\t\t\t\t (!aReturn[j] || !oSettings.bSortCellsTop) )\n\t\t\t\t{\n\t\t\t\t\taReturn[j] = aLayout[i][j].cell;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn aReturn;\n\t}\n\t\n\t/**\n\t * Create an Ajax call based on the table's settings, taking into account that\n\t * parameters can have multiple forms, and backwards compatibility.\n\t *\n\t * @param {object} oSettings dataTables settings object\n\t * @param {array} data Data to send to the server, required by\n\t *     DataTables - may be augmented by developer callbacks\n\t * @param {function} fn Callback function to run when data is obtained\n\t */\n\tfunction _fnBuildAjax( oSettings, data, fn )\n\t{\n\t\t// Compatibility with 1.9-, allow fnServerData and event to manipulate\n\t\t_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );\n\t\n\t\t// Convert to object based for 1.10+ if using the old array scheme which can\n\t\t// come from server-side processing or serverParams\n\t\tif ( data && $.isArray(data) ) {\n\t\t\tvar tmp = {};\n\t\t\tvar rbracket = /(.*?)\\[\\]$/;\n\t\n\t\t\t$.each( data, function (key, val) {\n\t\t\t\tvar match = val.name.match(rbracket);\n\t\n\t\t\t\tif ( match ) {\n\t\t\t\t\t// Support for arrays\n\t\t\t\t\tvar name = match[0];\n\t\n\t\t\t\t\tif ( ! tmp[ name ] ) {\n\t\t\t\t\t\ttmp[ name ] = [];\n\t\t\t\t\t}\n\t\t\t\t\ttmp[ name ].push( val.value );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttmp[val.name] = val.value;\n\t\t\t\t}\n\t\t\t} );\n\t\t\tdata = tmp;\n\t\t}\n\t\n\t\tvar ajaxData;\n\t\tvar ajax = oSettings.ajax;\n\t\tvar instance = oSettings.oInstance;\n\t\tvar callback = function ( json ) {\n\t\t\t_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );\n\t\t\tfn( json );\n\t\t};\n\t\n\t\tif ( $.isPlainObject( ajax ) && ajax.data )\n\t\t{\n\t\t\tajaxData = ajax.data;\n\t\n\t\t\tvar newData = $.isFunction( ajaxData ) ?\n\t\t\t\tajaxData( data, oSettings ) :  // fn can manipulate data or return\n\t\t\t\tajaxData;                      // an object object or array to merge\n\t\n\t\t\t// If the function returned something, use that alone\n\t\t\tdata = $.isFunction( ajaxData ) && newData ?\n\t\t\t\tnewData :\n\t\t\t\t$.extend( true, data, newData );\n\t\n\t\t\t// Remove the data property as we've resolved it already and don't want\n\t\t\t// jQuery to do it again (it is restored at the end of the function)\n\t\t\tdelete ajax.data;\n\t\t}\n\t\n\t\tvar baseAjax = {\n\t\t\t\"data\": data,\n\t\t\t\"success\": function (json) {\n\t\t\t\tvar error = json.error || json.sError;\n\t\t\t\tif ( error ) {\n\t\t\t\t\t_fnLog( oSettings, 0, error );\n\t\t\t\t}\n\t\n\t\t\t\toSettings.json = json;\n\t\t\t\tcallback( json );\n\t\t\t},\n\t\t\t\"dataType\": \"json\",\n\t\t\t\"cache\": false,\n\t\t\t\"type\": oSettings.sServerMethod,\n\t\t\t\"error\": function (xhr, error, thrown) {\n\t\t\t\tvar ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );\n\t\n\t\t\t\tif ( $.inArray( true, ret ) === -1 ) {\n\t\t\t\t\tif ( error == \"parsererror\" ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Invalid JSON response', 1 );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( xhr.readyState === 4 ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Ajax error', 7 );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\t}\n\t\t};\n\t\n\t\t// Store the data submitted for the API\n\t\toSettings.oAjaxData = data;\n\t\n\t\t// Allow plug-ins and external processes to modify the data\n\t\t_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );\n\t\n\t\tif ( oSettings.fnServerData )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.fnServerData.call( instance,\n\t\t\t\toSettings.sAjaxSource,\n\t\t\t\t$.map( data, function (val, key) { // Need to convert back to 1.9 trad format\n\t\t\t\t\treturn { name: key, value: val };\n\t\t\t\t} ),\n\t\t\t\tcallback,\n\t\t\t\toSettings\n\t\t\t);\n\t\t}\n\t\telse if ( oSettings.sAjaxSource || typeof ajax === 'string' )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, {\n\t\t\t\turl: ajax || oSettings.sAjaxSource\n\t\t\t} ) );\n\t\t}\n\t\telse if ( $.isFunction( ajax ) )\n\t\t{\n\t\t\t// Is a function - let the caller define what needs to be done\n\t\t\toSettings.jqXHR = ajax.call( instance, data, callback, oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Object to extend the base settings\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );\n\t\n\t\t\t// Restore for next time around\n\t\t\tajax.data = ajaxData;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Update the table using an Ajax call\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {boolean} Block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdate( settings )\n\t{\n\t\tif ( settings.bAjaxDataGet ) {\n\t\t\tsettings.iDraw++;\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t_fnBuildAjax(\n\t\t\t\tsettings,\n\t\t\t\t_fnAjaxParameters( settings ),\n\t\t\t\tfunction(json) {\n\t\t\t\t\t_fnAjaxUpdateDraw( settings, json );\n\t\t\t\t}\n\t\t\t);\n\t\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\t\n\t/**\n\t * Build up the parameters in an object needed for a server-side processing\n\t * request. Note that this is basically done twice, is different ways - a modern\n\t * method which is used by default in DataTables 1.10 which uses objects and\n\t * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if\n\t * the sAjaxSource option is used in the initialisation, or the legacyAjax\n\t * option is set.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {bool} block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxParameters( settings )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tcolumnCount = columns.length,\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tpreSearch = settings.oPreviousSearch,\n\t\t\tpreColSearch = settings.aoPreSearchCols,\n\t\t\ti, data = [], dataProp, column, columnSearch,\n\t\t\tsort = _fnSortFlatten( settings ),\n\t\t\tdisplayStart = settings._iDisplayStart,\n\t\t\tdisplayLength = features.bPaginate !== false ?\n\t\t\t\tsettings._iDisplayLength :\n\t\t\t\t-1;\n\t\n\t\tvar param = function ( name, value ) {\n\t\t\tdata.push( { 'name': name, 'value': value } );\n\t\t};\n\t\n\t\t// DataTables 1.9- compatible method\n\t\tparam( 'sEcho',          settings.iDraw );\n\t\tparam( 'iColumns',       columnCount );\n\t\tparam( 'sColumns',       _pluck( columns, 'sName' ).join(',') );\n\t\tparam( 'iDisplayStart',  displayStart );\n\t\tparam( 'iDisplayLength', displayLength );\n\t\n\t\t// DataTables 1.10+ method\n\t\tvar d = {\n\t\t\tdraw:    settings.iDraw,\n\t\t\tcolumns: [],\n\t\t\torder:   [],\n\t\t\tstart:   displayStart,\n\t\t\tlength:  displayLength,\n\t\t\tsearch:  {\n\t\t\t\tvalue: preSearch.sSearch,\n\t\t\t\tregex: preSearch.bRegex\n\t\t\t}\n\t\t};\n\t\n\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcolumnSearch = preColSearch[i];\n\t\t\tdataProp = typeof column.mData==\"function\" ? 'function' : column.mData ;\n\t\n\t\t\td.columns.push( {\n\t\t\t\tdata:       dataProp,\n\t\t\t\tname:       column.sName,\n\t\t\t\tsearchable: column.bSearchable,\n\t\t\t\torderable:  column.bSortable,\n\t\t\t\tsearch:     {\n\t\t\t\t\tvalue: columnSearch.sSearch,\n\t\t\t\t\tregex: columnSearch.bRegex\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\tparam( \"mDataProp_\"+i, dataProp );\n\t\n\t\t\tif ( features.bFilter ) {\n\t\t\t\tparam( 'sSearch_'+i,     columnSearch.sSearch );\n\t\t\t\tparam( 'bRegex_'+i,      columnSearch.bRegex );\n\t\t\t\tparam( 'bSearchable_'+i, column.bSearchable );\n\t\t\t}\n\t\n\t\t\tif ( features.bSort ) {\n\t\t\t\tparam( 'bSortable_'+i, column.bSortable );\n\t\t\t}\n\t\t}\n\t\n\t\tif ( features.bFilter ) {\n\t\t\tparam( 'sSearch', preSearch.sSearch );\n\t\t\tparam( 'bRegex', preSearch.bRegex );\n\t\t}\n\t\n\t\tif ( features.bSort ) {\n\t\t\t$.each( sort, function ( i, val ) {\n\t\t\t\td.order.push( { column: val.col, dir: val.dir } );\n\t\n\t\t\t\tparam( 'iSortCol_'+i, val.col );\n\t\t\t\tparam( 'sSortDir_'+i, val.dir );\n\t\t\t} );\n\t\n\t\t\tparam( 'iSortingCols', sort.length );\n\t\t}\n\t\n\t\t// If the legacy.ajax parameter is null, then we automatically decide which\n\t\t// form to use, based on sAjaxSource\n\t\tvar legacy = DataTable.ext.legacy.ajax;\n\t\tif ( legacy === null ) {\n\t\t\treturn settings.sAjaxSource ? data : d;\n\t\t}\n\t\n\t\t// Otherwise, if legacy has been specified then we use that to decide on the\n\t\t// form\n\t\treturn legacy ? data : d;\n\t}\n\t\n\t\n\t/**\n\t * Data the data from the server (nuking the old) and redraw the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} json json data return from the server.\n\t *  @param {string} json.sEcho Tracking flag for DataTables to match requests\n\t *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering\n\t *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering\n\t *  @param {array} json.aaData The data to display on this page\n\t *  @param {string} [json.sColumns] Column ordering (sName, comma separated)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdateDraw ( settings, json )\n\t{\n\t\t// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.\n\t\t// Support both\n\t\tvar compat = function ( old, modern ) {\n\t\t\treturn json[old] !== undefined ? json[old] : json[modern];\n\t\t};\n\t\n\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\tvar draw            = compat( 'sEcho',                'draw' );\n\t\tvar recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );\n\t\tvar recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );\n\t\n\t\tif ( draw ) {\n\t\t\t// Protect against out of sequence returns\n\t\t\tif ( draw*1 < settings.iDraw ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettings.iDraw = draw * 1;\n\t\t}\n\t\n\t\t_fnClearTable( settings );\n\t\tsettings._iRecordsTotal   = parseInt(recordsTotal, 10);\n\t\tsettings._iRecordsDisplay = parseInt(recordsFiltered, 10);\n\t\n\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t_fnAddData( settings, data[i] );\n\t\t}\n\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\n\t\tsettings.bAjaxDataGet = false;\n\t\t_fnDraw( settings );\n\t\n\t\tif ( ! settings._bInitComplete ) {\n\t\t\t_fnInitComplete( settings, json );\n\t\t}\n\t\n\t\tsettings.bAjaxDataGet = true;\n\t\t_fnProcessingDisplay( settings, false );\n\t}\n\t\n\t\n\t/**\n\t * Get the data from the JSON data source to use for drawing a table. Using\n\t * `_fnGetObjectDataFn` allows the data to be sourced from a property of the\n\t * source object, or from a processing function.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param  {object} json Data source object / array from the server\n\t *  @return {array} Array of data to use\n\t */\n\tfunction _fnAjaxDataSrc ( oSettings, json )\n\t{\n\t\tvar dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?\n\t\t\toSettings.ajax.dataSrc :\n\t\t\toSettings.sAjaxDataProp; // Compatibility with 1.9-.\n\t\n\t\t// Compatibility with 1.9-. In order to read from aaData, check if the\n\t\t// default has been changed, if not, check for aaData\n\t\tif ( dataSrc === 'data' ) {\n\t\t\treturn json.aaData || json[dataSrc];\n\t\t}\n\t\n\t\treturn dataSrc !== \"\" ?\n\t\t\t_fnGetObjectDataFn( dataSrc )( json ) :\n\t\t\tjson;\n\t}\n\t\n\t/**\n\t * Generate the node required for filtering text\n\t *  @returns {node} Filter control element\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlFilter ( settings )\n\t{\n\t\tvar classes = settings.oClasses;\n\t\tvar tableId = settings.sTableId;\n\t\tvar language = settings.oLanguage;\n\t\tvar previousSearch = settings.oPreviousSearch;\n\t\tvar features = settings.aanFeatures;\n\t\tvar input = '<input type=\"search\" class=\"'+classes.sFilterInput+'\"/>';\n\t\n\t\tvar str = language.sSearch;\n\t\tstr = str.match(/_INPUT_/) ?\n\t\t\tstr.replace('_INPUT_', input) :\n\t\t\tstr+input;\n\t\n\t\tvar filter = $('<div/>', {\n\t\t\t\t'id': ! features.f ? tableId+'_filter' : null,\n\t\t\t\t'class': classes.sFilter\n\t\t\t} )\n\t\t\t.append( $('<label/>' ).append( str ) );\n\t\n\t\tvar searchFn = function() {\n\t\t\t/* Update all other filter input elements for the new display */\n\t\t\tvar n = features.f;\n\t\t\tvar val = !this.value ? \"\" : this.value; // mental IE8 fix :-(\n\t\n\t\t\t/* Now do the filter */\n\t\t\tif ( val != previousSearch.sSearch ) {\n\t\t\t\t_fnFilterComplete( settings, {\n\t\t\t\t\t\"sSearch\": val,\n\t\t\t\t\t\"bRegex\": previousSearch.bRegex,\n\t\t\t\t\t\"bSmart\": previousSearch.bSmart ,\n\t\t\t\t\t\"bCaseInsensitive\": previousSearch.bCaseInsensitive\n\t\t\t\t} );\n\t\n\t\t\t\t// Need to redraw, without resorting\n\t\t\t\tsettings._iDisplayStart = 0;\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t};\n\t\n\t\tvar searchDelay = settings.searchDelay !== null ?\n\t\t\tsettings.searchDelay :\n\t\t\t_fnDataSource( settings ) === 'ssp' ?\n\t\t\t\t400 :\n\t\t\t\t0;\n\t\n\t\tvar jqFilter = $('input', filter)\n\t\t\t.val( previousSearch.sSearch )\n\t\t\t.attr( 'placeholder', language.sSearchPlaceholder )\n\t\t\t.on(\n\t\t\t\t'keyup.DT search.DT input.DT paste.DT cut.DT',\n\t\t\t\tsearchDelay ?\n\t\t\t\t\t_fnThrottle( searchFn, searchDelay ) :\n\t\t\t\t\tsearchFn\n\t\t\t)\n\t\t\t.on( 'keypress.DT', function(e) {\n\t\t\t\t/* Prevent form submission */\n\t\t\t\tif ( e.keyCode == 13 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.attr('aria-controls', tableId);\n\t\n\t\t// Update the input elements whenever the table is filtered\n\t\t$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame...\n\t\t\t\ttry {\n\t\t\t\t\tif ( jqFilter[0] !== document.activeElement ) {\n\t\t\t\t\t\tjqFilter.val( previousSearch.sSearch );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch ( e ) {}\n\t\t\t}\n\t\t} );\n\t\n\t\treturn filter[0];\n\t}\n\t\n\t\n\t/**\n\t * Filter the table using both the global filter and column based filtering\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oSearch search information\n\t *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterComplete ( oSettings, oInput, iForce )\n\t{\n\t\tvar oPrevSearch = oSettings.oPreviousSearch;\n\t\tvar aoPrevSearch = oSettings.aoPreSearchCols;\n\t\tvar fnSaveFilter = function ( oFilter ) {\n\t\t\t/* Save the filtering values */\n\t\t\toPrevSearch.sSearch = oFilter.sSearch;\n\t\t\toPrevSearch.bRegex = oFilter.bRegex;\n\t\t\toPrevSearch.bSmart = oFilter.bSmart;\n\t\t\toPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;\n\t\t};\n\t\tvar fnRegex = function ( o ) {\n\t\t\t// Backwards compatibility with the bEscapeRegex option\n\t\t\treturn o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;\n\t\t};\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo As per sort - can this be moved into an event handler?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\t/* In server-side processing all filtering is done by the server, so no point hanging around here */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' )\n\t\t{\n\t\t\t/* Global filter */\n\t\t\t_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );\n\t\t\tfnSaveFilter( oInput );\n\t\n\t\t\t/* Now do the individual column filter */\n\t\t\tfor ( var i=0 ; i<aoPrevSearch.length ; i++ )\n\t\t\t{\n\t\t\t\t_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),\n\t\t\t\t\taoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );\n\t\t\t}\n\t\n\t\t\t/* Custom filtering */\n\t\t\t_fnFilterCustom( oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfnSaveFilter( oInput );\n\t\t}\n\t\n\t\t/* Tell the draw function we have been filtering */\n\t\toSettings.bFiltered = true;\n\t\t_fnCallbackFire( oSettings, null, 'search', [oSettings] );\n\t}\n\t\n\t\n\t/**\n\t * Apply custom filtering functions\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCustom( settings )\n\t{\n\t\tvar filters = DataTable.ext.search;\n\t\tvar displayRows = settings.aiDisplay;\n\t\tvar row, rowIdx;\n\t\n\t\tfor ( var i=0, ien=filters.length ; i<ien ; i++ ) {\n\t\t\tvar rows = [];\n\t\n\t\t\t// Loop over each row and see if it should be included\n\t\t\tfor ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {\n\t\t\t\trowIdx = displayRows[ j ];\n\t\t\t\trow = settings.aoData[ rowIdx ];\n\t\n\t\t\t\tif ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {\n\t\t\t\t\trows.push( rowIdx );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// So the array reference doesn't break set the results into the\n\t\t\t// existing array\n\t\t\tdisplayRows.length = 0;\n\t\t\t$.merge( displayRows, rows );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Filter the table on a per-column basis\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sInput string to filter on\n\t *  @param {int} iColumn column to filter\n\t *  @param {bool} bRegex treat search string as a regular expression or not\n\t *  @param {bool} bSmart use smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )\n\t{\n\t\tif ( searchStr === '' ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar data;\n\t\tvar out = [];\n\t\tvar display = settings.aiDisplay;\n\t\tvar rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );\n\t\n\t\tfor ( var i=0 ; i<display.length ; i++ ) {\n\t\t\tdata = settings.aoData[ display[i] ]._aFilterData[ colIdx ];\n\t\n\t\t\tif ( rpSearch.test( data ) ) {\n\t\t\t\tout.push( display[i] );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aiDisplay = out;\n\t}\n\t\n\t\n\t/**\n\t * Filter the data table based on user input and draw the table\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} input string to filter on\n\t *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)\n\t *  @param {bool} regex treat as a regular expression or not\n\t *  @param {bool} smart perform smart filtering or not\n\t *  @param {bool} caseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilter( settings, input, force, regex, smart, caseInsensitive )\n\t{\n\t\tvar rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );\n\t\tvar prevSearch = settings.oPreviousSearch.sSearch;\n\t\tvar displayMaster = settings.aiDisplayMaster;\n\t\tvar display, invalidated, i;\n\t\tvar filtered = [];\n\t\n\t\t// Need to take account of custom filtering functions - always filter\n\t\tif ( DataTable.ext.search.length !== 0 ) {\n\t\t\tforce = true;\n\t\t}\n\t\n\t\t// Check if any of the rows were invalidated\n\t\tinvalidated = _fnFilterData( settings );\n\t\n\t\t// If the input is blank - we just want the full data set\n\t\tif ( input.length <= 0 ) {\n\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t}\n\t\telse {\n\t\t\t// New search - start from the master array\n\t\t\tif ( invalidated ||\n\t\t\t\t force ||\n\t\t\t\t prevSearch.length > input.length ||\n\t\t\t\t input.indexOf(prevSearch) !== 0 ||\n\t\t\t\t settings.bSorted // On resort, the display master needs to be\n\t\t\t\t                  // re-filtered since indexes will have changed\n\t\t\t) {\n\t\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t\t}\n\t\n\t\t\t// Search the display array\n\t\t\tdisplay = settings.aiDisplay;\n\t\n\t\t\tfor ( i=0 ; i<display.length ; i++ ) {\n\t\t\t\tif ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {\n\t\t\t\t\tfiltered.push( display[i] );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tsettings.aiDisplay = filtered;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a regular expression object suitable for searching a table\n\t *  @param {string} sSearch string to search for\n\t *  @param {bool} bRegex treat as a regular expression or not\n\t *  @param {bool} bSmart perform smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insensitive matching or not\n\t *  @returns {RegExp} constructed object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCreateSearch( search, regex, smart, caseInsensitive )\n\t{\n\t\tsearch = regex ?\n\t\t\tsearch :\n\t\t\t_fnEscapeRegex( search );\n\t\t\n\t\tif ( smart ) {\n\t\t\t/* For smart filtering we want to allow the search to work regardless of\n\t\t\t * word order. We also want double quoted text to be preserved, so word\n\t\t\t * order is important - a la google. So this is what we want to\n\t\t\t * generate:\n\t\t\t * \n\t\t\t * ^(?=.*?\\bone\\b)(?=.*?\\btwo three\\b)(?=.*?\\bfour\\b).*$\n\t\t\t */\n\t\t\tvar a = $.map( search.match( /\"[^\"]+\"|[^ ]+/g ) || [''], function ( word ) {\n\t\t\t\tif ( word.charAt(0) === '\"' ) {\n\t\t\t\t\tvar m = word.match( /^\"(.*)\"$/ );\n\t\t\t\t\tword = m ? m[1] : word;\n\t\t\t\t}\n\t\n\t\t\t\treturn word.replace('\"', '');\n\t\t\t} );\n\t\n\t\t\tsearch = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';\n\t\t}\n\t\n\t\treturn new RegExp( search, caseInsensitive ? 'i' : '' );\n\t}\n\t\n\t\n\t/**\n\t * Escape a string such that it can be used in a regular expression\n\t *  @param {string} sVal string to escape\n\t *  @returns {string} escaped string\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnEscapeRegex = DataTable.util.escapeRegex;\n\t\n\tvar __filter_div = $('<div>')[0];\n\tvar __filter_div_textContent = __filter_div.textContent !== undefined;\n\t\n\t// Update the filtering data for each row if needed (by invalidation or first run)\n\tfunction _fnFilterData ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar column;\n\t\tvar i, j, ien, jen, filterData, cellData, row;\n\t\tvar fomatters = DataTable.ext.type.search;\n\t\tvar wasInvalidated = false;\n\t\n\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aFilterData ) {\n\t\t\t\tfilterData = [];\n\t\n\t\t\t\tfor ( j=0, jen=columns.length ; j<jen ; j++ ) {\n\t\t\t\t\tcolumn = columns[j];\n\t\n\t\t\t\t\tif ( column.bSearchable ) {\n\t\t\t\t\t\tcellData = _fnGetCellData( settings, i, j, 'filter' );\n\t\n\t\t\t\t\t\tif ( fomatters[ column.sType ] ) {\n\t\t\t\t\t\t\tcellData = fomatters[ column.sType ]( cellData );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Search in DataTables 1.10 is string based. In 1.11 this\n\t\t\t\t\t\t// should be altered to also allow strict type checking.\n\t\t\t\t\t\tif ( cellData === null ) {\n\t\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( typeof cellData !== 'string' && cellData.toString ) {\n\t\t\t\t\t\t\tcellData = cellData.toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If it looks like there is an HTML entity in the string,\n\t\t\t\t\t// attempt to decode it so sorting works as expected. Note that\n\t\t\t\t\t// we could use a single line of jQuery to do this, but the DOM\n\t\t\t\t\t// method used here is much faster http://jsperf.com/html-decode\n\t\t\t\t\tif ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {\n\t\t\t\t\t\t__filter_div.innerHTML = cellData;\n\t\t\t\t\t\tcellData = __filter_div_textContent ?\n\t\t\t\t\t\t\t__filter_div.textContent :\n\t\t\t\t\t\t\t__filter_div.innerText;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tif ( cellData.replace ) {\n\t\t\t\t\t\tcellData = cellData.replace(/[\\r\\n]/g, '');\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfilterData.push( cellData );\n\t\t\t\t}\n\t\n\t\t\t\trow._aFilterData = filterData;\n\t\t\t\trow._sFilterRow = filterData.join('  ');\n\t\t\t\twasInvalidated = true;\n\t\t\t}\n\t\t}\n\t\n\t\treturn wasInvalidated;\n\t}\n\t\n\t\n\t/**\n\t * Convert from the internal Hungarian notation to camelCase for external\n\t * interaction\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToCamel ( obj )\n\t{\n\t\treturn {\n\t\t\tsearch:          obj.sSearch,\n\t\t\tsmart:           obj.bSmart,\n\t\t\tregex:           obj.bRegex,\n\t\t\tcaseInsensitive: obj.bCaseInsensitive\n\t\t};\n\t}\n\t\n\t\n\t\n\t/**\n\t * Convert from camelCase notation to the internal Hungarian. We could use the\n\t * Hungarian convert function here, but this is cleaner\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToHung ( obj )\n\t{\n\t\treturn {\n\t\t\tsSearch:          obj.search,\n\t\t\tbSmart:           obj.smart,\n\t\t\tbRegex:           obj.regex,\n\t\t\tbCaseInsensitive: obj.caseInsensitive\n\t\t};\n\t}\n\t\n\t/**\n\t * Generate the node required for the info display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Information element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlInfo ( settings )\n\t{\n\t\tvar\n\t\t\ttid = settings.sTableId,\n\t\t\tnodes = settings.aanFeatures.i,\n\t\t\tn = $('<div/>', {\n\t\t\t\t'class': settings.oClasses.sInfo,\n\t\t\t\t'id': ! nodes ? tid+'_info' : null\n\t\t\t} );\n\t\n\t\tif ( ! nodes ) {\n\t\t\t// Update display on each draw\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": _fnUpdateInfo,\n\t\t\t\t\"sName\": \"information\"\n\t\t\t} );\n\t\n\t\t\tn\n\t\t\t\t.attr( 'role', 'status' )\n\t\t\t\t.attr( 'aria-live', 'polite' );\n\t\n\t\t\t// Table is described by our info div\n\t\t\t$(settings.nTable).attr( 'aria-describedby', tid+'_info' );\n\t\t}\n\t\n\t\treturn n[0];\n\t}\n\t\n\t\n\t/**\n\t * Update the information elements in the display\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnUpdateInfo ( settings )\n\t{\n\t\t/* Show information about the table */\n\t\tvar nodes = settings.aanFeatures.i;\n\t\tif ( nodes.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\tlang  = settings.oLanguage,\n\t\t\tstart = settings._iDisplayStart+1,\n\t\t\tend   = settings.fnDisplayEnd(),\n\t\t\tmax   = settings.fnRecordsTotal(),\n\t\t\ttotal = settings.fnRecordsDisplay(),\n\t\t\tout   = total ?\n\t\t\t\tlang.sInfo :\n\t\t\t\tlang.sInfoEmpty;\n\t\n\t\tif ( total !== max ) {\n\t\t\t/* Record set after filtering */\n\t\t\tout += ' ' + lang.sInfoFiltered;\n\t\t}\n\t\n\t\t// Convert the macros\n\t\tout += lang.sInfoPostFix;\n\t\tout = _fnInfoMacros( settings, out );\n\t\n\t\tvar callback = lang.fnInfoCallback;\n\t\tif ( callback !== null ) {\n\t\t\tout = callback.call( settings.oInstance,\n\t\t\t\tsettings, start, end, max, total, out\n\t\t\t);\n\t\t}\n\t\n\t\t$(nodes).html( out );\n\t}\n\t\n\t\n\tfunction _fnInfoMacros ( settings, str )\n\t{\n\t\t// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only\n\t\t// internally\n\t\tvar\n\t\t\tformatter  = settings.fnFormatNumber,\n\t\t\tstart      = settings._iDisplayStart+1,\n\t\t\tlen        = settings._iDisplayLength,\n\t\t\tvis        = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn str.\n\t\t\treplace(/_START_/g, formatter.call( settings, start ) ).\n\t\t\treplace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).\n\t\t\treplace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).\n\t\t\treplace(/_TOTAL_/g, formatter.call( settings, vis ) ).\n\t\t\treplace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).\n\t\t\treplace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );\n\t}\n\t\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitialise ( settings )\n\t{\n\t\tvar i, iLen, iAjaxStart=settings.iInitDisplayStart;\n\t\tvar columns = settings.aoColumns, column;\n\t\tvar features = settings.oFeatures;\n\t\tvar deferLoading = settings.bDeferLoading; // value modified by the draw\n\t\n\t\t/* Ensure that the table data is fully initialised */\n\t\tif ( ! settings.bInitialised ) {\n\t\t\tsetTimeout( function(){ _fnInitialise( settings ); }, 200 );\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Show the display HTML options */\n\t\t_fnAddOptionsHtml( settings );\n\t\n\t\t/* Build and draw the header / footer for the table */\n\t\t_fnBuildHead( settings );\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t/* Okay to show that something is going on now */\n\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t/* Calculate sizes for columns */\n\t\tif ( features.bAutoWidth ) {\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\n\t\t\tif ( column.sWidth ) {\n\t\t\t\tcolumn.nTh.style.width = _fnStringToCss( column.sWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'preInit', [settings] );\n\t\n\t\t// If there is default sorting required - let's do it. The sort function\n\t\t// will do the drawing for us. Otherwise we draw the table regardless of the\n\t\t// Ajax source - this allows the table to look initialised for Ajax sourcing\n\t\t// data (show 'loading' message possibly)\n\t\t_fnReDraw( settings );\n\t\n\t\t// Server-side processing init complete is done by _fnAjaxUpdateDraw\n\t\tvar dataSrc = _fnDataSource( settings );\n\t\tif ( dataSrc != 'ssp' || deferLoading ) {\n\t\t\t// if there is an ajax source load the data\n\t\t\tif ( dataSrc == 'ajax' ) {\n\t\t\t\t_fnBuildAjax( settings, [], function(json) {\n\t\t\t\t\tvar aData = _fnAjaxDataSrc( settings, json );\n\t\n\t\t\t\t\t// Got the data - add it to the table\n\t\t\t\t\tfor ( i=0 ; i<aData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( settings, aData[i] );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Reset the init display for cookie saving. We've already done\n\t\t\t\t\t// a filter, and therefore cleared it before. So we need to make\n\t\t\t\t\t// it appear 'fresh'\n\t\t\t\t\tsettings.iInitDisplayStart = iAjaxStart;\n\t\n\t\t\t\t\t_fnReDraw( settings );\n\t\n\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t_fnInitComplete( settings, json );\n\t\t\t\t}, settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t_fnInitComplete( settings );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} [json] JSON from the server that completed the table, if using Ajax source\n\t *    with client-side processing (optional)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitComplete ( settings, json )\n\t{\n\t\tsettings._bInitComplete = true;\n\t\n\t\t// When data was added after the initialisation (data or Ajax) we need to\n\t\t// calculate the column sizing\n\t\tif ( json || settings.oInit.aaData ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'plugin-init', [settings, json] );\n\t\t_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );\n\t}\n\t\n\t\n\tfunction _fnLengthChange ( settings, val )\n\t{\n\t\tvar len = parseInt( val, 10 );\n\t\tsettings._iDisplayLength = len;\n\t\n\t\t_fnLengthOverflow( settings );\n\t\n\t\t// Fire length change event\n\t\t_fnCallbackFire( settings, null, 'length', [settings, len] );\n\t}\n\t\n\t\n\t/**\n\t * Generate the node required for user display length changing\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Display length feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlLength ( settings )\n\t{\n\t\tvar\n\t\t\tclasses  = settings.oClasses,\n\t\t\ttableId  = settings.sTableId,\n\t\t\tmenu     = settings.aLengthMenu,\n\t\t\td2       = $.isArray( menu[0] ),\n\t\t\tlengths  = d2 ? menu[0] : menu,\n\t\t\tlanguage = d2 ? menu[1] : menu;\n\t\n\t\tvar select = $('<select/>', {\n\t\t\t'name':          tableId+'_length',\n\t\t\t'aria-controls': tableId,\n\t\t\t'class':         classes.sLengthSelect\n\t\t} );\n\t\n\t\tfor ( var i=0, ien=lengths.length ; i<ien ; i++ ) {\n\t\t\tselect[0][ i ] = new Option( language[i], lengths[i] );\n\t\t}\n\t\n\t\tvar div = $('<div><label/></div>').addClass( classes.sLength );\n\t\tif ( ! settings.aanFeatures.l ) {\n\t\t\tdiv[0].id = tableId+'_length';\n\t\t}\n\t\n\t\tdiv.children().append(\n\t\t\tsettings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )\n\t\t);\n\t\n\t\t// Can't use `select` variable as user might provide their own and the\n\t\t// reference is broken by the use of outerHTML\n\t\t$('select', div)\n\t\t\t.val( settings._iDisplayLength )\n\t\t\t.on( 'change.DT', function(e) {\n\t\t\t\t_fnLengthChange( settings, $(this).val() );\n\t\t\t\t_fnDraw( settings );\n\t\t\t} );\n\t\n\t\t// Update node value whenever anything changes the table's length\n\t\t$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t$('select', div).val( len );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn div[0];\n\t}\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Note that most of the paging logic is done in\n\t * DataTable.ext.pager\n\t */\n\t\n\t/**\n\t * Generate the node required for default pagination\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Pagination feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlPaginate ( settings )\n\t{\n\t\tvar\n\t\t\ttype   = settings.sPaginationType,\n\t\t\tplugin = DataTable.ext.pager[ type ],\n\t\t\tmodern = typeof plugin === 'function',\n\t\t\tredraw = function( settings ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t},\n\t\t\tnode = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],\n\t\t\tfeatures = settings.aanFeatures;\n\t\n\t\tif ( ! modern ) {\n\t\t\tplugin.fnInit( settings, node, redraw );\n\t\t}\n\t\n\t\t/* Add a draw callback for the pagination on first instance, to update the paging display */\n\t\tif ( ! features.p )\n\t\t{\n\t\t\tnode.id = settings.sTableId+'_paginate';\n\t\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": function( settings ) {\n\t\t\t\t\tif ( modern ) {\n\t\t\t\t\t\tvar\n\t\t\t\t\t\t\tstart      = settings._iDisplayStart,\n\t\t\t\t\t\t\tlen        = settings._iDisplayLength,\n\t\t\t\t\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\t\t\t\t\tall        = len === -1,\n\t\t\t\t\t\t\tpage = all ? 0 : Math.ceil( start / len ),\n\t\t\t\t\t\t\tpages = all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\t\t\t\tbuttons = plugin(page, pages),\n\t\t\t\t\t\t\ti, ien;\n\t\n\t\t\t\t\t\tfor ( i=0, ien=features.p.length ; i<ien ; i++ ) {\n\t\t\t\t\t\t\t_fnRenderer( settings, 'pageButton' )(\n\t\t\t\t\t\t\t\tsettings, features.p[i], i, buttons, page, pages\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tplugin.fnUpdate( settings, redraw );\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"sName\": \"pagination\"\n\t\t\t} );\n\t\t}\n\t\n\t\treturn node;\n\t}\n\t\n\t\n\t/**\n\t * Alter the display settings to change the page\n\t *  @param {object} settings DataTables settings object\n\t *  @param {string|int} action Paging action to take: \"first\", \"previous\",\n\t *    \"next\" or \"last\" or page number to jump to (integer)\n\t *  @param [bool] redraw Automatically draw the update or not\n\t *  @returns {bool} true page has changed, false - no change\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnPageChange ( settings, action, redraw )\n\t{\n\t\tvar\n\t\t\tstart     = settings._iDisplayStart,\n\t\t\tlen       = settings._iDisplayLength,\n\t\t\trecords   = settings.fnRecordsDisplay();\n\t\n\t\tif ( records === 0 || len === -1 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( typeof action === \"number\" )\n\t\t{\n\t\t\tstart = action * len;\n\t\n\t\t\tif ( start > records )\n\t\t\t{\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"first\" )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( action == \"previous\" )\n\t\t{\n\t\t\tstart = len >= 0 ?\n\t\t\t\tstart - len :\n\t\t\t\t0;\n\t\n\t\t\tif ( start < 0 )\n\t\t\t{\n\t\t\t  start = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"next\" )\n\t\t{\n\t\t\tif ( start + len < records )\n\t\t\t{\n\t\t\t\tstart += len;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"last\" )\n\t\t{\n\t\t\tstart = Math.floor( (records-1) / len) * len;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_fnLog( settings, 0, \"Unknown paging action: \"+action, 5 );\n\t\t}\n\t\n\t\tvar changed = settings._iDisplayStart !== start;\n\t\tsettings._iDisplayStart = start;\n\t\n\t\tif ( changed ) {\n\t\t\t_fnCallbackFire( settings, null, 'page', [settings] );\n\t\n\t\t\tif ( redraw ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t}\n\t\n\t\treturn changed;\n\t}\n\t\n\t\n\t\n\t/**\n\t * Generate the node required for the processing node\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Processing element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlProcessing ( settings )\n\t{\n\t\treturn $('<div/>', {\n\t\t\t\t'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,\n\t\t\t\t'class': settings.oClasses.sProcessing\n\t\t\t} )\n\t\t\t.html( settings.oLanguage.sProcessing )\n\t\t\t.insertBefore( settings.nTable )[0];\n\t}\n\t\n\t\n\t/**\n\t * Display or hide the processing indicator\n\t *  @param {object} settings dataTables settings object\n\t *  @param {bool} show Show the processing indicator (true) or not (false)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnProcessingDisplay ( settings, show )\n\t{\n\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t$(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'processing', [settings, show] );\n\t}\n\t\n\t/**\n\t * Add any control elements for the table - specifically scrolling\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Node to add to the DOM\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlTable ( settings )\n\t{\n\t\tvar table = $(settings.nTable);\n\t\n\t\t// Add the ARIA grid role to the table\n\t\ttable.attr( 'role', 'grid' );\n\t\n\t\t// Scrolling from here on in\n\t\tvar scroll = settings.oScroll;\n\t\n\t\tif ( scroll.sX === '' && scroll.sY === '' ) {\n\t\t\treturn settings.nTable;\n\t\t}\n\t\n\t\tvar scrollX = scroll.sX;\n\t\tvar scrollY = scroll.sY;\n\t\tvar classes = settings.oClasses;\n\t\tvar caption = table.children('caption');\n\t\tvar captionSide = caption.length ? caption[0]._captionSide : null;\n\t\tvar headerClone = $( table[0].cloneNode(false) );\n\t\tvar footerClone = $( table[0].cloneNode(false) );\n\t\tvar footer = table.children('tfoot');\n\t\tvar _div = '<div/>';\n\t\tvar size = function ( s ) {\n\t\t\treturn !s ? null : _fnStringToCss( s );\n\t\t};\n\t\n\t\tif ( ! footer.length ) {\n\t\t\tfooter = null;\n\t\t}\n\t\n\t\t/*\n\t\t * The HTML structure that we want to generate in this function is:\n\t\t *  div - scroller\n\t\t *    div - scroll head\n\t\t *      div - scroll head inner\n\t\t *        table - scroll head table\n\t\t *          thead - thead\n\t\t *    div - scroll body\n\t\t *      table - table (master table)\n\t\t *        thead - thead clone for sizing\n\t\t *        tbody - tbody\n\t\t *    div - scroll foot\n\t\t *      div - scroll foot inner\n\t\t *        table - scroll foot table\n\t\t *          tfoot - tfoot\n\t\t */\n\t\tvar scroller = $( _div, { 'class': classes.sScrollWrapper } )\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollHead } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollHeadInner } )\n\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t'box-sizing': 'content-box',\n\t\t\t\t\t\t\t\twidth: scroll.sXInner || '100%'\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\theaderClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'top' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('thead')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t)\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollBody } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\toverflow: 'auto',\n\t\t\t\t\t\twidth: size( scrollX )\n\t\t\t\t\t} )\n\t\t\t\t\t.append( table )\n\t\t\t);\n\t\n\t\tif ( footer ) {\n\t\t\tscroller.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollFoot } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollFootInner } )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\tfooterClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'bottom' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('tfoot')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\n\t\tvar children = scroller.children();\n\t\tvar scrollHead = children[0];\n\t\tvar scrollBody = children[1];\n\t\tvar scrollFoot = footer ? children[2] : null;\n\t\n\t\t// When the body is scrolled, then we also want to scroll the headers\n\t\tif ( scrollX ) {\n\t\t\t$(scrollBody).on( 'scroll.DT', function (e) {\n\t\t\t\tvar scrollLeft = this.scrollLeft;\n\t\n\t\t\t\tscrollHead.scrollLeft = scrollLeft;\n\t\n\t\t\t\tif ( footer ) {\n\t\t\t\t\tscrollFoot.scrollLeft = scrollLeft;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\n\t\t$(scrollBody).css(\n\t\t\tscrollY && scroll.bCollapse ? 'max-height' : 'height', \n\t\t\tscrollY\n\t\t);\n\t\n\t\tsettings.nScrollHead = scrollHead;\n\t\tsettings.nScrollBody = scrollBody;\n\t\tsettings.nScrollFoot = scrollFoot;\n\t\n\t\t// On redraw - align columns\n\t\tsettings.aoDrawCallback.push( {\n\t\t\t\"fn\": _fnScrollDraw,\n\t\t\t\"sName\": \"scrolling\"\n\t\t} );\n\t\n\t\treturn scroller[0];\n\t}\n\t\n\t\n\t\n\t/**\n\t * Update the header, footer and body tables for resizing - i.e. column\n\t * alignment.\n\t *\n\t * Welcome to the most horrible function DataTables. The process that this\n\t * function follows is basically:\n\t *   1. Re-create the table inside the scrolling div\n\t *   2. Take live measurements from the DOM\n\t *   3. Apply the measurements to align the columns\n\t *   4. Clean up\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnScrollDraw ( settings )\n\t{\n\t\t// Given that this is such a monster function, a lot of variables are use\n\t\t// to try and keep the minimised size as small as possible\n\t\tvar\n\t\t\tscroll         = settings.oScroll,\n\t\t\tscrollX        = scroll.sX,\n\t\t\tscrollXInner   = scroll.sXInner,\n\t\t\tscrollY        = scroll.sY,\n\t\t\tbarWidth       = scroll.iBarWidth,\n\t\t\tdivHeader      = $(settings.nScrollHead),\n\t\t\tdivHeaderStyle = divHeader[0].style,\n\t\t\tdivHeaderInner = divHeader.children('div'),\n\t\t\tdivHeaderInnerStyle = divHeaderInner[0].style,\n\t\t\tdivHeaderTable = divHeaderInner.children('table'),\n\t\t\tdivBodyEl      = settings.nScrollBody,\n\t\t\tdivBody        = $(divBodyEl),\n\t\t\tdivBodyStyle   = divBodyEl.style,\n\t\t\tdivFooter      = $(settings.nScrollFoot),\n\t\t\tdivFooterInner = divFooter.children('div'),\n\t\t\tdivFooterTable = divFooterInner.children('table'),\n\t\t\theader         = $(settings.nTHead),\n\t\t\ttable          = $(settings.nTable),\n\t\t\ttableEl        = table[0],\n\t\t\ttableStyle     = tableEl.style,\n\t\t\tfooter         = settings.nTFoot ? $(settings.nTFoot) : null,\n\t\t\tbrowser        = settings.oBrowser,\n\t\t\tie67           = browser.bScrollOversize,\n\t\t\tdtHeaderCells  = _pluck( settings.aoColumns, 'nTh' ),\n\t\t\theaderTrgEls, footerTrgEls,\n\t\t\theaderSrcEls, footerSrcEls,\n\t\t\theaderCopy, footerCopy,\n\t\t\theaderWidths=[], footerWidths=[],\n\t\t\theaderContent=[], footerContent=[],\n\t\t\tidx, correction, sanityWidth,\n\t\t\tzeroOut = function(nSizer) {\n\t\t\t\tvar style = nSizer.style;\n\t\t\t\tstyle.paddingTop = \"0\";\n\t\t\t\tstyle.paddingBottom = \"0\";\n\t\t\t\tstyle.borderTopWidth = \"0\";\n\t\t\t\tstyle.borderBottomWidth = \"0\";\n\t\t\t\tstyle.height = 0;\n\t\t\t};\n\t\n\t\t// If the scrollbar visibility has changed from the last draw, we need to\n\t\t// adjust the column sizes as the table width will have changed to account\n\t\t// for the scrollbar\n\t\tvar scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;\n\t\t\n\t\tif ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t\treturn; // adjust column sizing will call this function again\n\t\t}\n\t\telse {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t}\n\t\n\t\t/*\n\t\t * 1. Re-create the table inside the scrolling div\n\t\t */\n\t\n\t\t// Remove the old minimised thead and tfoot elements in the inner table\n\t\ttable.children('thead, tfoot').remove();\n\t\n\t\tif ( footer ) {\n\t\t\tfooterCopy = footer.clone().prependTo( table );\n\t\t\tfooterTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized\n\t\t\tfooterSrcEls = footerCopy.find('tr');\n\t\t}\n\t\n\t\t// Clone the current header and footer elements and then place it into the inner table\n\t\theaderCopy = header.clone().prependTo( table );\n\t\theaderTrgEls = header.find('tr'); // original header is in its own table\n\t\theaderSrcEls = headerCopy.find('tr');\n\t\theaderCopy.find('th, td').removeAttr('tabindex');\n\t\n\t\n\t\t/*\n\t\t * 2. Take live measurements from the DOM - do not alter the DOM itself!\n\t\t */\n\t\n\t\t// Remove old sizing and apply the calculated column widths\n\t\t// Get the unique column headers in the newly created (cloned) header. We want to apply the\n\t\t// calculated sizes to this header\n\t\tif ( ! scrollX )\n\t\t{\n\t\t\tdivBodyStyle.width = '100%';\n\t\t\tdivHeader[0].style.width = '100%';\n\t\t}\n\t\n\t\t$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {\n\t\t\tidx = _fnVisibleToColumnIndex( settings, i );\n\t\t\tel.style.width = settings.aoColumns[idx].sWidth;\n\t\t} );\n\t\n\t\tif ( footer ) {\n\t\t\t_fnApplyToChildren( function(n) {\n\t\t\t\tn.style.width = \"\";\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Size the table as a whole\n\t\tsanityWidth = table.outerWidth();\n\t\tif ( scrollX === \"\" ) {\n\t\t\t// No x scrolling\n\t\t\ttableStyle.width = \"100%\";\n\t\n\t\t\t// IE7 will make the width of the table when 100% include the scrollbar\n\t\t\t// - which is shouldn't. When there is a scrollbar we need to take this\n\t\t\t// into account.\n\t\t\tif ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);\n\t\t\t}\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\telse if ( scrollXInner !== \"\" ) {\n\t\t\t// legacy x scroll inner has been given - use it\n\t\t\ttableStyle.width = _fnStringToCss(scrollXInner);\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\n\t\t// Hidden header should have zero height, so remove padding and borders. Then\n\t\t// set the width based on the real headers\n\t\n\t\t// Apply all styles in one pass\n\t\t_fnApplyToChildren( zeroOut, headerSrcEls );\n\t\n\t\t// Read all widths in next pass\n\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\theaderContent.push( nSizer.innerHTML );\n\t\t\theaderWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t}, headerSrcEls );\n\t\n\t\t// Apply all widths in final pass\n\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t// Only apply widths to the DataTables detected header cells - this\n\t\t\t// prevents complex headers from having contradictory sizes applied\n\t\t\tif ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {\n\t\t\t\tnToSize.style.width = headerWidths[i];\n\t\t\t}\n\t\t}, headerTrgEls );\n\t\n\t\t$(headerSrcEls).height(0);\n\t\n\t\t/* Same again with the footer if we have one */\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( zeroOut, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\t\tfooterContent.push( nSizer.innerHTML );\n\t\t\t\tfooterWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t\t}, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t\tnToSize.style.width = footerWidths[i];\n\t\t\t}, footerTrgEls );\n\t\n\t\t\t$(footerSrcEls).height(0);\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 3. Apply the measurements\n\t\t */\n\t\n\t\t// \"Hide\" the header and footer that we used for the sizing. We need to keep\n\t\t// the content of the cell so that the width applied to the header and body\n\t\t// both match, but we want to hide it completely. We want to also fix their\n\t\t// width to what they currently are\n\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\" style=\"height:0;overflow:hidden;\">'+headerContent[i]+'</div>';\n\t\t\tnSizer.style.width = headerWidths[i];\n\t\t}, headerSrcEls );\n\t\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\" style=\"height:0;overflow:hidden;\">'+footerContent[i]+'</div>';\n\t\t\t\tnSizer.style.width = footerWidths[i];\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Sanity check that the table is of a sensible width. If not then we are going to get\n\t\t// misalignment - try to prevent this by not allowing the table to shrink below its min width\n\t\tif ( table.outerWidth() < sanityWidth )\n\t\t{\n\t\t\t// The min width depends upon if we have a vertical scrollbar visible or not */\n\t\t\tcorrection = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")) ?\n\t\t\t\t\tsanityWidth+barWidth :\n\t\t\t\t\tsanityWidth;\n\t\n\t\t\t// IE6/7 are a law unto themselves...\n\t\t\tif ( ie67 && (divBodyEl.scrollHeight >\n\t\t\t\tdivBodyEl.offsetHeight || divBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( correction-barWidth );\n\t\t\t}\n\t\n\t\t\t// And give the user a warning that we've stopped the table getting too small\n\t\t\tif ( scrollX === \"\" || scrollXInner !== \"\" ) {\n\t\t\t\t_fnLog( settings, 1, 'Possible column misalignment', 6 );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcorrection = '100%';\n\t\t}\n\t\n\t\t// Apply to the container elements\n\t\tdivBodyStyle.width = _fnStringToCss( correction );\n\t\tdivHeaderStyle.width = _fnStringToCss( correction );\n\t\n\t\tif ( footer ) {\n\t\t\tsettings.nScrollFoot.style.width = _fnStringToCss( correction );\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 4. Clean up\n\t\t */\n\t\tif ( ! scrollY ) {\n\t\t\t/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting\n\t\t\t * the scrollbar height from the visible display, rather than adding it on. We need to\n\t\t\t * set the height in order to sort this. Don't want to do it in any other browsers.\n\t\t\t */\n\t\t\tif ( ie67 ) {\n\t\t\t\tdivBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Finally set the width's of the header and footer tables */\n\t\tvar iOuterWidth = table.outerWidth();\n\t\tdivHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\tdivHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );\n\t\n\t\t// Figure out if there are scrollbar present - if so then we need a the header and footer to\n\t\t// provide a bit more space to allow \"overflow\" scrolling (i.e. past the scrollbar)\n\t\tvar bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == \"scroll\";\n\t\tvar padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );\n\t\tdivHeaderInnerStyle[ padding ] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\n\t\tif ( footer ) {\n\t\t\tdivFooterTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style[padding] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\t}\n\t\n\t\t// Correct DOM ordering for colgroup - comes before the thead\n\t\ttable.children('colgroup').insertBefore( table.children('thead') );\n\t\n\t\t/* Adjust the position of the header in case we loose the y-scrollbar */\n\t\tdivBody.scroll();\n\t\n\t\t// If sorting or filtering has occurred, jump the scrolling back to the top\n\t\t// only if we aren't holding the position\n\t\tif ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {\n\t\t\tdivBodyEl.scrollTop = 0;\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Apply a given function to the display child nodes of an element array (typically\n\t * TD children of TR rows\n\t *  @param {function} fn Method to apply to the objects\n\t *  @param array {nodes} an1 List of elements to look through for display children\n\t *  @param array {nodes} an2 Another list (identical structure to the first) - optional\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyToChildren( fn, an1, an2 )\n\t{\n\t\tvar index=0, i=0, iLen=an1.length;\n\t\tvar nNode1, nNode2;\n\t\n\t\twhile ( i < iLen ) {\n\t\t\tnNode1 = an1[i].firstChild;\n\t\t\tnNode2 = an2 ? an2[i].firstChild : null;\n\t\n\t\t\twhile ( nNode1 ) {\n\t\t\t\tif ( nNode1.nodeType === 1 ) {\n\t\t\t\t\tif ( an2 ) {\n\t\t\t\t\t\tfn( nNode1, nNode2, index );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfn( nNode1, index );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\n\t\t\t\tnNode1 = nNode1.nextSibling;\n\t\t\t\tnNode2 = an2 ? nNode2.nextSibling : null;\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t}\n\t}\n\t\n\t\n\t\n\tvar __re_html_remove = /<.*?>/g;\n\t\n\t\n\t/**\n\t * Calculate the width of columns for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCalculateColumnWidths ( oSettings )\n\t{\n\t\tvar\n\t\t\ttable = oSettings.nTable,\n\t\t\tcolumns = oSettings.aoColumns,\n\t\t\tscroll = oSettings.oScroll,\n\t\t\tscrollY = scroll.sY,\n\t\t\tscrollX = scroll.sX,\n\t\t\tscrollXInner = scroll.sXInner,\n\t\t\tcolumnCount = columns.length,\n\t\t\tvisibleColumns = _fnGetColumns( oSettings, 'bVisible' ),\n\t\t\theaderCells = $('th', oSettings.nTHead),\n\t\t\ttableWidthAttr = table.getAttribute('width'), // from DOM element\n\t\t\ttableContainer = table.parentNode,\n\t\t\tuserInputs = false,\n\t\t\ti, column, columnIdx, width, outerWidth,\n\t\t\tbrowser = oSettings.oBrowser,\n\t\t\tie67 = browser.bScrollOversize;\n\t\n\t\tvar styleWidth = table.style.width;\n\t\tif ( styleWidth && styleWidth.indexOf('%') !== -1 ) {\n\t\t\ttableWidthAttr = styleWidth;\n\t\t}\n\t\n\t\t/* Convert any user input sizes into pixel sizes */\n\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\tif ( column.sWidth !== null ) {\n\t\t\t\tcolumn.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );\n\t\n\t\t\t\tuserInputs = true;\n\t\t\t}\n\t\t}\n\t\n\t\t/* If the number of columns in the DOM equals the number that we have to\n\t\t * process in DataTables, then we can use the offsets that are created by\n\t\t * the web- browser. No custom sizes can be set in order for this to happen,\n\t\t * nor scrolling used\n\t\t */\n\t\tif ( ie67 || ! userInputs && ! scrollX && ! scrollY &&\n\t\t     columnCount == _fnVisbleColumns( oSettings ) &&\n\t\t     columnCount == headerCells.length\n\t\t) {\n\t\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\t\tvar colIdx = _fnVisibleToColumnIndex( oSettings, i );\n\t\n\t\t\t\tif ( colIdx !== null ) {\n\t\t\t\t\tcolumns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise construct a single row, worst case, table with the widest\n\t\t\t// node in the data, assign any user defined widths, then insert it into\n\t\t\t// the DOM and allow the browser to do all the hard work of calculating\n\t\t\t// table widths\n\t\t\tvar tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table\n\t\t\t\t.css( 'visibility', 'hidden' )\n\t\t\t\t.removeAttr( 'id' );\n\t\n\t\t\t// Clean up the table body\n\t\t\ttmpTable.find('tbody tr').remove();\n\t\t\tvar tr = $('<tr/>').appendTo( tmpTable.find('tbody') );\n\t\n\t\t\t// Clone the table header and footer - we can't use the header / footer\n\t\t\t// from the cloned table, since if scrolling is active, the table's\n\t\t\t// real header and footer are contained in different table tags\n\t\t\ttmpTable.find('thead, tfoot').remove();\n\t\t\ttmpTable\n\t\t\t\t.append( $(oSettings.nTHead).clone() )\n\t\t\t\t.append( $(oSettings.nTFoot).clone() );\n\t\n\t\t\t// Remove any assigned widths from the footer (from scrolling)\n\t\t\ttmpTable.find('tfoot th, tfoot td').css('width', '');\n\t\n\t\t\t// Apply custom sizing to the cloned header\n\t\t\theaderCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );\n\t\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\t\theaderCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?\n\t\t\t\t\t_fnStringToCss( column.sWidthOrig ) :\n\t\t\t\t\t'';\n\t\n\t\t\t\t// For scrollX we need to force the column width otherwise the\n\t\t\t\t// browser will collapse it. If this width is smaller than the\n\t\t\t\t// width the column requires, then it will have no effect\n\t\t\t\tif ( column.sWidthOrig && scrollX ) {\n\t\t\t\t\t$( headerCells[i] ).append( $('<div/>').css( {\n\t\t\t\t\t\twidth: column.sWidthOrig,\n\t\t\t\t\t\tmargin: 0,\n\t\t\t\t\t\tpadding: 0,\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\theight: 1\n\t\t\t\t\t} ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Find the widest cell for each column and put it into the table\n\t\t\tif ( oSettings.aoData.length ) {\n\t\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\t\tcolumnIdx = visibleColumns[i];\n\t\t\t\t\tcolumn = columns[ columnIdx ];\n\t\n\t\t\t\t\t$( _fnGetWidestNode( oSettings, columnIdx ) )\n\t\t\t\t\t\t.clone( false )\n\t\t\t\t\t\t.append( column.sContentPadding )\n\t\t\t\t\t\t.appendTo( tr );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Tidy the temporary table - remove name attributes so there aren't\n\t\t\t// duplicated in the dom (radio elements for example)\n\t\t\t$('[name]', tmpTable).removeAttr('name');\n\t\n\t\t\t// Table has been built, attach to the document so we can work with it.\n\t\t\t// A holding element is used, positioned at the top of the container\n\t\t\t// with minimal height, so it has no effect on if the container scrolls\n\t\t\t// or not. Otherwise it might trigger scrolling when it actually isn't\n\t\t\t// needed\n\t\t\tvar holder = $('<div/>').css( scrollX || scrollY ?\n\t\t\t\t\t{\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\theight: 1,\n\t\t\t\t\t\tright: 0,\n\t\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t\t} :\n\t\t\t\t\t{}\n\t\t\t\t)\n\t\t\t\t.append( tmpTable )\n\t\t\t\t.appendTo( tableContainer );\n\t\n\t\t\t// When scrolling (X or Y) we want to set the width of the table as \n\t\t\t// appropriate. However, when not scrolling leave the table width as it\n\t\t\t// is. This results in slightly different, but I think correct behaviour\n\t\t\tif ( scrollX && scrollXInner ) {\n\t\t\t\ttmpTable.width( scrollXInner );\n\t\t\t}\n\t\t\telse if ( scrollX ) {\n\t\t\t\ttmpTable.css( 'width', 'auto' );\n\t\t\t\ttmpTable.removeAttr('width');\n\t\n\t\t\t\t// If there is no width attribute or style, then allow the table to\n\t\t\t\t// collapse\n\t\t\t\tif ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {\n\t\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( scrollY ) {\n\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t}\n\t\t\telse if ( tableWidthAttr ) {\n\t\t\t\ttmpTable.width( tableWidthAttr );\n\t\t\t}\n\t\n\t\t\t// Get the width of each column in the constructed table - we need to\n\t\t\t// know the inner width (so it can be assigned to the other table's\n\t\t\t// cells) and the outer width so we can calculate the full width of the\n\t\t\t// table. This is safe since DataTables requires a unique cell for each\n\t\t\t// column, but if ever a header can span multiple columns, this will\n\t\t\t// need to be modified.\n\t\t\tvar total = 0;\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tvar cell = $(headerCells[i]);\n\t\t\t\tvar border = cell.outerWidth() - cell.width();\n\t\n\t\t\t\t// Use getBounding... where possible (not IE8-) because it can give\n\t\t\t\t// sub-pixel accuracy, which we then want to round up!\n\t\t\t\tvar bounding = browser.bBounding ?\n\t\t\t\t\tMath.ceil( headerCells[i].getBoundingClientRect().width ) :\n\t\t\t\t\tcell.outerWidth();\n\t\n\t\t\t\t// Total is tracked to remove any sub-pixel errors as the outerWidth\n\t\t\t\t// of the table might not equal the total given here (IE!).\n\t\t\t\ttotal += bounding;\n\t\n\t\t\t\t// Width for each column to use\n\t\t\t\tcolumns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );\n\t\t\t}\n\t\n\t\t\ttable.style.width = _fnStringToCss( total );\n\t\n\t\t\t// Finished with the table - ditch it\n\t\t\tholder.remove();\n\t\t}\n\t\n\t\t// If there is a width attr, we want to attach an event listener which\n\t\t// allows the table sizing to automatically adjust when the window is\n\t\t// resized. Use the width attr rather than CSS, since we can't know if the\n\t\t// CSS is a relative value or absolute - DOM read is always px.\n\t\tif ( tableWidthAttr ) {\n\t\t\ttable.style.width = _fnStringToCss( tableWidthAttr );\n\t\t}\n\t\n\t\tif ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {\n\t\t\tvar bindResize = function () {\n\t\t\t\t$(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {\n\t\t\t\t\t_fnAdjustColumnSizing( oSettings );\n\t\t\t\t} ) );\n\t\t\t};\n\t\n\t\t\t// IE6/7 will crash if we bind a resize event handler on page load.\n\t\t\t// To be removed in 1.11 which drops IE6/7 support\n\t\t\tif ( ie67 ) {\n\t\t\t\tsetTimeout( bindResize, 1000 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbindResize();\n\t\t\t}\n\t\n\t\t\toSettings._reszEvt = true;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Throttle the calls to a function. Arguments and context are maintained for\n\t * the throttled function\n\t *  @param {function} fn Function to be called\n\t *  @param {int} [freq=200] call frequency in mS\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnThrottle = DataTable.util.throttle;\n\t\n\t\n\t/**\n\t * Convert a CSS unit width to pixels (e.g. 2em)\n\t *  @param {string} width width to be converted\n\t *  @param {node} parent parent to get the with for (required for relative widths) - optional\n\t *  @returns {int} width in pixels\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnConvertToWidth ( width, parent )\n\t{\n\t\tif ( ! width ) {\n\t\t\treturn 0;\n\t\t}\n\t\n\t\tvar n = $('<div/>')\n\t\t\t.css( 'width', _fnStringToCss( width ) )\n\t\t\t.appendTo( parent || document.body );\n\t\n\t\tvar val = n[0].offsetWidth;\n\t\tn.remove();\n\t\n\t\treturn val;\n\t}\n\t\n\t\n\t/**\n\t * Get the widest node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {node} widest table node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetWidestNode( settings, colIdx )\n\t{\n\t\tvar idx = _fnGetMaxLenString( settings, colIdx );\n\t\tif ( idx < 0 ) {\n\t\t\treturn null;\n\t\t}\n\t\n\t\tvar data = settings.aoData[ idx ];\n\t\treturn ! data.nTr ? // Might not have been created when deferred rendering\n\t\t\t$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :\n\t\t\tdata.anCells[ colIdx ];\n\t}\n\t\n\t\n\t/**\n\t * Get the maximum strlen for each data column\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {string} max string length for each column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetMaxLenString( settings, colIdx )\n\t{\n\t\tvar s, max=-1, maxIdx = -1;\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\ts = _fnGetCellData( settings, i, colIdx, 'display' )+'';\n\t\t\ts = s.replace( __re_html_remove, '' );\n\t\t\ts = s.replace( /&nbsp;/g, ' ' );\n\t\n\t\t\tif ( s.length > max ) {\n\t\t\t\tmax = s.length;\n\t\t\t\tmaxIdx = i;\n\t\t\t}\n\t\t}\n\t\n\t\treturn maxIdx;\n\t}\n\t\n\t\n\t/**\n\t * Append a CSS unit (only if required) to a string\n\t *  @param {string} value to css-ify\n\t *  @returns {string} value with css unit\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnStringToCss( s )\n\t{\n\t\tif ( s === null ) {\n\t\t\treturn '0px';\n\t\t}\n\t\n\t\tif ( typeof s == 'number' ) {\n\t\t\treturn s < 0 ?\n\t\t\t\t'0px' :\n\t\t\t\ts+'px';\n\t\t}\n\t\n\t\t// Check it has a unit character already\n\t\treturn s.match(/\\d$/) ?\n\t\t\ts+'px' :\n\t\t\ts;\n\t}\n\t\n\t\n\t\n\tfunction _fnSortFlatten ( settings )\n\t{\n\t\tvar\n\t\t\ti, iLen, k, kLen,\n\t\t\taSort = [],\n\t\t\taiOrig = [],\n\t\t\taoColumns = settings.aoColumns,\n\t\t\taDataSort, iCol, sType, srcCol,\n\t\t\tfixed = settings.aaSortingFixed,\n\t\t\tfixedObj = $.isPlainObject( fixed ),\n\t\t\tnestedSort = [],\n\t\t\tadd = function ( a ) {\n\t\t\t\tif ( a.length && ! $.isArray( a[0] ) ) {\n\t\t\t\t\t// 1D array\n\t\t\t\t\tnestedSort.push( a );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// 2D array\n\t\t\t\t\t$.merge( nestedSort, a );\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t// Build the sort array, with pre-fix and post-fix options if they have been\n\t\t// specified\n\t\tif ( $.isArray( fixed ) ) {\n\t\t\tadd( fixed );\n\t\t}\n\t\n\t\tif ( fixedObj && fixed.pre ) {\n\t\t\tadd( fixed.pre );\n\t\t}\n\t\n\t\tadd( settings.aaSorting );\n\t\n\t\tif (fixedObj && fixed.post ) {\n\t\t\tadd( fixed.post );\n\t\t}\n\t\n\t\tfor ( i=0 ; i<nestedSort.length ; i++ )\n\t\t{\n\t\t\tsrcCol = nestedSort[i][0];\n\t\t\taDataSort = aoColumns[ srcCol ].aDataSort;\n\t\n\t\t\tfor ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )\n\t\t\t{\n\t\t\t\tiCol = aDataSort[k];\n\t\t\t\tsType = aoColumns[ iCol ].sType || 'string';\n\t\n\t\t\t\tif ( nestedSort[i]._idx === undefined ) {\n\t\t\t\t\tnestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );\n\t\t\t\t}\n\t\n\t\t\t\taSort.push( {\n\t\t\t\t\tsrc:       srcCol,\n\t\t\t\t\tcol:       iCol,\n\t\t\t\t\tdir:       nestedSort[i][1],\n\t\t\t\t\tindex:     nestedSort[i]._idx,\n\t\t\t\t\ttype:      sType,\n\t\t\t\t\tformatter: DataTable.ext.type.order[ sType+\"-pre\" ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\treturn aSort;\n\t}\n\t\n\t/**\n\t * Change the order of the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t *  @todo This really needs split up!\n\t */\n\tfunction _fnSort ( oSettings )\n\t{\n\t\tvar\n\t\t\ti, ien, iLen, j, jLen, k, kLen,\n\t\t\tsDataType, nTh,\n\t\t\taiOrig = [],\n\t\t\toExtSort = DataTable.ext.type.order,\n\t\t\taoData = oSettings.aoData,\n\t\t\taoColumns = oSettings.aoColumns,\n\t\t\taDataSort, data, iCol, sType, oSort,\n\t\t\tformatters = 0,\n\t\t\tsortCol,\n\t\t\tdisplayMaster = oSettings.aiDisplayMaster,\n\t\t\taSort;\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo Can this be moved into a 'data-ready' handler which is called when\n\t\t//   data is going to be used in the table?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\taSort = _fnSortFlatten( oSettings );\n\t\n\t\tfor ( i=0, ien=aSort.length ; i<ien ; i++ ) {\n\t\t\tsortCol = aSort[i];\n\t\n\t\t\t// Track if we can use the fast sort algorithm\n\t\t\tif ( sortCol.formatter ) {\n\t\t\t\tformatters++;\n\t\t\t}\n\t\n\t\t\t// Load the data needed for the sort, for each cell\n\t\t\t_fnSortData( oSettings, sortCol.col );\n\t\t}\n\t\n\t\t/* No sorting required if server-side or no sorting array */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )\n\t\t{\n\t\t\t// Create a value - key array of the current row positions such that we can use their\n\t\t\t// current position during the sort, if values match, in order to perform stable sorting\n\t\t\tfor ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {\n\t\t\t\taiOrig[ displayMaster[i] ] = i;\n\t\t\t}\n\t\n\t\t\t/* Do the sort - here we want multi-column sorting based on a given data source (column)\n\t\t\t * and sorting function (from oSort) in a certain direction. It's reasonably complex to\n\t\t\t * follow on it's own, but this is what we want (example two column sorting):\n\t\t\t *  fnLocalSorting = function(a,b){\n\t\t\t *    var iTest;\n\t\t\t *    iTest = oSort['string-asc']('data11', 'data12');\n\t\t\t *      if (iTest !== 0)\n\t\t\t *        return iTest;\n\t\t\t *    iTest = oSort['numeric-desc']('data21', 'data22');\n\t\t\t *    if (iTest !== 0)\n\t\t\t *      return iTest;\n\t\t\t *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );\n\t\t\t *  }\n\t\t\t * Basically we have a test for each sorting column, if the data in that column is equal,\n\t\t\t * test the next column. If all columns match, then we use a numeric sort on the row\n\t\t\t * positions in the original data array to provide a stable sort.\n\t\t\t *\n\t\t\t * Note - I know it seems excessive to have two sorting methods, but the first is around\n\t\t\t * 15% faster, so the second is only maintained for backwards compatibility with sorting\n\t\t\t * methods which do not have a pre-sort formatting function.\n\t\t\t */\n\t\t\tif ( formatters === aSort.length ) {\n\t\t\t\t// All sort types have formatting functions\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, test, sort,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\ttest = x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn sort.dir === 'asc' ? test : -test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Depreciated - remove in 1.11 (providing a plug-in option)\n\t\t\t\t// Not all sort types have formatting methods, so we have to call their sorting\n\t\t\t\t// methods.\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, l, test, sort, fn,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\tfn = oExtSort[ sort.type+\"-\"+sort.dir ] || oExtSort[ \"string-\"+sort.dir ];\n\t\t\t\t\t\ttest = fn( x, y );\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Tell the draw function that we have sorted the data */\n\t\toSettings.bSorted = true;\n\t}\n\t\n\t\n\tfunction _fnSortAria ( settings )\n\t{\n\t\tvar label;\n\t\tvar nextSort;\n\t\tvar columns = settings.aoColumns;\n\t\tvar aSort = _fnSortFlatten( settings );\n\t\tvar oAria = settings.oLanguage.oAria;\n\t\n\t\t// ARIA attributes - need to loop all columns, to update all (removing old\n\t\t// attributes as needed)\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar col = columns[i];\n\t\t\tvar asSorting = col.asSorting;\n\t\t\tvar sTitle = col.sTitle.replace( /<.*?>/g, \"\" );\n\t\t\tvar th = col.nTh;\n\t\n\t\t\t// IE7 is throwing an error when setting these properties with jQuery's\n\t\t\t// attr() and removeAttr() methods...\n\t\t\tth.removeAttribute('aria-sort');\n\t\n\t\t\t/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */\n\t\t\tif ( col.bSortable ) {\n\t\t\t\tif ( aSort.length > 0 && aSort[0].col == i ) {\n\t\t\t\t\tth.setAttribute('aria-sort', aSort[0].dir==\"asc\" ? \"ascending\" : \"descending\" );\n\t\t\t\t\tnextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnextSort = asSorting[0];\n\t\t\t\t}\n\t\n\t\t\t\tlabel = sTitle + ( nextSort === \"asc\" ?\n\t\t\t\t\toAria.sSortAscending :\n\t\t\t\t\toAria.sSortDescending\n\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlabel = sTitle;\n\t\t\t}\n\t\n\t\t\tth.setAttribute('aria-label', label);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Function to run on user sort request\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {boolean} [append=false] Append the requested sort to the existing\n\t *    sort if true (i.e. multi-column sort)\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortListener ( settings, colIdx, append, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\tvar sorting = settings.aaSorting;\n\t\tvar asSorting = col.asSorting;\n\t\tvar nextSortIdx;\n\t\tvar next = function ( a, overflow ) {\n\t\t\tvar idx = a._idx;\n\t\t\tif ( idx === undefined ) {\n\t\t\t\tidx = $.inArray( a[1], asSorting );\n\t\t\t}\n\t\n\t\t\treturn idx+1 < asSorting.length ?\n\t\t\t\tidx+1 :\n\t\t\t\toverflow ?\n\t\t\t\t\tnull :\n\t\t\t\t\t0;\n\t\t};\n\t\n\t\t// Convert to 2D array if needed\n\t\tif ( typeof sorting[0] === 'number' ) {\n\t\t\tsorting = settings.aaSorting = [ sorting ];\n\t\t}\n\t\n\t\t// If appending the sort then we are multi-column sorting\n\t\tif ( append && settings.oFeatures.bSortMulti ) {\n\t\t\t// Are we already doing some kind of sort on this column?\n\t\t\tvar sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );\n\t\n\t\t\tif ( sortIdx !== -1 ) {\n\t\t\t\t// Yes, modify the sort\n\t\t\t\tnextSortIdx = next( sorting[sortIdx], true );\n\t\n\t\t\t\tif ( nextSortIdx === null && sorting.length === 1 ) {\n\t\t\t\t\tnextSortIdx = 0; // can't remove sorting completely\n\t\t\t\t}\n\t\n\t\t\t\tif ( nextSortIdx === null ) {\n\t\t\t\t\tsorting.splice( sortIdx, 1 );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tsorting[sortIdx][1] = asSorting[ nextSortIdx ];\n\t\t\t\t\tsorting[sortIdx]._idx = nextSortIdx;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// No sort on this column yet\n\t\t\t\tsorting.push( [ colIdx, asSorting[0], 0 ] );\n\t\t\t\tsorting[sorting.length-1]._idx = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( sorting.length && sorting[0][0] == colIdx ) {\n\t\t\t// Single column - already sorting on this column, modify the sort\n\t\t\tnextSortIdx = next( sorting[0] );\n\t\n\t\t\tsorting.length = 1;\n\t\t\tsorting[0][1] = asSorting[ nextSortIdx ];\n\t\t\tsorting[0]._idx = nextSortIdx;\n\t\t}\n\t\telse {\n\t\t\t// Single column - sort only on this column\n\t\t\tsorting.length = 0;\n\t\t\tsorting.push( [ colIdx, asSorting[0] ] );\n\t\t\tsorting[0]._idx = 0;\n\t\t}\n\t\n\t\t// Run the sort by calling a full redraw\n\t\t_fnReDraw( settings );\n\t\n\t\t// callback used for async user interaction\n\t\tif ( typeof callback == 'function' ) {\n\t\t\tcallback( settings );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Attach a sort handler (click) to a node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortAttachListener ( settings, attachTo, colIdx, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\n\t\t_fnBindAction( attachTo, {}, function (e) {\n\t\t\t/* If the column is not sortable - don't to anything */\n\t\t\tif ( col.bSortable === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If processing is enabled use a timeout to allow the processing\n\t\t\t// display to be shown - otherwise to it synchronously\n\t\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t\tsetTimeout( function() {\n\t\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\n\t\t\t\t\t// In server-side processing, the draw callback will remove the\n\t\t\t\t\t// processing display\n\t\t\t\t\tif ( _fnDataSource( settings ) !== 'ssp' ) {\n\t\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t}\n\t\t\t\t}, 0 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Set the sorting classes on table's body, Note: it is safe to call this function\n\t * when bSort and bSortClasses are false\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortingClasses( settings )\n\t{\n\t\tvar oldSort = settings.aLastSort;\n\t\tvar sortClass = settings.oClasses.sSortColumn;\n\t\tvar sort = _fnSortFlatten( settings );\n\t\tvar features = settings.oFeatures;\n\t\tvar i, ien, colIdx;\n\t\n\t\tif ( features.bSort && features.bSortClasses ) {\n\t\t\t// Remove old sorting classes\n\t\t\tfor ( i=0, ien=oldSort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = oldSort[i].src;\n\t\n\t\t\t\t// Remove column sorting\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.removeClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\n\t\t\t// Add new column sorting\n\t\t\tfor ( i=0, ien=sort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = sort[i].src;\n\t\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.addClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aLastSort = sort;\n\t}\n\t\n\t\n\t// Get the data to sort a column, be it from cache, fresh (populating the\n\t// cache), or from a sort formatter\n\tfunction _fnSortData( settings, idx )\n\t{\n\t\t// Custom sorting function - provided by the sort data type\n\t\tvar column = settings.aoColumns[ idx ];\n\t\tvar customSort = DataTable.ext.order[ column.sSortDataType ];\n\t\tvar customData;\n\t\n\t\tif ( customSort ) {\n\t\t\tcustomData = customSort.call( settings.oInstance, settings, idx,\n\t\t\t\t_fnColumnIndexToVisible( settings, idx )\n\t\t\t);\n\t\t}\n\t\n\t\t// Use / populate cache\n\t\tvar row, cellData;\n\t\tvar formatter = DataTable.ext.type.order[ column.sType+\"-pre\" ];\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aSortData ) {\n\t\t\t\trow._aSortData = [];\n\t\t\t}\n\t\n\t\t\tif ( ! row._aSortData[idx] || customSort ) {\n\t\t\t\tcellData = customSort ?\n\t\t\t\t\tcustomData[i] : // If there was a custom sort function, use data from there\n\t\t\t\t\t_fnGetCellData( settings, i, idx, 'sort' );\n\t\n\t\t\t\trow._aSortData[ idx ] = formatter ?\n\t\t\t\t\tformatter( cellData ) :\n\t\t\t\t\tcellData;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Save the state of a table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSaveState ( settings )\n\t{\n\t\tif ( !settings.oFeatures.bStateSave || settings.bDestroying )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Store the interesting variables */\n\t\tvar state = {\n\t\t\ttime:    +new Date(),\n\t\t\tstart:   settings._iDisplayStart,\n\t\t\tlength:  settings._iDisplayLength,\n\t\t\torder:   $.extend( true, [], settings.aaSorting ),\n\t\t\tsearch:  _fnSearchToCamel( settings.oPreviousSearch ),\n\t\t\tcolumns: $.map( settings.aoColumns, function ( col, i ) {\n\t\t\t\treturn {\n\t\t\t\t\tvisible: col.bVisible,\n\t\t\t\t\tsearch: _fnSearchToCamel( settings.aoPreSearchCols[i] )\n\t\t\t\t};\n\t\t\t} )\n\t\t};\n\t\n\t\t_fnCallbackFire( settings, \"aoStateSaveParams\", 'stateSaveParams', [settings, state] );\n\t\n\t\tsettings.oSavedState = state;\n\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, state );\n\t}\n\t\n\t\n\t/**\n\t * Attempt to load a saved table state\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oInit DataTables init object so we can override settings\n\t *  @param {function} callback Callback to execute when the state has been loaded\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLoadState ( settings, oInit, callback )\n\t{\n\t\tvar i, ien;\n\t\tvar columns = settings.aoColumns;\n\t\tvar loaded = function ( s ) {\n\t\t\tif ( ! s || ! s.time ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Allow custom and plug-in manipulation functions to alter the saved data set and\n\t\t\t// cancelling of loading by returning false\n\t\t\tvar abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );\n\t\t\tif ( $.inArray( false, abStateLoad ) !== -1 ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Reject old data\n\t\t\tvar duration = settings.iStateDuration;\n\t\t\tif ( duration > 0 && s.time < +new Date() - (duration*1000) ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Number of columns have changed - all bets are off, no restore of settings\n\t\t\tif ( s.columns && columns.length !== s.columns.length ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Store the saved state so it might be accessed at any time\n\t\t\tsettings.oLoadedState = $.extend( true, {}, state );\n\t\n\t\t\t// Restore key features - todo - for 1.11 this needs to be done by\n\t\t\t// subscribed events\n\t\t\tif ( s.start !== undefined ) {\n\t\t\t\tsettings._iDisplayStart    = s.start;\n\t\t\t\tsettings.iInitDisplayStart = s.start;\n\t\t\t}\n\t\t\tif ( s.length !== undefined ) {\n\t\t\t\tsettings._iDisplayLength   = s.length;\n\t\t\t}\n\t\n\t\t\t// Order\n\t\t\tif ( s.order !== undefined ) {\n\t\t\t\tsettings.aaSorting = [];\n\t\t\t\t$.each( s.order, function ( i, col ) {\n\t\t\t\t\tsettings.aaSorting.push( col[0] >= columns.length ?\n\t\t\t\t\t\t[ 0, col[1] ] :\n\t\t\t\t\t\tcol\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Search\n\t\t\tif ( s.search !== undefined ) {\n\t\t\t\t$.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );\n\t\t\t}\n\t\n\t\t\t// Columns\n\t\t\t// \n\t\t\tif ( s.columns ) {\n\t\t\t\tfor ( i=0, ien=s.columns.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar col = s.columns[i];\n\t\n\t\t\t\t\t// Visibility\n\t\t\t\t\tif ( col.visible !== undefined ) {\n\t\t\t\t\t\tcolumns[i].bVisible = col.visible;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Search\n\t\t\t\t\tif ( col.search !== undefined ) {\n\t\t\t\t\t\t$.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );\n\t\t\tcallback();\n\t\t}\n\t\n\t\tif ( ! settings.oFeatures.bStateSave ) {\n\t\t\tcallback();\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );\n\t\n\t\tif ( state !== undefined ) {\n\t\t\tloaded( state );\n\t\t}\n\t\t// otherwise, wait for the loaded callback to be executed\n\t}\n\t\n\t\n\t/**\n\t * Return the settings object for a particular table\n\t *  @param {node} table table we are using as a dataTable\n\t *  @returns {object} Settings object - or null if not found\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSettingsFromNode ( table )\n\t{\n\t\tvar settings = DataTable.settings;\n\t\tvar idx = $.inArray( table, _pluck( settings, 'nTable' ) );\n\t\n\t\treturn idx !== -1 ?\n\t\t\tsettings[ idx ] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Log an error message\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} level log error messages, or display them to the user\n\t *  @param {string} msg error message\n\t *  @param {int} tn Technical note id to get more information about the error.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLog( settings, level, msg, tn )\n\t{\n\t\tmsg = 'DataTables warning: '+\n\t\t\t(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;\n\t\n\t\tif ( tn ) {\n\t\t\tmsg += '. For more information about this error, please see '+\n\t\t\t'http://datatables.net/tn/'+tn;\n\t\t}\n\t\n\t\tif ( ! level  ) {\n\t\t\t// Backwards compatibility pre 1.10\n\t\t\tvar ext = DataTable.ext;\n\t\t\tvar type = ext.sErrMode || ext.errMode;\n\t\n\t\t\tif ( settings ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );\n\t\t\t}\n\t\n\t\t\tif ( type == 'alert' ) {\n\t\t\t\talert( msg );\n\t\t\t}\n\t\t\telse if ( type == 'throw' ) {\n\t\t\t\tthrow new Error(msg);\n\t\t\t}\n\t\t\telse if ( typeof type == 'function' ) {\n\t\t\t\ttype( settings, tn, msg );\n\t\t\t}\n\t\t}\n\t\telse if ( window.console && console.log ) {\n\t\t\tconsole.log( msg );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * See if a property is defined on one object, if so assign it to the other object\n\t *  @param {object} ret target object\n\t *  @param {object} src source object\n\t *  @param {string} name property\n\t *  @param {string} [mappedName] name to map too - optional, name used if not given\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnMap( ret, src, name, mappedName )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\t$.each( name, function (i, val) {\n\t\t\t\tif ( $.isArray( val ) ) {\n\t\t\t\t\t_fnMap( ret, src, val[0], val[1] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_fnMap( ret, src, val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( mappedName === undefined ) {\n\t\t\tmappedName = name;\n\t\t}\n\t\n\t\tif ( src[name] !== undefined ) {\n\t\t\tret[mappedName] = src[name];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Extend objects - very similar to jQuery.extend, but deep copy objects, and\n\t * shallow copy arrays. The reason we need to do this, is that we don't want to\n\t * deep copy array init values (such as aaSorting) since the dev wouldn't be\n\t * able to override them, but we do want to deep copy arrays.\n\t *  @param {object} out Object to extend\n\t *  @param {object} extender Object from which the properties will be applied to\n\t *      out\n\t *  @param {boolean} breakRefs If true, then arrays will be sliced to take an\n\t *      independent copy with the exception of the `data` or `aaData` parameters\n\t *      if they are present. This is so you can pass in a collection to\n\t *      DataTables and have that used as your data source without breaking the\n\t *      references\n\t *  @returns {object} out Reference, just for convenience - out === the return.\n\t *  @memberof DataTable#oApi\n\t *  @todo This doesn't take account of arrays inside the deep copied objects.\n\t */\n\tfunction _fnExtend( out, extender, breakRefs )\n\t{\n\t\tvar val;\n\t\n\t\tfor ( var prop in extender ) {\n\t\t\tif ( extender.hasOwnProperty(prop) ) {\n\t\t\t\tval = extender[prop];\n\t\n\t\t\t\tif ( $.isPlainObject( val ) ) {\n\t\t\t\t\tif ( ! $.isPlainObject( out[prop] ) ) {\n\t\t\t\t\t\tout[prop] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, out[prop], val );\n\t\t\t\t}\n\t\t\t\telse if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {\n\t\t\t\t\tout[prop] = val.slice();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tout[prop] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t}\n\t\n\t\n\t/**\n\t * Bind an event handers to allow a click or return key to activate the callback.\n\t * This is good for accessibility since a return on the keyboard will have the\n\t * same effect as a click, if the element has focus.\n\t *  @param {element} n Element to bind the action to\n\t *  @param {object} oData Data object to pass to the triggered function\n\t *  @param {function} fn Callback function for when the event is triggered\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBindAction( n, oData, fn )\n\t{\n\t\t$(n)\n\t\t\t.on( 'click.DT', oData, function (e) {\n\t\t\t\t\tn.blur(); // Remove focus outline for mouse users\n\t\t\t\t\tfn(e);\n\t\t\t\t} )\n\t\t\t.on( 'keypress.DT', oData, function (e){\n\t\t\t\t\tif ( e.which === 13 ) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tfn(e);\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t.on( 'selectstart.DT', function () {\n\t\t\t\t\t/* Take the brutal approach to cancelling text selection */\n\t\t\t\t\treturn false;\n\t\t\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Register a callback function. Easily allows a callback function to be added to\n\t * an array store of callback functions that can then all be called together.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sStore Name of the array storage for the callbacks in oSettings\n\t *  @param {function} fn Function to be called back\n\t *  @param {string} sName Identifying name for the callback (i.e. a label)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackReg( oSettings, sStore, fn, sName )\n\t{\n\t\tif ( fn )\n\t\t{\n\t\t\toSettings[sStore].push( {\n\t\t\t\t\"fn\": fn,\n\t\t\t\t\"sName\": sName\n\t\t\t} );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Fire callback functions and trigger events. Note that the loop over the\n\t * callback array store is done backwards! Further note that you do not want to\n\t * fire off triggers in time sensitive applications (for example cell creation)\n\t * as its slow.\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} callbackArr Name of the array storage for the callbacks in\n\t *      oSettings\n\t *  @param {string} eventName Name of the jQuery custom event to trigger. If\n\t *      null no trigger is fired\n\t *  @param {array} args Array of arguments to pass to the callback function /\n\t *      trigger\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackFire( settings, callbackArr, eventName, args )\n\t{\n\t\tvar ret = [];\n\t\n\t\tif ( callbackArr ) {\n\t\t\tret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {\n\t\t\t\treturn val.fn.apply( settings.oInstance, args );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( eventName !== null ) {\n\t\t\tvar e = $.Event( eventName+'.dt' );\n\t\n\t\t\t$(settings.nTable).trigger( e, args );\n\t\n\t\t\tret.push( e.result );\n\t\t}\n\t\n\t\treturn ret;\n\t}\n\t\n\t\n\tfunction _fnLengthOverflow ( settings )\n\t{\n\t\tvar\n\t\t\tstart = settings._iDisplayStart,\n\t\t\tend = settings.fnDisplayEnd(),\n\t\t\tlen = settings._iDisplayLength;\n\t\n\t\t/* If we have space to show extra rows (backing up from the end point - then do so */\n\t\tif ( start >= end )\n\t\t{\n\t\t\tstart = end - len;\n\t\t}\n\t\n\t\t// Keep the start record on the current page\n\t\tstart -= (start % len);\n\t\n\t\tif ( len === -1 || start < 0 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\n\t\tsettings._iDisplayStart = start;\n\t}\n\t\n\t\n\tfunction _fnRenderer( settings, type )\n\t{\n\t\tvar renderer = settings.renderer;\n\t\tvar host = DataTable.ext.renderer[type];\n\t\n\t\tif ( $.isPlainObject( renderer ) && renderer[type] ) {\n\t\t\t// Specific renderer for this type. If available use it, otherwise use\n\t\t\t// the default.\n\t\t\treturn host[renderer[type]] || host._;\n\t\t}\n\t\telse if ( typeof renderer === 'string' ) {\n\t\t\t// Common renderer - if there is one available for this type use it,\n\t\t\t// otherwise use the default\n\t\t\treturn host[renderer] || host._;\n\t\t}\n\t\n\t\t// Use the default\n\t\treturn host._;\n\t}\n\t\n\t\n\t/**\n\t * Detect the data source being used for the table. Used to simplify the code\n\t * a little (ajax) and to make it compress a little smaller.\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {string} Data source\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDataSource ( settings )\n\t{\n\t\tif ( settings.oFeatures.bServerSide ) {\n\t\t\treturn 'ssp';\n\t\t}\n\t\telse if ( settings.ajax || settings.sAjaxSource ) {\n\t\t\treturn 'ajax';\n\t\t}\n\t\treturn 'dom';\n\t}\n\t\n\n\t\n\t\n\t/**\n\t * Computed structure of the DataTables API, defined by the options passed to\n\t * `DataTable.Api.register()` when building the API.\n\t *\n\t * The structure is built in order to speed creation and extension of the Api\n\t * objects since the extensions are effectively pre-parsed.\n\t *\n\t * The array is an array of objects with the following structure, where this\n\t * base array represents the Api prototype base:\n\t *\n\t *     [\n\t *       {\n\t *         name:      'data'                -- string   - Property name\n\t *         val:       function () {},       -- function - Api method (or undefined if just an object\n\t *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t *       },\n\t *       {\n\t *         name:     'row'\n\t *         val:       {},\n\t *         methodExt: [ ... ],\n\t *         propExt:   [\n\t *           {\n\t *             name:      'data'\n\t *             val:       function () {},\n\t *             methodExt: [ ... ],\n\t *             propExt:   [ ... ]\n\t *           },\n\t *           ...\n\t *         ]\n\t *       }\n\t *     ]\n\t *\n\t * @type {Array}\n\t * @ignore\n\t */\n\tvar __apiStruct = [];\n\t\n\t\n\t/**\n\t * `Array.prototype` reference.\n\t *\n\t * @type object\n\t * @ignore\n\t */\n\tvar __arrayProto = Array.prototype;\n\t\n\t\n\t/**\n\t * Abstraction for `context` parameter of the `Api` constructor to allow it to\n\t * take several different forms for ease of use.\n\t *\n\t * Each of the input parameter types will be converted to a DataTables settings\n\t * object where possible.\n\t *\n\t * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one\n\t *   of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t *   * `DataTables.Api` - API instance\n\t * @return {array|null} Matching DataTables settings objects. `null` or\n\t *   `undefined` is returned if no matching DataTable is found.\n\t * @ignore\n\t */\n\tvar _toSettings = function ( mixed )\n\t{\n\t\tvar idx, jq;\n\t\tvar settings = DataTable.settings;\n\t\tvar tables = $.map( settings, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\tif ( ! mixed ) {\n\t\t\treturn [];\n\t\t}\n\t\telse if ( mixed.nTable && mixed.oApi ) {\n\t\t\t// DataTables settings object\n\t\t\treturn [ mixed ];\n\t\t}\n\t\telse if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {\n\t\t\t// Table node\n\t\t\tidx = $.inArray( mixed, tables );\n\t\t\treturn idx !== -1 ? [ settings[idx] ] : null;\n\t\t}\n\t\telse if ( mixed && typeof mixed.settings === 'function' ) {\n\t\t\treturn mixed.settings().toArray();\n\t\t}\n\t\telse if ( typeof mixed === 'string' ) {\n\t\t\t// jQuery selector\n\t\t\tjq = $(mixed);\n\t\t}\n\t\telse if ( mixed instanceof $ ) {\n\t\t\t// jQuery object (also DataTables instance)\n\t\t\tjq = mixed;\n\t\t}\n\t\n\t\tif ( jq ) {\n\t\t\treturn jq.map( function(i) {\n\t\t\t\tidx = $.inArray( this, tables );\n\t\t\t\treturn idx !== -1 ? settings[idx] : null;\n\t\t\t} ).toArray();\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * DataTables API class - used to control and interface with  one or more\n\t * DataTables enhanced tables.\n\t *\n\t * The API class is heavily based on jQuery, presenting a chainable interface\n\t * that you can use to interact with tables. Each instance of the API class has\n\t * a \"context\" - i.e. the tables that it will operate on. This could be a single\n\t * table, all tables on a page or a sub-set thereof.\n\t *\n\t * Additionally the API is designed to allow you to easily work with the data in\n\t * the tables, retrieving and manipulating it as required. This is done by\n\t * presenting the API class as an array like interface. The contents of the\n\t * array depend upon the actions requested by each method (for example\n\t * `rows().nodes()` will return an array of nodes, while `rows().data()` will\n\t * return an array of objects or arrays depending upon your table's\n\t * configuration). The API object has a number of array like methods (`push`,\n\t * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,\n\t * `unique` etc) to assist your working with the data held in a table.\n\t *\n\t * Most methods (those which return an Api instance) are chainable, which means\n\t * the return from a method call also has all of the methods available that the\n\t * top level object had. For example, these two calls are equivalent:\n\t *\n\t *     // Not chained\n\t *     api.row.add( {...} );\n\t *     api.draw();\n\t *\n\t *     // Chained\n\t *     api.row.add( {...} ).draw();\n\t *\n\t * @class DataTable.Api\n\t * @param {array|object|string|jQuery} context DataTable identifier. This is\n\t *   used to define which DataTables enhanced tables this API will operate on.\n\t *   Can be one of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t * @param {array} [data] Data to initialise the Api instance with.\n\t *\n\t * @example\n\t *   // Direct initialisation during DataTables construction\n\t *   var api = $('#example').DataTable();\n\t *\n\t * @example\n\t *   // Initialisation using a DataTables jQuery object\n\t *   var api = $('#example').dataTable().api();\n\t *\n\t * @example\n\t *   // Initialisation as a constructor\n\t *   var api = new $.fn.DataTable.Api( 'table.dataTable' );\n\t */\n\t_Api = function ( context, data )\n\t{\n\t\tif ( ! (this instanceof _Api) ) {\n\t\t\treturn new _Api( context, data );\n\t\t}\n\t\n\t\tvar settings = [];\n\t\tvar ctxSettings = function ( o ) {\n\t\t\tvar a = _toSettings( o );\n\t\t\tif ( a ) {\n\t\t\t\tsettings = settings.concat( a );\n\t\t\t}\n\t\t};\n\t\n\t\tif ( $.isArray( context ) ) {\n\t\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tctxSettings( context[i] );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tctxSettings( context );\n\t\t}\n\t\n\t\t// Remove duplicates\n\t\tthis.context = _unique( settings );\n\t\n\t\t// Initial data\n\t\tif ( data ) {\n\t\t\t$.merge( this, data );\n\t\t}\n\t\n\t\t// selector\n\t\tthis.selector = {\n\t\t\trows: null,\n\t\t\tcols: null,\n\t\t\topts: null\n\t\t};\n\t\n\t\t_Api.extend( this, this, __apiStruct );\n\t};\n\t\n\tDataTable.Api = _Api;\n\t\n\t// Don't destroy the existing prototype, just extend it. Required for jQuery 2's\n\t// isPlainObject.\n\t$.extend( _Api.prototype, {\n\t\tany: function ()\n\t\t{\n\t\t\treturn this.count() !== 0;\n\t\t},\n\t\n\t\n\t\tconcat:  __arrayProto.concat,\n\t\n\t\n\t\tcontext: [], // array of table settings objects\n\t\n\t\n\t\tcount: function ()\n\t\t{\n\t\t\treturn this.flatten().length;\n\t\t},\n\t\n\t\n\t\teach: function ( fn )\n\t\t{\n\t\t\tfor ( var i=0, ien=this.length ; i<ien; i++ ) {\n\t\t\t\tfn.call( this, this[i], i, this );\n\t\t\t}\n\t\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\teq: function ( idx )\n\t\t{\n\t\t\tvar ctx = this.context;\n\t\n\t\t\treturn ctx.length > idx ?\n\t\t\t\tnew _Api( ctx[idx], this[idx] ) :\n\t\t\t\tnull;\n\t\t},\n\t\n\t\n\t\tfilter: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.filter ) {\n\t\t\t\ta = __arrayProto.filter.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( fn.call( this, this[i], i, this ) ) {\n\t\t\t\t\t\ta.push( this[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tflatten: function ()\n\t\t{\n\t\t\tvar a = [];\n\t\t\treturn new _Api( this.context, a.concat.apply( a, this.toArray() ) );\n\t\t},\n\t\n\t\n\t\tjoin:    __arrayProto.join,\n\t\n\t\n\t\tindexOf: __arrayProto.indexOf || function (obj, start)\n\t\t{\n\t\t\tfor ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {\n\t\t\t\tif ( this[i] === obj ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1;\n\t\t},\n\t\n\t\titerator: function ( flatten, type, fn, alwaysNew ) {\n\t\t\tvar\n\t\t\t\ta = [], ret,\n\t\t\t\ti, ien, j, jen,\n\t\t\t\tcontext = this.context,\n\t\t\t\trows, items, item,\n\t\t\t\tselector = this.selector;\n\t\n\t\t\t// Argument shifting\n\t\t\tif ( typeof flatten === 'string' ) {\n\t\t\t\talwaysNew = fn;\n\t\t\t\tfn = type;\n\t\t\t\ttype = flatten;\n\t\t\t\tflatten = false;\n\t\t\t}\n\t\n\t\t\tfor ( i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tvar apiInst = new _Api( context[i] );\n\t\n\t\t\t\tif ( type === 'table' ) {\n\t\t\t\t\tret = fn.call( apiInst, context[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'columns' || type === 'rows' ) {\n\t\t\t\t\t// this has same length as context - one entry for each table\n\t\t\t\t\tret = fn.call( apiInst, context[i], this[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {\n\t\t\t\t\t// columns and rows share the same structure.\n\t\t\t\t\t// 'this' is an array of column indexes for each context\n\t\t\t\t\titems = this[i];\n\t\n\t\t\t\t\tif ( type === 'column-rows' ) {\n\t\t\t\t\t\trows = _selector_row_indexes( context[i], selector.opts );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfor ( j=0, jen=items.length ; j<jen ; j++ ) {\n\t\t\t\t\t\titem = items[j];\n\t\n\t\t\t\t\t\tif ( type === 'cell' ) {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item.row, item.column, i, j );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item, i, j, rows );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( a.length || alwaysNew ) {\n\t\t\t\tvar api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );\n\t\t\t\tvar apiSelector = api.selector;\n\t\t\t\tapiSelector.rows = selector.rows;\n\t\t\t\tapiSelector.cols = selector.cols;\n\t\t\t\tapiSelector.opts = selector.opts;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\tlastIndexOf: __arrayProto.lastIndexOf || function (obj, start)\n\t\t{\n\t\t\t// Bit cheeky...\n\t\t\treturn this.indexOf.apply( this.toArray.reverse(), arguments );\n\t\t},\n\t\n\t\n\t\tlength:  0,\n\t\n\t\n\t\tmap: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.map ) {\n\t\t\t\ta = __arrayProto.map.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\ta.push( fn.call( this, this[i], i ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tpluck: function ( prop )\n\t\t{\n\t\t\treturn this.map( function ( el ) {\n\t\t\t\treturn el[ prop ];\n\t\t\t} );\n\t\t},\n\t\n\t\tpop:     __arrayProto.pop,\n\t\n\t\n\t\tpush:    __arrayProto.push,\n\t\n\t\n\t\t// Does not return an API instance\n\t\treduce: __arrayProto.reduce || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, 0, this.length, 1 );\n\t\t},\n\t\n\t\n\t\treduceRight: __arrayProto.reduceRight || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, this.length-1, -1, -1 );\n\t\t},\n\t\n\t\n\t\treverse: __arrayProto.reverse,\n\t\n\t\n\t\t// Object with rows, columns and opts\n\t\tselector: null,\n\t\n\t\n\t\tshift:   __arrayProto.shift,\n\t\n\t\n\t\tsort:    __arrayProto.sort, // ? name - order?\n\t\n\t\n\t\tsplice:  __arrayProto.splice,\n\t\n\t\n\t\ttoArray: function ()\n\t\t{\n\t\t\treturn __arrayProto.slice.call( this );\n\t\t},\n\t\n\t\n\t\tto$: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\ttoJQuery: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\tunique: function ()\n\t\t{\n\t\t\treturn new _Api( this.context, _unique(this) );\n\t\t},\n\t\n\t\n\t\tunshift: __arrayProto.unshift\n\t} );\n\t\n\t\n\t_Api.extend = function ( scope, obj, ext )\n\t{\n\t\t// Only extend API instances and static properties of the API\n\t\tif ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\tj, jen,\n\t\t\tstruct, inner,\n\t\t\tmethodScoping = function ( scope, fn, struc ) {\n\t\t\t\treturn function () {\n\t\t\t\t\tvar ret = fn.apply( scope, arguments );\n\t\n\t\t\t\t\t// Method extension\n\t\t\t\t\t_Api.extend( ret, ret, struc.methodExt );\n\t\t\t\t\treturn ret;\n\t\t\t\t};\n\t\t\t};\n\t\n\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\tstruct = ext[i];\n\t\n\t\t\t// Value\n\t\t\tobj[ struct.name ] = typeof struct.val === 'function' ?\n\t\t\t\tmethodScoping( scope, struct.val, struct ) :\n\t\t\t\t$.isPlainObject( struct.val ) ?\n\t\t\t\t\t{} :\n\t\t\t\t\tstruct.val;\n\t\n\t\t\tobj[ struct.name ].__dt_wrapper = true;\n\t\n\t\t\t// Property extension\n\t\t\t_Api.extend( scope, obj[ struct.name ], struct.propExt );\n\t\t}\n\t};\n\t\n\t\n\t// @todo - Is there need for an augment function?\n\t// _Api.augment = function ( inst, name )\n\t// {\n\t// \t// Find src object in the structure from the name\n\t// \tvar parts = name.split('.');\n\t\n\t// \t_Api.extend( inst, obj );\n\t// };\n\t\n\t\n\t//     [\n\t//       {\n\t//         name:      'data'                -- string   - Property name\n\t//         val:       function () {},       -- function - Api method (or undefined if just an object\n\t//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t//       },\n\t//       {\n\t//         name:     'row'\n\t//         val:       {},\n\t//         methodExt: [ ... ],\n\t//         propExt:   [\n\t//           {\n\t//             name:      'data'\n\t//             val:       function () {},\n\t//             methodExt: [ ... ],\n\t//             propExt:   [ ... ]\n\t//           },\n\t//           ...\n\t//         ]\n\t//       }\n\t//     ]\n\t\n\t_Api.register = _api_register = function ( name, val )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\tfor ( var j=0, jen=name.length ; j<jen ; j++ ) {\n\t\t\t\t_Api.register( name[j], val );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\their = name.split('.'),\n\t\t\tstruct = __apiStruct,\n\t\t\tkey, method;\n\t\n\t\tvar find = function ( src, name ) {\n\t\t\tfor ( var i=0, ien=src.length ; i<ien ; i++ ) {\n\t\t\t\tif ( src[i].name === name ) {\n\t\t\t\t\treturn src[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\n\t\tfor ( i=0, ien=heir.length ; i<ien ; i++ ) {\n\t\t\tmethod = heir[i].indexOf('()') !== -1;\n\t\t\tkey = method ?\n\t\t\t\their[i].replace('()', '') :\n\t\t\t\their[i];\n\t\n\t\t\tvar src = find( struct, key );\n\t\t\tif ( ! src ) {\n\t\t\t\tsrc = {\n\t\t\t\t\tname:      key,\n\t\t\t\t\tval:       {},\n\t\t\t\t\tmethodExt: [],\n\t\t\t\t\tpropExt:   []\n\t\t\t\t};\n\t\t\t\tstruct.push( src );\n\t\t\t}\n\t\n\t\t\tif ( i === ien-1 ) {\n\t\t\t\tsrc.val = val;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstruct = method ?\n\t\t\t\t\tsrc.methodExt :\n\t\t\t\t\tsrc.propExt;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\t_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {\n\t\t_Api.register( pluralName, val );\n\t\n\t\t_Api.register( singularName, function () {\n\t\t\tvar ret = val.apply( this, arguments );\n\t\n\t\t\tif ( ret === this ) {\n\t\t\t\t// Returned item is the API instance that was passed in, return it\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\telse if ( ret instanceof _Api ) {\n\t\t\t\t// New API instance returned, want the value from the first item\n\t\t\t\t// in the returned array for the singular result.\n\t\t\t\treturn ret.length ?\n\t\t\t\t\t$.isArray( ret[0] ) ?\n\t\t\t\t\t\tnew _Api( ret.context, ret[0] ) : // Array results are 'enhanced'\n\t\t\t\t\t\tret[0] :\n\t\t\t\t\tundefined;\n\t\t\t}\n\t\n\t\t\t// Non-API return - just fire it back\n\t\t\treturn ret;\n\t\t} );\n\t};\n\t\n\t\n\t/**\n\t * Selector for HTML tables. Apply the given selector to the give array of\n\t * DataTables settings objects.\n\t *\n\t * @param {string|integer} [selector] jQuery selector string or integer\n\t * @param  {array} Array of DataTables settings objects to be filtered\n\t * @return {array}\n\t * @ignore\n\t */\n\tvar __table_selector = function ( selector, a )\n\t{\n\t\t// Integer is used to pick out a table by index\n\t\tif ( typeof selector === 'number' ) {\n\t\t\treturn [ a[ selector ] ];\n\t\t}\n\t\n\t\t// Perform a jQuery selector on the table nodes\n\t\tvar nodes = $.map( a, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\treturn $(nodes)\n\t\t\t.filter( selector )\n\t\t\t.map( function (i) {\n\t\t\t\t// Need to translate back from the table node to the settings\n\t\t\t\tvar idx = $.inArray( this, nodes );\n\t\t\t\treturn a[ idx ];\n\t\t\t} )\n\t\t\t.toArray();\n\t};\n\t\n\t\n\t\n\t/**\n\t * Context selector for the API's context (i.e. the tables the API instance\n\t * refers to.\n\t *\n\t * @name    DataTable.Api#tables\n\t * @param {string|integer} [selector] Selector to pick which tables the iterator\n\t *   should operate on. If not given, all tables in the current context are\n\t *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to\n\t *   select multiple tables or as an integer to select a single table.\n\t * @returns {DataTable.Api} Returns a new API instance if a selector is given.\n\t */\n\t_api_register( 'tables()', function ( selector ) {\n\t\t// A new instance is created if there was a selector specified\n\t\treturn selector ?\n\t\t\tnew _Api( __table_selector( selector, this.context ) ) :\n\t\t\tthis;\n\t} );\n\t\n\t\n\t_api_register( 'table()', function ( selector ) {\n\t\tvar tables = this.tables( selector );\n\t\tvar ctx = tables.context;\n\t\n\t\t// Truncate to the first matched table\n\t\treturn ctx.length ?\n\t\t\tnew _Api( ctx[0] ) :\n\t\t\ttables;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTable;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().body()', 'table().body()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTBody;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().header()', 'table().header()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTHead;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTFoot;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().containers()', 'table().container()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTableWrapper;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Redraw the tables in the current context.\n\t */\n\t_api_register( 'draw()', function ( paging ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( paging === 'page' ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ( typeof paging === 'string' ) {\n\t\t\t\t\tpaging = paging === 'full-hold' ?\n\t\t\t\t\t\tfalse :\n\t\t\t\t\t\ttrue;\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, paging===false );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get the current page index.\n\t *\n\t * @return {integer} Current page index (zero based)\n\t *//**\n\t * Set the current page.\n\t *\n\t * Note that if you attempt to show a page which does not exist, DataTables will\n\t * not throw an error, but rather reset the paging.\n\t *\n\t * @param {integer|string} action The paging action to take. This can be one of:\n\t *  * `integer` - The page index to jump to\n\t *  * `string` - An action to take:\n\t *    * `first` - Jump to first page.\n\t *    * `next` - Jump to the next page\n\t *    * `previous` - Jump to previous page\n\t *    * `last` - Jump to the last page.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page()', function ( action ) {\n\t\tif ( action === undefined ) {\n\t\t\treturn this.page.info().page; // not an expensive call\n\t\t}\n\t\n\t\t// else, have an action to take on all tables\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnPageChange( settings, action );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Paging information for the first table in the current context.\n\t *\n\t * If you require paging information for another table, use the `table()` method\n\t * with a suitable selector.\n\t *\n\t * @return {object} Object with the following properties set:\n\t *  * `page` - Current page index (zero based - i.e. the first page is `0`)\n\t *  * `pages` - Total number of pages\n\t *  * `start` - Display index for the first record shown on the current page\n\t *  * `end` - Display index for the last record shown on the current page\n\t *  * `length` - Display length (number of records). Note that generally `start\n\t *    + length = end`, but this is not always true, for example if there are\n\t *    only 2 records to show on the final page, with a length of 10.\n\t *  * `recordsTotal` - Full data set length\n\t *  * `recordsDisplay` - Data set length once the current filtering criterion\n\t *    are applied.\n\t */\n\t_api_register( 'page.info()', function ( action ) {\n\t\tif ( this.context.length === 0 ) {\n\t\t\treturn undefined;\n\t\t}\n\t\n\t\tvar\n\t\t\tsettings   = this.context[0],\n\t\t\tstart      = settings._iDisplayStart,\n\t\t\tlen        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,\n\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn {\n\t\t\t\"page\":           all ? 0 : Math.floor( start / len ),\n\t\t\t\"pages\":          all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\"start\":          start,\n\t\t\t\"end\":            settings.fnDisplayEnd(),\n\t\t\t\"length\":         len,\n\t\t\t\"recordsTotal\":   settings.fnRecordsTotal(),\n\t\t\t\"recordsDisplay\": visRecords,\n\t\t\t\"serverSide\":     _fnDataSource( settings ) === 'ssp'\n\t\t};\n\t} );\n\t\n\t\n\t/**\n\t * Get the current page length.\n\t *\n\t * @return {integer} Current page length. Note `-1` indicates that all records\n\t *   are to be shown.\n\t *//**\n\t * Set the current page length.\n\t *\n\t * @param {integer} Page length to set. Use `-1` to show all records.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page.len()', function ( len ) {\n\t\t// Note that we can't call this function 'length()' because `length`\n\t\t// is a Javascript property of functions which defines how many arguments\n\t\t// the function expects.\n\t\tif ( len === undefined ) {\n\t\t\treturn this.context.length !== 0 ?\n\t\t\t\tthis.context[0]._iDisplayLength :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// else, set the page length\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnLengthChange( settings, len );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\tvar __reload = function ( settings, holdPosition, callback ) {\n\t\t// Use the draw event to trigger a callback\n\t\tif ( callback ) {\n\t\t\tvar api = new _Api( settings );\n\t\n\t\t\tapi.one( 'draw', function () {\n\t\t\t\tcallback( api.ajax.json() );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t_fnReDraw( settings, holdPosition );\n\t\t}\n\t\telse {\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t// Cancel an existing request\n\t\t\tvar xhr = settings.jqXHR;\n\t\t\tif ( xhr && xhr.readyState !== 4 ) {\n\t\t\t\txhr.abort();\n\t\t\t}\n\t\n\t\t\t// Trigger xhr\n\t\t\t_fnBuildAjax( settings, [], function( json ) {\n\t\t\t\t_fnClearTable( settings );\n\t\n\t\t\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\t_fnAddData( settings, data[i] );\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, holdPosition );\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Get the JSON response from the last Ajax request that DataTables made to the\n\t * server. Note that this returns the JSON from the first table in the current\n\t * context.\n\t *\n\t * @return {object} JSON received from the server.\n\t */\n\t_api_register( 'ajax.json()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].json;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Get the data submitted in the last Ajax request\n\t */\n\t_api_register( 'ajax.params()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].oAjaxData;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Reload tables from the Ajax data source. Note that this function will\n\t * automatically re-draw the table when the remote data has been loaded.\n\t *\n\t * @param {boolean} [reset=true] Reset (default) or hold the current paging\n\t *   position. A full re-sort and re-filter is performed when this method is\n\t *   called, which is why the pagination reset is the default action.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.reload()', function ( callback, resetPaging ) {\n\t\treturn this.iterator( 'table', function (settings) {\n\t\t\t__reload( settings, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Get the current Ajax URL. Note that this returns the URL from the first\n\t * table in the current context.\n\t *\n\t * @return {string} Current Ajax source URL\n\t *//**\n\t * Set the Ajax URL. Note that this will set the URL for all tables in the\n\t * current context.\n\t *\n\t * @param {string} url URL to set.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url()', function ( url ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( url === undefined ) {\n\t\t\t// get\n\t\t\tif ( ctx.length === 0 ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tctx = ctx[0];\n\t\n\t\t\treturn ctx.ajax ?\n\t\t\t\t$.isPlainObject( ctx.ajax ) ?\n\t\t\t\t\tctx.ajax.url :\n\t\t\t\t\tctx.ajax :\n\t\t\t\tctx.sAjaxSource;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( $.isPlainObject( settings.ajax ) ) {\n\t\t\t\tsettings.ajax.url = url;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsettings.ajax = url;\n\t\t\t}\n\t\t\t// No need to consider sAjaxSource here since DataTables gives priority\n\t\t\t// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any\n\t\t\t// value of `sAjaxSource` redundant.\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Load data from the newly set Ajax URL. Note that this method is only\n\t * available when `ajax.url()` is used to set a URL. Additionally, this method\n\t * has the same effect as calling `ajax.reload()` but is provided for\n\t * convenience when setting a new URL. Like `ajax.reload()` it will\n\t * automatically redraw the table once the remote data has been loaded.\n\t *\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {\n\t\t// Same as a reload, but makes sense to present it for easy access after a\n\t\t// url change\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\t__reload( ctx, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t\n\tvar _selector_run = function ( type, selector, selectFn, settings, opts )\n\t{\n\t\tvar\n\t\t\tout = [], res,\n\t\t\ta, i, ien, j, jen,\n\t\t\tselectorType = typeof selector;\n\t\n\t\t// Can't just check for isArray here, as an API or jQuery instance might be\n\t\t// given with their array like look\n\t\tif ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {\n\t\t\tselector = [ selector ];\n\t\t}\n\t\n\t\tfor ( i=0, ien=selector.length ; i<ien ; i++ ) {\n\t\t\t// Only split on simple strings - complex expressions will be jQuery selectors\n\t\t\ta = selector[i] && selector[i].split && ! selector[i].match(/[\\[\\(:]/) ?\n\t\t\t\tselector[i].split(',') :\n\t\t\t\t[ selector[i] ];\n\t\n\t\t\tfor ( j=0, jen=a.length ; j<jen ; j++ ) {\n\t\t\t\tres = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );\n\t\n\t\t\t\tif ( res && res.length ) {\n\t\t\t\t\tout = out.concat( res );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// selector extensions\n\t\tvar ext = _ext.selector[ type ];\n\t\tif ( ext.length ) {\n\t\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\t\tout = ext[i]( settings, opts, out );\n\t\t\t}\n\t\t}\n\t\n\t\treturn _unique( out );\n\t};\n\t\n\t\n\tvar _selector_opts = function ( opts )\n\t{\n\t\tif ( ! opts ) {\n\t\t\topts = {};\n\t\t}\n\t\n\t\t// Backwards compatibility for 1.9- which used the terminology filter rather\n\t\t// than search\n\t\tif ( opts.filter && opts.search === undefined ) {\n\t\t\topts.search = opts.filter;\n\t\t}\n\t\n\t\treturn $.extend( {\n\t\t\tsearch: 'none',\n\t\t\torder: 'current',\n\t\t\tpage: 'all'\n\t\t}, opts );\n\t};\n\t\n\t\n\tvar _selector_first = function ( inst )\n\t{\n\t\t// Reduce the API instance to the first item found\n\t\tfor ( var i=0, ien=inst.length ; i<ien ; i++ ) {\n\t\t\tif ( inst[i].length > 0 ) {\n\t\t\t\t// Assign the first element to the first item in the instance\n\t\t\t\t// and truncate the instance and context\n\t\t\t\tinst[0] = inst[i];\n\t\t\t\tinst[0].length = 1;\n\t\t\t\tinst.length = 1;\n\t\t\t\tinst.context = [ inst.context[i] ];\n\t\n\t\t\t\treturn inst;\n\t\t\t}\n\t\t}\n\t\n\t\t// Not found - return an empty instance\n\t\tinst.length = 0;\n\t\treturn inst;\n\t};\n\t\n\t\n\tvar _selector_row_indexes = function ( settings, opts )\n\t{\n\t\tvar\n\t\t\ti, ien, tmp, a=[],\n\t\t\tdisplayFiltered = settings.aiDisplay,\n\t\t\tdisplayMaster = settings.aiDisplayMaster;\n\t\n\t\tvar\n\t\t\tsearch = opts.search,  // none, applied, removed\n\t\t\torder  = opts.order,   // applied, current, index (original - compatibility with 1.9)\n\t\t\tpage   = opts.page;    // all, current\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t// In server-side processing mode, most options are irrelevant since\n\t\t\t// rows not shown don't exist and the index order is the applied order\n\t\t\t// Removed is a special case - for consistency just return an empty\n\t\t\t// array\n\t\t\treturn search === 'removed' ?\n\t\t\t\t[] :\n\t\t\t\t_range( 0, displayMaster.length );\n\t\t}\n\t\telse if ( page == 'current' ) {\n\t\t\t// Current page implies that order=current and fitler=applied, since it is\n\t\t\t// fairly senseless otherwise, regardless of what order and search actually\n\t\t\t// are\n\t\t\tfor ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {\n\t\t\t\ta.push( displayFiltered[i] );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'current' || order == 'applied' ) {\n\t\t\ta = search == 'none' ?\n\t\t\t\tdisplayMaster.slice() :                      // no search\n\t\t\t\tsearch == 'applied' ?\n\t\t\t\t\tdisplayFiltered.slice() :                // applied search\n\t\t\t\t\t$.map( displayMaster, function (el, i) { // removed search\n\t\t\t\t\t\treturn $.inArray( el, displayFiltered ) === -1 ? el : null;\n\t\t\t\t\t} );\n\t\t}\n\t\telse if ( order == 'index' || order == 'original' ) {\n\t\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tif ( search == 'none' ) {\n\t\t\t\t\ta.push( i );\n\t\t\t\t}\n\t\t\t\telse { // applied | removed\n\t\t\t\t\ttmp = $.inArray( i, displayFiltered );\n\t\n\t\t\t\t\tif ((tmp === -1 && search == 'removed') ||\n\t\t\t\t\t\t(tmp >= 0   && search == 'applied') )\n\t\t\t\t\t{\n\t\t\t\t\t\ta.push( i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn a;\n\t};\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Rows\n\t *\n\t * {}          - no selector - use all available rows\n\t * {integer}   - row aoData index\n\t * {node}      - TR node\n\t * {string}    - jQuery selector to apply to the TR elements\n\t * {array}     - jQuery array of nodes, or simply an array of TR nodes\n\t *\n\t */\n\t\n\t\n\tvar __row_selector = function ( settings, selector, opts )\n\t{\n\t\tvar rows;\n\t\tvar run = function ( sel ) {\n\t\t\tvar selInt = _intVal( sel );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Short cut - selector is a number and no options provided (default is\n\t\t\t// all records, so no need to check if the index is in there, since it\n\t\t\t// must be - dev error if the index doesn't exist).\n\t\t\tif ( selInt !== null && ! opts ) {\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\n\t\t\tif ( ! rows ) {\n\t\t\t\trows = _selector_row_indexes( settings, opts );\n\t\t\t}\n\t\n\t\t\tif ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {\n\t\t\t\t// Selector - integer\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\t\telse if ( sel === null || sel === undefined || sel === '' ) {\n\t\t\t\t// Selector - none\n\t\t\t\treturn rows;\n\t\t\t}\n\t\n\t\t\t// Selector - function\n\t\t\tif ( typeof sel === 'function' ) {\n\t\t\t\treturn $.map( rows, function (idx) {\n\t\t\t\t\tvar row = settings.aoData[ idx ];\n\t\t\t\t\treturn sel( idx, row._aData, row.nTr ) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Get nodes in the order from the `rows` array with null values removed\n\t\t\tvar nodes = _removeEmpty(\n\t\t\t\t_pluck_order( settings.aoData, rows, 'nTr' )\n\t\t\t);\n\t\n\t\t\t// Selector - node\n\t\t\tif ( sel.nodeName ) {\n\t\t\t\tif ( sel._DT_RowIndex !== undefined ) {\n\t\t\t\t\treturn [ sel._DT_RowIndex ]; // Property added by DT for fast lookup\n\t\t\t\t}\n\t\t\t\telse if ( sel._DT_CellIndex ) {\n\t\t\t\t\treturn [ sel._DT_CellIndex.row ];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tvar host = $(sel).closest('*[data-dt-row]');\n\t\t\t\t\treturn host.length ?\n\t\t\t\t\t\t[ host.data('dt-row') ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// ID selector. Want to always be able to select rows by id, regardless\n\t\t\t// of if the tr element has been created or not, so can't rely upon\n\t\t\t// jQuery here - hence a custom implementation. This does not match\n\t\t\t// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,\n\t\t\t// but to select it using a CSS selector engine (like Sizzle or\n\t\t\t// querySelect) it would need to need to be escaped for some characters.\n\t\t\t// DataTables simplifies this for row selectors since you can select\n\t\t\t// only a row. A # indicates an id any anything that follows is the id -\n\t\t\t// unescaped.\n\t\t\tif ( typeof sel === 'string' && sel.charAt(0) === '#' ) {\n\t\t\t\t// get row index from id\n\t\t\t\tvar rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];\n\t\t\t\tif ( rowObj !== undefined ) {\n\t\t\t\t\treturn [ rowObj.idx ];\n\t\t\t\t}\n\t\n\t\t\t\t// need to fall through to jQuery in case there is DOM id that\n\t\t\t\t// matches\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery selector string, array of nodes or jQuery object/\n\t\t\t// As jQuery's .filter() allows jQuery objects to be passed in filter,\n\t\t\t// it also allows arrays, so this will cope with all three options\n\t\t\treturn $(nodes)\n\t\t\t\t.filter( sel )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn this._DT_RowIndex;\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\t};\n\t\n\t\treturn _selector_run( 'row', selector, run, settings, opts );\n\t};\n\t\n\t\n\t_api_register( 'rows()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __row_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in __row_selector?\n\t\tinst.selector.rows = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_register( 'rows().nodes()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn settings.aoData[ row ].nTr || undefined;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'rows().data()', function () {\n\t\treturn this.iterator( true, 'rows', function ( settings, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, '_aData' );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\tvar r = settings.aoData[ row ];\n\t\t\treturn type === 'search' ? r._aFilterData : r._aSortData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\t_fnInvalidate( settings, row, src );\n\t\t} );\n\t} );\n\t\n\t_api_registerPlural( 'rows().indexes()', 'row().index()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn row;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {\n\t\tvar a = [];\n\t\tvar context = this.context;\n\t\n\t\t// `iterator` will drop undefined values, but in this case we want them\n\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\tfor ( var j=0, jen=this[i].length ; j<jen ; j++ ) {\n\t\t\t\tvar id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );\n\t\t\t\ta.push( (hash === true ? '#' : '' )+ id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn new _Api( context, a );\n\t} );\n\t\n\t_api_registerPlural( 'rows().remove()', 'row().remove()', function () {\n\t\tvar that = this;\n\t\n\t\tthis.iterator( 'row', function ( settings, row, thatIdx ) {\n\t\t\tvar data = settings.aoData;\n\t\t\tvar rowData = data[ row ];\n\t\t\tvar i, ien, j, jen;\n\t\t\tvar loopRow, loopCells;\n\t\n\t\t\tdata.splice( row, 1 );\n\t\n\t\t\t// Update the cached indexes\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\tloopRow = data[i];\n\t\t\t\tloopCells = loopRow.anCells;\n\t\n\t\t\t\t// Rows\n\t\t\t\tif ( loopRow.nTr !== null ) {\n\t\t\t\t\tloopRow.nTr._DT_RowIndex = i;\n\t\t\t\t}\n\t\n\t\t\t\t// Cells\n\t\t\t\tif ( loopCells !== null ) {\n\t\t\t\t\tfor ( j=0, jen=loopCells.length ; j<jen ; j++ ) {\n\t\t\t\t\t\tloopCells[j]._DT_CellIndex.row = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Delete from the display arrays\n\t\t\t_fnDeleteIndex( settings.aiDisplayMaster, row );\n\t\t\t_fnDeleteIndex( settings.aiDisplay, row );\n\t\t\t_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes\n\t\n\t\t\t// Check for an 'overflow' they case for displaying the table\n\t\t\t_fnLengthOverflow( settings );\n\t\n\t\t\t// Remove the row's ID reference if there is one\n\t\t\tvar id = settings.rowIdFn( rowData._aData );\n\t\t\tif ( id !== undefined ) {\n\t\t\t\tdelete settings.aIds[ id ];\n\t\t\t}\n\t\t} );\n\t\n\t\tthis.iterator( 'table', function ( settings ) {\n\t\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tsettings.aoData[i].idx = i;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'rows.add()', function ( rows ) {\n\t\tvar newRows = this.iterator( 'table', function ( settings ) {\n\t\t\t\tvar row, i, ien;\n\t\t\t\tvar out = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\t\t\tout.push( _fnAddTr( settings, row )[0] );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tout.push( _fnAddData( settings, row ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn out;\n\t\t\t}, 1 );\n\t\n\t\t// Return an Api.rows() extended instance, so rows().nodes() etc can be used\n\t\tvar modRows = this.rows( -1 );\n\t\tmodRows.pop();\n\t\t$.merge( modRows, newRows );\n\t\n\t\treturn modRows;\n\t} );\n\t\n\t\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( 'row()', function ( selector, opts ) {\n\t\treturn _selector_first( this.rows( selector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'row().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._aData :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\tctx[0].aoData[ this[0] ]._aData = data;\n\t\n\t\t// Automatically invalidate\n\t\t_fnInvalidate( ctx[0], this[0], 'data' );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'row().node()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\treturn ctx.length && this.length ?\n\t\t\tctx[0].aoData[ this[0] ].nTr || null :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'row.add()', function ( row ) {\n\t\t// Allow a jQuery object to be passed in - only a single row is added from\n\t\t// it though - the first element in the set\n\t\tif ( row instanceof $ && row.length ) {\n\t\t\trow = row[0];\n\t\t}\n\t\n\t\tvar rows = this.iterator( 'table', function ( settings ) {\n\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\treturn _fnAddTr( settings, row )[0];\n\t\t\t}\n\t\t\treturn _fnAddData( settings, row );\n\t\t} );\n\t\n\t\t// Return an Api.rows() extended instance, with the newly added row selected\n\t\treturn this.row( rows[0] );\n\t} );\n\t\n\t\n\t\n\tvar __details_add = function ( ctx, row, data, klass )\n\t{\n\t\t// Convert to array of TR elements\n\t\tvar rows = [];\n\t\tvar addRow = function ( r, k ) {\n\t\t\t// Recursion to allow for arrays of jQuery objects\n\t\t\tif ( $.isArray( r ) || r instanceof $ ) {\n\t\t\t\tfor ( var i=0, ien=r.length ; i<ien ; i++ ) {\n\t\t\t\t\taddRow( r[i], k );\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If we get a TR element, then just add it directly - up to the dev\n\t\t\t// to add the correct number of columns etc\n\t\t\tif ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {\n\t\t\t\trows.push( r );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Otherwise create a row with a wrapper\n\t\t\t\tvar created = $('<tr><td/></tr>').addClass( k );\n\t\t\t\t$('td', created)\n\t\t\t\t\t.addClass( k )\n\t\t\t\t\t.html( r )\n\t\t\t\t\t[0].colSpan = _fnVisbleColumns( ctx );\n\t\n\t\t\t\trows.push( created[0] );\n\t\t\t}\n\t\t};\n\t\n\t\taddRow( data, klass );\n\t\n\t\tif ( row._details ) {\n\t\t\trow._details.detach();\n\t\t}\n\t\n\t\trow._details = $(rows);\n\t\n\t\t// If the children were already shown, that state should be retained\n\t\tif ( row._detailsShow ) {\n\t\t\trow._details.insertAfter( row.nTr );\n\t\t}\n\t};\n\t\n\t\n\tvar __details_remove = function ( api, idx )\n\t{\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length ) {\n\t\t\tvar row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];\n\t\n\t\t\tif ( row && row._details ) {\n\t\t\t\trow._details.remove();\n\t\n\t\t\t\trow._detailsShow = undefined;\n\t\t\t\trow._details = undefined;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_display = function ( api, show ) {\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length && api.length ) {\n\t\t\tvar row = ctx[0].aoData[ api[0] ];\n\t\n\t\t\tif ( row._details ) {\n\t\t\t\trow._detailsShow = show;\n\t\n\t\t\t\tif ( show ) {\n\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\trow._details.detach();\n\t\t\t\t}\n\t\n\t\t\t\t__details_events( ctx[0] );\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_events = function ( settings )\n\t{\n\t\tvar api = new _Api( settings );\n\t\tvar namespace = '.dt.DT_details';\n\t\tvar drawEvent = 'draw'+namespace;\n\t\tvar colvisEvent = 'column-visibility'+namespace;\n\t\tvar destroyEvent = 'destroy'+namespace;\n\t\tvar data = settings.aoData;\n\t\n\t\tapi.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );\n\t\n\t\tif ( _pluck( data, '_details' ).length > 0 ) {\n\t\t\t// On each draw, insert the required elements into the document\n\t\t\tapi.on( drawEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tapi.rows( {page:'current'} ).eq(0).each( function (idx) {\n\t\t\t\t\t// Internal data grab\n\t\t\t\t\tvar row = data[ idx ];\n\t\n\t\t\t\t\tif ( row._detailsShow ) {\n\t\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\n\t\t\t// Column visibility change - update the colspan\n\t\t\tapi.on( colvisEvent, function ( e, ctx, idx, vis ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t// Update the colspan for the details rows (note, only if it already has\n\t\t\t\t// a colspan)\n\t\t\t\tvar row, visible = _fnVisbleColumns( ctx );\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = data[i];\n\t\n\t\t\t\t\tif ( row._details ) {\n\t\t\t\t\t\trow._details.children('td[colspan]').attr('colspan', visible );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\t// Table destroyed - nuke any child rows\n\t\t\tapi.on( destroyEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( data[i]._details ) {\n\t\t\t\t\t\t__details_remove( api, i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t// Strings for the method names to help minification\n\tvar _emp = '';\n\tvar _child_obj = _emp+'row().child';\n\tvar _child_mth = _child_obj+'()';\n\t\n\t// data can be:\n\t//  tr\n\t//  string\n\t//  jQuery or array of any of the above\n\t_api_register( _child_mth, function ( data, klass ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._details :\n\t\t\t\tundefined;\n\t\t}\n\t\telse if ( data === true ) {\n\t\t\t// show\n\t\t\tthis.child.show();\n\t\t}\n\t\telse if ( data === false ) {\n\t\t\t// remove\n\t\t\t__details_remove( this );\n\t\t}\n\t\telse if ( ctx.length && this.length ) {\n\t\t\t// set\n\t\t\t__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );\n\t\t}\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.show()',\n\t\t_child_mth+'.show()' // only when `child()` was called with parameters (without\n\t], function ( show ) {   // it returns an object and this method is not executed)\n\t\t__details_display( this, true );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.hide()',\n\t\t_child_mth+'.hide()' // only when `child()` was called with parameters (without\n\t], function () {         // it returns an object and this method is not executed)\n\t\t__details_display( this, false );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.remove()',\n\t\t_child_mth+'.remove()' // only when `child()` was called with parameters (without\n\t], function () {           // it returns an object and this method is not executed)\n\t\t__details_remove( this );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( _child_obj+'.isShown()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length && this.length ) {\n\t\t\t// _detailsShown as false or undefined will fall through to return false\n\t\t\treturn ctx[0].aoData[ this[0] ]._detailsShow || false;\n\t\t}\n\t\treturn false;\n\t} );\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Columns\n\t *\n\t * {integer}           - column index (>=0 count from left, <0 count from right)\n\t * \"{integer}:visIdx\"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)\n\t * \"{integer}:visible\" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)\n\t * \"{string}:name\"     - column name\n\t * \"{string}\"          - jQuery selector on column header nodes\n\t *\n\t */\n\t\n\t// can be an array of these items, comma separated list, or an array of comma\n\t// separated lists\n\t\n\tvar __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;\n\t\n\t\n\t// r1 and r2 are redundant - but it means that the parameters match for the\n\t// iterator callback in columns().data()\n\tvar __columnData = function ( settings, column, r1, r2, rows ) {\n\t\tvar a = [];\n\t\tfor ( var row=0, ien=rows.length ; row<ien ; row++ ) {\n\t\t\ta.push( _fnGetCellData( settings, rows[row], column ) );\n\t\t}\n\t\treturn a;\n\t};\n\t\n\t\n\tvar __column_selector = function ( settings, selector, opts )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tnames = _pluck( columns, 'sName' ),\n\t\t\tnodes = _pluck( columns, 'nTh' );\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar selInt = _intVal( s );\n\t\n\t\t\t// Selector - all\n\t\t\tif ( s === '' ) {\n\t\t\t\treturn _range( columns.length );\n\t\t\t}\n\t\n\t\t\t// Selector - index\n\t\t\tif ( selInt !== null ) {\n\t\t\t\treturn [ selInt >= 0 ?\n\t\t\t\t\tselInt : // Count from left\n\t\t\t\t\tcolumns.length + selInt // Count from right (+ because its a negative value)\n\t\t\t\t];\n\t\t\t}\n\t\n\t\t\t// Selector = function\n\t\t\tif ( typeof s === 'function' ) {\n\t\t\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\n\t\t\t\treturn $.map( columns, function (col, idx) {\n\t\t\t\t\treturn s(\n\t\t\t\t\t\t\tidx,\n\t\t\t\t\t\t\t__columnData( settings, idx, 0, 0, rows ),\n\t\t\t\t\t\t\tnodes[ idx ]\n\t\t\t\t\t\t) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// jQuery or string selector\n\t\t\tvar match = typeof s === 'string' ?\n\t\t\t\ts.match( __re_column_selector ) :\n\t\t\t\t'';\n\t\n\t\t\tif ( match ) {\n\t\t\t\tswitch( match[2] ) {\n\t\t\t\t\tcase 'visIdx':\n\t\t\t\t\tcase 'visible':\n\t\t\t\t\t\tvar idx = parseInt( match[1], 10 );\n\t\t\t\t\t\t// Visible index given, convert to column index\n\t\t\t\t\t\tif ( idx < 0 ) {\n\t\t\t\t\t\t\t// Counting from the right\n\t\t\t\t\t\t\tvar visColumns = $.map( columns, function (col,i) {\n\t\t\t\t\t\t\t\treturn col.bVisible ? i : null;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\treturn [ visColumns[ visColumns.length + idx ] ];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Counting from the left\n\t\t\t\t\t\treturn [ _fnVisibleToColumnIndex( settings, idx ) ];\n\t\n\t\t\t\t\tcase 'name':\n\t\t\t\t\t\t// match by name. `names` is column index complete and in order\n\t\t\t\t\t\treturn $.map( names, function (name, i) {\n\t\t\t\t\t\t\treturn name === match[1] ? i : null;\n\t\t\t\t\t\t} );\n\t\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Cell in the table body\n\t\t\tif ( s.nodeName && s._DT_CellIndex ) {\n\t\t\t\treturn [ s._DT_CellIndex.column ];\n\t\t\t}\n\t\n\t\t\t// jQuery selector on the TH elements for the columns\n\t\t\tvar jqResult = $( nodes )\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn $.inArray( this, nodes ); // `nodes` is column index complete and in order\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise a node which might have a `dt-column` data attribute, or be\n\t\t\t// a child or such an element\n\t\t\tvar host = $(s).closest('*[data-dt-column]');\n\t\t\treturn host.length ?\n\t\t\t\t[ host.data('dt-column') ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'column', selector, run, settings, opts );\n\t};\n\t\n\t\n\tvar __setColumnVis = function ( settings, column, vis ) {\n\t\tvar\n\t\t\tcols = settings.aoColumns,\n\t\t\tcol  = cols[ column ],\n\t\t\tdata = settings.aoData,\n\t\t\trow, cells, i, ien, tr;\n\t\n\t\t// Get\n\t\tif ( vis === undefined ) {\n\t\t\treturn col.bVisible;\n\t\t}\n\t\n\t\t// Set\n\t\t// No change\n\t\tif ( col.bVisible === vis ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( vis ) {\n\t\t\t// Insert column\n\t\t\t// Need to decide if we should use appendChild or insertBefore\n\t\t\tvar insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );\n\t\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\ttr = data[i].nTr;\n\t\t\t\tcells = data[i].anCells;\n\t\n\t\t\t\tif ( tr ) {\n\t\t\t\t\t// insertBefore can act like appendChild if 2nd arg is null\n\t\t\t\t\ttr.insertBefore( cells[ column ], cells[ insertBefore ] || null );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Remove column\n\t\t\t$( _pluck( settings.aoData, 'anCells', column ) ).detach();\n\t\t}\n\t\n\t\t// Common actions\n\t\tcol.bVisible = vis;\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t_fnSaveState( settings );\n\t};\n\t\n\t\n\t_api_register( 'columns()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __column_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in _row_selector?\n\t\tinst.selector.cols = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTh;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTf;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().data()', 'column().data()', function () {\n\t\treturn this.iterator( 'column-rows', __columnData, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].mData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows,\n\t\t\t\ttype === 'search' ? '_aFilterData' : '_aSortData', column\n\t\t\t);\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, 'anCells', column ) ;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {\n\t\tvar ret = this.iterator( 'column', function ( settings, column ) {\n\t\t\tif ( vis === undefined ) {\n\t\t\t\treturn settings.aoColumns[ column ].bVisible;\n\t\t\t} // else\n\t\t\t__setColumnVis( settings, column, vis );\n\t\t} );\n\t\n\t\t// Group the column visibility changes\n\t\tif ( vis !== undefined ) {\n\t\t\t// Second loop once the first is done for events\n\t\t\tthis.iterator( 'column', function ( settings, column ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );\n\t\t\t} );\n\t\n\t\t\tif ( calc === undefined || calc ) {\n\t\t\t\tthis.columns.adjust();\n\t\t\t}\n\t\t}\n\t\n\t\treturn ret;\n\t} );\n\t\n\t_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn type === 'visible' ?\n\t\t\t\t_fnColumnIndexToVisible( settings, column ) :\n\t\t\t\tcolumn;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'columns.adjust()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'column.index()', function ( type, idx ) {\n\t\tif ( this.context.length !== 0 ) {\n\t\t\tvar ctx = this.context[0];\n\t\n\t\t\tif ( type === 'fromVisible' || type === 'toData' ) {\n\t\t\t\treturn _fnVisibleToColumnIndex( ctx, idx );\n\t\t\t}\n\t\t\telse if ( type === 'fromData' || type === 'toVisible' ) {\n\t\t\t\treturn _fnColumnIndexToVisible( ctx, idx );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t_api_register( 'column()', function ( selector, opts ) {\n\t\treturn _selector_first( this.columns( selector, opts ) );\n\t} );\n\t\n\t\n\t\n\tvar __cell_selector = function ( settings, selector, opts )\n\t{\n\t\tvar data = settings.aoData;\n\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\tvar cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );\n\t\tvar allCells = $( [].concat.apply([], cells) );\n\t\tvar row;\n\t\tvar columns = settings.aoColumns.length;\n\t\tvar a, i, ien, j, o, host;\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar fnSelector = typeof s === 'function';\n\t\n\t\t\tif ( s === null || s === undefined || fnSelector ) {\n\t\t\t\t// All cells and function selectors\n\t\t\t\ta = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tfor ( j=0 ; j<columns ; j++ ) {\n\t\t\t\t\t\to = {\n\t\t\t\t\t\t\trow: row,\n\t\t\t\t\t\t\tcolumn: j\n\t\t\t\t\t\t};\n\t\n\t\t\t\t\t\tif ( fnSelector ) {\n\t\t\t\t\t\t\t// Selector - function\n\t\t\t\t\t\t\thost = data[ row ];\n\t\n\t\t\t\t\t\t\tif ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {\n\t\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Selector - all\n\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn a;\n\t\t\t}\n\t\t\t\n\t\t\t// Selector - index\n\t\t\tif ( $.isPlainObject( s ) ) {\n\t\t\t\treturn [s];\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery filtered cells\n\t\t\tvar jqResult = allCells\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function (i, el) {\n\t\t\t\t\treturn { // use a new object, in case someone changes the values\n\t\t\t\t\t\trow:    el._DT_CellIndex.row,\n\t\t\t\t\t\tcolumn: el._DT_CellIndex.column\n\t \t\t\t\t};\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise the selector is a node, and there is one last option - the\n\t\t\t// element might be a child of an element which has dt-row and dt-column\n\t\t\t// data attributes\n\t\t\thost = $(s).closest('*[data-dt-row]');\n\t\t\treturn host.length ?\n\t\t\t\t[ {\n\t\t\t\t\trow: host.data('dt-row'),\n\t\t\t\t\tcolumn: host.data('dt-column')\n\t\t\t\t} ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'cell', selector, run, settings, opts );\n\t};\n\t\n\t\n\t\n\t\n\t_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {\n\t\t// Argument shifting\n\t\tif ( $.isPlainObject( rowSelector ) ) {\n\t\t\t// Indexes\n\t\t\tif ( rowSelector.row === undefined ) {\n\t\t\t\t// Selector options in first parameter\n\t\t\t\topts = rowSelector;\n\t\t\t\trowSelector = null;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Cell index objects in first parameter\n\t\t\t\topts = columnSelector;\n\t\t\t\tcolumnSelector = null;\n\t\t\t}\n\t\t}\n\t\tif ( $.isPlainObject( columnSelector ) ) {\n\t\t\topts = columnSelector;\n\t\t\tcolumnSelector = null;\n\t\t}\n\t\n\t\t// Cell selector\n\t\tif ( columnSelector === null || columnSelector === undefined ) {\n\t\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t\treturn __cell_selector( settings, rowSelector, _selector_opts( opts ) );\n\t\t\t} );\n\t\t}\n\t\n\t\t// Row + column selector\n\t\tvar columns = this.columns( columnSelector, opts );\n\t\tvar rows = this.rows( rowSelector, opts );\n\t\tvar a, i, ien, j, jen;\n\t\n\t\tvar cells = this.iterator( 'table', function ( settings, idx ) {\n\t\t\ta = [];\n\t\n\t\t\tfor ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {\n\t\t\t\tfor ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {\n\t\t\t\t\ta.push( {\n\t\t\t\t\t\trow:    rows[idx][i],\n\t\t\t\t\t\tcolumn: columns[idx][j]\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn a;\n\t\t}, 1 );\n\t\n\t\t$.extend( cells.selector, {\n\t\t\tcols: columnSelector,\n\t\t\trows: rowSelector,\n\t\t\topts: opts\n\t\t} );\n\t\n\t\treturn cells;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\tvar data = settings.aoData[ row ];\n\t\n\t\t\treturn data && data.anCells ?\n\t\t\t\tdata.anCells[ column ] :\n\t\t\t\tundefined;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_register( 'cells().data()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {\n\t\ttype = type === 'search' ? '_aFilterData' : '_aSortData';\n\t\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn settings.aoData[ row ][ type ][ column ];\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column, type );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn {\n\t\t\t\trow: row,\n\t\t\t\tcolumn: column,\n\t\t\t\tcolumnVisible: _fnColumnIndexToVisible( settings, column )\n\t\t\t};\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\t_fnInvalidate( settings, row, src, column );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {\n\t\treturn _selector_first( this.cells( rowSelector, columnSelector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'cell().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\tvar cell = this[0];\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && cell.length ?\n\t\t\t\t_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\t_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );\n\t\t_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get current ordering (sorting) that has been applied to the table.\n\t *\n\t * @returns {array} 2D array containing the sorting information for the first\n\t *   table in the current context. Each element in the parent array represents\n\t *   a column being sorted upon (i.e. multi-sorting with two columns would have\n\t *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is\n\t *   the column index that the sorting condition applies to, the second is the\n\t *   direction of the sort (`desc` or `asc`) and, optionally, the third is the\n\t *   index of the sorting order from the `column.sorting` initialisation array.\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {integer} order Column index to sort upon.\n\t * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 1D array of sorting information to be applied.\n\t * @param {array} [...] Optional additional sorting conditions\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 2D array of sorting information to be applied.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order()', function ( order, dir ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( order === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].aaSorting :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\tif ( typeof order === 'number' ) {\n\t\t\t// Simple column / direction passed in\n\t\t\torder = [ [ order, dir ] ];\n\t\t}\n\t\telse if ( order.length && ! $.isArray( order[0] ) ) {\n\t\t\t// Arguments passed in (list of 1D arrays)\n\t\t\torder = Array.prototype.slice.call( arguments );\n\t\t}\n\t\t// otherwise a 2D array was passed in\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSorting = order.slice();\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Attach a sort listener to an element for a given column\n\t *\n\t * @param {node|jQuery|string} node Identifier for the element(s) to attach the\n\t *   listener to. This can take the form of a single DOM node, a jQuery\n\t *   collection of nodes or a jQuery selector which will identify the node(s).\n\t * @param {integer} column the column that a click on this node will sort on\n\t * @param {function} [callback] callback function when sort is run\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order.listener()', function ( node, column, callback ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSortAttachListener( settings, node, column, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'order.fixed()', function ( set ) {\n\t\tif ( ! set ) {\n\t\t\tvar ctx = this.context;\n\t\t\tvar fixed = ctx.length ?\n\t\t\t\tctx[0].aaSortingFixed :\n\t\t\t\tundefined;\n\t\n\t\t\treturn $.isArray( fixed ) ?\n\t\t\t\t{ pre: fixed } :\n\t\t\t\tfixed;\n\t\t}\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSortingFixed = $.extend( true, {}, set );\n\t\t} );\n\t} );\n\t\n\t\n\t// Order by the selected column(s)\n\t_api_register( [\n\t\t'columns().order()',\n\t\t'column().order()'\n\t], function ( dir ) {\n\t\tvar that = this;\n\t\n\t\treturn this.iterator( 'table', function ( settings, i ) {\n\t\t\tvar sort = [];\n\t\n\t\t\t$.each( that[i], function (j, col) {\n\t\t\t\tsort.push( [ col, dir ] );\n\t\t\t} );\n\t\n\t\t\tsettings.aaSorting = sort;\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'search()', function ( input, regex, smart, caseInsen ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( input === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].oPreviousSearch.sSearch :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {\n\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t} ), 1 );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural(\n\t\t'columns().search()',\n\t\t'column().search()',\n\t\tfunction ( input, regex, smart, caseInsen ) {\n\t\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\t\tvar preSearch = settings.aoPreSearchCols;\n\t\n\t\t\t\tif ( input === undefined ) {\n\t\t\t\t\t// get\n\t\t\t\t\treturn preSearch[ column ].sSearch;\n\t\t\t\t}\n\t\n\t\t\t\t// set\n\t\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t$.extend( preSearch[ column ], {\n\t\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t\t} );\n\t\n\t\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch, 1 );\n\t\t\t} );\n\t\t}\n\t);\n\t\n\t/*\n\t * State API methods\n\t */\n\t\n\t_api_register( 'state()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oSavedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t// Save an empty object\n\t\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, {} );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'state.loaded()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oLoadedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.save()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSaveState( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Provide a common method for plug-ins to check the version of DataTables being\n\t * used, in order to ensure compatibility.\n\t *\n\t *  @param {string} version Version string to check for, in the format \"X.Y.Z\".\n\t *    Note that the formats \"X\" and \"X.Y\" are also acceptable.\n\t *  @returns {boolean} true if this version of DataTables is greater or equal to\n\t *    the required version, or false if this version of DataTales is not\n\t *    suitable\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );\n\t */\n\tDataTable.versionCheck = DataTable.fnVersionCheck = function( version )\n\t{\n\t\tvar aThis = DataTable.version.split('.');\n\t\tvar aThat = version.split('.');\n\t\tvar iThis, iThat;\n\t\n\t\tfor ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {\n\t\t\tiThis = parseInt( aThis[i], 10 ) || 0;\n\t\t\tiThat = parseInt( aThat[i], 10 ) || 0;\n\t\n\t\t\t// Parts are the same, keep comparing\n\t\t\tif (iThis === iThat) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\t// Parts are different, return immediately\n\t\t\treturn iThis > iThat;\n\t\t}\n\t\n\t\treturn true;\n\t};\n\t\n\t\n\t/**\n\t * Check if a `<table>` node is a DataTable table already or not.\n\t *\n\t *  @param {node|jquery|string} table Table node, jQuery object or jQuery\n\t *      selector for the table to test. Note that if more than more than one\n\t *      table is passed on, only the first will be checked\n\t *  @returns {boolean} true the table given is a DataTable, or false otherwise\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {\n\t *      $('#example').dataTable();\n\t *    }\n\t */\n\tDataTable.isDataTable = DataTable.fnIsDataTable = function ( table )\n\t{\n\t\tvar t = $(table).get(0);\n\t\tvar is = false;\n\t\n\t\tif ( table instanceof DataTable.Api ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\t$.each( DataTable.settings, function (i, o) {\n\t\t\tvar head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;\n\t\t\tvar foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;\n\t\n\t\t\tif ( o.nTable === t || head === t || foot === t ) {\n\t\t\t\tis = true;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn is;\n\t};\n\t\n\t\n\t/**\n\t * Get all DataTable tables that have been initialised - optionally you can\n\t * select to get only currently visible tables.\n\t *\n\t *  @param {boolean} [visible=false] Flag to indicate if you want all (default)\n\t *    or visible tables only.\n\t *  @returns {array} Array of `table` nodes (not DataTable instances) which are\n\t *    DataTables\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    $.each( $.fn.dataTable.tables(true), function () {\n\t *      $(table).DataTable().columns.adjust();\n\t *    } );\n\t */\n\tDataTable.tables = DataTable.fnTables = function ( visible )\n\t{\n\t\tvar api = false;\n\t\n\t\tif ( $.isPlainObject( visible ) ) {\n\t\t\tapi = visible.api;\n\t\t\tvisible = visible.visible;\n\t\t}\n\t\n\t\tvar a = $.map( DataTable.settings, function (o) {\n\t\t\tif ( !visible || (visible && $(o.nTable).is(':visible')) ) {\n\t\t\t\treturn o.nTable;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn api ?\n\t\t\tnew _Api( a ) :\n\t\t\ta;\n\t};\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian notation. This is made public\n\t * for the extensions to provide the same ability as DataTables core to accept\n\t * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase\n\t * parameters.\n\t *\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t */\n\tDataTable.camelToHungarian = _fnCamelToHungarian;\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( '$()', function ( selector, opts ) {\n\t\tvar\n\t\t\trows   = this.rows( opts ).nodes(), // Get all rows\n\t\t\tjqRows = $(rows);\n\t\n\t\treturn $( [].concat(\n\t\t\tjqRows.filter( selector ).toArray(),\n\t\t\tjqRows.find( selector ).toArray()\n\t\t) );\n\t} );\n\t\n\t\n\t// jQuery functions to operate on the tables\n\t$.each( [ 'on', 'one', 'off' ], function (i, key) {\n\t\t_api_register( key+'()', function ( /* event, handler */ ) {\n\t\t\tvar args = Array.prototype.slice.call(arguments);\n\t\n\t\t\t// Add the `dt` namespace automatically if it isn't already present\n\t\t\targs[0] = $.map( args[0].split( /\\s/ ), function ( e ) {\n\t\t\t\treturn ! e.match(/\\.dt\\b/) ?\n\t\t\t\t\te+'.dt' :\n\t\t\t\t\te;\n\t\t\t\t} ).join( ' ' );\n\t\n\t\t\tvar inst = $( this.tables().nodes() );\n\t\t\tinst[key].apply( inst, args );\n\t\t\treturn this;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnClearTable( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'settings()', function () {\n\t\treturn new _Api( this.context, this.context );\n\t} );\n\t\n\t\n\t_api_register( 'init()', function () {\n\t\tvar ctx = this.context;\n\t\treturn ctx.length ? ctx[0].oInit : null;\n\t} );\n\t\n\t\n\t_api_register( 'data()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\treturn _pluck( settings.aoData, '_aData' );\n\t\t} ).flatten();\n\t} );\n\t\n\t\n\t_api_register( 'destroy()', function ( remove ) {\n\t\tremove = remove || false;\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tvar orig      = settings.nTableWrapper.parentNode;\n\t\t\tvar classes   = settings.oClasses;\n\t\t\tvar table     = settings.nTable;\n\t\t\tvar tbody     = settings.nTBody;\n\t\t\tvar thead     = settings.nTHead;\n\t\t\tvar tfoot     = settings.nTFoot;\n\t\t\tvar jqTable   = $(table);\n\t\t\tvar jqTbody   = $(tbody);\n\t\t\tvar jqWrapper = $(settings.nTableWrapper);\n\t\t\tvar rows      = $.map( settings.aoData, function (r) { return r.nTr; } );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Flag to note that the table is currently being destroyed - no action\n\t\t\t// should be taken\n\t\t\tsettings.bDestroying = true;\n\t\n\t\t\t// Fire off the destroy callbacks for plug-ins etc\n\t\t\t_fnCallbackFire( settings, \"aoDestroyCallback\", \"destroy\", [settings] );\n\t\n\t\t\t// If not being removed from the document, make all columns visible\n\t\t\tif ( ! remove ) {\n\t\t\t\tnew _Api( settings ).columns().visible( true );\n\t\t\t}\n\t\n\t\t\t// Blitz all `DT` namespaced events (these are internal events, the\n\t\t\t// lowercase, `dt` events are user subscribed and they are responsible\n\t\t\t// for removing them\n\t\t\tjqWrapper.off('.DT').find(':not(tbody *)').off('.DT');\n\t\t\t$(window).off('.DT-'+settings.sInstance);\n\t\n\t\t\t// When scrolling we had to break the table up - restore it\n\t\t\tif ( table != thead.parentNode ) {\n\t\t\t\tjqTable.children('thead').detach();\n\t\t\t\tjqTable.append( thead );\n\t\t\t}\n\t\n\t\t\tif ( tfoot && table != tfoot.parentNode ) {\n\t\t\t\tjqTable.children('tfoot').detach();\n\t\t\t\tjqTable.append( tfoot );\n\t\t\t}\n\t\n\t\t\tsettings.aaSorting = [];\n\t\t\tsettings.aaSortingFixed = [];\n\t\t\t_fnSortingClasses( settings );\n\t\n\t\t\t$( rows ).removeClass( settings.asStripeClasses.join(' ') );\n\t\n\t\t\t$('th, td', thead).removeClass( classes.sSortable+' '+\n\t\t\t\tclasses.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone\n\t\t\t);\n\t\n\t\t\tif ( settings.bJUI ) {\n\t\t\t\t$('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();\n\t\t\t\t$('th, td', thead).each( function () {\n\t\t\t\t\tvar wrapper = $('div.'+classes.sSortJUIWrapper, this);\n\t\t\t\t\t$(this).append( wrapper.contents() );\n\t\t\t\t\twrapper.detach();\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Add the TR elements back into the table in their original order\n\t\t\tjqTbody.children().detach();\n\t\t\tjqTbody.append( rows );\n\t\n\t\t\t// Remove the DataTables generated nodes, events and classes\n\t\t\tvar removedMethod = remove ? 'remove' : 'detach';\n\t\t\tjqTable[ removedMethod ]();\n\t\t\tjqWrapper[ removedMethod ]();\n\t\n\t\t\t// If we need to reattach the table to the document\n\t\t\tif ( ! remove && orig ) {\n\t\t\t\t// insertBefore acts like appendChild if !arg[1]\n\t\t\t\torig.insertBefore( table, settings.nTableReinsertBefore );\n\t\n\t\t\t\t// Restore the width of the original table - was read from the style property,\n\t\t\t\t// so we can restore directly to that\n\t\t\t\tjqTable\n\t\t\t\t\t.css( 'width', settings.sDestroyWidth )\n\t\t\t\t\t.removeClass( classes.sTable );\n\t\n\t\t\t\t// If the were originally stripe classes - then we add them back here.\n\t\t\t\t// Note this is not fool proof (for example if not all rows had stripe\n\t\t\t\t// classes - but it's a good effort without getting carried away\n\t\t\t\tien = settings.asDestroyStripes.length;\n\t\n\t\t\t\tif ( ien ) {\n\t\t\t\t\tjqTbody.children().each( function (i) {\n\t\t\t\t\t\t$(this).addClass( settings.asDestroyStripes[i % ien] );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Remove the settings object from the settings array */\n\t\t\tvar idx = $.inArray( settings, DataTable.settings );\n\t\t\tif ( idx !== -1 ) {\n\t\t\t\tDataTable.settings.splice( idx, 1 );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t// Add the `every()` method for rows, columns and cells in a compact form\n\t$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {\n\t\t_api_register( type+'s().every()', function ( fn ) {\n\t\t\tvar opts = this.selector.opts;\n\t\t\tvar api = this;\n\t\n\t\t\treturn this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {\n\t\t\t\t// Rows and columns:\n\t\t\t\t//  arg1 - index\n\t\t\t\t//  arg2 - table counter\n\t\t\t\t//  arg3 - loop counter\n\t\t\t\t//  arg4 - undefined\n\t\t\t\t// Cells:\n\t\t\t\t//  arg1 - row index\n\t\t\t\t//  arg2 - column index\n\t\t\t\t//  arg3 - table counter\n\t\t\t\t//  arg4 - loop counter\n\t\t\t\tfn.call(\n\t\t\t\t\tapi[ type ](\n\t\t\t\t\t\targ1,\n\t\t\t\t\t\ttype==='cell' ? arg2 : opts,\n\t\t\t\t\t\ttype==='cell' ? opts : undefined\n\t\t\t\t\t),\n\t\t\t\t\targ1, arg2, arg3, arg4\n\t\t\t\t);\n\t\t\t} );\n\t\t} );\n\t} );\n\t\n\t\n\t// i18n method for extensions to be able to use the language object from the\n\t// DataTable\n\t_api_register( 'i18n()', function ( token, def, plural ) {\n\t\tvar ctx = this.context[0];\n\t\tvar resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );\n\t\n\t\tif ( resolved === undefined ) {\n\t\t\tresolved = def;\n\t\t}\n\t\n\t\tif ( plural !== undefined && $.isPlainObject( resolved ) ) {\n\t\t\tresolved = resolved[ plural ] !== undefined ?\n\t\t\t\tresolved[ plural ] :\n\t\t\t\tresolved._;\n\t\t}\n\t\n\t\treturn resolved.replace( '%d', plural ); // nb: plural might be undefined,\n\t} );\n\n\t/**\n\t * Version string for plug-ins to check compatibility. Allowed format is\n\t * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used\n\t * only for non-release builds. See http://semver.org/ for more information.\n\t *  @member\n\t *  @type string\n\t *  @default Version number\n\t */\n\tDataTable.version = \"1.10.13\";\n\n\t/**\n\t * Private data store, containing all of the settings objects that are\n\t * created for the tables on a given page.\n\t *\n\t * Note that the `DataTable.settings` object is aliased to\n\t * `jQuery.fn.dataTableExt` through which it may be accessed and\n\t * manipulated, or `jQuery.fn.dataTable.settings`.\n\t *  @member\n\t *  @type array\n\t *  @default []\n\t *  @private\n\t */\n\tDataTable.settings = [];\n\n\t/**\n\t * Object models container, for the various models that DataTables has\n\t * available to it. These models define the objects that are used to hold\n\t * the active state and configuration of the table.\n\t *  @namespace\n\t */\n\tDataTable.models = {};\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * search information for the global filter and individual column filters.\n\t *  @namespace\n\t */\n\tDataTable.models.oSearch = {\n\t\t/**\n\t\t * Flag to indicate if the filtering should be case insensitive or not\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bCaseInsensitive\": true,\n\t\n\t\t/**\n\t\t * Applied search term\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sSearch\": \"\",\n\t\n\t\t/**\n\t\t * Flag to indicate if the search term should be interpreted as a\n\t\t * regular expression (true) or not (false) and therefore and special\n\t\t * regex characters escaped.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bRegex\": false,\n\t\n\t\t/**\n\t\t * Flag to indicate if DataTables is to use its smart filtering or not.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bSmart\": true\n\t};\n\t\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * each individual row. This is the object format used for the settings\n\t * aoData array.\n\t *  @namespace\n\t */\n\tDataTable.models.oRow = {\n\t\t/**\n\t\t * TR element for the row\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTr\": null,\n\t\n\t\t/**\n\t\t * Array of TD elements for each row. This is null until the row has been\n\t\t * created.\n\t\t *  @type array nodes\n\t\t *  @default []\n\t\t */\n\t\t\"anCells\": null,\n\t\n\t\t/**\n\t\t * Data object from the original data source for the row. This is either\n\t\t * an array if using the traditional form of DataTables, or an object if\n\t\t * using mData options. The exact type will depend on the passed in\n\t\t * data from the data source, or will be an array if using DOM a data\n\t\t * source.\n\t\t *  @type array|object\n\t\t *  @default []\n\t\t */\n\t\t\"_aData\": [],\n\t\n\t\t/**\n\t\t * Sorting data cache - this array is ostensibly the same length as the\n\t\t * number of columns (although each index is generated only as it is\n\t\t * needed), and holds the data that is used for sorting each column in the\n\t\t * row. We do this cache generation at the start of the sort in order that\n\t\t * the formatting of the sort data need be done only once for each cell\n\t\t * per sort. This array should not be read from or written to by anything\n\t\t * other than the master sorting methods.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aSortData\": null,\n\t\n\t\t/**\n\t\t * Per cell filtering data cache. As per the sort data cache, used to\n\t\t * increase the performance of the filtering in DataTables\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aFilterData\": null,\n\t\n\t\t/**\n\t\t * Filtering data cache. This is the same as the cell filtering cache, but\n\t\t * in this case a string rather than an array. This is easily computed with\n\t\t * a join on `_aFilterData`, but is provided as a cache so the join isn't\n\t\t * needed on every search (memory traded for performance)\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sFilterRow\": null,\n\t\n\t\t/**\n\t\t * Cache of the class name that DataTables has applied to the row, so we\n\t\t * can quickly look at this variable rather than needing to do a DOM check\n\t\t * on className for the nTr property.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *  @private\n\t\t */\n\t\t\"_sRowStripe\": \"\",\n\t\n\t\t/**\n\t\t * Denote if the original data source was from the DOM, or the data source\n\t\t * object. This is used for invalidating data, so DataTables can\n\t\t * automatically read data from the original source, unless uninstructed\n\t\t * otherwise.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"src\": null,\n\t\n\t\t/**\n\t\t * Index in the aoData array. This saves an indexOf lookup when we have the\n\t\t * object, but want to know the index\n\t\t *  @type integer\n\t\t *  @default -1\n\t\t *  @private\n\t\t */\n\t\t\"idx\": -1\n\t};\n\t\n\t\n\t/**\n\t * Template object for the column information object in DataTables. This object\n\t * is held in the settings aoColumns array and contains all the information that\n\t * DataTables needs about each individual column.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults.column}\n\t * but this one is the internal data store for DataTables's cache of columns.\n\t * It should NOT be manipulated outside of DataTables. Any configuration should\n\t * be done through the initialisation options.\n\t *  @namespace\n\t */\n\tDataTable.models.oColumn = {\n\t\t/**\n\t\t * Column index. This could be worked out on-the-fly with $.inArray, but it\n\t\t * is faster to just hold it as a variable\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"idx\": null,\n\t\n\t\t/**\n\t\t * A list of the columns that sorting should occur on when this column\n\t\t * is sorted. That this property is an array allows multi-column sorting\n\t\t * to be defined for a column (for example first name / last name columns\n\t\t * would benefit from this). The values are integers pointing to the\n\t\t * columns to be sorted on (typically it will be a single integer pointing\n\t\t * at itself, but that doesn't need to be the case).\n\t\t *  @type array\n\t\t */\n\t\t\"aDataSort\": null,\n\t\n\t\t/**\n\t\t * Define the sorting directions that are applied to the column, in sequence\n\t\t * as the column is repeatedly sorted upon - i.e. the first value is used\n\t\t * as the sorting direction when the column if first sorted (clicked on).\n\t\t * Sort it again (click again) and it will move on to the next index.\n\t\t * Repeat until loop.\n\t\t *  @type array\n\t\t */\n\t\t\"asSorting\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is searchable, and thus should be included\n\t\t * in the filtering or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSearchable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is sortable or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is currently visible in the table or not\n\t\t *  @type boolean\n\t\t */\n\t\t\"bVisible\": null,\n\t\n\t\t/**\n\t\t * Store for manual type assignment using the `column.type` option. This\n\t\t * is held in store so we can manipulate the column's `sType` property.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sManualType\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if HTML5 data attributes should be used as the data\n\t\t * source for filtering or sorting. True is either are.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @private\n\t\t */\n\t\t\"_bAttrSrc\": false,\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} nTd The TD node that has been created\n\t\t *  @param {*} sData The Data for the cell\n\t\t *  @param {array|object} oData The data for the whole row\n\t\t *  @param {int} iRow The row index for the aoData data store\n\t\t *  @default null\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\t/**\n\t\t * Function to get data from a cell in a column. You should <b>never</b>\n\t\t * access data directly through _aData internally in DataTables - always use\n\t\t * the method attached to this property. It allows mData to function as\n\t\t * required. This function is automatically assigned by the column\n\t\t * initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {string} sSpecific The specific data type you want to get -\n\t\t *    'display', 'type' 'filter' 'sort'\n\t\t *  @returns {*} The data for the cell from the given row's data\n\t\t *  @default null\n\t\t */\n\t\t\"fnGetData\": null,\n\t\n\t\t/**\n\t\t * Function to set data for a cell in the column. You should <b>never</b>\n\t\t * set the data directly to _aData internally in DataTables - always use\n\t\t * this method. It allows mData to function as required. This function\n\t\t * is automatically assigned by the column initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {*} sValue Value to set\n\t\t *  @default null\n\t\t */\n\t\t\"fnSetData\": null,\n\t\n\t\t/**\n\t\t * Property to read the value for the cells in the column from the data\n\t\t * source array / object. If null, then the default content is used, if a\n\t\t * function is given then the return from the function is used.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\t/**\n\t\t * Partner property to mData which is used (only when defined) to get\n\t\t * the data - i.e. it is basically the same as mData, but without the\n\t\t * 'set' option, and also the data fed to it is the result from mData.\n\t\t * This is the rendering method to match the data method of mData.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\t/**\n\t\t * Unique header TH/TD element for this column - this is what the sorting\n\t\t * listener is attached to (if sorting is enabled.)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTh\": null,\n\t\n\t\t/**\n\t\t * Unique footer TH/TD element for this column (if there is one). Not used\n\t\t * in DataTables as such, but can be used for plug-ins to reference the\n\t\t * footer for each column.\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTf\": null,\n\t\n\t\t/**\n\t\t * The class to apply to all TD elements in the table's TBODY for the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sClass\": null,\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t *  @type string\n\t\t */\n\t\t\"sContentPadding\": null,\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because mData\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\t/**\n\t\t * Name for the column, allowing reference to the column by name as well as\n\t\t * by index (needs a lookup to work by name).\n\t\t *  @type string\n\t\t */\n\t\t\"sName\": null,\n\t\n\t\t/**\n\t\t * Custom sorting data type - defines which of the available plug-ins in\n\t\t * afnSortData the custom sorting will use - if any is defined.\n\t\t *  @type string\n\t\t *  @default std\n\t\t */\n\t\t\"sSortDataType\": 'std',\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClass\": null,\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column -\n\t\t * when jQuery UI theming is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClassJUI\": null,\n\t\n\t\t/**\n\t\t * Title of the column - what is seen in the TH element (nTh).\n\t\t *  @type string\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\t/**\n\t\t * Column sorting and filtering type\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\t/**\n\t\t * Width of the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidth\": null,\n\t\n\t\t/**\n\t\t * Width of the column when it was first \"encountered\"\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidthOrig\": null\n\t};\n\t\n\t\n\t/*\n\t * Developer note: The properties of the object below are given in Hungarian\n\t * notation, that was used as the interface for DataTables prior to v1.10, however\n\t * from v1.10 onwards the primary interface is camel case. In order to avoid\n\t * breaking backwards compatibility utterly with this change, the Hungarian\n\t * version is still, internally the primary interface, but is is not documented\n\t * - hence the @name tags in each doc comment. This allows a Javascript function\n\t * to create a map from Hungarian notation to camel case (going the other direction\n\t * would require each property to be listed, which would at around 3K to the size\n\t * of DataTables, while this method is about a 0.5K hit.\n\t *\n\t * Ultimately this does pave the way for Hungarian notation to be dropped\n\t * completely, but that is a massive amount of work and will break current\n\t * installs (therefore is on-hold until v2).\n\t */\n\t\n\t/**\n\t * Initialisation options that can be given to DataTables at initialisation\n\t * time.\n\t *  @namespace\n\t */\n\tDataTable.defaults = {\n\t\t/**\n\t\t * An array of data to use for the table, passed in at initialisation which\n\t\t * will be used in preference to any data which is already in the DOM. This is\n\t\t * particularly useful for constructing tables purely in Javascript, for\n\t\t * example with a custom Ajax call.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.data\n\t\t *\n\t\t *  @example\n\t\t *    // Using a 2D array data source\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],\n\t\t *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\" },\n\t\t *          { \"title\": \"Browser\" },\n\t\t *          { \"title\": \"Platform\" },\n\t\t *          { \"title\": \"Version\" },\n\t\t *          { \"title\": \"Grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using an array of objects as a data source (`data`)\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 4.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  4,\n\t\t *            \"grade\":    \"X\"\n\t\t *          },\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 5.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  5,\n\t\t *            \"grade\":    \"C\"\n\t\t *          }\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\",   \"data\": \"engine\" },\n\t\t *          { \"title\": \"Browser\",  \"data\": \"browser\" },\n\t\t *          { \"title\": \"Platform\", \"data\": \"platform\" },\n\t\t *          { \"title\": \"Version\",  \"data\": \"version\" },\n\t\t *          { \"title\": \"Grade\",    \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaData\": null,\n\t\n\t\n\t\t/**\n\t\t * If ordering is enabled, then DataTables will perform a first pass sort on\n\t\t * initialisation. You can define which column(s) the sort is performed\n\t\t * upon, and the sorting direction, with this variable. The `sorting` array\n\t\t * should contain an array for each column to be sorted initially containing\n\t\t * the column's index and a direction string ('asc' or 'desc').\n\t\t *  @type array\n\t\t *  @default [[0,'asc']]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.order\n\t\t *\n\t\t *  @example\n\t\t *    // Sort by 3rd column first, and then 4th column\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": [[2,'asc'], [3,'desc']]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *    // No initial sorting\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": []\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaSorting\": [[0,'asc']],\n\t\n\t\n\t\t/**\n\t\t * This parameter is basically identical to the `sorting` parameter, but\n\t\t * cannot be overridden by user interaction with the table. What this means\n\t\t * is that you could have a column (visible or hidden) which the sorting\n\t\t * will always be forced on first - any sorting after that (from the user)\n\t\t * will then be performed as required. This can be useful for grouping rows\n\t\t * together.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.orderFixed\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderFixed\": [[0,'asc']]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\n\t\t/**\n\t\t * DataTables can be instructed to load data to display in the table from a\n\t\t * Ajax source. This option defines how that Ajax call is made and where to.\n\t\t *\n\t\t * The `ajax` property has three different modes of operation, depending on\n\t\t * how it is defined. These are:\n\t\t *\n\t\t * * `string` - Set the URL from where the data should be loaded from.\n\t\t * * `object` - Define properties for `jQuery.ajax`.\n\t\t * * `function` - Custom data get function\n\t\t *\n\t\t * `string`\n\t\t * --------\n\t\t *\n\t\t * As a string, the `ajax` property simply defines the URL from which\n\t\t * DataTables will load data.\n\t\t *\n\t\t * `object`\n\t\t * --------\n\t\t *\n\t\t * As an object, the parameters in the object are passed to\n\t\t * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control\n\t\t * of the Ajax request. DataTables has a number of default parameters which\n\t\t * you can override using this option. Please refer to the jQuery\n\t\t * documentation for a full description of the options available, although\n\t\t * the following parameters provide additional options in DataTables or\n\t\t * require special consideration:\n\t\t *\n\t\t * * `data` - As with jQuery, `data` can be provided as an object, but it\n\t\t *   can also be used as a function to manipulate the data DataTables sends\n\t\t *   to the server. The function takes a single parameter, an object of\n\t\t *   parameters with the values that DataTables has readied for sending. An\n\t\t *   object may be returned which will be merged into the DataTables\n\t\t *   defaults, or you can add the items to the object that was passed in and\n\t\t *   not return anything from the function. This supersedes `fnServerParams`\n\t\t *   from DataTables 1.9-.\n\t\t *\n\t\t * * `dataSrc` - By default DataTables will look for the property `data` (or\n\t\t *   `aaData` for compatibility with DataTables 1.9-) when obtaining data\n\t\t *   from an Ajax source or for server-side processing - this parameter\n\t\t *   allows that property to be changed. You can use Javascript dotted\n\t\t *   object notation to get a data source for multiple levels of nesting, or\n\t\t *   it my be used as a function. As a function it takes a single parameter,\n\t\t *   the JSON returned from the server, which can be manipulated as\n\t\t *   required, with the returned value being that used by DataTables as the\n\t\t *   data source for the table. This supersedes `sAjaxDataProp` from\n\t\t *   DataTables 1.9-.\n\t\t *\n\t\t * * `success` - Should not be overridden it is used internally in\n\t\t *   DataTables. To manipulate / transform the data returned by the server\n\t\t *   use `ajax.dataSrc`, or use `ajax` as a function (see below).\n\t\t *\n\t\t * `function`\n\t\t * ----------\n\t\t *\n\t\t * As a function, making the Ajax call is left up to yourself allowing\n\t\t * complete control of the Ajax request. Indeed, if desired, a method other\n\t\t * than Ajax could be used to obtain the required data, such as Web storage\n\t\t * or an AIR database.\n\t\t *\n\t\t * The function is given four parameters and no return is required. The\n\t\t * parameters are:\n\t\t *\n\t\t * 1. _object_ - Data to send to the server\n\t\t * 2. _function_ - Callback function that must be executed when the required\n\t\t *    data has been obtained. That data should be passed into the callback\n\t\t *    as the only parameter\n\t\t * 3. _object_ - DataTables settings object for the table\n\t\t *\n\t\t * Note that this supersedes `fnServerData` from DataTables 1.9-.\n\t\t *\n\t\t *  @type string|object|function\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.ajax\n\t\t *  @since 1.10.0\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax.\n\t\t *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": \"data.json\"\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to change\n\t\t *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"tableData\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to read data\n\t\t *   // from a plain array rather than an array in an object\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Manipulate the data returned from the server - add a link to data\n\t\t *   // (note this can, should, be done using `render` for the column - this\n\t\t *   // is just a simple example of how the data can be manipulated).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": function ( json ) {\n\t\t *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {\n\t\t *           json[i][0] = '<a href=\"/message/'+json[i][0]+'>View message</a>';\n\t\t *         }\n\t\t *         return json;\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Add data to the request\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"data\": function ( d ) {\n\t\t *         return {\n\t\t *           \"extra_search\": $('#extra').val()\n\t\t *         };\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Send request as POST\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"type\": \"POST\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get the data from localStorage (could interface with a form for\n\t\t *   // adding, editing and removing rows).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": function (data, callback, settings) {\n\t\t *       callback(\n\t\t *         JSON.parse( localStorage.getItem('dataTablesData') )\n\t\t *       );\n\t\t *     }\n\t\t *   } );\n\t\t */\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to readily specify the entries in the length drop\n\t\t * down menu that DataTables shows when pagination is enabled. It can be\n\t\t * either a 1D array of options which will be used for both the displayed\n\t\t * option and the value, or a 2D array which will use the array in the first\n\t\t * position as the value, and the array in the second position as the\n\t\t * displayed options (useful for language strings such as 'All').\n\t\t *\n\t\t * Note that the `pageLength` property will be automatically set to the\n\t\t * first value given in this array, unless `pageLength` is also provided.\n\t\t *  @type array\n\t\t *  @default [ 10, 25, 50, 100 ]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.lengthMenu\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthMenu\": [[10, 25, 50, -1], [10, 25, 50, \"All\"]]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aLengthMenu\": [ 10, 25, 50, 100 ],\n\t\n\t\n\t\t/**\n\t\t * The `columns` option in the initialisation parameter allows you to define\n\t\t * details about the way individual columns behave. For a full list of\n\t\t * column options that can be set, please see\n\t\t * {@link DataTable.defaults.column}. Note that if you use `columns` to\n\t\t * define your columns, you must have an entry in the array for every single\n\t\t * column that you have in your table (these can be null if you don't which\n\t\t * to specify any options).\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.column\n\t\t */\n\t\t\"aoColumns\": null,\n\t\n\t\t/**\n\t\t * Very similar to `columns`, `columnDefs` allows you to target a specific\n\t\t * column, multiple columns, or all columns, using the `targets` property of\n\t\t * each object in the array. This allows great flexibility when creating\n\t\t * tables, as the `columnDefs` arrays can be of any length, targeting the\n\t\t * columns you specifically want. `columnDefs` may use any of the column\n\t\t * options available: {@link DataTable.defaults.column}, but it _must_\n\t\t * have `targets` defined in each object in the array. Values in the `targets`\n\t\t * array may be:\n\t\t *   <ul>\n\t\t *     <li>a string - class name will be matched on the TH for the column</li>\n\t\t *     <li>0 or a positive integer - column index counting from the left</li>\n\t\t *     <li>a negative integer - column index counting from the right</li>\n\t\t *     <li>the string \"_all\" - all columns (i.e. assign a default)</li>\n\t\t *   </ul>\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.columnDefs\n\t\t */\n\t\t\"aoColumnDefs\": null,\n\t\n\t\n\t\t/**\n\t\t * Basically the same as `search`, this parameter defines the individual column\n\t\t * filtering state at initialisation time. The array must be of the same size\n\t\t * as the number of columns, and each element be an object with the parameters\n\t\t * `search` and `escapeRegex` (the latter is optional). 'null' is also\n\t\t * accepted and the default will be used.\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.searchCols\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchCols\": [\n\t\t *          null,\n\t\t *          { \"search\": \"My filter\" },\n\t\t *          null,\n\t\t *          { \"search\": \"^[0-9]\", \"escapeRegex\": false }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aoSearchCols\": [],\n\t\n\t\n\t\t/**\n\t\t * An array of CSS classes that should be applied to displayed rows. This\n\t\t * array may be of any length, and DataTables will apply each class\n\t\t * sequentially, looping when required.\n\t\t *  @type array\n\t\t *  @default null <i>Will take the values determined by the `oClasses.stripe*`\n\t\t *    options</i>\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.stripeClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stripeClasses\": [ 'strip1', 'strip2', 'strip3' ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable automatic column width calculation. This can be disabled\n\t\t * as an optimisation (it takes some time to calculate the widths) if the\n\t\t * tables widths are passed in using `columns`.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.autoWidth\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"autoWidth\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bAutoWidth\": true,\n\t\n\t\n\t\t/**\n\t\t * Deferred rendering can provide DataTables with a huge speed boost when you\n\t\t * are using an Ajax or JS data source for the table. This option, when set to\n\t\t * true, will cause DataTables to defer the creation of the table elements for\n\t\t * each row until they are needed for a draw - saving a significant amount of\n\t\t * time.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.deferRender\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajax\": \"sources/arrays.txt\",\n\t\t *        \"deferRender\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDeferRender\": false,\n\t\n\t\n\t\t/**\n\t\t * Replace a DataTable which matches the given selector and replace it with\n\t\t * one which has the properties of the new initialisation object passed. If no\n\t\t * table matches the selector, then the new DataTable will be constructed as\n\t\t * per normal.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.destroy\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"srollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      // Some time later....\n\t\t *      $('#example').dataTable( {\n\t\t *        \"filter\": false,\n\t\t *        \"destroy\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDestroy\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering of data. Filtering in DataTables is \"smart\" in\n\t\t * that it allows the end user to input multiple words (space separated) and\n\t\t * will match a row containing those words, even if not in the order that was\n\t\t * specified (this allow matching across multiple columns). Note that if you\n\t\t * wish to use filtering in DataTables this must remain 'true' - to remove the\n\t\t * default filtering input box and retain filtering abilities, please use\n\t\t * {@link DataTable.defaults.dom}.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.searching\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searching\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bFilter\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the table information display. This shows information\n\t\t * about the data that is currently visible on the page, including information\n\t\t * about filtered data if that action is being performed.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.info\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"info\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bInfo\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some\n\t\t * slightly different and additional mark-up from what DataTables has\n\t\t * traditionally used).\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.jQueryUI\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"jQueryUI\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bJQueryUI\": false,\n\t\n\t\n\t\t/**\n\t\t * Allows the end user to select the size of a formatted page from a select\n\t\t * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.lengthChange\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthChange\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bLengthChange\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable pagination.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.paging\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"paging\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bPaginate\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of a 'processing' indicator when the table is\n\t\t * being processed (e.g. a sort). This is particularly useful for tables with\n\t\t * large amounts of data where it can take a noticeable amount of time to sort\n\t\t * the entries.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.processing\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"processing\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bProcessing\": false,\n\t\n\t\n\t\t/**\n\t\t * Retrieve the DataTables object for the given selector. Note that if the\n\t\t * table has already been initialised, this parameter will cause DataTables\n\t\t * to simply return the object that has already been set up - it will not take\n\t\t * account of any changes you might have made to the initialisation object\n\t\t * passed to DataTables (setting this parameter to true is an acknowledgement\n\t\t * that you understand this). `destroy` can be used to reinitialise a table if\n\t\t * you need.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.retrieve\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      initTable();\n\t\t *      tableActions();\n\t\t *    } );\n\t\t *\n\t\t *    function initTable ()\n\t\t *    {\n\t\t *      return $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false,\n\t\t *        \"retrieve\": true\n\t\t *      } );\n\t\t *    }\n\t\t *\n\t\t *    function tableActions ()\n\t\t *    {\n\t\t *      var table = initTable();\n\t\t *      // perform API operations with oTable\n\t\t *    }\n\t\t */\n\t\t\"bRetrieve\": false,\n\t\n\t\n\t\t/**\n\t\t * When vertical (y) scrolling is enabled, DataTables will force the height of\n\t\t * the table's viewport to the given height at all times (useful for layout).\n\t\t * However, this can look odd when filtering data down to a small data set,\n\t\t * and the footer is left \"floating\" further down. This parameter (when\n\t\t * enabled) will cause DataTables to collapse the table's viewport down when\n\t\t * the result set will fit within the given Y height.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollCollapse\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200\",\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bScrollCollapse\": false,\n\t\n\t\n\t\t/**\n\t\t * Configure DataTables to use server-side processing. Note that the\n\t\t * `ajax` parameter must also be given in order to give DataTables a\n\t\t * source to obtain the required data for each draw.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverSide\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"xhr.php\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bServerSide\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable sorting of columns. Sorting of individual columns can be\n\t\t * disabled by the `sortable` option for each column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.ordering\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ordering\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSort\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or display DataTables' ability to sort multiple columns at the\n\t\t * same time (activated by shift-click by the user).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderMulti\n\t\t *\n\t\t *  @example\n\t\t *    // Disable multiple column sorting ability\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderMulti\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortMulti\": true,\n\t\n\t\n\t\t/**\n\t\t * Allows control over whether DataTables should use the top (true) unique\n\t\t * cell that is found for a single column, or the bottom (false - default).\n\t\t * This is useful when using complex headers.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderCellsTop\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderCellsTop\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortCellsTop\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the addition of the classes `sorting\\_1`, `sorting\\_2` and\n\t\t * `sorting\\_3` to the columns which are currently being sorted on. This is\n\t\t * presented as a feature switch as it can increase processing time (while\n\t\t * classes are removed and added) so for large data sets you might want to\n\t\t * turn this off.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.orderClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderClasses\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortClasses\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable state saving. When enabled HTML5 `localStorage` will be\n\t\t * used to save table display information such as pagination information,\n\t\t * display length, filtering and sorting. As such when the end user reloads\n\t\t * the page the display display will match what thy had previously set up.\n\t\t *\n\t\t * Due to the use of `localStorage` the default state saving is not supported\n\t\t * in IE6 or 7. If state saving is required in those browsers, use\n\t\t * `stateSaveCallback` to provide a storage solution such as cookies.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.stateSave\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bStateSave\": false,\n\t\n\t\n\t\t/**\n\t\t * This function is called when a TR element is created (and all TD child\n\t\t * elements have been inserted), or registered if using a DOM source, allowing\n\t\t * manipulation of the TR element (adding classes etc).\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} dataIndex The index of this row in the internal aoData array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.createdRow\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"createdRow\": function( row, data, dataIndex ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" )\n\t\t *          {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedRow\": null,\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify any aspect you want about the created DOM.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.drawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"drawCallback\": function( settings ) {\n\t\t *          alert( 'DataTables has redrawn the table' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Identical to fnHeaderCallback() but for the table footer this function\n\t\t * allows you to modify the table footer on every 'draw' event.\n\t\t *  @type function\n\t\t *  @param {node} foot \"TR\" element for the footer\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.footerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"footerCallback\": function( tfoot, data, start, end, display ) {\n\t\t *          tfoot.getElementsByTagName('th')[0].innerHTML = \"Starting index is \"+start;\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnFooterCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * When rendering large numbers in the information element for the table\n\t\t * (i.e. \"Showing 1 to 10 of 57 entries\") DataTables will render large numbers\n\t\t * to have a comma separator for the 'thousands' units (e.g. 1 million is\n\t\t * rendered as \"1,000,000\") to help readability for the end user. This\n\t\t * function will override the default method DataTables uses.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {int} toFormat number to be formatted\n\t\t *  @returns {string} formatted string for DataTables to show the number\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.formatNumber\n\t\t *\n\t\t *  @example\n\t\t *    // Format a number using a single quote for the separator (note that\n\t\t *    // this can also be done with the language.thousands option)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"formatNumber\": function ( toFormat ) {\n\t\t *          return toFormat.toString().replace(\n\t\t *            /\\B(?=(\\d{3})+(?!\\d))/g, \"'\"\n\t\t *          );\n\t\t *        };\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnFormatNumber\": function ( toFormat ) {\n\t\t\treturn toFormat.toString().replace(\n\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g,\n\t\t\t\tthis.oLanguage.sThousands\n\t\t\t);\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify the header row. This can be used to calculate and\n\t\t * display useful information about the table.\n\t\t *  @type function\n\t\t *  @param {node} head \"TR\" element for the header\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.headerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"fheaderCallback\": function( head, data, start, end, display ) {\n\t\t *          head.getElementsByTagName('th')[0].innerHTML = \"Displaying \"+(end-start)+\" records\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnHeaderCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * The information element can be used to convey information about the current\n\t\t * state of the table. Although the internationalisation options presented by\n\t\t * DataTables are quite capable of dealing with most customisations, there may\n\t\t * be times where you wish to customise the string further. This callback\n\t\t * allows you to do exactly that.\n\t\t *  @type function\n\t\t *  @param {object} oSettings DataTables settings object\n\t\t *  @param {int} start Starting position in data for the draw\n\t\t *  @param {int} end End position in data for the draw\n\t\t *  @param {int} max Total number of rows in the table (regardless of\n\t\t *    filtering)\n\t\t *  @param {int} total Total number of rows in the data set, after filtering\n\t\t *  @param {string} pre The string that DataTables has formatted using it's\n\t\t *    own rules\n\t\t *  @returns {string} The string to be displayed in the information element.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.infoCallback\n\t\t *\n\t\t *  @example\n\t\t *    $('#example').dataTable( {\n\t\t *      \"infoCallback\": function( settings, start, end, max, total, pre ) {\n\t\t *        return start +\" to \"+ end;\n\t\t *      }\n\t\t *    } );\n\t\t */\n\t\t\"fnInfoCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Called when the table has been initialised. Normally DataTables will\n\t\t * initialise sequentially and there will be no need for this function,\n\t\t * however, this does not hold true when using external language information\n\t\t * since that is obtained using an async XHR call.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} json The JSON object request from the server - only\n\t\t *    present if client-side Ajax sourced data is used\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.initComplete\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"initComplete\": function(settings, json) {\n\t\t *          alert( 'DataTables has finished its initialisation.' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnInitComplete\": null,\n\t\n\t\n\t\t/**\n\t\t * Called at the very start of each table draw and can be used to cancel the\n\t\t * draw by returning false, any other return (including undefined) results in\n\t\t * the full draw occurring).\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @returns {boolean} False will cancel the draw, anything else (including no\n\t\t *    return) will allow it to complete.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.preDrawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"preDrawCallback\": function( settings ) {\n\t\t *          if ( $('#test').val() == 1 ) {\n\t\t *            return false;\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnPreDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * This function allows you to 'post process' each row after it have been\n\t\t * generated for each table draw, but before it is rendered on screen. This\n\t\t * function might be used for setting the row class name etc.\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} displayIndex The display index for the current table draw\n\t\t *  @param {int} displayIndexFull The index of the data in the full list of\n\t\t *    rows (after filtering)\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.rowCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"rowCallback\": function( row, data, displayIndex, displayIndexFull ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" ) {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnRowCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * This parameter allows you to override the default function which obtains\n\t\t * the data from the server so something more suitable for your application.\n\t\t * For example you could use POST data, or pull information from a Gears or\n\t\t * AIR database.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {string} source HTTP source to obtain the data from (`ajax`)\n\t\t *  @param {array} data A key/value pair object containing the data to send\n\t\t *    to the server\n\t\t *  @param {function} callback to be called on completion of the data get\n\t\t *    process that will draw the data on the page.\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverData\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t *  It is often useful to send extra data to the server when making an Ajax\n\t\t * request - for example custom filtering information, and this callback\n\t\t * function makes it trivial to send extra information to the server. The\n\t\t * passed in parameter is the data set that has been constructed by\n\t\t * DataTables, and you can add to this or modify it as you require.\n\t\t *  @type function\n\t\t *  @param {array} data Data array (array of objects which are name/value\n\t\t *    pairs) that has been constructed by DataTables and will be sent to the\n\t\t *    server. In the case of Ajax sourced data with server-side processing\n\t\t *    this will be an empty array, for server-side processing there will be a\n\t\t *    significant number of parameters!\n\t\t *  @returns {undefined} Ensure that you modify the data array passed in,\n\t\t *    as this is passed by reference.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverParams\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Load the table state. With this function you can define from where, and how, the\n\t\t * state of a table is loaded. By default DataTables will load from `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} callback Callback that can be executed when done. It\n\t\t *    should be passed the loaded state object.\n\t\t *  @return {object} The DataTables state object to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadCallback\": function (settings, callback) {\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_load\",\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"success\": function (json) {\n\t\t *              callback( json );\n\t\t *            }\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadCallback\": function ( settings ) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(\n\t\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(\n\t\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the saved state prior to loading that state.\n\t\t * This callback is called when the table is loading state from the stored data, but\n\t\t * prior to the settings object being modified by the saved state. Note that for\n\t\t * plug-in authors, you should use the `stateLoadParams` event to load parameters for\n\t\t * a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that is to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never loaded\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Disallow state loading by returning false\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          return false;\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Callback that is called when the state has been loaded from the state saving method\n\t\t * and the DataTables settings object has been modified as a result of the loaded state.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that was loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoaded\n\t\t *\n\t\t *  @example\n\t\t *    // Show an alert with the filtering value that was saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoaded\": function (settings, data) {\n\t\t *          alert( 'Saved filter was: '+data.oSearch.sSearch );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoaded\": null,\n\t\n\t\n\t\t/**\n\t\t * Save the table state. This function allows you to define where and how the state\n\t\t * information for the table is stored By default DataTables will use `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveCallback\": function (settings, data) {\n\t\t *          // Send an Ajax request to the server with the state object\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_save\",\n\t\t *            \"data\": data,\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"method\": \"POST\"\n\t\t *            \"success\": function () {}\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveCallback\": function ( settings, data ) {\n\t\t\ttry {\n\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(\n\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname,\n\t\t\t\t\tJSON.stringify( data )\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the state to be saved. Called when the table\n\t\t * has changed state a new state save is required. This method allows modification of\n\t\t * the state saving object prior to actually doing the save, including addition or\n\t\t * other state properties or modification. Note that for plug-in authors, you should\n\t\t * use the `stateSaveParams` event to save parameters for a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Duration for which the saved state information is considered valid. After this period\n\t\t * has elapsed the state will be returned to the default.\n\t\t * Value is given in seconds.\n\t\t *  @type int\n\t\t *  @default 7200 <i>(2 hours)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.stateDuration\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateDuration\": 60*60*24; // 1 day\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iStateDuration\": 7200,\n\t\n\t\n\t\t/**\n\t\t * When enabled DataTables will not make a request to the server for the first\n\t\t * page draw - rather it will use the data already on the page (no sorting etc\n\t\t * will be applied to it), thus saving on an XHR at load time. `deferLoading`\n\t\t * is used to indicate that deferred loading is required, but it is also used\n\t\t * to tell DataTables how many records there are in the full table (allowing\n\t\t * the information element and pagination to be displayed correctly). In the case\n\t\t * where a filtering is applied to the table on initial load, this can be\n\t\t * indicated by giving the parameter as an array, where the first element is\n\t\t * the number of records available after filtering and the second element is the\n\t\t * number of records without filtering (allowing the table information element\n\t\t * to be shown correctly).\n\t\t *  @type int | array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.deferLoading\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records available in the table, no filtering applied\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": 57\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records after filtering, 100 without filtering (an initial filter applied)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": [ 57, 100 ],\n\t\t *        \"search\": {\n\t\t *          \"search\": \"my_filter\"\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iDeferLoading\": null,\n\t\n\t\n\t\t/**\n\t\t * Number of rows to display on a single page when using pagination. If\n\t\t * feature enabled (`lengthChange`) then the end user will be able to override\n\t\t * this to a custom setting using a pop-up menu.\n\t\t *  @type int\n\t\t *  @default 10\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pageLength\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pageLength\": 50\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayLength\": 10,\n\t\n\t\n\t\t/**\n\t\t * Define the starting point for data display when using DataTables with\n\t\t * pagination. Note that this parameter is the number of records, rather than\n\t\t * the page number, so if you have 10 records per page and want to start on\n\t\t * the third page, it should be \"20\".\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.displayStart\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"displayStart\": 20\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayStart\": 0,\n\t\n\t\n\t\t/**\n\t\t * By default DataTables allows keyboard navigation of the table (sorting, paging,\n\t\t * and filtering) by adding a `tabindex` attribute to the required elements. This\n\t\t * allows you to tab through the controls and press the enter key to activate them.\n\t\t * The tabindex is default 0, meaning that the tab follows the flow of the document.\n\t\t * You can overrule this using this parameter if you wish. Use a value of -1 to\n\t\t * disable built-in keyboard navigation.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.tabIndex\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"tabIndex\": 1\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\n\t\t/**\n\t\t * Classes that DataTables assigns to the various components and features\n\t\t * that it adds to the HTML table. This allows classes to be configured\n\t\t * during initialisation in addition to through the static\n\t\t * {@link DataTable.ext.oStdClasses} object).\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.classes\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\n\t\t/**\n\t\t * All strings that DataTables uses in the user interface that it creates\n\t\t * are defined in this object, allowing you to modified them individually or\n\t\t * completely replace them all as required.\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.language\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Strings that are used for WAI-ARIA labels and controls only (these are not\n\t\t\t * actually visible on the page, but will be read by screenreaders, and thus\n\t\t\t * must be internationalised as well).\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.aria\n\t\t\t */\n\t\t\t\"oAria\": {\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted ascending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortAscending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortAscending\": \" - click/return to sort ascending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortAscending\": \": activate to sort column ascending\",\n\t\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted descending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortDescending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortDescending\": \" - click/return to sort descending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortDescending\": \": activate to sort column descending\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * Pagination string used by DataTables for the built-in pagination\n\t\t\t * control types.\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.paginate\n\t\t\t */\n\t\t\t\"oPaginate\": {\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the first page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default First\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.first\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"first\": \"First page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sFirst\": \"First\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the last page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Last\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.last\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"last\": \"Last page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sLast\": \"Last\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'next' pagination button (to take the user to the\n\t\t\t\t * next page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Next\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.next\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"next\": \"Next page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sNext\": \"Next\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'previous' pagination button (to take the user to\n\t\t\t\t * the previous page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Previous\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.previous\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"previous\": \"Previous page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sPrevious\": \"Previous\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * This string is shown in preference to `zeroRecords` when the table is\n\t\t\t * empty of data (regardless of filtering). Note that this is an optional\n\t\t\t * parameter - if it is not given, the value of `zeroRecords` will be used\n\t\t\t * instead (either the default or given value).\n\t\t\t *  @type string\n\t\t\t *  @default No data available in table\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.emptyTable\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"emptyTable\": \"No data available in table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sEmptyTable\": \"No data available in table\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This string gives information to the end user about the information\n\t\t\t * that is current on display on the page. The following tokens can be\n\t\t\t * used in the string and will be dynamically replaced as the table\n\t\t\t * display updates. This tokens can be placed anywhere in the string, or\n\t\t\t * removed as needed by the language requires:\n\t\t\t *\n\t\t\t * * `\\_START\\_` - Display index of the first record on the current page\n\t\t\t * * `\\_END\\_` - Display index of the last record on the current page\n\t\t\t * * `\\_TOTAL\\_` - Number of records in the table after filtering\n\t\t\t * * `\\_MAX\\_` - Number of records in the table without filtering\n\t\t\t * * `\\_PAGE\\_` - Current page number\n\t\t\t * * `\\_PAGES\\_` - Total number of pages of data in the table\n\t\t\t *\n\t\t\t *  @type string\n\t\t\t *  @default Showing _START_ to _END_ of _TOTAL_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.info\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"info\": \"Showing page _PAGE_ of _PAGES_\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfo\": \"Showing _START_ to _END_ of _TOTAL_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Display information string for when the table is empty. Typically the\n\t\t\t * format of this string should match `info`.\n\t\t\t *  @type string\n\t\t\t *  @default Showing 0 to 0 of 0 entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoEmpty\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoEmpty\": \"No entries to show\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoEmpty\": \"Showing 0 to 0 of 0 entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When a user filters the information in a table, this string is appended\n\t\t\t * to the information (`info`) to give an idea of how strong the filtering\n\t\t\t * is. The variable _MAX_ is dynamically updated.\n\t\t\t *  @type string\n\t\t\t *  @default (filtered from _MAX_ total entries)\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoFiltered\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoFiltered\": \" - filtering from _MAX_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoFiltered\": \"(filtered from _MAX_ total entries)\",\n\t\n\t\n\t\t\t/**\n\t\t\t * If can be useful to append extra information to the info string at times,\n\t\t\t * and this variable does exactly that. This information will be appended to\n\t\t\t * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are\n\t\t\t * being used) at all times.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoPostFix\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoPostFix\": \"All records shown are derived from real information.\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoPostFix\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This decimal place operator is a little different from the other\n\t\t\t * language options since DataTables doesn't output floating point\n\t\t\t * numbers, so it won't ever use this for display of a number. Rather,\n\t\t\t * what this parameter does is modify the sort methods of the table so\n\t\t\t * that numbers which are in a format which has a character other than\n\t\t\t * a period (`.`) as a decimal place will be sorted numerically.\n\t\t\t *\n\t\t\t * Note that numbers with different decimal places cannot be shown in\n\t\t\t * the same table and still be sortable, the table must be consistent.\n\t\t\t * However, multiple different tables on the page can use different\n\t\t\t * decimal place characters.\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.decimal\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"decimal\": \",\"\n\t\t\t *          \"thousands\": \".\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sDecimal\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * DataTables has a build in number formatter (`formatNumber`) which is\n\t\t\t * used to format large numbers that are used in the table information.\n\t\t\t * By default a comma is used, but this can be trivially changed to any\n\t\t\t * character you wish with this parameter.\n\t\t\t *  @type string\n\t\t\t *  @default ,\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.thousands\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"thousands\": \"'\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sThousands\": \",\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Detail the action that will be taken when the drop down menu for the\n\t\t\t * pagination length option is changed. The '_MENU_' variable is replaced\n\t\t\t * with a default select list of 10, 25, 50 and 100, and can be replaced\n\t\t\t * with a custom select box if required.\n\t\t\t *  @type string\n\t\t\t *  @default Show _MENU_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.lengthMenu\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language change only\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": \"Display _MENU_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language and options change\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": 'Display <select>'+\n\t\t\t *            '<option value=\"10\">10</option>'+\n\t\t\t *            '<option value=\"20\">20</option>'+\n\t\t\t *            '<option value=\"30\">30</option>'+\n\t\t\t *            '<option value=\"40\">40</option>'+\n\t\t\t *            '<option value=\"50\">50</option>'+\n\t\t\t *            '<option value=\"-1\">All</option>'+\n\t\t\t *            '</select> records'\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLengthMenu\": \"Show _MENU_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When using Ajax sourced data and during the first draw when DataTables is\n\t\t\t * gathering the data, this message is shown in an empty row in the table to\n\t\t\t * indicate to the end user the the data is being loaded. Note that this\n\t\t\t * parameter is not used when loading data by server-side processing, just\n\t\t\t * Ajax sourced data with client-side processing.\n\t\t\t *  @type string\n\t\t\t *  @default Loading...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.loadingRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"loadingRecords\": \"Please wait - loading...\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLoadingRecords\": \"Loading...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text which is displayed when the table is processing a user action\n\t\t\t * (usually a sort command or similar).\n\t\t\t *  @type string\n\t\t\t *  @default Processing...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.processing\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"processing\": \"DataTables is currently busy\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sProcessing\": \"Processing...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Details the actions that will be taken when the user types into the\n\t\t\t * filtering input text box. The variable \"_INPUT_\", if used in the string,\n\t\t\t * is replaced with the HTML text box for the filtering input allowing\n\t\t\t * control over where it appears in the string. If \"_INPUT_\" is not given\n\t\t\t * then the input box is appended to the string automatically.\n\t\t\t *  @type string\n\t\t\t *  @default Search:\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.search\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Input text box will be appended at the end automatically\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Filter records:\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Specify where the filter should appear\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Apply filter _INPUT_ to table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sSearch\": \"Search:\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Assign a `placeholder` attribute to the search `input` element\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.searchPlaceholder\n\t\t\t */\n\t\t\t\"sSearchPlaceholder\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * All of the language information can be stored in a file on the\n\t\t\t * server-side, which DataTables will look up if this parameter is passed.\n\t\t\t * It must store the URL of the language file, which is in a JSON format,\n\t\t\t * and the object has the same properties as the oLanguage object in the\n\t\t\t * initialiser object (i.e. the above parameters). Please refer to one of\n\t\t\t * the example language files to see how this works in action.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string - i.e. disabled</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.url\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"url\": \"http://www.sprymedia.co.uk/dataTables/lang.txt\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sUrl\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text shown inside the table records when the is no information to be\n\t\t\t * displayed after filtering. `emptyTable` is shown when there is simply no\n\t\t\t * information in the table at all (regardless of filtering).\n\t\t\t *  @type string\n\t\t\t *  @default No matching records found\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.zeroRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"zeroRecords\": \"No records to display\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sZeroRecords\": \"No matching records found\"\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to have define the global filtering state at\n\t\t * initialisation time. As an object the `search` parameter must be\n\t\t * defined, but all other parameters are optional. When `regex` is true,\n\t\t * the search string will be treated as a regular expression, when false\n\t\t * (default) it will be treated as a straight string. When `smart`\n\t\t * DataTables will use it's smart filtering methods (to word match at\n\t\t * any point in the data), when false this will not be done.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.search\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"search\": {\"search\": \"Initial search\"}\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"oSearch\": $.extend( {}, DataTable.models.oSearch ),\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * By default DataTables will look for the property `data` (or `aaData` for\n\t\t * compatibility with DataTables 1.9-) when obtaining data from an Ajax\n\t\t * source or for server-side processing - this parameter allows that\n\t\t * property to be changed. You can use Javascript dotted object notation to\n\t\t * get a data source for multiple levels of nesting.\n\t\t *  @type string\n\t\t *  @default data\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxDataProp\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxDataProp\": \"data\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * You can instruct DataTables to load data from an external\n\t\t * source using this parameter (use aData if you want to pass data in you\n\t\t * already have). Simply provide a url a JSON object can be obtained from.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxSource\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\n\t\t/**\n\t\t * This initialisation variable allows you to specify exactly where in the\n\t\t * DOM you want DataTables to inject the various controls it adds to the page\n\t\t * (for example you might want the pagination controls at the top of the\n\t\t * table). DIV elements (with or without a custom class) can also be added to\n\t\t * aid styling. The follow syntax is used:\n\t\t *   <ul>\n\t\t *     <li>The following options are allowed:\n\t\t *       <ul>\n\t\t *         <li>'l' - Length changing</li>\n\t\t *         <li>'f' - Filtering input</li>\n\t\t *         <li>'t' - The table!</li>\n\t\t *         <li>'i' - Information</li>\n\t\t *         <li>'p' - Pagination</li>\n\t\t *         <li>'r' - pRocessing</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following constants are allowed:\n\t\t *       <ul>\n\t\t *         <li>'H' - jQueryUI theme \"header\" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>\n\t\t *         <li>'F' - jQueryUI theme \"footer\" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following syntax is expected:\n\t\t *       <ul>\n\t\t *         <li>'&lt;' and '&gt;' - div elements</li>\n\t\t *         <li>'&lt;\"class\" and '&gt;' - div with a class</li>\n\t\t *         <li>'&lt;\"#id\" and '&gt;' - div with an ID</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>Examples:\n\t\t *       <ul>\n\t\t *         <li>'&lt;\"wrapper\"flipt&gt;'</li>\n\t\t *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *   </ul>\n\t\t *  @type string\n\t\t *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>\n\t\t *    <\"H\"lfr>t<\"F\"ip> <i>(when `jQueryUI` is true)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.dom\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"dom\": '&lt;\"top\"i&gt;rt&lt;\"bottom\"flp&gt;&lt;\"clear\"&gt;'\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDom\": \"lfrtip\",\n\t\n\t\n\t\t/**\n\t\t * Search delay option. This will throttle full table searches that use the\n\t\t * DataTables provided search input element (it does not effect calls to\n\t\t * `dt-api search()`, providing a delay before the search is made.\n\t\t *  @type integer\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.searchDelay\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchDelay\": 200\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\n\t\t/**\n\t\t * DataTables features six different built-in options for the buttons to\n\t\t * display for pagination control:\n\t\t *\n\t\t * * `numbers` - Page number buttons only\n\t\t * * `simple` - 'Previous' and 'Next' buttons only\n\t\t * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers\n\t\t * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons\n\t\t * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers\n\t\t * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers\n\t\t *  \n\t\t * Further methods can be added using {@link DataTable.ext.oPagination}.\n\t\t *  @type string\n\t\t *  @default simple_numbers\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pagingType\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pagingType\": \"full_numbers\"\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"sPaginationType\": \"simple_numbers\",\n\t\n\t\n\t\t/**\n\t\t * Enable horizontal scrolling. When a table is too wide to fit into a\n\t\t * certain layout, or you have a large number of columns in the table, you\n\t\t * can enable x-scrolling to show the table in a viewport, which can be\n\t\t * scrolled. This property can be `true` which will allow the table to\n\t\t * scroll horizontally when needed, or any CSS unit, or a number (in which\n\t\t * case it will be treated as a pixel measurement). Setting as simply `true`\n\t\t * is recommended.\n\t\t *  @type boolean|string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollX\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": true,\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollX\": \"\",\n\t\n\t\n\t\t/**\n\t\t * This property can be used to force a DataTable to use more width than it\n\t\t * might otherwise do when x-scrolling is enabled. For example if you have a\n\t\t * table which requires to be well spaced, this parameter is useful for\n\t\t * \"over-sizing\" the table, and thus forcing scrolling. This property can by\n\t\t * any CSS unit, or a number (in which case it will be treated as a pixel\n\t\t * measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollXInner\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": \"100%\",\n\t\t *        \"scrollXInner\": \"110%\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollXInner\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Enable vertical scrolling. Vertical scrolling will constrain the DataTable\n\t\t * to the given height, and enable scrolling for any data which overflows the\n\t\t * current viewport. This can be used as an alternative to paging to display\n\t\t * a lot of data in a small area (although paging and scrolling can both be\n\t\t * enabled at the same time). This property can be any CSS unit, or a number\n\t\t * (in which case it will be treated as a pixel measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollY\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollY\": \"\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * Set the HTTP method that is used to make the Ajax call for server-side\n\t\t * processing or Ajax sourced data.\n\t\t *  @type string\n\t\t *  @default GET\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverMethod\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sServerMethod\": \"GET\",\n\t\n\t\n\t\t/**\n\t\t * DataTables makes use of renderers when displaying HTML elements for\n\t\t * a table. These renderers can be added or modified by plug-ins to\n\t\t * generate suitable mark-up for a site. For example the Bootstrap\n\t\t * integration plug-in for DataTables uses a paging button renderer to\n\t\t * display pagination buttons in the mark-up required by Bootstrap.\n\t\t *\n\t\t * For further information about the renderers available see\n\t\t * DataTable.ext.renderer\n\t\t *  @type string|object\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.renderer\n\t\t *\n\t\t */\n\t\t\"renderer\": null,\n\t\n\t\n\t\t/**\n\t\t * Set the data property name that DataTables should use to get a row's id\n\t\t * to set as the `id` property in the node.\n\t\t *  @type string\n\t\t *  @default DT_RowId\n\t\t *\n\t\t *  @name DataTable.defaults.rowId\n\t\t */\n\t\t\"rowId\": \"DT_RowId\"\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults );\n\t\n\t\n\t\n\t/*\n\t * Developer note - See note in model.defaults.js about the use of Hungarian\n\t * notation and camel case.\n\t */\n\t\n\t/**\n\t * Column options that can be given to DataTables at initialisation time.\n\t *  @namespace\n\t */\n\tDataTable.defaults.column = {\n\t\t/**\n\t\t * Define which column(s) an order will occur on for this column. This\n\t\t * allows a column's ordering to take multiple columns into account when\n\t\t * doing a sort or use the data from a different column. For example first\n\t\t * name / last name columns make sense to do a multi-column sort over the\n\t\t * two columns.\n\t\t *  @type array|int\n\t\t *  @default null <i>Takes the value of the column index automatically</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderData\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderData\": [ 0, 1 ], \"targets\": [ 0 ] },\n\t\t *          { \"orderData\": [ 1, 0 ], \"targets\": [ 1 ] },\n\t\t *          { \"orderData\": 2, \"targets\": [ 2 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderData\": [ 0, 1 ] },\n\t\t *          { \"orderData\": [ 1, 0 ] },\n\t\t *          { \"orderData\": 2 },\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aDataSort\": null,\n\t\t\"iDataSort\": -1,\n\t\n\t\n\t\t/**\n\t\t * You can control the default ordering direction, and even alter the\n\t\t * behaviour of the sort handler (i.e. only allow ascending ordering etc)\n\t\t * using this parameter.\n\t\t *  @type array\n\t\t *  @default [ 'asc', 'desc' ]\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderSequence\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderSequence\": [ \"asc\" ], \"targets\": [ 1 ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ], \"targets\": [ 2 ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ], \"targets\": [ 3 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          { \"orderSequence\": [ \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ] },\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"asSorting\": [ 'asc', 'desc' ],\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering on the data in this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.searchable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"searchable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"searchable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSearchable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable ordering on this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.visible\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"visible\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"visible\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bVisible\": true,\n\t\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} td The TD node that has been created\n\t\t *  @param {*} cellData The Data for the cell\n\t\t *  @param {array|object} rowData The data for the whole row\n\t\t *  @param {int} row The row index for the aoData data store\n\t\t *  @param {int} col The column index for aoColumns\n\t\t *\n\t\t *  @name DataTable.defaults.column.createdCell\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [3],\n\t\t *          \"createdCell\": function (td, cellData, rowData, row, col) {\n\t\t *            if ( cellData == \"1.7\" ) {\n\t\t *              $(td).css('color', 'blue')\n\t\t *            }\n\t\t *          }\n\t\t *        } ]\n\t\t *      });\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter has been replaced by `data` in DataTables to ensure naming\n\t\t * consistency. `dataProp` can still be used, as there is backwards\n\t\t * compatibility in DataTables for this option, but it is strongly\n\t\t * recommended that you use `data` in preference to `dataProp`.\n\t\t *  @name DataTable.defaults.column.dataProp\n\t\t */\n\t\n\t\n\t\t/**\n\t\t * This property can be used to read data from any data source property,\n\t\t * including deeply nested objects / properties. `data` can be given in a\n\t\t * number of different ways which effect its behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object. Note that\n\t\t *      function notation is recommended for use in `render` rather than\n\t\t *      `data` as it is much simpler to use as a renderer.\n\t\t * * `null` - use the original data source for the row rather than plucking\n\t\t *   data directly from it. This action has effects on two other\n\t\t *   initialisation options:\n\t\t *    * `defaultContent` - When null is given as the `data` option and\n\t\t *      `defaultContent` is specified for the column, the value defined by\n\t\t *      `defaultContent` will be used for the cell.\n\t\t *    * `render` - When null is used for the `data` option and the `render`\n\t\t *      option is specified for the column, the whole data source for the\n\t\t *      row is used for the renderer.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * `{array|object}` The data source for the row\n\t\t *      * `{string}` The type call data requested - this will be 'set' when\n\t\t *        setting data or 'filter', 'display', 'type', 'sort' or undefined\n\t\t *        when gathering data. Note that when `undefined` is given for the\n\t\t *        type DataTables expects to get the raw data for the object back<\n\t\t *      * `{*}` Data to set when the second parameter is 'set'.\n\t\t *    * Return:\n\t\t *      * The return value from the function is not required when 'set' is\n\t\t *        the type of call, but otherwise the return is what will be used\n\t\t *        for the data requested.\n\t\t *\n\t\t * Note that `data` is a getter and setter option. If you just require\n\t\t * formatting of data for output, you will likely want to use `render` which\n\t\t * is simply a getter and thus simpler to use.\n\t\t *\n\t\t * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The\n\t\t * name change reflects the flexibility of this property and is consistent\n\t\t * with the naming of mRender. If 'mDataProp' is given, then it will still\n\t\t * be used by DataTables, as it automatically maps the old name to the new\n\t\t * if required.\n\t\t *\n\t\t *  @type string|int|function|null\n\t\t *  @default null <i>Use automatically calculated column index</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.data\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Read table data from objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {value},\n\t\t *    //      \"version\": {value},\n\t\t *    //      \"grade\": {value}\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/objects.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform\" },\n\t\t *          { \"data\": \"version\" },\n\t\t *          { \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Read information from deeply nested objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {\n\t\t *    //         \"inner\": {value}\n\t\t *    //      },\n\t\t *    //      \"details\": [\n\t\t *    //         {value}, {value}\n\t\t *    //      ]\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform.inner\" },\n\t\t *          { \"data\": \"platform.details.0\" },\n\t\t *          { \"data\": \"platform.details.1\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `data` as a function to provide different information for\n\t\t *    // sorting, filtering and display. In this case, currency (price)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": function ( source, type, val ) {\n\t\t *            if (type === 'set') {\n\t\t *              source.price = val;\n\t\t *              // Store the computed dislay and filter values for efficiency\n\t\t *              source.price_display = val==\"\" ? \"\" : \"$\"+numberFormat(val);\n\t\t *              source.price_filter  = val==\"\" ? \"\" : \"$\"+numberFormat(val)+\" \"+val;\n\t\t *              return;\n\t\t *            }\n\t\t *            else if (type === 'display') {\n\t\t *              return source.price_display;\n\t\t *            }\n\t\t *            else if (type === 'filter') {\n\t\t *              return source.price_filter;\n\t\t *            }\n\t\t *            // 'sort', 'type' and undefined all just use the integer\n\t\t *            return source.price;\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using default content\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null,\n\t\t *          \"defaultContent\": \"Click to edit\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using array notation - outputting a list from an array\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"name[, ]\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\n\t\t/**\n\t\t * This property is the rendering partner to `data` and it is suggested that\n\t\t * when you want to manipulate data for display (including filtering,\n\t\t * sorting etc) without altering the underlying data for the table, use this\n\t\t * property. `render` can be considered to be the the read only companion to\n\t\t * `data` which is read / write (then as such more complex). Like `data`\n\t\t * this option can be given in a number of different ways to effect its\n\t\t * behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object.\n\t\t * * `object` - use different data for the different data types requested by\n\t\t *   DataTables ('filter', 'display', 'type' or 'sort'). The property names\n\t\t *   of the object is the data type the property refers to and the value can\n\t\t *   defined using an integer, string or function using the same rules as\n\t\t *   `render` normally does. Note that an `_` option _must_ be specified.\n\t\t *   This is the default value to use if you haven't specified a value for\n\t\t *   the data type requested by DataTables.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * {array|object} The data source for the row (based on `data`)\n\t\t *      * {string} The type call data requested - this will be 'filter',\n\t\t *        'display', 'type' or 'sort'.\n\t\t *      * {array|object} The full data source for the row (not based on\n\t\t *        `data`)\n\t\t *    * Return:\n\t\t *      * The return value from the function is what will be used for the\n\t\t *        data requested.\n\t\t *\n\t\t *  @type string|int|function|object|null\n\t\t *  @default null Use the data source value.\n\t\t *\n\t\t *  @name DataTable.defaults.column.render\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Create a comma separated list from an array of objects\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          {\n\t\t *            \"data\": \"platform\",\n\t\t *            \"render\": \"[, ].name\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Execute a function to obtain data\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": \"browserName()\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // As an object, extracting different data for the different types\n\t\t *    // This would be used with a data source such as:\n\t\t *    //   { \"phone\": 5552368, \"phone_filter\": \"5552368 555-2368\", \"phone_display\": \"555-2368\" }\n\t\t *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`\n\t\t *    // (which has both forms) is used for filtering for if a user inputs either format, while\n\t\t *    // the formatted phone number is the one that is shown in the table.\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": {\n\t\t *            \"_\": \"phone\",\n\t\t *            \"filter\": \"phone_filter\",\n\t\t *            \"display\": \"phone_display\"\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Use as a function to create a link from the data source\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"download_link\",\n\t\t *          \"render\": function ( data, type, full ) {\n\t\t *            return '<a href=\"'+data+'\">Download</a>';\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\n\t\t/**\n\t\t * Change the cell type created for the column - either TD cells or TH cells. This\n\t\t * can be useful as TH cells have semantic meaning in the table body, allowing them\n\t\t * to act as a header for a row (you may wish to add scope='row' to the TH elements).\n\t\t *  @type string\n\t\t *  @default td\n\t\t *\n\t\t *  @name DataTable.defaults.column.cellType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Make the first column use TH cells\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"cellType\": \"th\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sCellType\": \"td\",\n\t\n\t\n\t\t/**\n\t\t * Class to give to each cell in this column.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.class\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"class\": \"my_class\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"class\": \"my_class\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sClass\": \"\",\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t * Generally you shouldn't need this!\n\t\t *  @type string\n\t\t *  @default <i>Empty string<i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.contentPadding\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"contentPadding\": \"mmm\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sContentPadding\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because `data`\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.column.defaultContent\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\",\n\t\t *            \"targets\": [ -1 ]\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter is only used in DataTables' server-side processing. It can\n\t\t * be exceptionally useful to know what columns are being displayed on the\n\t\t * client side, and to map these to database fields. When defined, the names\n\t\t * also allow DataTables to reorder information from the server if it comes\n\t\t * back in an unexpected order (i.e. if you switch your columns around on the\n\t\t * client-side, your server-side code does not also need updating).\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.name\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"name\": \"engine\", \"targets\": [ 0 ] },\n\t\t *          { \"name\": \"browser\", \"targets\": [ 1 ] },\n\t\t *          { \"name\": \"platform\", \"targets\": [ 2 ] },\n\t\t *          { \"name\": \"version\", \"targets\": [ 3 ] },\n\t\t *          { \"name\": \"grade\", \"targets\": [ 4 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"name\": \"engine\" },\n\t\t *          { \"name\": \"browser\" },\n\t\t *          { \"name\": \"platform\" },\n\t\t *          { \"name\": \"version\" },\n\t\t *          { \"name\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sName\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Defines a data source type for the ordering which can be used to read\n\t\t * real-time information from the table (updating the internally cached\n\t\t * version) prior to ordering. This allows ordering to occur on user\n\t\t * editable elements such as form inputs.\n\t\t *  @type string\n\t\t *  @default std\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderDataType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderDataType\": \"dom-text\", \"targets\": [ 2, 3 ] },\n\t\t *          { \"type\": \"numeric\", \"targets\": [ 3 ] },\n\t\t *          { \"orderDataType\": \"dom-select\", \"targets\": [ 4 ] },\n\t\t *          { \"orderDataType\": \"dom-checkbox\", \"targets\": [ 5 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          { \"orderDataType\": \"dom-text\" },\n\t\t *          { \"orderDataType\": \"dom-text\", \"type\": \"numeric\" },\n\t\t *          { \"orderDataType\": \"dom-select\" },\n\t\t *          { \"orderDataType\": \"dom-checkbox\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sSortDataType\": \"std\",\n\t\n\t\n\t\t/**\n\t\t * The title of this column.\n\t\t *  @type string\n\t\t *  @default null <i>Derived from the 'TH' value for this column in the\n\t\t *    original HTML table.</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.title\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"title\": \"My column title\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"My column title\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\n\t\t/**\n\t\t * The type allows you to specify how the data for this column will be\n\t\t * ordered. Four types (string, numeric, date and html (which will strip\n\t\t * HTML tags before ordering)) are currently available. Note that only date\n\t\t * formats understood by Javascript's Date() object will be accepted as type\n\t\t * date. For example: \"Mar 26, 2008 5:03 PM\". May take the values: 'string',\n\t\t * 'numeric', 'date' or 'html' (by default). Further types can be adding\n\t\t * through plug-ins.\n\t\t *  @type string\n\t\t *  @default null <i>Auto-detected from raw data</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.type\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"type\": \"html\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"type\": \"html\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\n\t\t/**\n\t\t * Defining the width of the column, this parameter may take any CSS value\n\t\t * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not\n\t\t * been given a specific width through this interface ensuring that the table\n\t\t * remains readable.\n\t\t *  @type string\n\t\t *  @default null <i>Automatic</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.width\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"width\": \"20%\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"width\": \"20%\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sWidth\": null\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults.column );\n\t\n\t\n\t\n\t/**\n\t * DataTables settings object - this holds all the information needed for a\n\t * given table, including configuration, data and current application of the\n\t * table options. DataTables does not have a single instance for each DataTable\n\t * with the settings attached to that instance, but rather instances of the\n\t * DataTable \"class\" are created on-the-fly as needed (typically by a\n\t * $().dataTable() call) and the settings object is then applied to that\n\t * instance.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults} but this\n\t * one is the internal data store for DataTables's cache of columns. It should\n\t * NOT be manipulated outside of DataTables. Any configuration should be done\n\t * through the initialisation options.\n\t *  @namespace\n\t *  @todo Really should attach the settings object to individual instances so we\n\t *    don't need to create new instances on each $().dataTable() call (if the\n\t *    table already exists). It would also save passing oSettings around and\n\t *    into every single function. However, this is a very significant\n\t *    architecture change for DataTables and will almost certainly break\n\t *    backwards compatibility with older installations. This is something that\n\t *    will be done in 2.0.\n\t */\n\tDataTable.models.oSettings = {\n\t\t/**\n\t\t * Primary features of DataTables and their enablement state.\n\t\t *  @namespace\n\t\t */\n\t\t\"oFeatures\": {\n\t\n\t\t\t/**\n\t\t\t * Flag to say if DataTables should automatically try to calculate the\n\t\t\t * optimum table and columns widths (true) or not (false).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bAutoWidth\": null,\n\t\n\t\t\t/**\n\t\t\t * Delay the creation of TR and TD elements until they are actually\n\t\t\t * needed by a driven page draw. This can give a significant speed\n\t\t\t * increase for Ajax source and Javascript source data, but makes no\n\t\t\t * difference at all fro DOM and server-side processing tables.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bDeferRender\": null,\n\t\n\t\t\t/**\n\t\t\t * Enable filtering on the table or not. Note that if this is disabled\n\t\t\t * then there is no filtering at all on the table, including fnFilter.\n\t\t\t * To just remove the filtering input use sDom and remove the 'f' option.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bFilter\": null,\n\t\n\t\t\t/**\n\t\t\t * Table information element (the 'Showing x of y records' div) enable\n\t\t\t * flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bInfo\": null,\n\t\n\t\t\t/**\n\t\t\t * Present a user control allowing the end user to change the page size\n\t\t\t * when pagination is enabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bLengthChange\": null,\n\t\n\t\t\t/**\n\t\t\t * Pagination enabled or not. Note that if this is disabled then length\n\t\t\t * changing must also be disabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bPaginate\": null,\n\t\n\t\t\t/**\n\t\t\t * Processing indicator enable flag whenever DataTables is enacting a\n\t\t\t * user request - typically an Ajax request for server-side processing.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bProcessing\": null,\n\t\n\t\t\t/**\n\t\t\t * Server-side processing enabled flag - when enabled DataTables will\n\t\t\t * get all data from the server for every draw - there is no filtering,\n\t\t\t * sorting or paging done on the client-side.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bServerSide\": null,\n\t\n\t\t\t/**\n\t\t\t * Sorting enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSort\": null,\n\t\n\t\t\t/**\n\t\t\t * Multi-column sorting\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortMulti\": null,\n\t\n\t\t\t/**\n\t\t\t * Apply a class to the columns which are being sorted to provide a\n\t\t\t * visual highlight or not. This can slow things down when enabled since\n\t\t\t * there is a lot of DOM interaction.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortClasses\": null,\n\t\n\t\t\t/**\n\t\t\t * State saving enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bStateSave\": null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Scrolling settings for a table.\n\t\t *  @namespace\n\t\t */\n\t\t\"oScroll\": {\n\t\t\t/**\n\t\t\t * When the table is shorter in height than sScrollY, collapse the\n\t\t\t * table container down to the height of the table (when true).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bCollapse\": null,\n\t\n\t\t\t/**\n\t\t\t * Width of the scrollbar for the web-browser's platform. Calculated\n\t\t\t * during table initialisation.\n\t\t\t *  @type int\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"iBarWidth\": 0,\n\t\n\t\t\t/**\n\t\t\t * Viewport width for horizontal scrolling. Horizontal scrolling is\n\t\t\t * disabled if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sX\": null,\n\t\n\t\t\t/**\n\t\t\t * Width to expand the table to when using x-scrolling. Typically you\n\t\t\t * should not need to use this.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t *  @deprecated\n\t\t\t */\n\t\t\t\"sXInner\": null,\n\t\n\t\t\t/**\n\t\t\t * Viewport height for vertical scrolling. Vertical scrolling is disabled\n\t\t\t * if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sY\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Language information for the table.\n\t\t *  @namespace\n\t\t *  @extends DataTable.defaults.oLanguage\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Information callback function. See\n\t\t\t * {@link DataTable.defaults.fnInfoCallback}\n\t\t\t *  @type function\n\t\t\t *  @default null\n\t\t\t */\n\t\t\t\"fnInfoCallback\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Browser support parameters\n\t\t *  @namespace\n\t\t */\n\t\t\"oBrowser\": {\n\t\t\t/**\n\t\t\t * Indicate if the browser incorrectly calculates width:100% inside a\n\t\t\t * scrolling element (IE6/7)\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollOversize\": false,\n\t\n\t\t\t/**\n\t\t\t * Determine if the vertical scrollbar is on the right or left of the\n\t\t\t * scrolling container - needed for rtl language layout, although not\n\t\t\t * all browsers move the scrollbar (Safari).\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollbarLeft\": false,\n\t\n\t\t\t/**\n\t\t\t * Flag for if `getBoundingClientRect` is fully supported or not\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bBounding\": false,\n\t\n\t\t\t/**\n\t\t\t * Browser scrollbar width\n\t\t\t *  @type integer\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"barWidth\": 0\n\t\t},\n\t\n\t\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * Array referencing the nodes which are used for the features. The\n\t\t * parameters of this object match what is allowed by sDom - i.e.\n\t\t *   <ul>\n\t\t *     <li>'l' - Length changing</li>\n\t\t *     <li>'f' - Filtering input</li>\n\t\t *     <li>'t' - The table!</li>\n\t\t *     <li>'i' - Information</li>\n\t\t *     <li>'p' - Pagination</li>\n\t\t *     <li>'r' - pRocessing</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aanFeatures\": [],\n\t\n\t\t/**\n\t\t * Store data information - see {@link DataTable.models.oRow} for detailed\n\t\t * information.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoData\": [],\n\t\n\t\t/**\n\t\t * Array of indexes which are in the current display (after filtering etc)\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplay\": [],\n\t\n\t\t/**\n\t\t * Array of indexes for display - no filtering\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplayMaster\": [],\n\t\n\t\t/**\n\t\t * Map of row ids to data indexes\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"aIds\": {},\n\t\n\t\t/**\n\t\t * Store information about each column that is in use\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoColumns\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's header\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeader\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's footer\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooter\": [],\n\t\n\t\t/**\n\t\t * Store the applied global search information in case we want to force a\n\t\t * research or compare the old search to a new one.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t */\n\t\t\"oPreviousSearch\": {},\n\t\n\t\t/**\n\t\t * Store the applied search for each column - see\n\t\t * {@link DataTable.models.oSearch} for the format that is used for the\n\t\t * filtering information for each column.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreSearchCols\": [],\n\t\n\t\t/**\n\t\t * Sorting that is applied to the table. Note that the inner arrays are\n\t\t * used in the following manner:\n\t\t * <ul>\n\t\t *   <li>Index 0 - column number</li>\n\t\t *   <li>Index 1 - current sorting direction</li>\n\t\t * </ul>\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @todo These inner arrays should really be objects\n\t\t */\n\t\t\"aaSorting\": null,\n\t\n\t\t/**\n\t\t * Sorting that is always applied to the table (i.e. prefixed in front of\n\t\t * aaSorting).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\t/**\n\t\t * Classes to use for the striping of a table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its striping classes as well\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asDestroyStripes\": [],\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its width\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"sDestroyWidth\": 0,\n\t\n\t\t/**\n\t\t * Callback functions array for every time a row is inserted (i.e. on a draw).\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for the header on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeaderCallback\": [],\n\t\n\t\t/**\n\t\t * Callback function for the footer on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooterCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for draw callback functions\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for row created function\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCreatedCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for just before the table is redrawn. A return of\n\t\t * false will be used to cancel the draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for when the table has been initialised.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoInitComplete\": [],\n\t\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings to be stored for state saving, prior to\n\t\t * saving state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSaveParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings that have been stored for state saving\n\t\t * prior to using the stored values to restore the state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoadParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for operating on the settings object once the saved state has been\n\t\t * loaded\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoaded\": [],\n\t\n\t\t/**\n\t\t * Cache the table ID for quick access\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sTableId\": \"\",\n\t\n\t\t/**\n\t\t * The TABLE node for the main table\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTable\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the thead element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTHead\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tfoot element - if it exists\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTFoot\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tbody element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTBody\": null,\n\t\n\t\t/**\n\t\t * Cache the wrapper node (contains all DataTables controlled elements)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTableWrapper\": null,\n\t\n\t\t/**\n\t\t * Indicate if when using server-side processing the loading of data\n\t\t * should be deferred until the second draw.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDeferLoading\": false,\n\t\n\t\t/**\n\t\t * Indicate if all required information has been read in\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bInitialised\": false,\n\t\n\t\t/**\n\t\t * Information about open rows. Each object in the array has the parameters\n\t\t * 'nTr' and 'nParent'\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoOpenRows\": [],\n\t\n\t\t/**\n\t\t * Dictate the positioning of DataTables' control elements - see\n\t\t * {@link DataTable.model.oInit.sDom}.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDom\": null,\n\t\n\t\t/**\n\t\t * Search delay (in mS)\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\t/**\n\t\t * Which type of pagination should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default two_button\n\t\t */\n\t\t\"sPaginationType\": \"two_button\",\n\t\n\t\t/**\n\t\t * The state duration (for `stateSave`) in seconds.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iStateDuration\": 0,\n\t\n\t\t/**\n\t\t * Array of callback functions for state saving. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the JSON string to save that has been thus far created. Returns\n\t\t *       a JSON string to be inserted into a json object\n\t\t *       (i.e. '\"param\": [ 0, 1, 2]')</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSave\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for state loading. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the object stored. May return false to cancel state loading</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoad\": [],\n\t\n\t\t/**\n\t\t * State that was saved. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oSavedState\": null,\n\t\n\t\t/**\n\t\t * State that was loaded. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oLoadedState\": null,\n\t\n\t\t/**\n\t\t * Source url for AJAX data for the table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\t/**\n\t\t * Property from a given object from which to read the table data from. This\n\t\t * can be an empty string (when not server-side processing), in which case\n\t\t * it is  assumed an an array is given directly.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sAjaxDataProp\": null,\n\t\n\t\t/**\n\t\t * Note if draw should be blocked while getting data\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bAjaxDataGet\": true,\n\t\n\t\t/**\n\t\t * The last jQuery XHR object that was used for server-side data gathering.\n\t\t * This can be used for working with the XHR information in one of the\n\t\t * callbacks\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"jqXHR\": null,\n\t\n\t\t/**\n\t\t * JSON returned from the server in the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"json\": undefined,\n\t\n\t\t/**\n\t\t * Data submitted as part of the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"oAjaxData\": undefined,\n\t\n\t\t/**\n\t\t * Function to get the server-side data.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\t/**\n\t\t * Functions which are called prior to sending an Ajax request so extra\n\t\t * parameters can easily be sent to the server\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoServerParams\": [],\n\t\n\t\t/**\n\t\t * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if\n\t\t * required).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sServerMethod\": null,\n\t\n\t\t/**\n\t\t * Format numbers for display.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnFormatNumber\": null,\n\t\n\t\t/**\n\t\t * List of options that can be used for the user selectable length menu.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLengthMenu\": null,\n\t\n\t\t/**\n\t\t * Counter for the draws that the table does. Also used as a tracker for\n\t\t * server-side processing\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iDraw\": 0,\n\t\n\t\t/**\n\t\t * Indicate if a redraw is being done - useful for Ajax\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDrawing\": false,\n\t\n\t\t/**\n\t\t * Draw index (iDraw) of the last error when parsing the returned data\n\t\t *  @type int\n\t\t *  @default -1\n\t\t */\n\t\t\"iDrawError\": -1,\n\t\n\t\t/**\n\t\t * Paging display length\n\t\t *  @type int\n\t\t *  @default 10\n\t\t */\n\t\t\"_iDisplayLength\": 10,\n\t\n\t\t/**\n\t\t * Paging start point - aiDisplay index\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"_iDisplayStart\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the result set\n\t\t * (i.e. before filtering), Use fnRecordsTotal rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsTotal\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the current display set\n\t\t * (i.e. after filtering). Use fnRecordsDisplay rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type boolean\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsDisplay\": 0,\n\t\n\t\t/**\n\t\t * Flag to indicate if jQuery UI marking and classes should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bJUI\": null,\n\t\n\t\t/**\n\t\t * The classes to use for the table\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if filtering has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bFiltered\": false,\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if sorting has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bSorted\": false,\n\t\n\t\t/**\n\t\t * Indicate that if multiple rows are in the header and there is more than\n\t\t * one unique cell per column, if the top one (true) or bottom one (false)\n\t\t * should be used for sorting / title by DataTables.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortCellsTop\": null,\n\t\n\t\t/**\n\t\t * Initialisation object that is used for the table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInit\": null,\n\t\n\t\t/**\n\t\t * Destroy callback functions - for plug-ins to attach themselves to the\n\t\t * destroy so they can clean up markup and events.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDestroyCallback\": [],\n\t\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, before filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsTotal\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsTotal * 1 :\n\t\t\t\tthis.aiDisplayMaster.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, after filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsDisplay\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsDisplay * 1 :\n\t\t\t\tthis.aiDisplay.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the display end point - aiDisplay index\n\t\t *  @type function\n\t\t */\n\t\t\"fnDisplayEnd\": function ()\n\t\t{\n\t\t\tvar\n\t\t\t\tlen      = this._iDisplayLength,\n\t\t\t\tstart    = this._iDisplayStart,\n\t\t\t\tcalc     = start + len,\n\t\t\t\trecords  = this.aiDisplay.length,\n\t\t\t\tfeatures = this.oFeatures,\n\t\t\t\tpaginate = features.bPaginate;\n\t\n\t\t\tif ( features.bServerSide ) {\n\t\t\t\treturn paginate === false || len === -1 ?\n\t\t\t\t\tstart + records :\n\t\t\t\t\tMath.min( start+len, this._iRecordsDisplay );\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn ! paginate || calc>records || len===-1 ?\n\t\t\t\t\trecords :\n\t\t\t\t\tcalc;\n\t\t\t}\n\t\t},\n\t\n\t\t/**\n\t\t * The DataTables object for this table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInstance\": null,\n\t\n\t\t/**\n\t\t * Unique identifier for each instance of the DataTables object. If there\n\t\t * is an ID on the table node, then it takes that value, otherwise an\n\t\t * incrementing internal counter is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sInstance\": null,\n\t\n\t\t/**\n\t\t * tabindex attribute value that is added to DataTables control elements, allowing\n\t\t * keyboard navigation of the table and its controls.\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollHead\": null,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollFoot\": null,\n\t\n\t\t/**\n\t\t * Last applied sort\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLastSort\": [],\n\t\n\t\t/**\n\t\t * Stored plug-in instances\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oPlugins\": {},\n\t\n\t\t/**\n\t\t * Function used to get a row's id from the row's data\n\t\t *  @type function\n\t\t *  @default null\n\t\t */\n\t\t\"rowIdFn\": null,\n\t\n\t\t/**\n\t\t * Data location where to store a row's id\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"rowId\": null\n\t};\n\n\t/**\n\t * Extension object for DataTables that is used to provide all extension\n\t * options.\n\t *\n\t * Note that the `DataTable.ext` object is available through\n\t * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is\n\t * also aliased to `jQuery.fn.dataTableExt` for historic reasons.\n\t *  @namespace\n\t *  @extends DataTable.models.ext\n\t */\n\t\n\t\n\t/**\n\t * DataTables extensions\n\t * \n\t * This namespace acts as a collection area for plug-ins that can be used to\n\t * extend DataTables capabilities. Indeed many of the build in methods\n\t * use this method to provide their own capabilities (sorting methods for\n\t * example).\n\t *\n\t * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy\n\t * reasons\n\t *\n\t *  @namespace\n\t */\n\tDataTable.ext = _ext = {\n\t\t/**\n\t\t * Buttons. For use with the Buttons extension for DataTables. This is\n\t\t * defined here so other extensions can define buttons regardless of load\n\t\t * order. It is _not_ used by DataTables core.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tbuttons: {},\n\t\n\t\n\t\t/**\n\t\t * Element class names\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tclasses: {},\n\t\n\t\n\t\t/**\n\t\t * DataTables build type (expanded by the download builder)\n\t\t *\n\t\t *  @type string\n\t\t */\n\t\tbuild:\"dt/dt-1.10.13\",\n\t\n\t\n\t\t/**\n\t\t * Error reporting.\n\t\t * \n\t\t * How should DataTables report an error. Can take the value 'alert',\n\t\t * 'throw', 'none' or a function.\n\t\t *\n\t\t *  @type string|function\n\t\t *  @default alert\n\t\t */\n\t\terrMode: \"alert\",\n\t\n\t\n\t\t/**\n\t\t * Feature plug-ins.\n\t\t * \n\t\t * This is an array of objects which describe the feature plug-ins that are\n\t\t * available to DataTables. These feature plug-ins are then available for\n\t\t * use through the `dom` initialisation option.\n\t\t * \n\t\t * Each feature plug-in is described by an object which must have the\n\t\t * following properties:\n\t\t * \n\t\t * * `fnInit` - function that is used to initialise the plug-in,\n\t\t * * `cFeature` - a character so the feature can be enabled by the `dom`\n\t\t *   instillation option. This is case sensitive.\n\t\t *\n\t\t * The `fnInit` function has the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *\n\t\t * And the following return is expected:\n\t\t * \n\t\t * * {node|null} The element which contains your feature. Note that the\n\t\t *   return may also be void if your plug-in does not require to inject any\n\t\t *   DOM elements into DataTables control (`dom`) - for example this might\n\t\t *   be useful when developing a plug-in which allows table control via\n\t\t *   keyboard entry\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    $.fn.dataTable.ext.features.push( {\n\t\t *      \"fnInit\": function( oSettings ) {\n\t\t *        return new TableTools( { \"oDTSettings\": oSettings } );\n\t\t *      },\n\t\t *      \"cFeature\": \"T\"\n\t\t *    } );\n\t\t */\n\t\tfeature: [],\n\t\n\t\n\t\t/**\n\t\t * Row searching.\n\t\t * \n\t\t * This method of searching is complimentary to the default type based\n\t\t * searching, and a lot more comprehensive as it allows you complete control\n\t\t * over the searching logic. Each element in this array is a function\n\t\t * (parameters described below) that is called for every row in the table,\n\t\t * and your logic decides if it should be included in the searching data set\n\t\t * or not.\n\t\t *\n\t\t * Searching functions have the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{array|object}` Data for the row to be processed (same as the\n\t\t *    original format that was passed in as the data source, or an array\n\t\t *    from a DOM data source\n\t\t * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which\n\t\t *    can be useful to retrieve the `TR` element if you need DOM interaction.\n\t\t *\n\t\t * And the following return is expected:\n\t\t *\n\t\t * * {boolean} Include the row in the searched result set (true) or not\n\t\t *   (false)\n\t\t *\n\t\t * Note that as with the main search ability in DataTables, technically this\n\t\t * is \"filtering\", since it is subtractive. However, for consistency in\n\t\t * naming we call it searching here.\n\t\t *\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @example\n\t\t *    // The following example shows custom search being applied to the\n\t\t *    // fourth column (i.e. the data[3] index) based on two input values\n\t\t *    // from the end-user, matching the data in a certain range.\n\t\t *    $.fn.dataTable.ext.search.push(\n\t\t *      function( settings, data, dataIndex ) {\n\t\t *        var min = document.getElementById('min').value * 1;\n\t\t *        var max = document.getElementById('max').value * 1;\n\t\t *        var version = data[3] == \"-\" ? 0 : data[3]*1;\n\t\t *\n\t\t *        if ( min == \"\" && max == \"\" ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min == \"\" && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && \"\" == max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        return false;\n\t\t *      }\n\t\t *    );\n\t\t */\n\t\tsearch: [],\n\t\n\t\n\t\t/**\n\t\t * Selector extensions\n\t\t *\n\t\t * The `selector` option can be used to extend the options available for the\n\t\t * selector modifier options (`selector-modifier` object data type) that\n\t\t * each of the three built in selector types offer (row, column and cell +\n\t\t * their plural counterparts). For example the Select extension uses this\n\t\t * mechanism to provide an option to select only rows, columns and cells\n\t\t * that have been marked as selected by the end user (`{selected: true}`),\n\t\t * which can be used in conjunction with the existing built in selector\n\t\t * options.\n\t\t *\n\t\t * Each property is an array to which functions can be pushed. The functions\n\t\t * take three attributes:\n\t\t *\n\t\t * * Settings object for the host table\n\t\t * * Options object (`selector-modifier` object type)\n\t\t * * Array of selected item indexes\n\t\t *\n\t\t * The return is an array of the resulting item indexes after the custom\n\t\t * selector has been applied.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tselector: {\n\t\t\tcell: [],\n\t\t\tcolumn: [],\n\t\t\trow: []\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Internal functions, exposed for used in plug-ins.\n\t\t * \n\t\t * Please note that you should not need to use the internal methods for\n\t\t * anything other than a plug-in (and even then, try to avoid if possible).\n\t\t * The internal function may change between releases.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tinternal: {},\n\t\n\t\n\t\t/**\n\t\t * Legacy configuration options. Enable and disable legacy options that\n\t\t * are available in DataTables.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tlegacy: {\n\t\t\t/**\n\t\t\t * Enable / disable DataTables 1.9 compatible server-side processing\n\t\t\t * requests\n\t\t\t *\n\t\t\t *  @type boolean\n\t\t\t *  @default null\n\t\t\t */\n\t\t\tajax: null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Pagination plug-in methods.\n\t\t * \n\t\t * Each entry in this object is a function and defines which buttons should\n\t\t * be shown by the pagination rendering method that is used for the table:\n\t\t * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the\n\t\t * buttons are displayed in the document, while the functions here tell it\n\t\t * what buttons to display. This is done by returning an array of button\n\t\t * descriptions (what each button will do).\n\t\t *\n\t\t * Pagination types (the four built in options and any additional plug-in\n\t\t * options defined here) can be used through the `paginationType`\n\t\t * initialisation parameter.\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{int} page` The current page index\n\t\t * 2. `{int} pages` The number of pages in the table\n\t\t *\n\t\t * Each function is expected to return an array where each element of the\n\t\t * array can be one of:\n\t\t *\n\t\t * * `first` - Jump to first page when activated\n\t\t * * `last` - Jump to last page when activated\n\t\t * * `previous` - Show previous page when activated\n\t\t * * `next` - Show next page when activated\n\t\t * * `{int}` - Show page of the index given\n\t\t * * `{array}` - A nested array containing the above elements to add a\n\t\t *   containing 'DIV' element (might be useful for styling).\n\t\t *\n\t\t * Note that DataTables v1.9- used this object slightly differently whereby\n\t\t * an object with two functions would be defined for each plug-in. That\n\t\t * ability is still supported by DataTables 1.10+ to provide backwards\n\t\t * compatibility, but this option of use is now decremented and no longer\n\t\t * documented in DataTables 1.10+.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t *\n\t\t *  @example\n\t\t *    // Show previous, next and current page buttons only\n\t\t *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {\n\t\t *      return [ 'previous', page, 'next' ];\n\t\t *    };\n\t\t */\n\t\tpager: {},\n\t\n\t\n\t\trenderer: {\n\t\t\tpageButton: {},\n\t\t\theader: {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Ordering plug-ins - custom data source\n\t\t * \n\t\t * The extension options for ordering of data available here is complimentary\n\t\t * to the default type based ordering that DataTables typically uses. It\n\t\t * allows much greater control over the the data that is being used to\n\t\t * order a column, but is necessarily therefore more complex.\n\t\t * \n\t\t * This type of ordering is useful if you want to do ordering based on data\n\t\t * live from the DOM (for example the contents of an 'input' element) rather\n\t\t * than just the static string that DataTables knows of.\n\t\t * \n\t\t * The way these plug-ins work is that you create an array of the values you\n\t\t * wish to be ordering for the column in question and then return that\n\t\t * array. The data in the array much be in the index order of the rows in\n\t\t * the table (not the currently ordering order!). Which order data gathering\n\t\t * function is run here depends on the `dt-init columns.orderDataType`\n\t\t * parameter that is used for the column (if any).\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{int}` Target column index\n\t\t *\n\t\t * Each function is expected to return an array:\n\t\t *\n\t\t * * `{array}` Data for the column to be ordering upon\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    // Ordering using `input` node values\n\t\t *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )\n\t\t *    {\n\t\t *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {\n\t\t *        return $('input', td).val();\n\t\t *      } );\n\t\t *    }\n\t\t */\n\t\torder: {},\n\t\n\t\n\t\t/**\n\t\t * Type based plug-ins.\n\t\t *\n\t\t * Each column in DataTables has a type assigned to it, either by automatic\n\t\t * detection or by direct assignment using the `type` option for the column.\n\t\t * The type of a column will effect how it is ordering and search (plug-ins\n\t\t * can also make use of the column type if required).\n\t\t *\n\t\t * @namespace\n\t\t */\n\t\ttype: {\n\t\t\t/**\n\t\t\t * Type detection functions.\n\t\t\t *\n\t\t\t * The functions defined in this object are used to automatically detect\n\t\t\t * a column's type, making initialisation of DataTables super easy, even\n\t\t\t * when complex data is in the table.\n\t\t\t *\n\t\t\t * The functions defined take two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be analysed\n\t\t     *  2. `{settings}` DataTables settings object. This can be used to\n\t\t     *     perform context specific type detection - for example detection\n\t\t     *     based on language settings such as using a comma for a decimal\n\t\t     *     place. Generally speaking the options from the settings will not\n\t\t     *     be required\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Data type detected, or null if unknown (and thus\n\t\t\t *   pass it on to the other type detection functions.\n\t\t\t *\n\t\t\t *  @type array\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Currency type detection plug-in:\n\t\t\t *    $.fn.dataTable.ext.type.detect.push(\n\t\t\t *      function ( data, settings ) {\n\t\t\t *        // Check the numeric part\n\t\t\t *        if ( ! $.isNumeric( data.substring(1) ) ) {\n\t\t\t *          return null;\n\t\t\t *        }\n\t\t\t *\n\t\t\t *        // Check prefixed by currency\n\t\t\t *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {\n\t\t\t *          return 'currency';\n\t\t\t *        }\n\t\t\t *        return null;\n\t\t\t *      }\n\t\t\t *    );\n\t\t\t */\n\t\t\tdetect: [],\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based search formatting.\n\t\t\t *\n\t\t\t * The type based searching functions can be used to pre-format the\n\t\t\t * data to be search on. For example, it can be used to strip HTML\n\t\t\t * tags or to de-format telephone numbers for numeric only searching.\n\t\t\t *\n\t\t\t * Note that is a search is not defined for a column of a given type,\n\t\t\t * no search formatting will be performed.\n\t\t\t * \n\t\t\t * Pre-processing of searching data plug-ins - When you assign the sType\n\t\t\t * for a column (or have it automatically detected for you by DataTables\n\t\t\t * or a type detection plug-in), you will typically be using this for\n\t\t\t * custom sorting, but it can also be used to provide custom searching\n\t\t\t * by allowing you to pre-processing the data and returning the data in\n\t\t\t * the format that should be searched upon. This is done by adding\n\t\t\t * functions this object with a parameter name which matches the sType\n\t\t\t * for that target column. This is the corollary of <i>afnSortData</i>\n\t\t\t * for searching data.\n\t\t\t *\n\t\t\t * The functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for searching\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Formatted string that will be used for the searching.\n\t\t\t *\n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {\n\t\t\t *      return d.replace(/\\n/g,\" \").replace( /<.*?>/g, \"\" );\n\t\t\t *    }\n\t\t\t */\n\t\t\tsearch: {},\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based ordering.\n\t\t\t *\n\t\t\t * The column type tells DataTables what ordering to apply to the table\n\t\t\t * when a column is sorted upon. The order for each type that is defined,\n\t\t\t * is defined by the functions available in this object.\n\t\t\t *\n\t\t\t * Each ordering option can be described by three properties added to\n\t\t\t * this object:\n\t\t\t *\n\t\t\t * * `{type}-pre` - Pre-formatting function\n\t\t\t * * `{type}-asc` - Ascending order function\n\t\t\t * * `{type}-desc` - Descending order function\n\t\t\t *\n\t\t\t * All three can be used together, only `{type}-pre` or only\n\t\t\t * `{type}-asc` and `{type}-desc` together. It is generally recommended\n\t\t\t * that only `{type}-pre` is used, as this provides the optimal\n\t\t\t * implementation in terms of speed, although the others are provided\n\t\t\t * for compatibility with existing Javascript sort functions.\n\t\t\t *\n\t\t\t * `{type}-pre`: Functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for ordering\n\t\t\t *\n\t\t\t * And return:\n\t\t\t *\n\t\t\t * * `{*}` Data to be sorted upon\n\t\t\t *\n\t\t\t * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort\n\t\t\t * functions, taking two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data to compare to the second parameter\n\t\t     *  2. `{*}` Data to compare to the first parameter\n\t\t\t *\n\t\t\t * And returning:\n\t\t\t *\n\t\t\t * * `{*}` Ordering match: <0 if first parameter should be sorted lower\n\t\t\t *   than the second parameter, ===0 if the two parameters are equal and\n\t\t\t *   >0 if the first parameter should be sorted height than the second\n\t\t\t *   parameter.\n\t\t\t * \n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Numeric ordering of formatted numbers with a pre-formatter\n\t\t\t *    $.extend( $.fn.dataTable.ext.type.order, {\n\t\t\t *      \"string-pre\": function(x) {\n\t\t\t *        a = (a === \"-\" || a === \"\") ? 0 : a.replace( /[^\\d\\-\\.]/g, \"\" );\n\t\t\t *        return parseFloat( a );\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Case-sensitive string ordering, with no pre-formatting method\n\t\t\t *    $.extend( $.fn.dataTable.ext.order, {\n\t\t\t *      \"string-case-asc\": function(x,y) {\n\t\t\t *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t\t *      },\n\t\t\t *      \"string-case-desc\": function(x,y) {\n\t\t\t *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t */\n\t\t\torder: {}\n\t\t},\n\t\n\t\t/**\n\t\t * Unique DataTables instance counter\n\t\t *\n\t\t * @type int\n\t\t * @private\n\t\t */\n\t\t_unique: 0,\n\t\n\t\n\t\t//\n\t\t// Depreciated\n\t\t// The following properties are retained for backwards compatiblity only.\n\t\t// The should not be used in new projects and will be removed in a future\n\t\t// version\n\t\t//\n\t\n\t\t/**\n\t\t * Version check function.\n\t\t *  @type function\n\t\t *  @depreciated Since 1.10\n\t\t */\n\t\tfnVersionCheck: DataTable.fnVersionCheck,\n\t\n\t\n\t\t/**\n\t\t * Index for what 'this' index API functions should use\n\t\t *  @type int\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tiApiIndex: 0,\n\t\n\t\n\t\t/**\n\t\t * jQuery UI class container\n\t\t *  @type object\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\toJUIClasses: {},\n\t\n\t\n\t\t/**\n\t\t * Software version\n\t\t *  @type string\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tsVersion: DataTable.version\n\t};\n\t\n\t\n\t//\n\t// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts\n\t//\n\t$.extend( _ext, {\n\t\tafnFiltering: _ext.search,\n\t\taTypes:       _ext.type.detect,\n\t\tofnSearch:    _ext.type.search,\n\t\toSort:        _ext.type.order,\n\t\tafnSortData:  _ext.order,\n\t\taoFeatures:   _ext.feature,\n\t\toApi:         _ext.internal,\n\t\toStdClasses:  _ext.classes,\n\t\toPagination:  _ext.pager\n\t} );\n\t\n\t\n\t$.extend( DataTable.ext.classes, {\n\t\t\"sTable\": \"dataTable\",\n\t\t\"sNoFooter\": \"no-footer\",\n\t\n\t\t/* Paging buttons */\n\t\t\"sPageButton\": \"paginate_button\",\n\t\t\"sPageButtonActive\": \"current\",\n\t\t\"sPageButtonDisabled\": \"disabled\",\n\t\n\t\t/* Striping classes */\n\t\t\"sStripeOdd\": \"odd\",\n\t\t\"sStripeEven\": \"even\",\n\t\n\t\t/* Empty row */\n\t\t\"sRowEmpty\": \"dataTables_empty\",\n\t\n\t\t/* Features */\n\t\t\"sWrapper\": \"dataTables_wrapper\",\n\t\t\"sFilter\": \"dataTables_filter\",\n\t\t\"sInfo\": \"dataTables_info\",\n\t\t\"sPaging\": \"dataTables_paginate paging_\", /* Note that the type is postfixed */\n\t\t\"sLength\": \"dataTables_length\",\n\t\t\"sProcessing\": \"dataTables_processing\",\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\": \"sorting_asc\",\n\t\t\"sSortDesc\": \"sorting_desc\",\n\t\t\"sSortable\": \"sorting\", /* Sortable in both directions */\n\t\t\"sSortableAsc\": \"sorting_asc_disabled\",\n\t\t\"sSortableDesc\": \"sorting_desc_disabled\",\n\t\t\"sSortableNone\": \"sorting_disabled\",\n\t\t\"sSortColumn\": \"sorting_\", /* Note that an int is postfixed for the sorting order */\n\t\n\t\t/* Filtering */\n\t\t\"sFilterInput\": \"\",\n\t\n\t\t/* Page length */\n\t\t\"sLengthSelect\": \"\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollWrapper\": \"dataTables_scroll\",\n\t\t\"sScrollHead\": \"dataTables_scrollHead\",\n\t\t\"sScrollHeadInner\": \"dataTables_scrollHeadInner\",\n\t\t\"sScrollBody\": \"dataTables_scrollBody\",\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot\",\n\t\t\"sScrollFootInner\": \"dataTables_scrollFootInner\",\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\": \"\",\n\t\t\"sFooterTH\": \"\",\n\t\n\t\t// Deprecated\n\t\t\"sSortJUIAsc\": \"\",\n\t\t\"sSortJUIDesc\": \"\",\n\t\t\"sSortJUI\": \"\",\n\t\t\"sSortJUIAscAllowed\": \"\",\n\t\t\"sSortJUIDescAllowed\": \"\",\n\t\t\"sSortJUIWrapper\": \"\",\n\t\t\"sSortIcon\": \"\",\n\t\t\"sJUIHeader\": \"\",\n\t\t\"sJUIFooter\": \"\"\n\t} );\n\t\n\t\n\t(function() {\n\t\n\t// Reused strings for better compression. Closure compiler appears to have a\n\t// weird edge case where it is trying to expand strings rather than use the\n\t// variable version. This results in about 200 bytes being added, for very\n\t// little preference benefit since it this run on script load only.\n\tvar _empty = '';\n\t_empty = '';\n\t\n\tvar _stateDefault = _empty + 'ui-state-default';\n\tvar _sortIcon     = _empty + 'css_right ui-icon ui-icon-';\n\tvar _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';\n\t\n\t$.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {\n\t\t/* Full numbers paging buttons */\n\t\t\"sPageButton\":         \"fg-button ui-button \"+_stateDefault,\n\t\t\"sPageButtonActive\":   \"ui-state-disabled\",\n\t\t\"sPageButtonDisabled\": \"ui-state-disabled\",\n\t\n\t\t/* Features */\n\t\t\"sPaging\": \"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi \"+\n\t\t\t\"ui-buttonset-multi paging_\", /* Note that the type is postfixed */\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\":            _stateDefault+\" sorting_asc\",\n\t\t\"sSortDesc\":           _stateDefault+\" sorting_desc\",\n\t\t\"sSortable\":           _stateDefault+\" sorting\",\n\t\t\"sSortableAsc\":        _stateDefault+\" sorting_asc_disabled\",\n\t\t\"sSortableDesc\":       _stateDefault+\" sorting_desc_disabled\",\n\t\t\"sSortableNone\":       _stateDefault+\" sorting_disabled\",\n\t\t\"sSortJUIAsc\":         _sortIcon+\"triangle-1-n\",\n\t\t\"sSortJUIDesc\":        _sortIcon+\"triangle-1-s\",\n\t\t\"sSortJUI\":            _sortIcon+\"carat-2-n-s\",\n\t\t\"sSortJUIAscAllowed\":  _sortIcon+\"carat-1-n\",\n\t\t\"sSortJUIDescAllowed\": _sortIcon+\"carat-1-s\",\n\t\t\"sSortJUIWrapper\":     \"DataTables_sort_wrapper\",\n\t\t\"sSortIcon\":           \"DataTables_sort_icon\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollHead\": \"dataTables_scrollHead \"+_stateDefault,\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot \"+_stateDefault,\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\":  _stateDefault,\n\t\t\"sFooterTH\":  _stateDefault,\n\t\t\"sJUIHeader\": _headerFooter+\" ui-corner-tl ui-corner-tr\",\n\t\t\"sJUIFooter\": _headerFooter+\" ui-corner-bl ui-corner-br\"\n\t} );\n\t\n\t}());\n\t\n\t\n\t\n\tvar extPagination = DataTable.ext.pager;\n\t\n\tfunction _numbers ( page, pages ) {\n\t\tvar\n\t\t\tnumbers = [],\n\t\t\tbuttons = extPagination.numbers_length,\n\t\t\thalf = Math.floor( buttons / 2 ),\n\t\t\ti = 1;\n\t\n\t\tif ( pages <= buttons ) {\n\t\t\tnumbers = _range( 0, pages );\n\t\t}\n\t\telse if ( page <= half ) {\n\t\t\tnumbers = _range( 0, buttons-2 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t}\n\t\telse if ( page >= pages - 1 - half ) {\n\t\t\tnumbers = _range( pages-(buttons-2), pages );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\telse {\n\t\t\tnumbers = _range( page-half+2, page+half-1 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' );\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\n\t\tnumbers.DT_el = 'span';\n\t\treturn numbers;\n\t}\n\t\n\t\n\t$.extend( extPagination, {\n\t\tsimple: function ( page, pages ) {\n\t\t\treturn [ 'previous', 'next' ];\n\t\t},\n\t\n\t\tfull: function ( page, pages ) {\n\t\t\treturn [  'first', 'previous', 'next', 'last' ];\n\t\t},\n\t\n\t\tnumbers: function ( page, pages ) {\n\t\t\treturn [ _numbers(page, pages) ];\n\t\t},\n\t\n\t\tsimple_numbers: function ( page, pages ) {\n\t\t\treturn [ 'previous', _numbers(page, pages), 'next' ];\n\t\t},\n\t\n\t\tfull_numbers: function ( page, pages ) {\n\t\t\treturn [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];\n\t\t},\n\t\t\n\t\tfirst_last_numbers: function (page, pages) {\n\t \t\treturn ['first', _numbers(page, pages), 'last'];\n\t \t},\n\t\n\t\t// For testing and plug-ins to use\n\t\t_numbers: _numbers,\n\t\n\t\t// Number of number buttons (including ellipsis) to show. _Must be odd!_\n\t\tnumbers_length: 7\n\t} );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\tpageButton: {\n\t\t\t_: function ( settings, host, idx, buttons, page, pages ) {\n\t\t\t\tvar classes = settings.oClasses;\n\t\t\t\tvar lang = settings.oLanguage.oPaginate;\n\t\t\t\tvar aria = settings.oLanguage.oAria.paginate || {};\n\t\t\t\tvar btnDisplay, btnClass, counter=0;\n\t\n\t\t\t\tvar attach = function( container, buttons ) {\n\t\t\t\t\tvar i, ien, node, button;\n\t\t\t\t\tvar clickHandler = function ( e ) {\n\t\t\t\t\t\t_fnPageChange( settings, e.data.action, true );\n\t\t\t\t\t};\n\t\n\t\t\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tbutton = buttons[i];\n\t\n\t\t\t\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\t\t\t\tvar inner = $( '<'+(button.DT_el || 'div')+'/>' )\n\t\t\t\t\t\t\t\t.appendTo( container );\n\t\t\t\t\t\t\tattach( inner, button );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tbtnDisplay = null;\n\t\t\t\t\t\t\tbtnClass = '';\n\t\n\t\t\t\t\t\t\tswitch ( button ) {\n\t\t\t\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\t\t\t\tcontainer.append('<span class=\"ellipsis\">&#x2026;</span>');\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'first':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'next':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'last':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t\t\t\tclasses.sPageButtonActive : '';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\tif ( btnDisplay !== null ) {\n\t\t\t\t\t\t\t\tnode = $('<a>', {\n\t\t\t\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t\t\t\t.appendTo( container );\n\t\n\t\t\t\t\t\t\t\t_fnBindAction(\n\t\t\t\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t\t\t\t);\n\t\n\t\t\t\t\t\t\t\tcounter++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame. Try / catch the error. Not good for\n\t\t\t\t// accessibility, but neither are frames.\n\t\t\t\tvar activeEl;\n\t\n\t\t\t\ttry {\n\t\t\t\t\t// Because this approach is destroying and recreating the paging\n\t\t\t\t\t// elements, focus is lost on the select button which is bad for\n\t\t\t\t\t// accessibility. So we want to restore focus once the draw has\n\t\t\t\t\t// completed\n\t\t\t\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t\t\t\t}\n\t\t\t\tcatch (e) {}\n\t\n\t\t\t\tattach( $(host).empty(), buttons );\n\t\n\t\t\t\tif ( activeEl !== undefined ) {\n\t\t\t\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t\n\t\n\t// Built in type detection. See model.ext.aTypes for information about\n\t// what is required from this methods.\n\t$.extend( DataTable.ext.type.detect, [\n\t\t// Plain numbers - first since V8 detects some plain numbers as dates\n\t\t// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal ) ? 'num'+decimal : null;\n\t\t},\n\t\n\t\t// Dates (only those recognised by the browser's Date.parse)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\t// V8 tries _very_ hard to make a string passed into `Date.parse()`\n\t\t\t// valid, so we need to use a regex to restrict date formats. Use a\n\t\t\t// plug-in for anything other than ISO8601 style strings\n\t\t\tif ( d && !(d instanceof Date) && ! _re_date.test(d) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tvar parsed = Date.parse(d);\n\t\t\treturn (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;\n\t\t},\n\t\n\t\t// Formatted numbers\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric, formatted\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML (this is strict checking - there must be html)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\treturn _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?\n\t\t\t\t'html' : null;\n\t\t}\n\t] );\n\t\n\t\n\t\n\t// Filter formatting functions. See model.ext.ofnSearch for information about\n\t// what is required from these methods.\n\t// \n\t// Note that additional search methods are added for the html numbers and\n\t// html formatted numbers by `_addNumericSort()` when we know what the decimal\n\t// place is\n\t\n\t\n\t$.extend( DataTable.ext.type.search, {\n\t\thtml: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata\n\t\t\t\t\t\t.replace( _re_new_lines, \" \" )\n\t\t\t\t\t\t.replace( _re_html, \"\" ) :\n\t\t\t\t\t'';\n\t\t},\n\t\n\t\tstring: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata.replace( _re_new_lines, \" \" ) :\n\t\t\t\t\tdata;\n\t\t}\n\t} );\n\t\n\t\n\t\n\tvar __numericReplace = function ( d, decimalPlace, re1, re2 ) {\n\t\tif ( d !== 0 && (!d || d === '-') ) {\n\t\t\treturn -Infinity;\n\t\t}\n\t\n\t\t// If a decimal place other than `.` is used, it needs to be given to the\n\t\t// function so we can detect it and replace with a `.` which is the only\n\t\t// decimal place Javascript recognises - it is not locale aware.\n\t\tif ( decimalPlace ) {\n\t\t\td = _numToDecimal( d, decimalPlace );\n\t\t}\n\t\n\t\tif ( d.replace ) {\n\t\t\tif ( re1 ) {\n\t\t\t\td = d.replace( re1, '' );\n\t\t\t}\n\t\n\t\t\tif ( re2 ) {\n\t\t\t\td = d.replace( re2, '' );\n\t\t\t}\n\t\t}\n\t\n\t\treturn d * 1;\n\t};\n\t\n\t\n\t// Add the numeric 'deformatting' functions for sorting and search. This is done\n\t// in a function to provide an easy ability for the language options to add\n\t// additional methods if a non-period decimal place is used.\n\tfunction _addNumericSort ( decimalPlace ) {\n\t\t$.each(\n\t\t\t{\n\t\t\t\t// Plain numbers\n\t\t\t\t\"num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace );\n\t\t\t\t},\n\t\n\t\t\t\t// Formatted numbers\n\t\t\t\t\"num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_formatted_numeric );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric\n\t\t\t\t\"html-num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric, formatted\n\t\t\t\t\"html-num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );\n\t\t\t\t}\n\t\t\t},\n\t\t\tfunction ( key, fn ) {\n\t\t\t\t// Add the ordering method\n\t\t\t\t_ext.type.order[ key+decimalPlace+'-pre' ] = fn;\n\t\n\t\t\t\t// For HTML types add a search formatter that will strip the HTML\n\t\t\t\tif ( key.match(/^html\\-/) ) {\n\t\t\t\t\t_ext.type.search[ key+decimalPlace ] = _ext.type.search.html;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\t\n\t\n\t// Default sort methods\n\t$.extend( _ext.type.order, {\n\t\t// Dates\n\t\t\"date-pre\": function ( d ) {\n\t\t\treturn Date.parse( d ) || -Infinity;\n\t\t},\n\t\n\t\t// html\n\t\t\"html-pre\": function ( a ) {\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ta.replace ?\n\t\t\t\t\ta.replace( /<.*?>/g, \"\" ).toLowerCase() :\n\t\t\t\t\ta+'';\n\t\t},\n\t\n\t\t// string\n\t\t\"string-pre\": function ( a ) {\n\t\t\t// This is a little complex, but faster than always calling toString,\n\t\t\t// http://jsperf.com/tostring-v-check\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ttypeof a === 'string' ?\n\t\t\t\t\ta.toLowerCase() :\n\t\t\t\t\t! a.toString ?\n\t\t\t\t\t\t'' :\n\t\t\t\t\t\ta.toString();\n\t\t},\n\t\n\t\t// string-asc and -desc are retained only for compatibility with the old\n\t\t// sort methods\n\t\t\"string-asc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t},\n\t\n\t\t\"string-desc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t}\n\t} );\n\t\n\t\n\t// Numeric sorting types - order doesn't matter here\n\t_addNumericSort( '' );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\theader: {\n\t\t\t_: function ( settings, cell, column, classes ) {\n\t\t\t\t// No additional mark-up required\n\t\t\t\t// Attach a sort listener to update on sort - note that using the\n\t\t\t\t// `DT` namespace will allow the event to be removed automatically\n\t\t\t\t// on destroy, while the `dt` namespaced event is the one we are\n\t\t\t\t// listening for\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) { // need to check this this is the host\n\t\t\t\t\t\treturn;               // table, not a nested one\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tcolumn.sSortingClass +' '+\n\t\t\t\t\t\t\tclasses.sSortAsc +' '+\n\t\t\t\t\t\t\tclasses.sSortDesc\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t},\n\t\n\t\t\tjqueryui: function ( settings, cell, column, classes ) {\n\t\t\t\t$('<div/>')\n\t\t\t\t\t.addClass( classes.sSortJUIWrapper )\n\t\t\t\t\t.append( cell.contents() )\n\t\t\t\t\t.append( $('<span/>')\n\t\t\t\t\t\t.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo( cell );\n\t\n\t\t\t\t// Attach a sort listener to update on sort\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.find( 'span.'+classes.sSortIcon )\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tclasses.sSortJUIAsc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDesc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUI +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIAscAllowed +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDescAllowed\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortJUIAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortJUIDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClassJUI\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t/*\n\t * Public helper functions. These aren't used internally by DataTables, or\n\t * called by any of the options passed into DataTables, but they can be used\n\t * externally by developers working with DataTables. They are helper functions\n\t * to make working with DataTables a little bit easier.\n\t */\n\t\n\tvar __htmlEscapeEntities = function ( d ) {\n\t\treturn typeof d === 'string' ?\n\t\t\td.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;') :\n\t\t\td;\n\t};\n\t\n\t/**\n\t * Helpers for `columns.render`.\n\t *\n\t * The options defined here can be used with the `columns.render` initialisation\n\t * option to provide a display renderer. The following functions are defined:\n\t *\n\t * * `number` - Will format numeric data (defined by `columns.data`) for\n\t *   display, retaining the original unformatted data for sorting and filtering.\n\t *   It takes 5 parameters:\n\t *   * `string` - Thousands grouping separator\n\t *   * `string` - Decimal point indicator\n\t *   * `integer` - Number of decimal points to show\n\t *   * `string` (optional) - Prefix.\n\t *   * `string` (optional) - Postfix (/suffix).\n\t * * `text` - Escape HTML to help prevent XSS attacks. It has no optional\n\t *   parameters.\n\t *\n\t * @example\n\t *   // Column definition using the number renderer\n\t *   {\n\t *     data: \"salary\",\n\t *     render: $.fn.dataTable.render.number( '\\'', '.', 0, '$' )\n\t *   }\n\t *\n\t * @namespace\n\t */\n\tDataTable.render = {\n\t\tnumber: function ( thousands, decimal, precision, prefix, postfix ) {\n\t\t\treturn {\n\t\t\t\tdisplay: function ( d ) {\n\t\t\t\t\tif ( typeof d !== 'number' && typeof d !== 'string' ) {\n\t\t\t\t\t\treturn d;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar negative = d < 0 ? '-' : '';\n\t\t\t\t\tvar flo = parseFloat( d );\n\t\n\t\t\t\t\t// If NaN then there isn't much formatting that we can do - just\n\t\t\t\t\t// return immediately, escaping any HTML (this was supposed to\n\t\t\t\t\t// be a number after all)\n\t\t\t\t\tif ( isNaN( flo ) ) {\n\t\t\t\t\t\treturn __htmlEscapeEntities( d );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tflo = flo.toFixed( precision );\n\t\t\t\t\td = Math.abs( flo );\n\t\n\t\t\t\t\tvar intPart = parseInt( d, 10 );\n\t\t\t\t\tvar floatPart = precision ?\n\t\t\t\t\t\tdecimal+(d - intPart).toFixed( precision ).substring( 2 ):\n\t\t\t\t\t\t'';\n\t\n\t\t\t\t\treturn negative + (prefix||'') +\n\t\t\t\t\t\tintPart.toString().replace(\n\t\t\t\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g, thousands\n\t\t\t\t\t\t) +\n\t\t\t\t\t\tfloatPart +\n\t\t\t\t\t\t(postfix||'');\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\ttext: function () {\n\t\t\treturn {\n\t\t\t\tdisplay: __htmlEscapeEntities\n\t\t\t};\n\t\t}\n\t};\n\t\n\t\n\t/*\n\t * This is really a good bit rubbish this method of exposing the internal methods\n\t * publicly... - To be fixed in 2.0 using methods on the prototype\n\t */\n\t\n\t\n\t/**\n\t * Create a wrapper function for exporting an internal functions to an external API.\n\t *  @param {string} fn API function name\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#internal\n\t */\n\tfunction _fnExternApiFunc (fn)\n\t{\n\t\treturn function() {\n\t\t\tvar args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(\n\t\t\t\tArray.prototype.slice.call(arguments)\n\t\t\t);\n\t\t\treturn DataTable.ext.internal[fn].apply( this, args );\n\t\t};\n\t}\n\t\n\t\n\t/**\n\t * Reference to internal functions for use by plug-in developers. Note that\n\t * these methods are references to internal functions and are considered to be\n\t * private. If you use these methods, be aware that they are liable to change\n\t * between versions.\n\t *  @namespace\n\t */\n\t$.extend( DataTable.ext.internal, {\n\t\t_fnExternApiFunc: _fnExternApiFunc,\n\t\t_fnBuildAjax: _fnBuildAjax,\n\t\t_fnAjaxUpdate: _fnAjaxUpdate,\n\t\t_fnAjaxParameters: _fnAjaxParameters,\n\t\t_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,\n\t\t_fnAjaxDataSrc: _fnAjaxDataSrc,\n\t\t_fnAddColumn: _fnAddColumn,\n\t\t_fnColumnOptions: _fnColumnOptions,\n\t\t_fnAdjustColumnSizing: _fnAdjustColumnSizing,\n\t\t_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,\n\t\t_fnColumnIndexToVisible: _fnColumnIndexToVisible,\n\t\t_fnVisbleColumns: _fnVisbleColumns,\n\t\t_fnGetColumns: _fnGetColumns,\n\t\t_fnColumnTypes: _fnColumnTypes,\n\t\t_fnApplyColumnDefs: _fnApplyColumnDefs,\n\t\t_fnHungarianMap: _fnHungarianMap,\n\t\t_fnCamelToHungarian: _fnCamelToHungarian,\n\t\t_fnLanguageCompat: _fnLanguageCompat,\n\t\t_fnBrowserDetect: _fnBrowserDetect,\n\t\t_fnAddData: _fnAddData,\n\t\t_fnAddTr: _fnAddTr,\n\t\t_fnNodeToDataIndex: _fnNodeToDataIndex,\n\t\t_fnNodeToColumnIndex: _fnNodeToColumnIndex,\n\t\t_fnGetCellData: _fnGetCellData,\n\t\t_fnSetCellData: _fnSetCellData,\n\t\t_fnSplitObjNotation: _fnSplitObjNotation,\n\t\t_fnGetObjectDataFn: _fnGetObjectDataFn,\n\t\t_fnSetObjectDataFn: _fnSetObjectDataFn,\n\t\t_fnGetDataMaster: _fnGetDataMaster,\n\t\t_fnClearTable: _fnClearTable,\n\t\t_fnDeleteIndex: _fnDeleteIndex,\n\t\t_fnInvalidate: _fnInvalidate,\n\t\t_fnGetRowElements: _fnGetRowElements,\n\t\t_fnCreateTr: _fnCreateTr,\n\t\t_fnBuildHead: _fnBuildHead,\n\t\t_fnDrawHead: _fnDrawHead,\n\t\t_fnDraw: _fnDraw,\n\t\t_fnReDraw: _fnReDraw,\n\t\t_fnAddOptionsHtml: _fnAddOptionsHtml,\n\t\t_fnDetectHeader: _fnDetectHeader,\n\t\t_fnGetUniqueThs: _fnGetUniqueThs,\n\t\t_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,\n\t\t_fnFilterComplete: _fnFilterComplete,\n\t\t_fnFilterCustom: _fnFilterCustom,\n\t\t_fnFilterColumn: _fnFilterColumn,\n\t\t_fnFilter: _fnFilter,\n\t\t_fnFilterCreateSearch: _fnFilterCreateSearch,\n\t\t_fnEscapeRegex: _fnEscapeRegex,\n\t\t_fnFilterData: _fnFilterData,\n\t\t_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,\n\t\t_fnUpdateInfo: _fnUpdateInfo,\n\t\t_fnInfoMacros: _fnInfoMacros,\n\t\t_fnInitialise: _fnInitialise,\n\t\t_fnInitComplete: _fnInitComplete,\n\t\t_fnLengthChange: _fnLengthChange,\n\t\t_fnFeatureHtmlLength: _fnFeatureHtmlLength,\n\t\t_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,\n\t\t_fnPageChange: _fnPageChange,\n\t\t_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,\n\t\t_fnProcessingDisplay: _fnProcessingDisplay,\n\t\t_fnFeatureHtmlTable: _fnFeatureHtmlTable,\n\t\t_fnScrollDraw: _fnScrollDraw,\n\t\t_fnApplyToChildren: _fnApplyToChildren,\n\t\t_fnCalculateColumnWidths: _fnCalculateColumnWidths,\n\t\t_fnThrottle: _fnThrottle,\n\t\t_fnConvertToWidth: _fnConvertToWidth,\n\t\t_fnGetWidestNode: _fnGetWidestNode,\n\t\t_fnGetMaxLenString: _fnGetMaxLenString,\n\t\t_fnStringToCss: _fnStringToCss,\n\t\t_fnSortFlatten: _fnSortFlatten,\n\t\t_fnSort: _fnSort,\n\t\t_fnSortAria: _fnSortAria,\n\t\t_fnSortListener: _fnSortListener,\n\t\t_fnSortAttachListener: _fnSortAttachListener,\n\t\t_fnSortingClasses: _fnSortingClasses,\n\t\t_fnSortData: _fnSortData,\n\t\t_fnSaveState: _fnSaveState,\n\t\t_fnLoadState: _fnLoadState,\n\t\t_fnSettingsFromNode: _fnSettingsFromNode,\n\t\t_fnLog: _fnLog,\n\t\t_fnMap: _fnMap,\n\t\t_fnBindAction: _fnBindAction,\n\t\t_fnCallbackReg: _fnCallbackReg,\n\t\t_fnCallbackFire: _fnCallbackFire,\n\t\t_fnLengthOverflow: _fnLengthOverflow,\n\t\t_fnRenderer: _fnRenderer,\n\t\t_fnDataSource: _fnDataSource,\n\t\t_fnRowAttributes: _fnRowAttributes,\n\t\t_fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant\n\t\t                                // in 1.10, so this dead-end function is\n\t\t                                // added to prevent errors\n\t} );\n\t\n\n\t// jQuery access\n\t$.fn.dataTable = DataTable;\n\n\t// Provide access to the host jQuery object (circular reference)\n\tDataTable.$ = $;\n\n\t// Legacy aliases\n\t$.fn.dataTableSettings = DataTable.settings;\n\t$.fn.dataTableExt = DataTable.ext;\n\n\t// With a capital `D` we return a DataTables API instance rather than a\n\t// jQuery object\n\t$.fn.DataTable = function ( opts ) {\n\t\treturn $(this).dataTable( opts ).api();\n\t};\n\n\t// All properties that are available to $.fn.dataTable should also be\n\t// available on $.fn.DataTable\n\t$.each( DataTable, function ( prop, val ) {\n\t\t$.fn.DataTable[ prop ] = val;\n\t} );\n\n\n\t// Information about events fired by DataTables - for documentation.\n\t/**\n\t * Draw event, fired whenever the table is redrawn on the page, at the same\n\t * point as fnDrawCallback. This may be useful for binding events or\n\t * performing calculations when the table is altered at all.\n\t *  @name DataTable#draw.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Search event, fired when the searching applied to the table (using the\n\t * built-in global search, or column filters) is altered.\n\t *  @name DataTable#search.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page change event, fired when the paging of the table is altered.\n\t *  @name DataTable#page.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Order event, fired when the ordering applied to the table is altered.\n\t *  @name DataTable#order.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * DataTables initialisation complete event, fired when the table is fully\n\t * drawn, including Ajax data loaded, if Ajax data is required.\n\t *  @name DataTable#init.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The JSON object request from the server - only\n\t *    present if client-side Ajax sourced data is used</li></ol>\n\t */\n\n\t/**\n\t * State save event, fired when the table has changed state a new state save\n\t * is required. This event allows modification of the state saving object\n\t * prior to actually doing the save, including addition or other state\n\t * properties (for plug-ins) or modification of a DataTables core property.\n\t *  @name DataTable#stateSaveParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The state information to be saved\n\t */\n\n\t/**\n\t * State load event, fired when the table is loading state from the stored\n\t * data, but prior to the settings object being modified by the saved state\n\t * - allowing modification of the saved state is required or loading of\n\t * state for a plug-in.\n\t *  @name DataTable#stateLoadParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * State loaded event, fired when state has been loaded from stored data and\n\t * the settings object has been modified by the loaded data.\n\t *  @name DataTable#stateLoaded.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * Processing event, fired when DataTables is doing some kind of processing\n\t * (be it, order, searcg or anything else). It can be used to indicate to\n\t * the end user that there is something happening, or that something has\n\t * finished.\n\t *  @name DataTable#processing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {boolean} bShow Flag for if DataTables is doing processing or not\n\t */\n\n\t/**\n\t * Ajax (XHR) event, fired whenever an Ajax request is completed from a\n\t * request to made to the server for new data. This event is called before\n\t * DataTables processed the returned data, so it can also be used to pre-\n\t * process the data returned from the server, if needed.\n\t *\n\t * Note that this trigger is called in `fnServerData`, if you override\n\t * `fnServerData` and which to use this event, you need to trigger it in you\n\t * success function.\n\t *  @name DataTable#xhr.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {object} json JSON returned from the server\n\t *\n\t *  @example\n\t *     // Use a custom property returned from the server in another DOM element\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       $('#status').html( json.status );\n\t *     } );\n\t *\n\t *  @example\n\t *     // Pre-process the data returned from the server\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {\n\t *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;\n\t *       }\n\t *       // Note no return - manipulate the data directly in the JSON object.\n\t *     } );\n\t */\n\n\t/**\n\t * Destroy event, fired when the DataTable is destroyed by calling fnDestroy\n\t * or passing the bDestroy:true parameter in the initialisation object. This\n\t * can be used to remove bound events, added DOM nodes, etc.\n\t *  @name DataTable#destroy.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page length change event, fired when number of records to show on each\n\t * page (the length) is changed.\n\t *  @name DataTable#length.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {integer} len New length\n\t */\n\n\t/**\n\t * Column sizing has changed.\n\t *  @name DataTable#column-sizing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Column visibility has changed.\n\t *  @name DataTable#column-visibility.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {int} column Column index\n\t *  @param {bool} vis `false` if column now hidden, or `true` if visible\n\t */\n\n\treturn $.fn.dataTable;\n}));\n\n\n"
  },
  {
    "path": "platforms/browser/www/partial/about-help.html",
    "content": "<div class=\"mdl-cell mdl-cell--12-col mdl-card mdl-shadow--4dp\">\n    <div class=\"mdl-card__title\">\n        <h2 class=\"mdl-card__title-text\">About & Help</h2>\n    </div>\n\n    <div class=\"mdl-card__supporting-text\">\n        <h5><i class=\"material-icons\">bug_report</i> Bugs? Feedback?</h5>\n        <p>Please, fell free to write me an issue on the <a href=\"https://github.com/friimaind?tab=repositories\">Github project page</a>.</p>\n        \n        <hr />\n        \n        <h5><i class=\"material-icons\">help_outline</i> Help</h5>        \n        <p>If you get here you need help to find the credential for your Pi-hole. It's very easy!</p>\n        <p>On the App setting page you need to insert the <strong>IP of your Pi-hole</strong> (for example http://192.168.1.2) or the <strong>hostname</strong> (for example http://mypyhole.local). Note that you can also specify a <strong>custom port</strong> with this format http://192.168.1.2:99 and obviously you can use <strong>https</strong>.</p>\n        <p>The <strong>token string</strong> is required for access the Pi-hole's API and extract charts, table etc.<br />These credentials are <strong>saved locally</strong> on your smartphone.</p>\n        <p>To obtain the token string you can access to the admin web page of your Pi-hole and <strong>scan the QR code</strong> with your smartphone:</p>\n        <ul>\n            <li>Connect to your Pi-hole with a computer: http://RASPBERRY_IP/admin</li>\n            <li>Login and go to Settings</li>\n            <li>On the API tab click on \"Show API token\". It will open a new page with the QR code</li>\n            <li>On your smartphone click on the QR code scan icon near the token field</li>\n        </ul>\n        <p><em>Please note:</em> \"Show API token\" function is present on Pi-hole >= 2.5 Web Interface Version.</p>\n        <p>You can even obtain the token string with a manual operation: the token string is inside your Raspberry, I suggest you to use a PC and paste it inside Google Keep or any other shared app with your smartphone.</p>\n        <ul>\n            <li>Connect to your Pi-hole with SSH.<br /><pre class=\"language-markup\"><code>ssh pi@RASPBERRY_IP</code></pre></li>\n            <li>Look at the configuration file<br /><pre class=\"language-markup\"><code>less /etc/pihole/setupVars.conf</code></pre></li>\n            <li>The token is the long string after the <strong>WEBPASSWORD=</strong></li>\n        </ul>\n        \n        <hr />\n        \n        <h5><i class=\"material-icons\">android</i> About this app</h5>\n        <p>First of all: <strong>thank you</strong> for trying this app!</p>\n        <p>I'm <a href=\"https://blog.friimaind.it\">Massimiliano Monaro</a> and I developed this app as a playground to learn Apache Cordova.</p>\n        <p>I am not affiliated to Pi-hole team, this is an unofficial app.</p>\n        <p>It would not have been possible to develop it without the help of some great tools:</p>\n        <ul>\n            <li><a href=\"https://pi-hole.net\">Pi-hole</a>: the main protagonist, it saves my daily web browsing.</li>\n            <li><a href=\"https://cordova.apache.org\">Apache Cordova</a>: this great framework gave me the opportunity to use my favorite languages to develop this native app.</li>\n            <li><a href=\"https://jquery.com\">jQuery</a>: 90% of the app is made with this library.</li>\n            <li><a href=\"https://gionkunz.github.io/chartist-js\">Chartist JS</a>: all charts is made with this wonderful library.</li>\n            <li><a href=\"https://getmdl.io\">MDL</a>: this library helped me to create the graphic interface of the app.</li>\n            <li><a href=\"https://datatables.net\">DataTables</a>: the Query Log page is handled by this jQuery plugin.</li>\n            <li><a href=\"http://hammerjs.github.io\">Hammer.js</a>: the library to recognize touch gestures.</li>\n        </ul>\n        <p>Lastly, I would like to thank my <strong>girlfriend Elisa</strong> who pushes me to accomplish things I love and my former colleague and friend <a href=\"https://melodycode.com/\">Daniele Simonin</a> for his technical help.</p>\n        <p>On Github you can find the <a href=\"https://github.com/friimaind/pi-hole-droid/blob/master/PRIVACY.MD\">Privacy Policy</a>.</p>\n    </div>   \n</div>"
  },
  {
    "path": "platforms/browser/www/partial/app-settings.html",
    "content": "<div class=\"mdl-cell mdl-cell--12-col mdl-card mdl-shadow--4dp\">\n    <div class=\"mdl-card__title\">\n        <h2 class=\"mdl-card__title-text\">Settings</h2>\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">vpn_key</i>\n    </div>\n\n    <div class=\"mdl-card__supporting-text\">\n        <p>Please insert here your Pi-hole settings.</p>\n        <p>To obtain the token you can <strong>scan your Pi-hole's QR code</strong> from the admin web page. Click on the icon near the token field.</p>\n        <p>Need help? <a href=\"#/\" id=\"go_to_help\">Go to the Help page</a></p>\n        <form id=\"form_settings\" class=\"fullwidth\" method=\"POST\">\n            <div class=\"mdl-textfield mdl-js-textfield mdl-textfield--floating-label\">\n                <input class=\"mdl-textfield__input\" type=\"url\" id=\"pihole_host\">\n                <label class=\"mdl-textfield__label\" for=\"pihole_host\">Pi-hole's IP or hostname</label>                \n            </div>\n            <div class=\"mdl-textfield mdl-js-textfield mdl-textfield--floating-label\">\n                <input class=\"mdl-textfield__input\" type=\"text\" id=\"pihole_token\">\n                <label class=\"mdl-textfield__label\" for=\"pihole_token\">Pi-hole's token string</label>\n                <img id=\"qrcode_scan\" src=\"img/qrcode-scan.svg\" />\n            </div>\n            \n            <button type=\"submit\" class=\"mdl-button mdl-js-button mdl-button--raised mdl-button--accent\">                                \n                Save                \n            </button>\n        </form>\n    </div>\n\n    <dialog class=\"mdl-dialog\">\n        <h4 class=\"mdl-dialog__title\"><i class=\"material-icons mdl-color-text--red\">warning</i> Uhm...</h4>\n        <div class=\"mdl-dialog__content\">\n            <p>I'm sorry but I <strong>cannot connect</strong> to your Pi-hole.</p>\n            <p>Please insert a valid url (http://IP_OR_HOSTNAME) and the correct token.</p>\n        </div>\n        <div class=\"mdl-dialog__actions\">\n            <button type=\"button\" class=\"mdl-button close\">OK</button>\n        </div>\n    </dialog>\n</div>"
  },
  {
    "path": "platforms/browser/www/partial/dashboard.html",
    "content": "<div class=\"centered-element\">\n    <div id=\"ads_blocked_today\" class=\"pihole-card pihole-card-floating mdl-card mdl-shadow--2dp bg-aqua\">\n        <div class=\"mdl-card__title mdl-card--expand\">\n            <h2><i class=\"material-icons loading\">refresh</i></h2>\n        </div>    \n        <div class=\"mdl-card__actions mdl-card--border\">\n            DNS Queries Blocked Today\n\n            <div class=\"mdl-layout-spacer\"></div>\n            <i class=\"material-icons\">today</i>\n        </div>\n    </div>\n\n    <div id=\"dns_queries_today\" class=\"pihole-card pihole-card-floating mdl-card mdl-shadow--2dp bg-green\">\n        <div class=\"mdl-card__title mdl-card--expand\">\n            <h2><i class=\"material-icons loading\">refresh</i></h2>\n        </div>\n        <div class=\"mdl-card__actions mdl-card--border\">\n            DNS Queries Today\n\n            <div class=\"mdl-layout-spacer\"></div>\n            <i class=\"material-icons\">public</i>\n        </div>\n    </div>\n\n    <div id=\"ads_percentage_today\" class=\"pihole-card pihole-card-floating mdl-card mdl-shadow--2dp bg-yellow\">\n        <div class=\"mdl-card__title mdl-card--expand\">\n            <h2><i class=\"material-icons loading\">refresh</i></h2>\n        </div>\n        <div class=\"mdl-card__actions mdl-card--border\">\n            Of Today's Queries Were Blocked\n\n            <div class=\"mdl-layout-spacer\"></div>\n            <i class=\"material-icons\">block</i>\n        </div>\n    </div>\n\n    <div id=\"domains_being_blocked\" class=\"pihole-card pihole-card-floating mdl-card mdl-shadow--2dp bg-red\">\n        <div class=\"mdl-card__title mdl-card--expand\">\n            <h2><i class=\"material-icons loading\">refresh</i></h2>\n        </div>\n        <div class=\"mdl-card__actions mdl-card--border\">\n            Domains Being Blocked\n\n            <div class=\"mdl-layout-spacer\"></div>\n            <i class=\"material-icons\">list</i>\n        </div>\n    </div>\n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Query types\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card__title mdl-card--expand\">        \n        <div class=\"ct-chart ct-chart-query-types\"><i class=\"material-icons loading\">refresh</i></div>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Forward destinations\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">forward</i>\n    </div>\n    <div class=\"mdl-card__title mdl-card--expand\">\n        <div class=\"ct-chart ct-chart-forward-destinations\"><i class=\"material-icons loading\">refresh</i></div>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Top domains\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card--expand\">        \n        <table class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth\">\n            <thead>\n                <tr>\n                    <th class=\"mdl-data-table__cell--non-numeric fullwidth\">Domain</th>\n                    <th class=\"fullwidth\">Hit</th>\n                </tr>\n            </thead>\n            <tbody id=\"tbody-table-top-queries\">\n                <tr>\n                    <td colspan=\"2\">\n                        <p class=\"mdl-typography--text-center\">\n                            <i class=\"material-icons loading\">refresh</i>\n                        </p>\n                    </td>\n                </tr>\n            </tbody>\n        </table>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Top advertisers\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card--expand\">\n        <table class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth\">\n            <thead>\n                <tr>\n                    <th class=\"mdl-data-table__cell--non-numeric fullwidth\">Domain</th>\n                    <th class=\"fullwidth\">Hit</th>\n                </tr>\n            </thead>\n            <tbody id=\"tbody-table-top-ads\">\n                <tr>\n                    <td colspan=\"2\">\n                        <p class=\"mdl-typography--text-center\">\n                            <i class=\"material-icons loading\">refresh</i>\n                        </p>\n                    </td>\n                </tr>\n            </tbody>\n        </table>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Top clients\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card--expand\">\n        <table class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth\">\n            <thead>\n                <tr>\n                    <th class=\"mdl-data-table__cell--non-numeric fullwidth\">Client</th>\n                    <th class=\"fullwidth\">Hit</th>\n                </tr>\n            </thead>\n            <tbody id=\"tbody-table-top-clients\">\n                <tr>\n                    <td colspan=\"2\">\n                        <p class=\"mdl-typography--text-center\">\n                            <i class=\"material-icons loading\">refresh</i>\n                        </p>\n                    </td>\n                </tr>\n            </tbody>\n            </tbody>\n        </table>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Recent items\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card--expand\">\n        <p class=\"please-rotate mdl-typography--text-center\">\n            <span class=\"mdl-chip mdl-chip--contact\">\n                <span class=\"mdl-chip__contact mdl-color--indigo mdl-color-text--white material-icons\">rotate_left</span>\n                <span class=\"mdl-chip__text\">Please rotate your device</span>\n            </span>\n        </p>\n        <table class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth force-landscape\">            \n            <thead>\n                <tr>\n                    <th class=\"mdl-data-table__cell--non-numeric fullwidth\">Time</th>\n                    <th>Domain</th>\n                    <th>IP</th>\n                </tr>\n            </thead>\n            <tbody id=\"tbody-table-recent-items\">\n                <tr>\n                    <td colspan=\"3\">\n                        <p class=\"mdl-typography--text-center\">\n                            <i class=\"material-icons loading\">refresh</i>\n                        </p>\n                    </td>\n                </tr>\n            </tbody>            \n        </table>\n    </div>    \n</div>"
  },
  {
    "path": "platforms/browser/www/partial/query-log.html",
    "content": "<p class=\"please-rotate mdl-typography--text-center\">\n    <span class=\"mdl-chip mdl-chip--contact\">\n        <span class=\"mdl-chip__contact mdl-color--indigo mdl-color-text--white material-icons\">rotate_left</span>\n        <span class=\"mdl-chip__text\">Please rotate your device</span>\n    </span>\n</p>\n\n<div class=\"force-landscape\">\n    <p class=\"mdl-typography--text-center\">\n        <span class=\"mdl-chip mdl-chip--contact mdl-please-wait\">\n            <span class=\"mdl-chip__contact mdl-color--indigo mdl-color-text--white\"><i class=\"material-icons loading\">refresh</i></span>\n            <span class=\"mdl-chip__text\">Please wait, there are a lot of data to be processed.</span>\n        </span>\n    </p>\n    \n    <table id=\"query-log-table\" class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth\" cellspacing=\"0\" width=\"100%\"></table>\n</div>"
  },
  {
    "path": "platforms/browser/www/platform.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nmodule.exports = {\n    id: 'browser',\n    cordovaVersion: '3.4.0',\n\n    bootstrap: function() {\n\n        var modulemapper = require('cordova/modulemapper');\n        var channel = require('cordova/channel');\n\n        modulemapper.clobbers('cordova/exec/proxy', 'cordova.commandProxy');\n\n        channel.onNativeReady.fire();\n\n        // FIXME is this the right place to clobber pause/resume? I am guessing not\n        // FIXME pause/resume should be deprecated IN CORDOVA for pagevisiblity api\n        document.addEventListener('webkitvisibilitychange', function() {\n            if (document.webkitHidden) {\n                channel.onPause.fire();\n            }\n            else {\n                channel.onResume.fire();\n            }\n        }, false);\n\n    // End of bootstrap\n    }\n};\n"
  },
  {
    "path": "platforms/browser/www/plugins/cordova-plugin-splashscreen/src/browser/SplashScreenProxy.js",
    "content": "cordova.define(\"cordova-plugin-splashscreen.SplashScreenProxy\", function(require, exports, module) { /*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n// Default parameter values including image size can be changed in `config.xml`\nvar splashImageWidth = 170;\nvar splashImageHeight = 200;\nvar position = { x: 0, y: 0, width: splashImageWidth, height: splashImageHeight }; \nvar localSplash; // the image to display\nvar localSplashImage;\nvar bgColor = \"#464646\";\nvar imageSrc = '/img/logo.png';\nvar splashScreenDelay = 3000; // in milliseconds\nvar showSplashScreen = true; // show splashcreen by default\nvar cordova = require('cordova');\nvar configHelper = cordova.require('cordova/confighelper');\n\nfunction updateImageLocation() {\n    position.width = Math.min(splashImageWidth, window.innerWidth);\n    position.height = position.width * (splashImageHeight / splashImageWidth);\n\n    localSplash.style.width = window.innerWidth + \"px\";\n    localSplash.style.height = window.innerHeight + \"px\";\n    localSplash.style.top = \"0px\";\n    localSplash.style.left = \"0px\";\n\n    localSplashImage.style.top = \"50%\";\n    localSplashImage.style.left = \"50%\";\n    localSplashImage.style.height = position.height + \"px\";\n    localSplashImage.style.width = position.width + \"px\";\n    localSplashImage.style.marginTop = (-position.height / 2) + \"px\";\n    localSplashImage.style.marginLeft = (-position.width / 2) + \"px\";\n}\n\nfunction onResize() {\n    updateImageLocation();\n}\n\nvar SplashScreen = {\n    setBGColor: function (cssBGColor) {\n        bgColor = cssBGColor;\n        if (localSplash) {\n            localSplash.style.backgroundColor = bgColor;\n        }\n    },\n    show: function () {\n        if(!localSplash) {\n            window.addEventListener(\"resize\", onResize, false);\n            localSplash = document.createElement(\"div\");\n            localSplash.style.backgroundColor = bgColor;\n            localSplash.style.position = \"absolute\";\n\n            localSplashImage = document.createElement(\"img\");\n            localSplashImage.src = imageSrc;\n            localSplashImage.style.position = \"absolute\";\n\n            updateImageLocation();\n\n            localSplash.appendChild(localSplashImage);\n            document.body.appendChild(localSplash);\n        }\n    },\n    hide: function () {\n        if(localSplash) {\n            window.removeEventListener(\"resize\", onResize, false);\n            document.body.removeChild(localSplash);\n            localSplash = null;\n        }\n    }\n};\n\n/**\n * Reads preferences via ConfigHelper and substitutes default parameters.\n */\nfunction readPreferencesFromCfg(cfg) {\n    try {\n        var value = cfg.getPreferenceValue('ShowSplashScreen');\n        if(typeof value != 'undefined') {\n            showSplashScreen = value === 'true';\n        }\n\n        splashScreenDelay = cfg.getPreferenceValue('SplashScreenDelay') || splashScreenDelay;\n        imageSrc = cfg.getPreferenceValue('SplashScreen') || imageSrc;\n        bgColor = cfg.getPreferenceValue('SplashScreenBackgroundColor') || bgColor;\n        splashImageWidth = cfg.getPreferenceValue('SplashScreenWidth') || splashImageWidth;\n        splashImageHeight = cfg.getPreferenceValue('SplashScreenHeight') || splashImageHeight;\n    } catch(e) {\n        var msg = '[Browser][SplashScreen] Error occured on loading preferences from config.xml: ' + JSON.stringify(e);\n        console.error(msg);\n    }\n}\n\n/**\n * Shows and hides splashscreen if it is enabled, with a delay according the current preferences.\n */\nfunction showAndHide() {\n    if(showSplashScreen) {\n        SplashScreen.show();\n\n        window.setTimeout(function() {\n            SplashScreen.hide();\n        }, splashScreenDelay);\n    }\n}\n\n/**\n * Tries to read config.xml and override default properties and then shows and hides splashcreen if it is enabled.\n */\n(function initAndShow() {\n    configHelper.readConfig(function(config) {\n        readPreferencesFromCfg(config);\n        showAndHide();\n    }, function(err) {\n        console.error(err);\n    });\n})();\n\nmodule.exports = SplashScreen;\n\nrequire(\"cordova/exec/proxy\").add(\"SplashScreen\", SplashScreen);\n\n\n});\n"
  },
  {
    "path": "platforms/browser/www/plugins/cordova-plugin-splashscreen/www/splashscreen.js",
    "content": "cordova.define(\"cordova-plugin-splashscreen.SplashScreen\", function(require, exports, module) { /*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nvar exec = require('cordova/exec');\n\nvar splashscreen = {\n    show:function() {\n        exec(null, null, \"SplashScreen\", \"show\", []);\n    },\n    hide:function() {\n        exec(null, null, \"SplashScreen\", \"hide\", []);\n    }\n};\n\nmodule.exports = splashscreen;\n\n});\n"
  },
  {
    "path": "platforms/browser/www/plugins/phonegap-plugin-barcodescanner/src/browser/BarcodeScannerProxy.js",
    "content": "cordova.define(\"phonegap-plugin-barcodescanner.BarcodeScannerProxy\", function(require, exports, module) { function scan(success, error) {\n    var code = window.prompt(\"Enter barcode value (empty value will fire the error handler):\");\n    if(code) {\n        var result = {\n            text:code,\n            format:\"Fake\",\n            cancelled:false\n        };\n        success(result);\n    } else {\n        error(\"No barcode\");\n    }\n}\n\nfunction encode(type, data, success, errorCallback) {\n    success();\n}\n\nmodule.exports = {\n    scan: scan,\n    encode: encode\n};\n\nrequire(\"cordova/exec/proxy\").add(\"BarcodeScanner\",module.exports);\n});\n"
  },
  {
    "path": "platforms/browser/www/plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js",
    "content": "cordova.define(\"phonegap-plugin-barcodescanner.BarcodeScanner\", function(require, exports, module) { /**\n * cordova is available under *either* the terms of the modified BSD license *or* the\n * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.\n *\n * Copyright (c) Matt Kane 2010\n * Copyright (c) 2011, IBM Corporation\n */\n\n\n        var exec = cordova.require(\"cordova/exec\");\n\n        var scanInProgress = false;\n\n        /**\n         * Constructor.\n         *\n         * @returns {BarcodeScanner}\n         */\n        function BarcodeScanner() {\n\n            /**\n             * Encoding constants.\n             *\n             * @type Object\n             */\n            this.Encode = {\n                TEXT_TYPE: \"TEXT_TYPE\",\n                EMAIL_TYPE: \"EMAIL_TYPE\",\n                PHONE_TYPE: \"PHONE_TYPE\",\n                SMS_TYPE: \"SMS_TYPE\"\n                //  CONTACT_TYPE: \"CONTACT_TYPE\",  // TODO:  not implemented, requires passing a Bundle class from Javascript to Java\n                //  LOCATION_TYPE: \"LOCATION_TYPE\" // TODO:  not implemented, requires passing a Bundle class from Javascript to Java\n            };\n\n    /**\n     * Barcode format constants, defined in ZXing library.\n     *\n     * @type Object\n     */\n    this.format = {\n        \"all_1D\": 61918,\n        \"aztec\": 1,\n        \"codabar\": 2,\n        \"code_128\": 16,\n        \"code_39\": 4,\n        \"code_93\": 8,\n        \"data_MATRIX\": 32,\n        \"ean_13\": 128,\n        \"ean_8\": 64,\n        \"itf\": 256,\n        \"maxicode\": 512,\n        \"msi\": 131072,\n        \"pdf_417\": 1024,\n        \"plessey\": 262144,\n        \"qr_CODE\": 2048,\n        \"rss_14\": 4096,\n        \"rss_EXPANDED\": 8192,\n        \"upc_A\": 16384,\n        \"upc_E\": 32768,\n        \"upc_EAN_EXTENSION\": 65536\n        };\n  }\n\n/**\n * Read code from scanner.\n *\n * @param {Function} successCallback This function will recieve a result object: {\n         *        text : '12345-mock',    // The code that was scanned.\n         *        format : 'FORMAT_NAME', // Code format.\n         *        cancelled : true/false, // Was canceled.\n         *    }\n * @param {Function} errorCallback\n * @param config\n */\nBarcodeScanner.prototype.scan = function (successCallback, errorCallback, config) {\n\n            if (config instanceof Array) {\n                // do nothing\n            } else {\n                if (typeof(config) === 'object') {\n                    config = [ config ];\n                } else {\n                    config = [];\n                }\n            }\n\n            if (errorCallback == null) {\n                errorCallback = function () {\n                };\n            }\n\n            if (typeof errorCallback != \"function\") {\n                console.log(\"BarcodeScanner.scan failure: failure parameter not a function\");\n                return;\n            }\n\n            if (typeof successCallback != \"function\") {\n                console.log(\"BarcodeScanner.scan failure: success callback parameter must be a function\");\n                return;\n            }\n\n            if (scanInProgress) {\n                errorCallback('Scan is already in progress');\n                return;\n            }\n\n            scanInProgress = true;\n\n            exec(\n                function(result) {\n                    scanInProgress = false;\n                    successCallback(result);\n                },\n                function(error) {\n                    scanInProgress = false;\n                    errorCallback(error);\n                },\n                'BarcodeScanner',\n                'scan',\n                config\n            );\n        };\n\n        //-------------------------------------------------------------------\n        BarcodeScanner.prototype.encode = function (type, data, successCallback, errorCallback, options) {\n            if (errorCallback == null) {\n                errorCallback = function () {\n                };\n            }\n\n            if (typeof errorCallback != \"function\") {\n                console.log(\"BarcodeScanner.encode failure: failure parameter not a function\");\n                return;\n            }\n\n            if (typeof successCallback != \"function\") {\n                console.log(\"BarcodeScanner.encode failure: success callback parameter must be a function\");\n                return;\n            }\n\n            exec(successCallback, errorCallback, 'BarcodeScanner', 'encode', [\n                {\"type\": type, \"data\": data, \"options\": options}\n            ]);\n        };\n\n        var barcodeScanner = new BarcodeScanner();\n        module.exports = barcodeScanner;\n\n});\n"
  },
  {
    "path": "platforms/platforms.json",
    "content": "{\n    \"browser\": \"4.1.0\",\n    \"android\": \"6.2.1\"\n}"
  },
  {
    "path": "plugins/android.json",
    "content": "{\n    \"prepare_queue\": {\n        \"installed\": [],\n        \"uninstalled\": []\n    },\n    \"config_munge\": {\n        \"files\": {}\n    },\n    \"installed_plugins\": {\n        \"cordova-plugin-splashscreen\": {\n            \"PACKAGE_NAME\": \"friimaind.piholedroid\"\n        },\n        \"cordova-plugin-whitelist\": {\n            \"PACKAGE_NAME\": \"friimaind.piholedroid\"\n        },\n        \"phonegap-plugin-barcodescanner\": {\n            \"PACKAGE_NAME\": \"friimaind.piholedroid\"\n        }\n    },\n    \"dependent_plugins\": {\n        \"cordova-plugin-compat\": {\n            \"PACKAGE_NAME\": \"friimaind.piholedroid\"\n        }\n    }\n}"
  },
  {
    "path": "plugins/browser.json",
    "content": "{\n    \"prepare_queue\": {\n        \"installed\": [],\n        \"uninstalled\": []\n    },\n    \"config_munge\": {\n        \"files\": {}\n    },\n    \"installed_plugins\": {\n        \"cordova-plugin-whitelist\": {\n            \"PACKAGE_NAME\": \"io.cordova.hellocordova\"\n        },\n        \"cordova-plugin-splashscreen\": {\n            \"PACKAGE_NAME\": \"friimaind.piholedroid\"\n        },\n        \"phonegap-plugin-barcodescanner\": {\n            \"PACKAGE_NAME\": \"friimaind.piholedroid\"\n        }\n    },\n    \"dependent_plugins\": {}\n}"
  },
  {
    "path": "plugins/cordova-plugin-compat/README.md",
    "content": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#  KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n#\n-->\n\ncordova-plugin-compat\n------------------------\n\nThis repo is for remaining backwards compatible with previous versions of Cordova.\n\n## USAGE\n\nYour plugin can depend on this plugin and use it to handle the new run time permissions Android 6.0.0 (cordova-android 5.0.0) introduced. \n\nView [this commit](https://github.com/apache/cordova-plugin-camera/commit/a9c18710f23e86f5b7f8918dfab7c87a85064870) to see how to depend on `cordova-plugin-compat`. View [this file](https://github.com/apache/cordova-plugin-camera/blob/master/src/android/CameraLauncher.java) to see how `PermissionHelper` is being used to request and store permissions. Read more about Android permissions at http://cordova.apache.org/docs/en/latest/guide/platforms/android/plugin.html#android-permissions.\n"
  },
  {
    "path": "plugins/cordova-plugin-compat/RELEASENOTES.md",
    "content": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n# \n# http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#  KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n#\n-->\n# Release Notes\n\n### 1.1.0 (Nov 02, 2016)\n* [CB-11625](https://issues.apache.org/jira/browse/CB-11625) Adding the `BuildConfig` fetching code as a backup to using a new preference\n* Add github pull request template\n\n### 1.0.0 (Apr 15, 2016)\n* Initial release\n* Moved `PermissionHelper.java` into `src`\n"
  },
  {
    "path": "plugins/cordova-plugin-compat/package.json",
    "content": "{\n    \"name\": \"cordova-plugin-compat\",\n    \"description\": \"This repo is for remaining backwards compatible with previous versions of Cordova.\",\n    \"version\": \"1.1.0\",\n    \"homepage\": \"http://github.com/apache/cordova-plugin-compat#readme\",\n    \"repository\": {\n        \"type\": \"git\",\n        \"url\": \"git://github.com/apache/cordova-plugin-compat.git\"\n    },\n    \"bugs\": {\n        \"url\": \"https://github.com/apache/cordova-plugin-compat/issues\"\n    },\n    \"cordova\": {\n        \"id\": \"cordova-plugin-compat\",\n        \"platforms\": [\n            \"android\"\n        ]\n    },\n    \"keywords\": [\n        \"ecosystem:cordova\",\n        \"ecosystem:phonegap\",\n        \"cordova-android\"\n    ],\n    \"engines\": [\n        {\n            \"name\": \"cordova\",\n            \"version\": \">=5.0.0\"\n        }\n    ],\n    \"author\": \"Apache Software Foundation\",\n    \"license\": \"Apache-2.0\"\n}\n"
  },
  {
    "path": "plugins/cordova-plugin-compat/plugin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one\n  or more contributor license agreements.  See the NOTICE file\n  distributed with this work for additional information\n  regarding copyright ownership.  The ASF licenses this file\n  to you under the Apache License, Version 2.0 (the\n  \"License\"); you may not use this file except in compliance\n  with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an\n  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n  KIND, either express or implied.  See the License for the\n  specific language governing permissions and limitations\n  under the License.\n-->\n\n<plugin xmlns=\"http://cordova.apache.org/ns/plugins/1.0\"\n           id=\"cordova-plugin-compat\"\n      version=\"1.1.0\">\n    <name>Compat</name>\n    <description>Cordova Compatibility Plugin</description>\n    <license>Apache 2.0</license>\n    <keywords>cordova,compat</keywords>\n    <repo>https://git-wip-us.apache.org/repos/asf/cordova-plugin-compat.git</repo>\n\n    <!-- android -->\n    <platform name=\"android\">\n      <source-file src=\"src/android/PermissionHelper.java\" target-dir=\"src/org/apache/cordova\" />\n      <source-file src=\"src/android/BuildHelper.java\" target-dir=\"src/org/apache/cordova\" />\n    </platform>\n\n</plugin>\n"
  },
  {
    "path": "plugins/cordova-plugin-compat/src/android/BuildHelper.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova;\n\n/*\n * This is a utility class that allows us to get the BuildConfig variable, which is required\n * for the use of different providers.  This is not guaranteed to work, and it's better for this\n * to be set in the build step in config.xml\n *\n */\n\nimport android.app.Activity;\nimport android.content.Context;\n\nimport java.lang.reflect.Field;\n\n\npublic class BuildHelper {\n\n\n    private static String TAG=\"BuildHelper\";\n\n    /*\n     * This needs to be implemented if you wish to use the Camera Plugin or other plugins\n     * that read the Build Configuration.\n     *\n     * Thanks to Phil@Medtronic and Graham Borland for finding the answer and posting it to\n     * StackOverflow.  This is annoying as hell!  However, this method does not work with\n     * ProGuard, and you should use the config.xml to define the application_id\n     *\n     */\n\n    public static Object getBuildConfigValue(Context ctx, String key)\n    {\n        try\n        {\n            Class<?> clazz = Class.forName(ctx.getPackageName() + \".BuildConfig\");\n            Field field = clazz.getField(key);\n            return field.get(null);\n        } catch (ClassNotFoundException e) {\n            LOG.d(TAG, \"Unable to get the BuildConfig, is this built with ANT?\");\n            e.printStackTrace();\n        } catch (NoSuchFieldException e) {\n            LOG.d(TAG, key + \" is not a valid field. Check your build.gradle\");\n        } catch (IllegalAccessException e) {\n            LOG.d(TAG, \"Illegal Access Exception: Let's print a stack trace.\");\n            e.printStackTrace();\n        }\n\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "plugins/cordova-plugin-compat/src/android/PermissionHelper.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\npackage org.apache.cordova;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\n\nimport org.apache.cordova.CordovaInterface;\nimport org.apache.cordova.CordovaPlugin;\nimport org.apache.cordova.LOG;\n\nimport android.content.pm.PackageManager;\n\n/**\n * This class provides reflective methods for permission requesting and checking so that plugins\n * written for cordova-android 5.0.0+ can still compile with earlier cordova-android versions.\n */\npublic class PermissionHelper {\n    private static final String LOG_TAG = \"CordovaPermissionHelper\";\n\n    /**\n     * Requests a \"dangerous\" permission for the application at runtime. This is a helper method\n     * alternative to cordovaInterface.requestPermission() that does not require the project to be\n     * built with cordova-android 5.0.0+\n     *\n     * @param plugin        The plugin the permission is being requested for\n     * @param requestCode   A requestCode to be passed to the plugin's onRequestPermissionResult()\n     *                      along with the result of the permission request\n     * @param permission    The permission to be requested\n     */\n    public static void requestPermission(CordovaPlugin plugin, int requestCode, String permission) {\n        PermissionHelper.requestPermissions(plugin, requestCode, new String[] {permission});\n    }\n\n    /**\n     * Requests \"dangerous\" permissions for the application at runtime. This is a helper method\n     * alternative to cordovaInterface.requestPermissions() that does not require the project to be\n     * built with cordova-android 5.0.0+\n     *\n     * @param plugin        The plugin the permissions are being requested for\n     * @param requestCode   A requestCode to be passed to the plugin's onRequestPermissionResult()\n     *                      along with the result of the permissions request\n     * @param permissions   The permissions to be requested\n     */\n    public static void requestPermissions(CordovaPlugin plugin, int requestCode, String[] permissions) {\n        try {\n            Method requestPermission = CordovaInterface.class.getDeclaredMethod(\n                    \"requestPermissions\", CordovaPlugin.class, int.class, String[].class);\n\n            // If there is no exception, then this is cordova-android 5.0.0+\n            requestPermission.invoke(plugin.cordova, plugin, requestCode, permissions);\n        } catch (NoSuchMethodException noSuchMethodException) {\n            // cordova-android version is less than 5.0.0, so permission is implicitly granted\n            LOG.d(LOG_TAG, \"No need to request permissions \" + Arrays.toString(permissions));\n\n            // Notify the plugin that all were granted by using more reflection\n            deliverPermissionResult(plugin, requestCode, permissions);\n        } catch (IllegalAccessException illegalAccessException) {\n            // Should never be caught; this is a public method\n            LOG.e(LOG_TAG, \"IllegalAccessException when requesting permissions \" + Arrays.toString(permissions), illegalAccessException);\n        } catch(InvocationTargetException invocationTargetException) {\n            // This method does not throw any exceptions, so this should never be caught\n            LOG.e(LOG_TAG, \"invocationTargetException when requesting permissions \" + Arrays.toString(permissions), invocationTargetException);\n        }\n    }\n\n    /**\n     * Checks at runtime to see if the application has been granted a permission. This is a helper\n     * method alternative to cordovaInterface.hasPermission() that does not require the project to\n     * be built with cordova-android 5.0.0+\n     *\n     * @param plugin        The plugin the permission is being checked against\n     * @param permission    The permission to be checked\n     *\n     * @return              True if the permission has already been granted and false otherwise\n     */\n    public static boolean hasPermission(CordovaPlugin plugin, String permission) {\n        try {\n            Method hasPermission = CordovaInterface.class.getDeclaredMethod(\"hasPermission\", String.class);\n\n            // If there is no exception, then this is cordova-android 5.0.0+\n            return (Boolean) hasPermission.invoke(plugin.cordova, permission);\n        } catch (NoSuchMethodException noSuchMethodException) {\n            // cordova-android version is less than 5.0.0, so permission is implicitly granted\n            LOG.d(LOG_TAG, \"No need to check for permission \" + permission);\n            return true;\n        } catch (IllegalAccessException illegalAccessException) {\n            // Should never be caught; this is a public method\n            LOG.e(LOG_TAG, \"IllegalAccessException when checking permission \" + permission, illegalAccessException);\n        } catch(InvocationTargetException invocationTargetException) {\n            // This method does not throw any exceptions, so this should never be caught\n            LOG.e(LOG_TAG, \"invocationTargetException when checking permission \" + permission, invocationTargetException);\n        }\n        return false;\n    }\n\n    private static void deliverPermissionResult(CordovaPlugin plugin, int requestCode, String[] permissions) {\n        // Generate the request results\n        int[] requestResults = new int[permissions.length];\n        Arrays.fill(requestResults, PackageManager.PERMISSION_GRANTED);\n\n        try {\n            Method onRequestPermissionResult = CordovaPlugin.class.getDeclaredMethod(\n                    \"onRequestPermissionResult\", int.class, String[].class, int[].class);\n\n            onRequestPermissionResult.invoke(plugin, requestCode, permissions, requestResults);\n        } catch (NoSuchMethodException noSuchMethodException) {\n            // Should never be caught since the plugin must be written for cordova-android 5.0.0+ if it\n            // made it to this point\n            LOG.e(LOG_TAG, \"NoSuchMethodException when delivering permissions results\", noSuchMethodException);\n        } catch (IllegalAccessException illegalAccessException) {\n            // Should never be caught; this is a public method\n            LOG.e(LOG_TAG, \"IllegalAccessException when delivering permissions results\", illegalAccessException);\n        } catch(InvocationTargetException invocationTargetException) {\n            // This method may throw a JSONException. We are just duplicating cordova-android's\n            // exception handling behavior here; all it does is log the exception in CordovaActivity,\n            // print the stacktrace, and ignore it\n            LOG.e(LOG_TAG, \"InvocationTargetException when delivering permissions results\", invocationTargetException);\n        }\n    }\n}\n"
  },
  {
    "path": "plugins/cordova-plugin-compat/src/cordova-plugin-compat.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/android\" isTestSource=\"false\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/CONTRIBUTING.md",
    "content": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#  KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n#\n-->\n\n# Contributing to Apache Cordova\n\nAnyone can contribute to Cordova. And we need your contributions.\n\nThere are multiple ways to contribute: report bugs, improve the docs, and\ncontribute code.\n\nFor instructions on this, start with the \n[contribution overview](http://cordova.apache.org/contribute/).\n\nThe details are explained there, but the important items are:\n - Sign and submit an Apache ICLA (Contributor License Agreement).\n - Have a Jira issue open that corresponds to your contribution.\n - Run the tests so your patch doesn't break existing functionality.\n\nWe look forward to your contributions!\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/NOTICE",
    "content": "Apache Cordova\nCopyright 2012 The Apache Software Foundation\n\nThis product includes software developed at\nThe Apache Software Foundation (http://www.apache.org/).\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/README.md",
    "content": "---\ntitle: Splashscreen\ndescription: Control the splash screen for your app.\n---\n<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n|Android|iOS| Windows 8.1 Store | Windows 8.1 Phone | Windows 10 Store | Travis CI |\n|:-:|:-:|:-:|:-:|:-:|:-:|\n|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=android,PLUGIN=cordova-plugin-splashscreen)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=android,PLUGIN=cordova-plugin-splashscreen/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=ios,PLUGIN=cordova-plugin-splashscreen)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=ios,PLUGIN=cordova-plugin-splashscreen/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-8.1-store,PLUGIN=cordova-plugin-splashscreen)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-8.1-store,PLUGIN=cordova-plugin-splashscreen/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-8.1-phone,PLUGIN=cordova-plugin-splashscreen)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-8.1-phone,PLUGIN=cordova-plugin-splashscreen/)|[![Build Status](http://cordova-ci.cloudapp.net:8080/buildStatus/icon?job=cordova-periodic-build/PLATFORM=windows-10-store,PLUGIN=cordova-plugin-splashscreen)](http://cordova-ci.cloudapp.net:8080/job/cordova-periodic-build/PLATFORM=windows-10-store,PLUGIN=cordova-plugin-splashscreen/)|[![Build Status](https://travis-ci.org/apache/cordova-plugin-splashscreen.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-splashscreen)|\n\n# cordova-plugin-splashscreen\n\nThis plugin is required to work with splash screens. This plugin displays and hides a splash screen during application launch.\n\nReport issues with this plugin on the [Apache Cordova issue tracker][Apache Cordova issue tracker].\n\n## Installation\n\n    // npm hosted (new) id\n    cordova plugin add cordova-plugin-splashscreen\n\n    // you may also install directly from this repo\n    cordova plugin add https://github.com/apache/cordova-plugin-splashscreen.git\n\n## Supported Platforms\n\n- Amazon Fire OS\n- Android\n- BlackBerry 10\n- iOS\n- Windows Phone 7 and 8\n- Windows (`cordova-windows` version >= 4.4.0 is required)\n- Browser\n\n__Note__: Extended splashscreen does not require the plugin on Windows (as opposed to Android and iOS) in case you don't use the plugin API, i.e. programmatic hide/show.\n\n### iOS-specific information\n\nThere are two mechanisms for displaying a launch screen on iOS:\n\n1. Legacy launch images: images are sized exactly for the device's screen size. Does not support the iPad Pro 12.9's native resolution or split-screen/slide-over multitasking.\n\n2. Launch storyboard images: Images are sized based on scale, idiom, and size classes. Supports all devices, and can be used with split-screen/slide-over multitasking.\n\nApple is moving away from legacy launch images. There is no official support for providing a native-resolution launch image for the iPad Pro 12.9 or for providing launch images that work with split-screen multitasking or slide-over. If your app doesn't need to support these contexts, then you can continue to use legacy launch images for as long as you like. \n\nThe preferred method of providing launch images is to use a launch storyboard. For native app developers, the ideal launch storyboard is an unpopulated version of the app's user interface at launch. For non-native app developers who don't wish to learn Interface Builder, however, this plugin simulates the legacy launch image method as much as is feasible.\n\n#### Legacy launch images\n\nIf you choose to use legacy launch images, you will use the following syntax in `config.xml`:\n\n```\n    <splash src=\"res/screen/ios/Default~iphone.png\" width=\"320\" height=\"480\"/>\n    <splash src=\"res/screen/ios/Default@2x~iphone.png\" width=\"640\" height=\"960\"/>\n    <splash src=\"res/screen/ios/Default-Portrait~ipad.png\" width=\"768\" height=\"1024\"/>\n    <splash src=\"res/screen/ios/Default-Portrait@2x~ipad.png\" width=\"1536\" height=\"2048\"/>\n    <splash src=\"res/screen/ios/Default-Landscape~ipad.png\" width=\"1024\" height=\"768\"/>\n    <splash src=\"res/screen/ios/Default-Landscape@2x~ipad.png\" width=\"2048\" height=\"1536\"/>\n    <splash src=\"res/screen/ios/Default-568h@2x~iphone.png\" width=\"640\" height=\"1136\"/>\n    <splash src=\"res/screen/ios/Default-667h.png\" width=\"750\" height=\"1334\"/>\n    <splash src=\"res/screen/ios/Default-736h.png\" width=\"1242\" height=\"2208\"/>\n```\n\nTechnically the filename for the `src` attribute can be anything you want; the filenames are used because they match what will be used when your project is compiled. The width and height attributes determine which launch images are displayed on which devices as follows:\n\n|    width    |    height    |    device (orientation)   |\n|:-----------:|:------------:|:-------------------------:|\n|     320     |      480     | All non-retina iPhones and iPods |\n|     640     |      960     | iPhone 4/4s/5/5s (portrait)      |\n|     750     |     1334     | iPhone 6/6s/7 (portrait)         |\n|    1242     |     2208     | iPhone 6+/6s+/7+ (portrait)      |\n|    2208     |     1242     | iPhone 6+/6s+/7+ (landscape)     |\n|     768     |     1024     | All non-retina iPads (portrait)  |\n|    1024     |      768     | All non-retina iPads (landscape) |\n|    1536     |     2048     | All retina iPads (portrait)      |\n|    2048     |     1536     | All retina iPads (landscape)     |\n\nNote: It is vitally important that the source image actually matches the size specified in the `width` and `height` attributes. If it does not, the device may fail to render it properly, if at all.\n\n#### Launch storyboard images\n\nIn order to support newer form factors and split-screen/slide-over multitasking, you should use launch storyboard images. These are similar to the legacy launch images above, but there are crucial differences:\n\n - images are not specific to a given device.\n\n - images are scaled to fill the available viewport (while maintaining the aspect ratio).\n\n - the outer edges of the images will be cropped, and the amount will vary based on device an viewport.\n\n - there is no need to provide an image for each possible device, viewport, and orientation; iOS will choose the best image for the situation automatically.\n\n##### Designing launch storyboard images\n\nThe key to designing a launch storyboard image is understanding that the edges of the image will almost certainly be cropped. Therefore, one should not place any important information near the edges of any images provided to the launch storyboard. Only the center is a safe area, and this all but guarantees that following Apple's advice of presenting an unpopulated user interface will not work well.\n\nInstead, the following tips should enable you to create a launch image that works across a multitude of form factors, viewports, and orientations:\n\n - Important graphics (logos, icons, titles) should be centered. The safe bounding region will vary, so you will need to test to ensure that the important graphics are never cropped. Better yet, don't supply any important graphics in the first place.\n\n     - You _can_ fine-tune the placement and size of these graphics, but you don't have the same fine-grained control as you did with legacy launch images.\n\n - Use a simple color wash. If you use two colors, you'll want one color to fill the top half of the image, and the second to fill the bottom half.  If you use a gradient, you'll probably want to ensure that the middle of the gradient lines up with the center of the image. \n\n - Don't worry about pixel perfection -- because the images are scaled, there's almost no chance the images will be perfectly fit to the pixel grid. Since all supported iOS devices use retina screens, users will be hard pressed to notice it anyway.\n\nIt is important to understand the concept of scale, idiom, and size class traits in order to use launch storyboard images effectively. Of the images supplied to the launch storyboard, iOS will choose the image that best matches the device and viewport and render that image. It is possible to supply only one launch image if so desired, but it is also possible to fine-tune the displayed launch image based on traits. When fine-tuning, one can ignore traits that aren't targeted or supported by the app.\n\n> Note: If you are using launch storyboard images, there is no need to include legacy images. If you do, the legacy images will be copied, but not used.\n\n##### Scale\n\n|    scale    |    devices             |\n|:-----------:|:----------------------:|\n|     1x      | All non-retina devices |\n|     2x      | Most retina devices    |\n|     3x      | iPhone 6+/6s+,7s+      |\n\nIn general, you'll want to supply 2x and 3x images. Cordova only supports retina devices now, so there's no point in supplying 1x images.\n\n##### Idioms\n\n|    idiom    |    devices    |\n|:-----------:|:-------------:|\n|    ipad     | All iPads     |\n|   iphone    | All iPhones and iPod Touches    |\n|  universal  | All devices   |\n\nYou only need to provide universal images unless you need to fine-tune for a specific device idiom.\n\n##### Size classes\n\nThere are two size classes applies to both screen axes. Narrow viewports are considered to be the \"compact\" size class, and remaining viewports are considered \"regular\". When supplying images to Xcode, however, one must choose between \"any & compact\" and \"any & regular\". To stay consistent with the native terminology, this feature will match based on \"any\" and \"compact\". `any` will match regular-sized viewports. \n\nNote: this feature uses `com` as an abbreviation for \"compact\" classes.\n\nThe following classes are supported by this feature:\n\n|    width    |    height    |    orientation    |\n|:-----------:|:------------:|:-----------------:|\n|     any     |     any      |        any        |\n|     com     |     any      |     portrait      |\n|     any     |     com      |  landscape (wide) |\n|     com     |     com      | landscape (narrow)|\n\nTo see the complete list of size classes associated with devices and viewports, see <http://www.sizeclasses.com>.\n\n##### Single-image launch screen\n\nIf your launch image is simple, you may be able to avoid creating a lot of different launch images and supply only one. The launch image needs to meet the following requirements:\n\n - the image should be square\n\n - the image should be large enough to fit on an iPad Pro 12.9\": 2732x2732\n\n - anything important should fit within the center\n\n Keep in mind that the image will be cropped, possibly quite severely, depending upon the viewport. \n\nOnce the image is created, you can include it in your project by adding the following to `config.xml`:\n\n```\n    <splash src=\"res/screen/ios/Default@2x~universal~anyany.png\" />\n```\n\nBecause only one image is provided, iOS will utilize it in every context.\n\n##### Multi-image launch screen\n\nIf a single launch image won't meet your needs, you will probably need to supply at least six images, if not more. Furthermore, keep in mind that it will not be possible to fine tune the image to a specific device, but only to a device class, display factor, and viewport size.\n\nIf you don't need to target images to a specific idiom, you should create six images, as follows:\n\n|    scale    |    idiom    |    width    |    height    |    size    |    filename    |\n|:-----------:|:-----------:|:-----------:|:------------:|:----------:|:--------------:|\n|     2x*     |  universal  |     any     |     any      | 2732x2732  | `Default@2x~universal~anyany.png` |\n|     2x      |  universal  |     com     |     any      | 1278x2732  | `Default@2x~universal~comany.png` |\n|     2x      |  universal  |     com     |     com      | 1334x750   | `Default@2x~universal~comcom.png` |\n|     3x*     |  universal  |     any     |     any      | 2208x2208  | `Default@3x~universal~anyany.png` |\n|     3x      |  universal  |     any     |     com      | 2208x1242  | `Default@3x~universal~anycom.png` |\n|     3x      |  universal  |     com     |     any      | 1242x2208  | `Default@3x~universal~comany.png` |\n\n\\* this image is required in order for iOS utilize the other images within this scale and idiom.\n\n> Note: If the 3x sizes look small too you, that's because there's only one device class that currently has a 3x density: the iPhone 6+/6s+/7+.\n\nThe above looks like the following snippet when present in `config.xml`:\n\n```\n    <splash src=\"res/screen/ios/Default@2x~universal~anyany.png\" />\n    <splash src=\"res/screen/ios/Default@2x~universal~comany.png\" />\n    <splash src=\"res/screen/ios/Default@2x~universal~comcom.png\" />\n    <splash src=\"res/screen/ios/Default@3x~universal~anyany.png\" />\n    <splash src=\"res/screen/ios/Default@3x~universal~anycom.png\" />\n    <splash src=\"res/screen/ios/Default@3x~universal~comany.png\" />\n```\n\nShould one need to further fine tune based upon device idiom, one can do so. This might look like so:\n\n|    scale    |    idiom    |    width    |    height    |    size    |    filename    |\n|:-----------:|:-----------:|:-----------:|:------------:|:----------:|:--------------:|\n|     2x*     |    iphone   |     any     |     any      | 1334x1334  | `Default@2x~iphone~anyany.png` |\n|     2x      |    iphone   |     com     |     any      | 750x1334   | `Default@2x~iphone~comany.png` |\n|     2x      |    iphone   |     com     |     com      | 1334x750   | `Default@2x~iphone~comcom.png` |\n|     3x*     |    iphone   |     any     |     any      | 2208x2208  | `Default@3x~iphone~anyany.png` |\n|     3x      |    iphone   |     any     |     com      | 2208x1242  | `Default@3x~iphone~anycom.png` |\n|     3x      |    iphone   |     com     |     any      | 1242x2208  | `Default@3x~iphone~comany.png` |\n|     2x*     |     ipad    |     any     |     any      | 2732x2732  | `Default@2x~ipad~anyany.png`   |\n|     2x      |     ipad    |     com     |     any      | 1278x2732  | `Default@2x~ipad~comany.png`   |\n\n\\* this image is required in order for iOS utilize the other images within this scale and idiom.\n\nThe above looks like the following in `config.xml`:\n\n```\n    <splash src=\"res/screen/ios/Default@2x~iphone~anyany.png\" />\n    <splash src=\"res/screen/ios/Default@2x~iphone~comany.png\" />\n    <splash src=\"res/screen/ios/Default@2x~iphone~comcom.png\" />\n    <splash src=\"res/screen/ios/Default@3x~iphone~anyany.png\" />\n    <splash src=\"res/screen/ios/Default@3x~iphone~anycom.png\" />\n    <splash src=\"res/screen/ios/Default@3x~iphone~comany.png\" />\n    <splash src=\"res/screen/ios/Default@2x~ipad~anyany.png\" />\n    <splash src=\"res/screen/ios/Default@2x~ipad~comany.png\" />\n```\n\n##### Quirks and Known Issues\n\n1. **App on target may not reflect changes to images**\n   Once you run the app on a target, iOS caches the launch image. Unfortunately, when you chance the images, iOS does _not_ invalidate the cache, which means you'll still see the old launch image. You should either: delete the app, or reset content & settings (simulator).\n\n2. **Simulator may not show expected images when launched from CLI**\n   When Xcode deploys to a specific simulator, it only copies the assets that match the simulator's characteristics. For example, if you try to run an app on the iPhone 6s Plus simulator, only @3x launch images are copied. When compiling from the CLI, however, the default is to assume an iPhone 5s, which means only @2x launch images are copied. Unless your launch images are markedly different, chances are good the difference would go unnoticed, but this does mean that the only accurate method of testing is to test on a physical device.\n\n3. **`anyany` must be provided for other variations to be used**\n   If you don't provide an `anyany` version of the launch image for a specific scale and idiom, the other variations (like `anycom`, `comany`, and `comcom`) will ignored. \n\n## Windows-specific information\n\nSplash screen images can be defined using the [MRT](https://cordova.apache.org/docs/en/dev/config_ref/images.html#windows) concept.  \nIf you specify src=\"res/windows/splashscreen.png\" the following files will be copied into the application's images folder:  \n`res/windows/splashscreen.png` | `res/windows/splashscreen.scale-100.png`, `res/windows/splashscreen.scale-125.png`, etc.  \nThe following are supported:\n\n|   Scale, %   |       Project       |    Width    |    Height    |             Filename              |\n|:------------:|:-------------------:|:-----------:|:------------:|:---------------------------------:|\n|     100      |  Windows 10/8.1     |     620     |     300      | `splashscreen.png` \\| `splashscreen.scale-100.png`              |\n|     125      |  Windows 10         |     775     |     375      | `splashscreen.scale-125.png`      |\n|     150      |  Windows 10         |     930     |     450      | `splashscreen.scale-150.png`      |\n|     200      |  Windows 10         |     1240    |     600      | `splashscreen.scale-200.png`      |\n|     400      |  Windows 10         |     2480    |     1200     | `splashscreen.scale-400.png`      |\n|     140      |  Windows 8.1        |     868     |     420      | `splashscreen.scale-140.png`      |\n|     180      |  Windows 8.1        |     1116    |     540      | `splashscreen.scale-180.png`      |\n|     100      |  Windows Phone 8.1  |     480     |     800      | `splashscreenphone.png` \\| `splashscreenphone.scale-100.png`         |\n|     140      |  Windows Phone 8.1  |     672     |     1120     | `splashscreenphone.scale-140.png` |\n|     240      |  Windows Phone 8.1  |     1152    |     1920     | `splashscreenphone.scale-240.png` |\n\n__Note__: SplashScreens size for Windows 10 project should not exceed 200 KBytes.  \n__Note__: Supported formats are `.png`, `.jpg`, `.jpeg`. Mixing of the extensions within a target is not supported. I.e. you can have `splashscreen.jpg` and `splashscreenphone.png` but not `splashscreen.scale-100.png`, `splashscreen.scale-400.jpg`.  \n__Note__: You may need to reopen Visual Studio solution after changing the images and doing a `cordova prepare` for the changes to take effect.\n\n## Example Configuration\nIn the top-level `config.xml` file (not the one in `platforms`), add configuration elements like those specified here.\n\nPlease notice that the value of the \"src\" attribute is relative to the project root directory and not to the www directory (see `Directory structure` below). You can name the source image whatever you like. The internal name in the app is determined by Cordova.\n\nDirectory structure:\n\n```\nprojectRoot\n    hooks\n    platforms\n    plugins\n    www\n        css\n        img\n        js\n    res\n        screen\n            android\n            ios\n            windows\n```\n\n```xml\n<platform name=\"android\">\n    <!-- you can use any density that exists in the Android project -->\n    <splash src=\"res/screen/android/splash-land-hdpi.png\" density=\"land-hdpi\"/>\n    <splash src=\"res/screen/android/splash-land-ldpi.png\" density=\"land-ldpi\"/>\n    <splash src=\"res/screen/android/splash-land-mdpi.png\" density=\"land-mdpi\"/>\n    <splash src=\"res/screen/android/splash-land-xhdpi.png\" density=\"land-xhdpi\"/>\n\n    <splash src=\"res/screen/android/splash-port-hdpi.png\" density=\"port-hdpi\"/>\n    <splash src=\"res/screen/android/splash-port-ldpi.png\" density=\"port-ldpi\"/>\n    <splash src=\"res/screen/android/splash-port-mdpi.png\" density=\"port-mdpi\"/>\n    <splash src=\"res/screen/android/splash-port-xhdpi.png\" density=\"port-xhdpi\"/>\n</platform>\n\n<platform name=\"ios\">\n    <!-- There are two mechanisms for showing launch images.\n      -- Legacy method (supports all devices except iPad Pro 12.9):\n      -- Note: Images are determined by width and height. The following are supported -->\n    <splash src=\"res/screen/ios/Default~iphone.png\" width=\"320\" height=\"480\"/>\n    <splash src=\"res/screen/ios/Default@2x~iphone.png\" width=\"640\" height=\"960\"/>\n    <splash src=\"res/screen/ios/Default-Portrait~ipad.png\" width=\"768\" height=\"1024\"/>\n    <splash src=\"res/screen/ios/Default-Portrait@2x~ipad.png\" width=\"1536\" height=\"2048\"/>\n    <splash src=\"res/screen/ios/Default-Landscape~ipad.png\" width=\"1024\" height=\"768\"/>\n    <splash src=\"res/screen/ios/Default-Landscape@2x~ipad.png\" width=\"2048\" height=\"1536\"/>\n    <splash src=\"res/screen/ios/Default-568h@2x~iphone.png\" width=\"640\" height=\"1136\"/>\n    <splash src=\"res/screen/ios/Default-667h.png\" width=\"750\" height=\"1334\"/>\n    <splash src=\"res/screen/ios/Default-736h.png\" width=\"1242\" height=\"2208\"/>\n    <splash src=\"res/screen/ios/Default-Landscape-736h.png\" width=\"2208\" height=\"1242\"/>\n    <!-- Storyboard method (supports all devices):\n      -- Important: If you use the storyboard method, legacy images are \n      -- copied but ignored.\n      -- Note: images are determined by scale, idiom, and size traits. The following\n      -- are suggested based on current device form factors -->\n    <splash src=\"res/screen/ios/Default@2x~universal~anyany.png\" />\n    <splash src=\"res/screen/ios/Default@2x~universal~comany.png\" />\n    <splash src=\"res/screen/ios/Default@2x~universal~comcom.png\" />\n    <splash src=\"res/screen/ios/Default@3x~universal~anyany.png\" />\n    <splash src=\"res/screen/ios/Default@3x~universal~anycom.png\" />\n    <splash src=\"res/screen/ios/Default@3x~universal~comany.png\" />\n    \n</platform>\n\n<!-- Configuration using MRT concept (Recommended, see \"Windows-specific information\" section for details): -->\n<platform name=\"windows\">\n    <splash src=\"res/screen/windows/splashscreen.png\" target=\"SplashScreen\"/>\n    <splash src=\"res/screen/windows/splashscreenphone.png\" target=\"SplashScreenPhone\"/>\n</platform>\n\n<!-- Configuration using image size: -->\n<!--<platform name=\"windows\">\n    <splash src=\"res/screen/windows/splashscreen.png\" width=\"620\" height=\"300\"/>\n    <splash src=\"res/screen/windows/splashscreenphone.png\" width=\"1152\" height=\"1920\"/>\n</platform>-->\n\n<platform name=\"blackberry10\">\n    <!-- Add a rim:splash element for each resolution and locale you wish -->\n    <!-- http://developer.blackberry.com/html5/documentation/rim_splash_element.html -->\n    <rim:splash src=\"res/screen/blackberry/splashscreen.png\"/>\n</platform>\n\n<preference name=\"SplashScreenDelay\" value=\"10000\" />\n```\n\n## Preferences\n\n#### config.xml\n\n- `AutoHideSplashScreen` (boolean, default to `true`). Indicates whether to hide splash screen automatically or not. Splash screen hidden after amount of time specified in the `SplashScreenDelay` preference.\n\n```xml\n    <preference name=\"AutoHideSplashScreen\" value=\"true\" />\n```\n\n- `SplashScreenDelay` (number, default to 3000). Amount of time in milliseconds to wait before automatically hide splash screen.\n\n```xml\n    <preference name=\"SplashScreenDelay\" value=\"3000\" />\n```\n\nNote also that this value used to be seconds, and not milliseconds, so values less than 30 will still be treated as seconds. ( Consider this a deprecated patch that will disapear in some future version. )\n\nTo disable the splashscreen add the following preference to `config.xml`:\n```xml\n<preference name=\"SplashScreenDelay\" value=\"0\"/>\n```\n\n**Windows Quirk**: You should disable the splashscreen in case you are updating the entire document body dynamically (f.e. with a SPA router) to avoid affecting UI/controls.  \nNote that you should also directly reference `WinJS/base.js` in the page HTML in this case to avoid the issues with activation context ([CB-11658](https://issues.apache.org/jira/browse/CB-11658)).\n\n**iOS Quirk**: to disable the splashscreen on `ios` platform you should also add `<preference name=\"FadeSplashScreenDuration\" value=\"0\"/>` to `config.xml`.\n\n- `FadeSplashScreen` (boolean, defaults to `true`): Set to `false` to\n  prevent the splash screen from fading in and out when its display\n  state changes.\n\n```xml\n    <preference name=\"FadeSplashScreen\" value=\"false\"/>\n```\n\n- `FadeSplashScreenDuration` (float, defaults to `500`): Specifies the\n  number of milliseconds for the splash screen fade effect to execute.\n\n```xml\n    <preference name=\"FadeSplashScreenDuration\" value=\"750\"/>\n```\n\n_Note_: `FadeSplashScreenDuration` is included into `SplashScreenDelay`, for example if you have `<preference name=\"SplashScreenDelay\" value=\"3000\" />` and `<preference name=\"FadeSplashScreenDuration\" value=\"1000\"/>` defined in `config.xml`:\n\n- 00:00 - splashscreen is shown\n- 00:02 - fading has started\n- 00:03 - splashscreen is hidden\n\nTurning the fading off via `<preference name=\"FadeSplashScreen\" value=\"false\"/>` technically means fading duration to be `0` so that in this example the overall splash delay will still be 3 seconds.\n\n_Note_: This only applies to the app startup - you need to take the fading timeout into account when manually showing/hiding the splashscreen in the code:\n\n```javascript\nnavigator.splashscreen.show();\nwindow.setTimeout(function () {\n    navigator.splashscreen.hide();\n}, splashDuration - fadeDuration);\n```\n\n- `ShowSplashScreenSpinner` (boolean, defaults to `true`): Set to `false`\n  to hide the splash-screen spinner.\n\n```xml\n    <preference name=\"ShowSplashScreenSpinner\" value=\"false\"/>\n```\n\n### Android Quirks\n\nIn your `config.xml`, you can add the following preferences:\n\n```xml\n<preference name=\"SplashMaintainAspectRatio\" value=\"true|false\" />\n<preference name=\"SplashShowOnlyFirstTime\" value=\"true|false\" />\n```\n\n\"SplashMaintainAspectRatio\" preference is optional. If set to true, splash screen drawable is not stretched to fit screen, but instead simply \"covers\" the screen, like CSS \"background-size:cover\". This is very useful when splash screen images cannot be distorted in any way, for example when they contain scenery or text. This setting works best with images that have large margins (safe areas) that can be safely cropped on screens with different aspect ratios.\n\nThe plugin reloads splash drawable whenever orientation changes, so you can specify different drawables for portrait and landscape orientations.\n\n\"SplashShowOnlyFirstTime\" preference is also optional and defaults to `true`. When set to `true` splash screen will only appear on application launch. However, if you plan to use `navigator.app.exitApp()` to close application and force splash screen appear on next launch, you should set this property to `false` (this also applies to closing the App with Back button).\n\n### Browser Quirks\n\nYou can use the following preferences in your `config.xml`:\n\n```xml\n<platform name=\"browser\">\n    <preference name=\"SplashScreen\" value=\"/images/browser/splashscreen.jpg\" /> <!-- defaults to \"/img/logo.png\" -->\n    <preference name=\"SplashScreenDelay\" value=\"3000\" /> <!-- defaults to \"3000\" -->\n    <preference name=\"SplashScreenBackgroundColor\" value=\"green\" /> <!-- defaults to \"#464646\" -->\n    <preference name=\"ShowSplashScreen\" value=\"false\" /> <!-- defaults to \"true\" -->\n    <preference name=\"SplashScreenWidth\" value=\"600\" /> <!-- defaults to \"170\" -->\n    <preference name=\"SplashScreenHeight\" value=\"300\" /> <!-- defaults to \"200\" -->\n</platform>\n```\n\n__Note__: `SplashScreen` value should be absolute in order to work in a sub-page. The `SplashScreen` value is used only for the browser platform. The value will be ignored for other platforms.\n\n### iOS Quirks\n\n- In iOS, the splashscreen images are called launch images. These images are mandatory on iOS.\n\n### Windows Quirks\n\n- `SplashScreenSpinnerColor` (string, defaults to system accent color): hash, rgb notation or CSS color name.\n\n```xml\n<preference name=\"SplashScreenSpinnerColor\" value=\"#242424\"/>\n<preference name=\"SplashScreenSpinnerColor\" value=\"DarkRed\"/>\n<preference name=\"SplashScreenSpinnerColor\" value=\"rgb(50,128,128)\"/>\n```\n\n- `SplashScreenBackgroundColor` (string, defaults to #464646): hex notation.\n\n```xml\n<preference name=\"SplashScreenBackgroundColor\" value=\"0xFFFFFFFF\"/>\n```\n\n## Methods\n\n- splashscreen.show\n- splashscreen.hide\n\n## splashscreen.hide\n\nDismiss the splash screen.\n\n```js\nnavigator.splashscreen.hide();\n```\n\n\n### BlackBerry 10, WP8, iOS Quirk\n\nThe `config.xml` file's `AutoHideSplashScreen` setting must be\n`false`. To delay hiding the splash screen for two seconds, add a\ntimer such as the following in the `deviceready` event handler:\n\n```js\nsetTimeout(function() {\n    navigator.splashscreen.hide();\n}, 2000);\n```\n\n## splashscreen.show\n\nDisplays the splash screen.\n\n```js\nnavigator.splashscreen.show();\n```\n\nYour application cannot call `navigator.splashscreen.show()` until the app has\nstarted and the `deviceready` event has fired. But since typically the splash\nscreen is meant to be visible before your app has started, that would seem to\ndefeat the purpose of the splash screen.  Providing some configuration in\n`config.xml` will automatically `show` the splash screen immediately after your\napp launch and before it has fully started and received the `deviceready`\nevent. For this reason, it is unlikely you need to call `navigator.splashscreen.show()` to make the splash\nscreen visible for app startup.\n\n[Apache Cordova issue tracker]: https://issues.apache.org/jira/issues/?jql=project%20%3D%20CB%20AND%20status%20in%20%28Open%2C%20%22In%20Progress%22%2C%20Reopened%29%20AND%20resolution%20%3D%20Unresolved%20AND%20component%20%3D%20%22Plugin%20Splashscreen%22%20ORDER%20BY%20priority%20DESC%2C%20summary%20ASC%2C%20updatedDate%20DESC\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/RELEASENOTES.md",
    "content": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n# \n# http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#  KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n#\n-->\n# Release Notes\n\n### 4.0.1 (Dec 07, 2016)\n* [CB-11751](https://issues.apache.org/jira/browse/CB-11751) 'extendedSplashScreen' is undefined Document that splashscreen needs to be disabled on Windows in case of updating entire document body\n* [CB-9287](https://issues.apache.org/jira/browse/CB-9287) Not enough Icons and Splashscreens for Windows 8.1 and Windows Phone 8.1\n* [CB-11917](https://issues.apache.org/jira/browse/CB-11917) - Remove pull request template checklist item: \"iCLA has been submitted…\"\n* [CB-11830](https://issues.apache.org/jira/browse/CB-11830) (iOS) Fix doc typos in PR#114\n* [CB-11829](https://issues.apache.org/jira/browse/CB-11829) (iOS) Support for CB-9762; docs (CB-11830)\n* [CB-11832](https://issues.apache.org/jira/browse/CB-11832) Incremented plugin version.\n\n### 4.0.0 (Sep 08, 2016)\n* [CB-11795](https://issues.apache.org/jira/browse/CB-11795) Add 'protective' entry to cordovaDependencies\n* [CB-11326](https://issues.apache.org/jira/browse/CB-11326) Prevent crash when initializing plugin after navigating to another URL\n* Fix crash on **iOS** when reloading page from remote **Safari**\n* Add badges for paramedic builds on Jenkins\n* Add pull request template.\n* [CB-11179](https://issues.apache.org/jira/browse/CB-11179) Extend the windows-splashscreen docs\n* [CB-11159](https://issues.apache.org/jira/browse/CB-11159) Fix flaky splashscreen native tests\n* [CB-11156](https://issues.apache.org/jira/browse/CB-11156) Change default `FadeSplashScreenDuration` value\n* [CB-8056](https://issues.apache.org/jira/browse/CB-8056) Updated the dependency version, added it to the docs\n* [CB-10996](https://issues.apache.org/jira/browse/CB-10996) Adding front matter to README.md\n* [CB-8056](https://issues.apache.org/jira/browse/CB-8056) Implement splashscreen for **Windows** platform\n* [CB-6498](https://issues.apache.org/jira/browse/CB-6498) Misleading documentation in **Android** Quirks\n\n### 3.2.2 (Apr 15, 2016)\n* [CB-10979](https://issues.apache.org/jira/browse/CB-10979) Fix splashscreen **iOS** native tests. Added `jshintignore` for tests/ios\n* [CB-10895](https://issues.apache.org/jira/browse/CB-10895) Transparent Splashscreen view sometimes remains\n* [CB-10562](https://issues.apache.org/jira/browse/CB-10562) `hide()` not working in latest splashscreen plug in 3.1.0 in **iOS**\n* [CB-10688](https://issues.apache.org/jira/browse/CB-10688) Plugin Splashscreen Readme must have examples.\n* [CB-10864](https://issues.apache.org/jira/browse/CB-10864) Run **iOS** native tests on Travis\n\n### 3.2.1 (Mar 09, 2016)\n* [CB-10764](https://issues.apache.org/jira/browse/CB-10764) Remove emoji in cordova-plugin-splashscreen\n* [CB-10650](https://issues.apache.org/jira/browse/CB-10650) Non-index content.src causes Splashscreen to be not displayed on **Browser**\n* [CB-10636](https://issues.apache.org/jira/browse/CB-10636) Add JSHint for plugins\n* [CB-10606](https://issues.apache.org/jira/browse/CB-10606) fix deprecation warning for interfaceOrientation on **iOS**\n* chore: edit package.json license to match SPDX id\n\n### 3.2.0 (Feb 09, 2016)\n* [CB-10422](https://issues.apache.org/jira/browse/CB-10422) Splashscreen displays black screen with no image on Android\n* [CB-10412](https://issues.apache.org/jira/browse/CB-10412) AutoHideSplashScreen \"false\" isn't taken in account on iOS\n* [CB-9516](https://issues.apache.org/jira/browse/CB-9516) Android SplashScreen - Spinner Does Not Display\n* [CB-9094](https://issues.apache.org/jira/browse/CB-9094) Smarter autohide logic on Android\n* [CB-8396](https://issues.apache.org/jira/browse/CB-8396) Add AutoHideSplashScreen logic to Android's Splashscreen\n\n### 3.1.0 (Jan 15, 2016)\n* [CB-9538](https://issues.apache.org/jira/browse/CB-9538) Implementing `FadeSplashScreen` feature for **Android**\n* [CB-9240](https://issues.apache.org/jira/browse/CB-9240) Cordova splash screen plugin **iPad** landscape mode issue\n* [CB-10263](https://issues.apache.org/jira/browse/CB-10263) Fix splashscreen plugin filenames for Asset Catalog\n* [CB-9374](https://issues.apache.org/jira/browse/CB-9374) **Android** add `SplashShowOnlyFirstTime` as preference\n* [CB-10244](https://issues.apache.org/jira/browse/CB-10244) Don't rotate the **iPhone 6 Plus** splash\n* [CB-9043](https://issues.apache.org/jira/browse/CB-9043) Fix the **ios** splashscreen being deformed on orientation change\n* [CB-10079](https://issues.apache.org/jira/browse/CB-10079) Splashscreen plugin does not honor `SplashScreenDelay` on **iOS**\n* [CB-10231](https://issues.apache.org/jira/browse/CB-10231) Fix `FadeSplashScreen` to default to true on **iOS**\n\n### 3.0.0 (Nov 18, 2015)\n* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Updated `RELEASENOTES` to be newest to oldest\n* Fixing contribute link.\n* [CB-9750](https://issues.apache.org/jira/browse/CB-9750) `FadeSplashDuration` is now in `msecs`\n* [CB-8875](https://issues.apache.org/jira/browse/CB-8875) `FadeSplashScreen` was not fading\n* [CB-9467](https://issues.apache.org/jira/browse/CB-9467) SplashScreen does not show any image in hosted app on **Windows 10**\n* [CB-7282](https://issues.apache.org/jira/browse/CB-7282) Document `AutoHideSplashScreenpreference`\n* [CB-9327](https://issues.apache.org/jira/browse/CB-9327) - Splashscreen not receiving `CDVPageLoadNotification`\n* WP8: Avoid config `value` of a wrong element.\n\n### 2.1.0 (Jun 17, 2015)\n* added missing license headers\n* [CB-9128](https://issues.apache.org/jira/browse/CB-9128) cordova-plugin-splashscreen documentation translation: cordova-plugin-splashscreen\n* fix npm md issue\n* Fixed iOS unit tests.\n* [CB-3562](https://issues.apache.org/jira/browse/CB-3562): Disable screen rotation for iPhone when splash screen is shown. (closes #47)\n* [CB-8988](https://issues.apache.org/jira/browse/CB-8988): Fix rotation on iOS/iPad (closes #46)\n* [CB-8904](https://issues.apache.org/jira/browse/CB-8904): Don't reset the static variable when it's destroyed, otherwise we might as well just have a member variable\n* Removed wp7 from plugin.xml and package.json\n* [CB-8750](https://issues.apache.org/jira/browse/CB-8750) [wp8]: Rewrite resoultion helper\n* [CB-8750](https://issues.apache.org/jira/browse/CB-8750) [wp8]: Allow resolution-specific splashscreen images\n* [CB-8758](https://issues.apache.org/jira/browse/CB-8758) [wp8]: UnauthorizedAccessException on hide()\n\n### 2.0.0 (Apr 15, 2015)\n* give users a way to install the bleeding edge.\n* [CB-8746](https://issues.apache.org/jira/browse/CB-8746) gave plugin major version bump\n* [CB-8797](https://issues.apache.org/jira/browse/CB-8797) - Splashscreen preferences FadeSplashScreenDuration and FadeSplashScreen (iOS) are missing\n* [CB-8836](https://issues.apache.org/jira/browse/CB-8836) - Crashes after animating splashscreen\n* [CB-8753](https://issues.apache.org/jira/browse/CB-8753) android: Fix missing import in previous commit\n* [CB-8753](https://issues.apache.org/jira/browse/CB-8753) android: Adds `SplashMaintainAspectRatio` preference (close #43)\n* [CB-8683](https://issues.apache.org/jira/browse/CB-8683) changed plugin-id to pacakge-name\n* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) properly updated translated docs to use new id\n* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) updated translated docs to use new id\n* [CB-8345](https://issues.apache.org/jira/browse/CB-8345) Make default for splashscreen resource \"screen\" (which is what template and CLI assume it to be)\n* Revert \"CB-8345 android: Make \"splash\" the default resource ID instead of null\"\n* Use TRAVIS_BUILD_DIR, install paramedic by npm\n* [CB-8345](https://issues.apache.org/jira/browse/CB-8345) android: Make \"splash\" the default resource ID instead of null\n* docs: added Windows to supported platforms\n* [CB-7964](https://issues.apache.org/jira/browse/CB-7964) Add cordova-plugin-splashscreen support for browser platform\n* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) Updated Readme\n* [wp8] oops, Added back config parse result checks\n* [WP8] code cleanup, minor refactors, comments to clarify some stuff.\n* Extend WP8 Splash Screen to respect SplashScreen and SplashScreenDelay preferences from config file\n* [CB-8574](https://issues.apache.org/jira/browse/CB-8574) Integrate TravisCI\n* [CB-8438](https://issues.apache.org/jira/browse/CB-8438) cordova-plugin-splashscreen documentation translation: cordova-plugin-splashscreen\n* [CB-8538](https://issues.apache.org/jira/browse/CB-8538) Added package.json file\n* [CB-8397](https://issues.apache.org/jira/browse/CB-8397) Add support to 'windows' for showing the Windows Phone splashscreen\n\n### 1.0.0 (Feb 04, 2015)\n* [CB-8351](https://issues.apache.org/jira/browse/CB-8351) ios: Stop using deprecated IsIpad macro\n* [CB-3679](https://issues.apache.org/jira/browse/CB-3679) Add engine tag for Android >= 3.6.0 due to use of `preferences`\n* [CB-3679](https://issues.apache.org/jira/browse/CB-3679) Make SplashScreen plugin compatible with cordova-android@4.0.x\n\n### 0.3.5 (Dec 02, 2014)\n* [CB-7204](https://issues.apache.org/jira/browse/CB-7204) - Race condition when hiding and showing spinner (closes #21)\n* [CB-7700](https://issues.apache.org/jira/browse/CB-7700) cordova-plugin-splashscreen documentation translation: cordova-plugin-splashscreen\n\n### 0.3.4 (Oct 03, 2014)\n* Finalized iOS splash screen (image name) tests. 176 tests in all, 44 for each type of device (iPad, iPhone, iPhone5, iPhone6, iPhone 6 Plus).\n* [CB-7633](https://issues.apache.org/jira/browse/CB-7633) - (Re-fix based on updated unit tests) iPhone 6 Plus support\n* Updated iOS tests for locked orientations\n* Added more iOS splash screen tests.\n* [CB-7633](https://issues.apache.org/jira/browse/CB-7633) - Add support for iPhone 6/6+\n* Added failing iPhone 6/6 Plus tests.\n* Added 'npm test'\n* [CB-7663](https://issues.apache.org/jira/browse/CB-7663) - iOS unit tests for splash screen\n* Properly formatted splashscreen preference docs.\n\n### 0.3.3 (Sep 17, 2014)\n* [CB-7249](https://issues.apache.org/jira/browse/CB-7249) cordova-plugin-splashscreen documentation translation\n* Renamed test dir, added nested plugin.xml\n* added documentation for manual tests\n* [CB-7196](https://issues.apache.org/jira/browse/CB-7196) port splashscreen tests to framework\n\n### 0.3.2 (Aug 06, 2014)\n* [CB-6127](https://issues.apache.org/jira/browse/CB-6127) Updated translations for docs\n* [CB-7041](https://issues.apache.org/jira/browse/CB-7041) ios: Fix image filename logic when setting the iPad splash screen\n* fixes Splashscreen crash on WP8\n* Remove outdated doc\n\n### 0.3.1 (Jun 05, 2014)\n* documentation translation: cordova-plugin-splashscreen\n* Lisa testing pulling in plugins for plugin: cordova-plugin-splashscreen\n* Lisa testing pulling in plugins for plugin: cordova-plugin-splashscreen\n* Lisa testing pulling in plugins for plugin: cordova-plugin-splashscreen\n* Lisa testing pulling in plugins for plugin: cordova-plugin-splashscreen\n* [CB-6810](https://issues.apache.org/jira/browse/CB-6810) Add license to CONTRIBUTING.md\n* [wp8] updated quirk for  and combined iOS,WP8,BB10 quirks as they are all the same\n* [wp] implemented OnInit so splash screen can be shown before cordova page is loaded\n* [wp] plugin must be autoloaded for AutoHideSplashScreen preference to work\n* [CB-6483](https://issues.apache.org/jira/browse/CB-6483) Use splash screen image from manifest on Windows8\n* [CB-6491](https://issues.apache.org/jira/browse/CB-6491) add CONTRIBUTING.md\n* Revert \"Merge branch 'tizen' of http://github.com/siovene/cordova-plugin-splashscreen\"\n\n### 0.3.0 (Apr 17, 2014)\n* Add Tizen support to plugin\n* [CB-6422](https://issues.apache.org/jira/browse/CB-6422): [windows8] use cordova/exec/proxy\n* [CB-4051](https://issues.apache.org/jira/browse/CB-4051): [ios] - Re-fix - Splashscreen rotation problem (closes #13)\n* [CB-6460](https://issues.apache.org/jira/browse/CB-6460): Update license headers\n* [CB-6465](https://issues.apache.org/jira/browse/CB-6465): Add license headers to Tizen code\n* Add NOTICE file\n\n### 0.2.7 (Feb 05, 2014)\n* [CB-3562](https://issues.apache.org/jira/browse/CB-3562) Fix aspect ratio on landscape-only iPhone applications\n* [CB-4051](https://issues.apache.org/jira/browse/CB-4051) fix for splashscreen rotation problem\n\n### 0.2.6 (Jan 02, 2014)\n* [CB-5658](https://issues.apache.org/jira/browse/CB-5658) Add doc/index.md for Splashscreen plugin\n* Handle error when splash image is missing.\n\n### 0.2.5 (Dec 4, 2013)\n* add ubuntu platform\n* Added amazon-fireos platform. Change to use amazon-fireos as a platform if the user agent string contains 'cordova-amazon-fireos'\n* [CB-5124](https://issues.apache.org/jira/browse/CB-5124) - Remove splashscreen config.xml values from iOS Configuration Docs, move to plugin docs\n\n### 0.2.4 (Oct 28, 2013)\n* [CB-5128](https://issues.apache.org/jira/browse/CB-5128): add repo + issue tag to plugin.xml for splashscreen plugin\n* [CB-5010](https://issues.apache.org/jira/browse/CB-5010) Incremented plugin version on dev branch.\n\n### 0.2.3 (Oct 9, 2013)\n* [CB-4806](https://issues.apache.org/jira/browse/CB-4806) Re-fix Update splashscreen image bounds for iOS 7\n* [CB-4934](https://issues.apache.org/jira/browse/CB-4934) plugin-splashscreen should not show by default on Windows8\n* [CB-4929](https://issues.apache.org/jira/browse/CB-4929) plugin-splashscreen not loading proxy windows8\n* [CB-4915](https://issues.apache.org/jira/browse/CB-4915) Incremented plugin version on dev branch.\n\n### 0.2.2 (Sept 25, 2013)\n* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) bumping&resetting version\n* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) renaming org.apache.cordova.core.splashscreen to org.apache.cordova.splashscreen\n* Rename CHANGELOG.md -> RELEASENOTES.md\n* [CB-4806](https://issues.apache.org/jira/browse/CB-4806) Update splashscreen image bounds for iOS 7\n* [CB-4752](https://issues.apache.org/jira/browse/CB-4752) Incremented plugin version on dev branch.\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/de/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-splashscreen\n\n[![Build Status](https://travis-ci.org/apache/cordova-plugin-splashscreen.svg)](https://travis-ci.org/apache/cordova-plugin-splashscreen)\n\nDieses Plugin zeigt und verbirgt einen Splash-Screen beim Start der Anwendung.\n\n## Installation\n\n    // npm hosted (new) id\n    cordova plugin add cordova-plugin-splashscreen\n    // you may also install directly from this repo\n    cordova plugin add https://github.com/apache/cordova-plugin-splashscreen.git\n    \n\n## Unterstützte Plattformen\n\n  * Amazon Fire OS\n  * Android\n  * BlackBerry 10\n  * iOS\n  * Windows Phone 7 und 8\n  * Windows 8\n  * Windows\n  * Browser\n\n## Methoden\n\n  * SplashScreen.Show\n  * SplashScreen.Hide\n\n### Android Eigenarten\n\nSie müssen in Ihrem `\"config.xml\"`fügen Sie die folgenden Einstellungen:\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    <preference name=\"SplashMaintainAspectRatio\" value=\"true|false\" />\n    \n\nWo Foo ist der Name der Datei Splashscreen, vorzugsweise eine 9-Patch-Datei. Stellen Sie sicher, Splashcreen Dateien zu Ihrem res/xml-Verzeichnis unter den entsprechenden Ordnern hinzuzufügen. Der zweite Parameter stellt dar, wie lange das Splashscreen in Millisekunden angezeigt werden. Es wird standardmäßig auf 3000 ms. Weitere Informationen finden Sie unter [Symbole und Splash-Screens](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html).\n\n\"SplashMaintainAspectRatio\" Präferenz ist optional. Wenn wahr, Splash-Screen zeichenbaren nicht gestreckt wird, um den Bildschirm passen, sondern stattdessen einfach \"\" den Bildschirm, wie CSS abdeckt \"Hintergrund-Größe: Schutz vor\". Dies ist sehr nützlich, wenn Splash-Bildschirm Bilder können nicht, in keiner Weise, zum Beispiel verzerrt werden wenn sie Landschaft oder Text enthalten. Diese Einstellung funktioniert am besten mit Bildern, die große Margen (sichere Bereiche) haben, die sicher auf Bildschirme mit unterschiedlichen Seitenverhältnissen zugeschnitten werden können.\n\nDas Plugin lädt platsch zeichenbaren wenn Ausrichtung ändert, sodass Sie verschiedene Drawables für hoch- und Querformat Ausrichtungen angeben können.\n\n### Browser-Eigenheiten\n\nIn Ihrem `\"config.xml\"`können Sie die folgenden Einstellungen:\n\n    <platform name=\"browser\">\n        <preference name=\"SplashScreen\" value=\"images/browser/splashscreen.jpg\" /> <!-- defaults to \"img/logo.png\" -->\n        <preference name=\"SplashScreenDelay\" value=\"10000\" /> <!-- defaults to \"3000\" -->\n        <preference name=\"SplashScreenBackgroundColor\" value=\"green\" /> <!-- defaults to \"#464646\" -->\n        <preference name=\"ShowSplashScreen\" value=\"false\" /> <!-- defaults to \"true\" -->\n        <preference name=\"SplashScreenWidth\" value=\"600\" /> <!-- defaults to \"170\" -->\n        <preference name=\"SplashScreenHeight\" value=\"300\" /> <!-- defaults to \"200\" -->\n    </platform>\n    \n\n### iOS Macken\n\n  * `FadeSplashScreen` (Boolean, standardmäßig auf `true festgelegt`): um zu verhindern, dass den Begrüßungsbildschirm ein-und ausblenden bei ihrer Anzeige Statusänderungen auf `false` festgelegt.\n    \n        <preference name=\"FadeSplashScreen\" value=\"false\"/>\n        \n\n  * `FadeSplashScreenDuration` (float, Standardwert ist `2`): gibt die Anzahl der Sekunden für den Begrüßungsbildschirm fade Effekt ausgeführt.\n    \n        <preference name=\"FadeSplashScreenDuration\" value=\"4\"/>\n        \n\n  * `ShowSplashScreenSpinner` (Boolean, standardmäßig auf `true festgelegt`): auf `false` festgelegt wird, um den Begrüßungsbildschirm Spinner auszublenden.\n    \n        <preference name=\"ShowSplashScreenSpinner\" value=\"false\"/>\n        \n\n## SplashScreen.Hide\n\nSchließen Sie den Splash-Screen.\n\n    navigator.splashscreen.hide();\n    \n\n### BlackBerry 10, WP8, iOS Eigenarten\n\nDie Datei `config.xml` `AutoHideSplashScreen` Einstellung muss `false` sein. Verstecken des Begrüßungsbildschirms für zwei Sekunden Verzögerung, fügen Sie einen Timer wie die folgende in der `deviceready`-Ereignishandler:\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## SplashScreen.Show\n\nZeigt den Begrüßungsbildschirm.\n\n    navigator.splashscreen.show();\n    \n\nIhre Anwendung kann nicht `navigator.splashscreen.show()` aufrufen, bis die app begonnen hat und das `deviceready`-Ereignis ausgelöst hat. Aber da in der Regel der Splash-Screen soll sichtbar sein, bevor die Anwendung gestartet wurde, scheint die Niederlage der Zweck des Begrüßungsbildschirms. Somit einige Konfiguration in der Datei `config.xml` werden automatisch die Splash `show` sofort nach Ihrer app-Start und Bildschirm bevor es voll begonnen hat, und das `deviceready`-Ereignis empfangen. Weitere Informationen zu dieser Konfiguration finden Sie unter [Symbole und Splash-Screens](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html). Aus diesem Grund ist es unwahrscheinlich, dass Sie `navigator.splashscreen.show()` damit den Splash-Screen sichtbar ist für app-Start aufrufen müssen."
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/de/index.md",
    "content": "<!---\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n-->\n\n# cordova-plugin-splashscreen\n\nDieses Plugin zeigt und verbirgt einen Splash-Screen beim Start der Anwendung.\n\n## Installation\n\n    cordova plugin add cordova-plugin-splashscreen\n    \n\n## Unterstützte Plattformen\n\n*   Amazon Fire OS\n*   Android\n*   BlackBerry 10\n*   iOS\n*   Windows Phone 7 und 8\n*   Windows 8\n\n## Methoden\n\n*   SplashScreen.Show\n*   SplashScreen.Hide\n\n### Android Eigenarten\n\nSie müssen in der config.xml folgende Einstellungen vornehmen:\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    \n\nWo Foo ist der Name der Datei Splashscreen, vorzugsweise eine 9-Patch-Datei. Stellen Sie sicher, Splashcreen Dateien zu Ihrem res/xml-Verzeichnis unter den entsprechenden Ordnern hinzuzufügen. Der zweite Parameter stellt dar, wie lange das Splashscreen in Millisekunden angezeigt werden. Es wird standardmäßig auf 3000 ms. Weitere Informationen finden Sie unter [Symbole und Splash-Screens][1].\n\n [1]: http://cordova.apache.org/docs/en/edge/config_ref_images.md.html\n\n## SplashScreen.Hide\n\nSchließen Sie den Splash-Screen.\n\n    navigator.splashscreen.hide();\n    \n\n### BlackBerry 10, WP8, iOS Eigenarten\n\nDie Datei `config.xml` `AutoHideSplashScreen` Einstellung muss `false` sein. Verstecken des Begrüßungsbildschirms für zwei Sekunden Verzögerung, fügen Sie einen Timer wie die folgende in der `deviceready`-Ereignishandler:\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## SplashScreen.Show\n\nZeigt den Begrüßungsbildschirm.\n\n    navigator.splashscreen.show();\n    \n\nIhre Anwendung kann nicht `navigator.splashscreen.show()` aufrufen, bis die app begonnen hat und das `deviceready`-Ereignis ausgelöst hat. Aber da in der Regel der Splash-Screen soll sichtbar sein, bevor die Anwendung gestartet wurde, scheint die Niederlage der Zweck des Begrüßungsbildschirms. Somit einige Konfiguration in der Datei `config.xml` werden automatisch die Splash `show` sofort nach Ihrer app-Start und Bildschirm bevor es voll begonnen hat, und das `deviceready`-Ereignis empfangen. Weitere Informationen zu dieser Konfiguration finden Sie unter [Symbole und Splash-Screens][1]. Aus diesem Grund ist es unwahrscheinlich, dass Sie `navigator.splashscreen.show()` damit den Splash-Screen sichtbar ist für app-Start aufrufen müssen.\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/es/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-splashscreen\n\n[![Build Status](https://travis-ci.org/apache/cordova-plugin-splashscreen.svg)](https://travis-ci.org/apache/cordova-plugin-splashscreen)\n\nEste plugin muestra y esconde una pantalla de bienvenida durante el inicio de la aplicación.\n\n## Instalación\n\n    // npm hosted (new) id\n    cordova plugin add cordova-plugin-splashscreen\n    // you may also install directly from this repo\n    cordova plugin add https://github.com/apache/cordova-plugin-splashscreen.git\n    \n\n## Plataformas soportadas\n\n  * Amazon fire OS\n  * Android\n  * BlackBerry 10\n  * iOS\n  * Windows Phone 7 y 8\n  * Windows 8\n  * Windows\n  * Explorador\n\n## Métodos\n\n  * splashscreen.show\n  * splashscreen.hide\n\n### Rarezas Android\n\nEn el `archivo config.xml`, es necesario agregar las siguientes preferencias:\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    <preference name=\"SplashMaintainAspectRatio\" value=\"true|false\" />\n    \n\nDonde foo es el nombre del archivo splashscreen, preferiblemente un archivo de 9 parche. Asegúrese de agregar tus archivos splashcreen en tu directorio res/xml bajo las carpetas apropiadas. El segundo parámetro representa cuánto aparecerán el splashscreen en milisegundos. Valor predeterminado es ms 3000. Ver [los iconos y salpicadura pantallas](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html) para obtener más información.\n\nPreferencia \"SplashMaintainAspectRatio\" es opcional. Si establece en true, pantalla dibujable no es estirado para caber la pantalla, pero en su lugar simplemente \"cover\" la pantalla, como CSS \"background-size: cover\". Esto es muy útil cuando las imágenes de pantallas splash no distorsionadas de cualquier manera, por ejemplo cuando contienen texto o paisaje. Esta opción funciona mejor con imágenes que tienen bordes grandes (zonas seguras) que pueden ser recortadas con seguridad en pantallas con diferentes relaciones de aspecto.\n\nEl plugin recarga splash dibujable cuando cambia de orientación, por lo que puede especificar diferente dibujo para orientaciones vertical y horizontal.\n\n### Navegador rarezas\n\nPuede utilizar las siguientes preferencias en el `archivo config.xml`:\n\n    <platform name=\"browser\">\n        <preference name=\"SplashScreen\" value=\"images/browser/splashscreen.jpg\" /> <!-- defaults to \"img/logo.png\" -->\n        <preference name=\"SplashScreenDelay\" value=\"10000\" /> <!-- defaults to \"3000\" -->\n        <preference name=\"SplashScreenBackgroundColor\" value=\"green\" /> <!-- defaults to \"#464646\" -->\n        <preference name=\"ShowSplashScreen\" value=\"false\" /> <!-- defaults to \"true\" -->\n        <preference name=\"SplashScreenWidth\" value=\"600\" /> <!-- defaults to \"170\" -->\n        <preference name=\"SplashScreenHeight\" value=\"300\" /> <!-- defaults to \"200\" -->\n    </platform>\n    \n\n### iOS rarezas\n\n  * `FadeSplashScreen` (booleano, por defecto `true`): establecida en `false` para evitar que la pantalla de bienvenida de descolorarse adentro y hacia fuera cuando cambia su estado de presentación.\n    \n        <preference name=\"FadeSplashScreen\" value=\"false\"/>\n        \n\n  * `FadeSplashScreenDuration` (float, por defecto es `2`): especifica el número de segundos para que la pantalla se descolora efecto para ejecutar.\n    \n        <preference name=\"FadeSplashScreenDuration\" value=\"4\"/>\n        \n\n  * `ShowSplashScreenSpinner` (booleano, por defecto `true`): establecida en `false` para ocultar la ruleta de la pantalla de bienvenida.\n    \n        <preference name=\"ShowSplashScreenSpinner\" value=\"false\"/>\n        \n\n## splashscreen.hide\n\nDespedir a la pantalla de bienvenida.\n\n    navigator.splashscreen.hide();\n    \n\n### BlackBerry 10, WP8, iOS Quirk\n\nEl `config.xml` del archivo `AutoHideSplashScreen` la configuración debe ser `false` . Para retrasar oculta la pantalla splash durante dos segundos, agregue un temporizador como la siguiente en el `deviceready` controlador de eventos:\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen.show\n\nMuestra la pantalla de bienvenida.\n\n    navigator.splashscreen.show();\n    \n\nLa aplicación no se puede llamar `navigator.splashscreen.show()` hasta que haya iniciado la aplicación y el `deviceready` evento ha despedido. Pero puesto que normalmente la pantalla está destinada a ser visible antes de que comience su aplicación, que parecería que el propósito de la pantalla de bienvenida. Proporcionar cierta configuración en `config.xml` automáticamente `show` la pantalla de presentación inmediatamente después de su lanzamiento de la aplicación y antes de ser completamente ha iniciado y recibió el `deviceready` evento. Ver [los iconos y salpicadura pantallas](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html) para obtener más información sobre haciendo esta configuración. Por esta razón, es poco probable que necesitas llamar a `navigator.splashscreen.show()` para hacer la pantalla visible para el inicio de la aplicación."
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/es/index.md",
    "content": "<!---\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n-->\n\n# cordova-plugin-splashscreen\n\nEste plugin muestra y esconde una pantalla de bienvenida durante el inicio de la aplicación.\n\n## Instalación\n\n    cordova plugin add cordova-plugin-splashscreen\n    \n\n## Plataformas soportadas\n\n*   Amazon fire OS\n*   Android\n*   BlackBerry 10\n*   iOS\n*   Windows Phone 7 y 8\n*   Windows 8\n\n## Métodos\n\n*   splashscreen.show\n*   splashscreen.hide\n\n### Rarezas Android\n\nEn el archivo config.xml, tienes que añadir las siguientes preferencias:\n\n    < nombre de preferencia = \"SplashScreen\" value = \"foo\" / >< nombre de preferencia = \"SplashScreenDelay\" value = \"10000\" / >\n    \n\nDonde foo es el nombre del archivo splashscreen, preferiblemente un archivo de 9 parche. Asegúrese de agregar tus archivos splashcreen en tu directorio res/xml bajo las carpetas apropiadas. El segundo parámetro representa cuánto aparecerán el splashscreen en milisegundos. Valor predeterminado es ms 3000. Ver [los iconos y salpicadura pantallas][1] para obtener más información.\n\n [1]: http://cordova.apache.org/docs/en/edge/config_ref_images.md.html\n\n## splashscreen.hide\n\nDespedir a la pantalla de bienvenida.\n\n    Navigator.SplashScreen.Hide();\n    \n\n### BlackBerry 10, WP8, iOS Quirk\n\nEl `config.xml` del archivo `AutoHideSplashScreen` la configuración debe ser `false` . Para retrasar oculta la pantalla splash durante dos segundos, agregue un temporizador como la siguiente en el `deviceready` controlador de eventos:\n\n        setTimeout(function() {navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen.show\n\nMuestra la pantalla de bienvenida.\n\n    Navigator.SplashScreen.Show();\n    \n\nLa aplicación no se puede llamar `navigator.splashscreen.show()` hasta que haya iniciado la aplicación y el `deviceready` evento ha despedido. Pero puesto que normalmente la pantalla está destinada a ser visible antes de que comience su aplicación, que parecería que el propósito de la pantalla de bienvenida. Proporcionar cierta configuración en `config.xml` automáticamente `show` la pantalla de presentación inmediatamente después de su lanzamiento de la aplicación y antes de ser completamente ha iniciado y recibió el `deviceready` evento. Ver [los iconos y salpicadura pantallas][1] para obtener más información sobre haciendo esta configuración. Por esta razón, es poco probable que necesitas llamar a `navigator.splashscreen.show()` para hacer la pantalla visible para el inicio de la aplicación.\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/fr/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-splashscreen\n\n[![Build Status](https://travis-ci.org/apache/cordova-plugin-splashscreen.svg)](https://travis-ci.org/apache/cordova-plugin-splashscreen)\n\nCe plugin affiche et masque un écran de démarrage lors du lancement de l'application.\n\n## Installation\n\n    // npm hosted (new) id\n    cordova plugin add cordova-plugin-splashscreen\n    // you may also install directly from this repo\n    cordova plugin add https://github.com/apache/cordova-plugin-splashscreen.git\n    \n\n## Plates-formes supportées\n\n  * Amazon Fire OS\n  * Android\n  * BlackBerry 10\n  * iOS\n  * Windows Phone 7 et 8\n  * Windows 8\n  * Windows\n  * Navigateur\n\n## Méthodes\n\n  * splashscreen.Show\n  * splashscreen.Hide\n\n### Quirks Android\n\nDans votre `fichier config.xml`, vous devez ajouter les préférences suivantes :\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    <preference name=\"SplashMaintainAspectRatio\" value=\"true|false\" />\n    \n\nOù foo est le nom du fichier splashscreen, préférablement un fichier de 9 correctif. Assurez-vous d'ajouter vos fichiers splashcreen dans votre répertoire res/xml dans les dossiers appropriés. Le deuxième paramètre représente combien de temps le splashscreen apparaîtra en millisecondes. Il est par défaut à 3000 ms. Pour plus d'informations, consultez [icônes et écrans de démarrage](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html).\n\nPréférence de « SplashMaintainAspectRatio » est facultative. Si défini à true, écran de démarrage drawable n'est pas étirée pour s'adapter écran, mais plutôt simplement « couvre » l'écran, comme CSS \"fond-taille : couverture\". Ceci est très utile lorsque images écran de démarrage ne peut pas être déformées en quelque sorte, par exemple lorsqu'ils contiennent des décors ou texte. Ce paramètre fonctionne mieux avec des images qui ont des marges importantes (zones de sécurité) qui peuvent être recadrées en toute sécurité sur les écrans avec des proportions différentes.\n\nLe plugin recharge splash drawable chaque fois que l'orientation change, donc vous pouvez spécifier différents drawables pour les orientations portrait et paysage.\n\n### Bizarreries navigateur\n\nVous pouvez utiliser les préférences suivantes dans votre `fichier config.xml`:\n\n    <platform name=\"browser\">\n        <preference name=\"SplashScreen\" value=\"images/browser/splashscreen.jpg\" /> <!-- defaults to \"img/logo.png\" -->\n        <preference name=\"SplashScreenDelay\" value=\"10000\" /> <!-- defaults to \"3000\" -->\n        <preference name=\"SplashScreenBackgroundColor\" value=\"green\" /> <!-- defaults to \"#464646\" -->\n        <preference name=\"ShowSplashScreen\" value=\"false\" /> <!-- defaults to \"true\" -->\n        <preference name=\"SplashScreenWidth\" value=\"600\" /> <!-- defaults to \"170\" -->\n        <preference name=\"SplashScreenHeight\" value=\"300\" /> <!-- defaults to \"200\" -->\n    </platform>\n    \n\n### Notes au sujet d'iOS\n\n  * `FadeSplashScreen` (boolean, par défaut est `true`): la valeur `false` pour empêcher l'écran de démarrage de fading in et out lorsque son état d'affichage est modifié.\n    \n        <preference name=\"FadeSplashScreen\" value=\"false\"/>\n        \n\n  * `FadeSplashScreenDuration` (float, la valeur par défaut `2`): spécifie le nombre de secondes que l'écran de démarrage s'estomper l'effet d'exécuter.\n    \n        <preference name=\"FadeSplashScreenDuration\" value=\"4\"/>\n        \n\n  * `ShowSplashScreenSpinner` (boolean, par défaut est `true`): la valeur `false` pour masquer le cône de l'écran de démarrage.\n    \n        <preference name=\"ShowSplashScreenSpinner\" value=\"false\"/>\n        \n\n## splashscreen.Hide\n\nFaire disparaître de l'écran de démarrage.\n\n    navigator.splashscreen.hide();\n    \n\n### BlackBerry 10, WP8, iOS Quirk\n\nParamètre `AutoHideSplashScreen` du fichier `config.xml` doit avoir la valeur `false`. Pour retarder la cacher l'écran de démarrage pendant deux secondes, ajouter un minuteur semblable à la suivante dans le gestionnaire d'événements `deviceready` :\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen.Show\n\nAffiche l'écran de démarrage.\n\n    navigator.splashscreen.show();\n    \n\nVotre application ne peut pas appeler `navigator.splashscreen.show()` jusqu'à ce que l'application a commencé et l'événement `deviceready` est déclenché. Mais puisqu'en général, l'écran de démarrage est destiné à être visible avant que votre application a commencé, qui semblerait à l'encontre des objectifs de l'écran de démarrage. Fournir une configuration dans le fichier `config.xml` automatiquement `show` le splash projettera immédiatement après votre lancement de l'app et avant qu'il a complètement démarré et a reçu l'événement `deviceready`. Voir les [icônes et les écrans de démarrage](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html) pour plus d'informations sur la conduite de cette configuration. Pour cette raison, il est peu probable que vous devez appeler `navigator.splashscreen.show()` pour rendre l'écran de démarrage visible pour le démarrage de l'application."
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/fr/index.md",
    "content": "<!---\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n-->\n\n# cordova-plugin-splashscreen\n\nCe plugin affiche et masque un écran de démarrage lors du lancement de l'application.\n\n## Installation\n\n    cordova plugin add cordova-plugin-splashscreen\n    \n\n## Plates-formes prises en charge\n\n*   Amazon Fire OS\n*   Android\n*   BlackBerry 10\n*   iOS\n*   Windows Phone 7 et 8\n*   Windows 8\n\n## Méthodes\n\n*   splashscreen.Show\n*   splashscreen.Hide\n\n### Quirks Android\n\nDans votre fichier config.xml, vous devez ajouter les préférences suivantes :\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    \n\nOù foo est le nom du fichier splashscreen, préférablement un fichier de 9 correctif. Assurez-vous d'ajouter vos fichiers splashcreen dans votre répertoire res/xml dans les dossiers appropriés. Le deuxième paramètre représente combien de temps le splashscreen apparaîtra en millisecondes. Il est par défaut à 3000 ms. Pour plus d'informations, consultez [icônes et écrans de démarrage][1].\n\n [1]: http://cordova.apache.org/docs/en/edge/config_ref_images.md.html\n\n## splashscreen.Hide\n\nFaire disparaître de l'écran de démarrage.\n\n    navigator.splashscreen.hide();\n    \n\n### BlackBerry 10, WP8, iOS Quirk\n\nParamètre `AutoHideSplashScreen` du fichier `config.xml` doit avoir la valeur `false`. Pour retarder la cacher l'écran de démarrage pendant deux secondes, ajouter un minuteur semblable à la suivante dans le gestionnaire d'événements `deviceready` :\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen.Show\n\nAffiche l'écran de démarrage.\n\n    navigator.splashscreen.show();\n    \n\nVotre application ne peut pas appeler `navigator.splashscreen.show()` jusqu'à ce que l'application a commencé et l'événement `deviceready` est déclenché. Mais puisqu'en général, l'écran de démarrage est destiné à être visible avant que votre application a commencé, qui semblerait à l'encontre des objectifs de l'écran de démarrage. Fournir une configuration dans le fichier `config.xml` automatiquement `show` le splash projettera immédiatement après votre lancement de l'app et avant qu'il a complètement démarré et a reçu l'événement `deviceready`. Voir les [icônes et les écrans de démarrage][1] pour plus d'informations sur la conduite de cette configuration. Pour cette raison, il est peu probable que vous devez appeler `navigator.splashscreen.show()` pour rendre l'écran de démarrage visible pour le démarrage de l'application.\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/it/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-splashscreen\n\n[![Build Status](https://travis-ci.org/apache/cordova-plugin-splashscreen.svg)](https://travis-ci.org/apache/cordova-plugin-splashscreen)\n\nQuesto plugin Visualizza e nasconde una schermata iniziale durante l'avvio dell'applicazione.\n\n## Installazione\n\n    // npm hosted (new) id\n    cordova plugin add cordova-plugin-splashscreen\n    // you may also install directly from this repo\n    cordova plugin add https://github.com/apache/cordova-plugin-splashscreen.git\n    \n\n## Piattaforme supportate\n\n  * Amazon fuoco OS\n  * Android\n  * BlackBerry 10\n  * iOS\n  * Windows Phone 7 e 8\n  * Windows 8\n  * Windows\n  * Browser\n\n## Metodi\n\n  * splashscreen\n  * splashscreen.Hide\n\n### Stranezze Android\n\nNel vostro `config. XML`, è necessario aggiungere le seguenti preferenze:\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    <preference name=\"SplashMaintainAspectRatio\" value=\"true|false\" />\n    \n\nDove foo è il nome del file splashscreen, preferibilmente un file 9 patch. Assicurati di aggiungere i tuoi file splashcreen res/xml nella directory sotto cartelle appropriate. Il secondo parametro rappresenta quanto tempo lo splashscreen apparirà in millisecondi. Il valore predefinito è 3000 ms. Per ulteriori informazioni, vedere [icone e schermate iniziali](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html).\n\n\"SplashMaintainAspectRatio\" preferenza è facoltativo. Se impostato su true, schermata iniziale drawable non viene adattata per misura lo schermo, ma invece semplicemente \"copre\" lo schermo, come CSS \"sfondo-dimensione: copertina\". Questo è molto utile quando immagini schermata iniziale non possono essere distorta in qualche modo, per esempio quando contengono testo o scenario. Questa impostazione funziona meglio con immagini che hanno grandi margini (zone sicure) che possono essere ritagliati in modo sicuro su schermi con proporzioni diverse.\n\nIl plugin viene ricaricata splash drawable ogni volta che cambia orientamento, è possibile specificare diversi parte per orientamento verticale e orizzontale.\n\n### Stranezze browser\n\nNel vostro `config. XML`, è possibile utilizzare le seguenti preferenze:\n\n    <platform name=\"browser\">\n        <preference name=\"SplashScreen\" value=\"images/browser/splashscreen.jpg\" /> <!-- defaults to \"img/logo.png\" -->\n        <preference name=\"SplashScreenDelay\" value=\"10000\" /> <!-- defaults to \"3000\" -->\n        <preference name=\"SplashScreenBackgroundColor\" value=\"green\" /> <!-- defaults to \"#464646\" -->\n        <preference name=\"ShowSplashScreen\" value=\"false\" /> <!-- defaults to \"true\" -->\n        <preference name=\"SplashScreenWidth\" value=\"600\" /> <!-- defaults to \"170\" -->\n        <preference name=\"SplashScreenHeight\" value=\"300\" /> <!-- defaults to \"200\" -->\n    </platform>\n    \n\n### iOS stranezze\n\n  * `FadeSplashScreen` (boolean, impostazioni predefinite a `true`): impostare su `false` per impedire che la schermata iniziale e scompaiono quando cambia il relativo stato di visualizzazione.\n    \n        <preference name=\"FadeSplashScreen\" value=\"false\"/>\n        \n\n  * `FadeSplashScreenDuration` (float, il valore predefinito è `2`): specifica il numero di secondi per la schermata iniziale dissolvenza effetto da eseguire.\n    \n        <preference name=\"FadeSplashScreenDuration\" value=\"4\"/>\n        \n\n  * `ShowSplashScreenSpinner` (boolean, impostazioni predefinite a `true`): impostare su `false` per nascondere la filatrice schermata iniziale.\n    \n        <preference name=\"ShowSplashScreenSpinner\" value=\"false\"/>\n        \n\n## splashscreen.Hide\n\nRespingere la schermata iniziale.\n\n    navigator.splashscreen.hide();\n    \n\n### BlackBerry 10, WP8, iOS Quirk\n\nImpostazione `AutoHideSplashScreen` del file `config.xml` deve essere `false`. Per ritardare nascondendo la schermata iniziale per due secondi, aggiungere un timer ad esempio nel gestore eventi `deviceready`:\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen\n\nVisualizza la schermata iniziale.\n\n    navigator.splashscreen.show();\n    \n\nL'applicazione non può chiamare `navigator.splashscreen.show()` fino a quando l'app ha iniziato e ha generato l'evento `deviceready`. Ma poiché in genere la schermata iniziale è destinata ad essere visibile prima app ha iniziato, che sembrerebbe per sconfiggere lo scopo della schermata iniziale. Fornendo qualche configurazione nel `file config.xml` sarà automaticamente `show` il tonfo schermo subito dopo il lancio dell'app e prima che completamente ha iniziato e ha ricevuto l'evento `deviceready`. Per ulteriori informazioni su facendo questa configurazione, vedere [icone e schermate iniziali](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html). Per questo motivo, è improbabile che dovete chiamare `navigator.splashscreen.show()` per rendere la schermata visibile per avvio di app."
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/it/index.md",
    "content": "<!---\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n-->\n\n# cordova-plugin-splashscreen\n\nQuesto plugin Visualizza e nasconde una schermata iniziale durante l'avvio dell'applicazione.\n\n## Installazione\n\n    cordova plugin add cordova-plugin-splashscreen\n    \n\n## Piattaforme supportate\n\n*   Amazon fuoco OS\n*   Android\n*   BlackBerry 10\n*   iOS\n*   Windows Phone 7 e 8\n*   Windows 8\n\n## Metodi\n\n*   splashscreen\n*   splashscreen.Hide\n\n### Stranezze Android\n\nNel vostro config. xml, è necessario aggiungere le seguenti preferenze:\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    \n\nDove foo è il nome del file splashscreen, preferibilmente un file 9 patch. Assicurati di aggiungere i tuoi file splashcreen res/xml nella directory sotto cartelle appropriate. Il secondo parametro rappresenta quanto tempo lo splashscreen apparirà in millisecondi. Il valore predefinito è 3000 ms. Per ulteriori informazioni, vedere [icone e schermate iniziali][1].\n\n [1]: http://cordova.apache.org/docs/en/edge/config_ref_images.md.html\n\n## splashscreen.Hide\n\nRespingere la schermata iniziale.\n\n    navigator.splashscreen.hide();\n    \n\n### BlackBerry 10, WP8, iOS Quirk\n\nImpostazione `AutoHideSplashScreen` del file `config.xml` deve essere `false`. Per ritardare nascondendo la schermata iniziale per due secondi, aggiungere un timer ad esempio nel gestore eventi `deviceready`:\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen\n\nVisualizza la schermata iniziale.\n\n    navigator.splashscreen.show();\n    \n\nL'applicazione non può chiamare `navigator.splashscreen.show()` fino a quando l'app ha iniziato e ha generato l'evento `deviceready`. Ma poiché in genere la schermata iniziale è destinata ad essere visibile prima app ha iniziato, che sembrerebbe per sconfiggere lo scopo della schermata iniziale. Fornendo qualche configurazione nel `file config.xml` sarà automaticamente `show` il tonfo schermo subito dopo il lancio dell'app e prima che completamente ha iniziato e ha ricevuto l'evento `deviceready`. Per ulteriori informazioni su facendo questa configurazione, vedere [icone e schermate iniziali][1]. Per questo motivo, è improbabile che dovete chiamare `navigator.splashscreen.show()` per rendere la schermata visibile per avvio di app.\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/ja/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-splashscreen\n\n[![Build Status](https://travis-ci.org/apache/cordova-plugin-splashscreen.svg)](https://travis-ci.org/apache/cordova-plugin-splashscreen)\n\nこのプラグインが表示され、アプリケーションの起動中にスプラッシュ スクリーンを非表示にします。\n\n## インストール\n\n    // npm hosted (new) id\n    cordova plugin add cordova-plugin-splashscreen\n    // you may also install directly from this repo\n    cordova plugin add https://github.com/apache/cordova-plugin-splashscreen.git\n    \n\n## サポートされているプラットフォーム\n\n  * アマゾン火 OS\n  * アンドロイド\n  * ブラックベリー 10\n  * iOS\n  * Windows Phone 7 と 8\n  * Windows 8\n  * Windows\n  * ブラウザー\n\n## メソッド\n\n  * splashscreen.show\n  * splashscreen.hide\n\n### Android の癖\n\nあなたの`config.xml`内の次の設定を追加する必要があります。\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    <preference name=\"SplashMaintainAspectRatio\" value=\"true|false\" />\n    \n\nFoo ができれば 9 パッチファイル splashscreen ファイルの名前です。 解像度/xml ディレクトリの適切なフォルダーの下に splashcreen ファイルを追加することを確認します。 2 番目のパラメーターは、スプラッシュ ・ スクリーンがの表示時間 (ミリ秒単位) を表します。 デフォルトでは 3000 ミリ秒です。 詳細については、[アイコンとスプラッシュ画面](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html) を参照してください。\n\n\"SplashMaintainAspectRatio\"の設定はオプションです。 True の場合、スプラッシュ画面描画に設定画面を埋めるために拡大されませんが、代わりに単に「カバー」画面では、CSS のような場合「背景-サイズ: カバー」. これは、たとえば風景またはテキストが含まれている場合、任意の方法でスプラッシュ画面画像が歪むことができない非常に便利です。 この設定は、画面と異なる縦横比で安全にトリミングすることができます大規模なマージン (安全な地域) の画像に適しています。\n\n縦長と横長の異なるドロウアブルを指定できるように、プラグインは向きを変更するたびにスプラッシュ ドロウアブルをリロードします。\n\n### ブラウザーの癖\n\nあなたの`config.xml`で次の設定を使用できます。\n\n    <platform name=\"browser\">\n        <preference name=\"SplashScreen\" value=\"images/browser/splashscreen.jpg\" /> <!-- defaults to \"img/logo.png\" -->\n        <preference name=\"SplashScreenDelay\" value=\"10000\" /> <!-- defaults to \"3000\" -->\n        <preference name=\"SplashScreenBackgroundColor\" value=\"green\" /> <!-- defaults to \"#464646\" -->\n        <preference name=\"ShowSplashScreen\" value=\"false\" /> <!-- defaults to \"true\" -->\n        <preference name=\"SplashScreenWidth\" value=\"600\" /> <!-- defaults to \"170\" -->\n        <preference name=\"SplashScreenHeight\" value=\"300\" /> <!-- defaults to \"200\" -->\n    </platform>\n    \n\n### iOS の癖\n\n  * `FadeSplashScreen`(ブール値、既定で [ `true`): スプラッシュ画面がフェードインとフェードアウトの表示状態が変更されたときすることを防ぐために`false`に設定します。\n    \n        <preference name=\"FadeSplashScreen\" value=\"false\"/>\n        \n\n  * `FadeSplashScreenDuration`(float, デフォルトは`2`): スプラッシュ画面の秒数のフェードを実行する効果を指定します。\n    \n        <preference name=\"FadeSplashScreenDuration\" value=\"4\"/>\n        \n\n  * `ShowSplashScreenSpinner`(ブール値、既定で [ `true`): スプラッシュ スクリーン スピナーを非表示にするを`false`に設定します。\n    \n        <preference name=\"ShowSplashScreenSpinner\" value=\"false\"/>\n        \n\n## splashscreen.hide\n\nスプラッシュ スクリーンを閉じます。\n\n    navigator.splashscreen.hide();\n    \n\n### ブラックベリー 10、WP8、iOS の気まぐれ\n\n`config.xml` ファイルの `AutoHideSplashScreen` の設定は `false` である必要があります。 遅延を 2 秒間スプラッシュ スクリーンを非表示に `deviceready` イベント ハンドラーで、次のようタイマーを追加します。\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen.show\n\nスプラッシュ画面が表示されます。\n\n    navigator.splashscreen.show();\n    \n\nアプリが開始され、`deviceready` イベントが発生するまで、アプリケーションは `navigator.splashscreen.show()` を呼び出すことはできません。 しかし、以来、通常スプラッシュ画面アプリ開始前に表示するものですと思われる、スプラッシュ スクリーンの目的の敗北します。 `config.xml` にいくつかの構成を提供するは自動的に `表示` スプラッシュ画面、アプリを起動後すぐに、それが完全に起動し、`deviceready` イベントを受信する前に。 詳細についてはこの構成を行うには、[アイコンとスプラッシュ画面](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html) を参照してください。 この理由のためにアプリ起動時のスプラッシュ スクリーンを確認 `navigator.splashscreen.show()` をコールする必要がある可能性が高いです。"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/ja/index.md",
    "content": "<!---\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n-->\n\n# cordova-plugin-splashscreen\n\nこのプラグインが表示され、アプリケーションの起動中にスプラッシュ スクリーンを非表示にします。\n\n## インストール\n\n    cordova plugin add cordova-plugin-splashscreen\n    \n\n## サポートされているプラットフォーム\n\n*   アマゾン火 OS\n*   アンドロイド\n*   ブラックベリー 10\n*   iOS\n*   Windows Phone 7 と 8\n*   Windows 8\n\n## メソッド\n\n*   splashscreen.show\n*   splashscreen.hide\n\n### Android の癖\n\nあなたの config.xml を以下の設定を追加する必要があります。\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    \n\nFoo ができれば 9 パッチファイル splashscreen ファイルの名前です。 解像度/xml ディレクトリの適切なフォルダーの下に splashcreen ファイルを追加することを確認します。 2 番目のパラメーターは、スプラッシュ ・ スクリーンがの表示時間 (ミリ秒単位) を表します。 デフォルトでは 3000 ミリ秒です。 詳細については、[アイコンとスプラッシュ画面][1] を参照してください。\n\n [1]: http://cordova.apache.org/docs/en/edge/config_ref_images.md.html\n\n## splashscreen.hide\n\nスプラッシュ スクリーンを閉じます。\n\n    navigator.splashscreen.hide();\n    \n\n### ブラックベリー 10、WP8、iOS の気まぐれ\n\n`config.xml` ファイルの `AutoHideSplashScreen` の設定は `false` である必要があります。 遅延を 2 秒間スプラッシュ スクリーンを非表示に `deviceready` イベント ハンドラーで、次のようタイマーを追加します。\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen.show\n\nスプラッシュ画面が表示されます。\n\n    navigator.splashscreen.show();\n    \n\nアプリが開始され、`deviceready` イベントが発生するまで、アプリケーションは `navigator.splashscreen.show()` を呼び出すことはできません。 しかし、以来、通常スプラッシュ画面アプリ開始前に表示するものですと思われる、スプラッシュ スクリーンの目的の敗北します。 `config.xml` にいくつかの構成を提供するは自動的に `表示` スプラッシュ画面、アプリを起動後すぐに、それが完全に起動し、`deviceready` イベントを受信する前に。 詳細についてはこの構成を行うには、[アイコンとスプラッシュ画面][1] を参照してください。 この理由のためにアプリ起動時のスプラッシュ スクリーンを確認 `navigator.splashscreen.show()` をコールする必要がある可能性が高いです。\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/ko/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-splashscreen\n\n[![Build Status](https://travis-ci.org/apache/cordova-plugin-splashscreen.svg)](https://travis-ci.org/apache/cordova-plugin-splashscreen)\n\n이 플러그인은 표시 하 고 응용 프로그램 실행 하는 동안 시작 화면을 숨깁니다.\n\n## 설치\n\n    // npm hosted (new) id\n    cordova plugin add cordova-plugin-splashscreen\n    // you may also install directly from this repo\n    cordova plugin add https://github.com/apache/cordova-plugin-splashscreen.git\n    \n\n## 지원 되는 플랫폼\n\n  * 아마존 화재 운영 체제\n  * 안 드 로이드\n  * 블랙베리 10\n  * iOS\n  * Windows Phone 7과 8\n  * 윈도우 8\n  * 윈도우\n  * 브라우저\n\n## 메서드\n\n  * splashscreen.show\n  * splashscreen.hide\n\n### 안 드 로이드 단점\n\n`Config.xml`에 다음 환경 설정에 추가 해야 합니다.\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    <preference name=\"SplashMaintainAspectRatio\" value=\"true|false\" />\n    \n\n여기서 foo splashscreen 파일, 선호 9 패치 파일의 이름입니다. 적절 한 폴더 아래 res/xml 디렉토리에 splashcreen 파일을 추가 해야 합니다. 두 번째 매개 변수는 splashscreen 얼마나 밀리초 단위로 표시 됩니다 나타냅니다. 3000 ms 기본값으로 사용 됩니다. 자세한 내용은 [아이콘 및 시작 화면을](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html) 참조 하십시오.\n\n\"SplashMaintainAspectRatio\" 취향은 선택 사항입니다. Drawable, 시작 화면 설정 화면에 맞게 확장 되지 하지만 대신 단순히 \"커버\" CSS 같은 화면 \"배경-크기: 덮개\". 시작 화면 이미지 예: 풍경 또는 텍스트를 포함 하는 경우 어떤 식으로든에서 왜곡 될 수 없는 경우에 매우 유용 합니다. 이 설정은 큰 여백 (안전 지역) 안전 하 게 다른 종횡비와 화면에 자를 수 있는 이미지에 가장 적합 합니다.\n\n플러그인 다시 로드 스플래시 drawable 방향이 변경 될 때마다 세로 및 가로 방향에 대 한 다른 drawables를 지정할 수 있도록 합니다.\n\n### 브라우저 만지면\n\n`Config.xml`에 다음 기본 설정을 사용할 수 있습니다.\n\n    <platform name=\"browser\">\n        <preference name=\"SplashScreen\" value=\"images/browser/splashscreen.jpg\" /> <!-- defaults to \"img/logo.png\" -->\n        <preference name=\"SplashScreenDelay\" value=\"10000\" /> <!-- defaults to \"3000\" -->\n        <preference name=\"SplashScreenBackgroundColor\" value=\"green\" /> <!-- defaults to \"#464646\" -->\n        <preference name=\"ShowSplashScreen\" value=\"false\" /> <!-- defaults to \"true\" -->\n        <preference name=\"SplashScreenWidth\" value=\"600\" /> <!-- defaults to \"170\" -->\n        <preference name=\"SplashScreenHeight\" value=\"300\" /> <!-- defaults to \"200\" -->\n    </platform>\n    \n\n### iOS 단점\n\n  * `FadeSplashScreen` (부울 `true`로 기본값): 시작 화면 표시 상태로 변경 될 때 밖으로 퇴색 하지 않도록 하려면 `false` 로 설정.\n    \n        <preference name=\"FadeSplashScreen\" value=\"false\"/>\n        \n\n  * `FadeSplashScreenDuration` (부동, `2`기본값): 시작 화면에 대 한 초 페이드 효과를 실행 하는 지정 합니다.\n    \n        <preference name=\"FadeSplashScreenDuration\" value=\"4\"/>\n        \n\n  * `ShowSplashScreenSpinner` (부울 `true`로 기본값): 스플래시 화면 회전자를 숨기려면 `false` 로 설정.\n    \n        <preference name=\"ShowSplashScreenSpinner\" value=\"false\"/>\n        \n\n## splashscreen.hide\n\n시작 화면을 닫습니다.\n\n    navigator.splashscreen.hide();\n    \n\n### 블랙베리 10, WP8, iOS 특질\n\n`config.xml` 파일의 `AutoHideSplashScreen` 설정을 `false` 여야 합니다. 2 초 동안 시작 화면을 숨기고 지연, `deviceready` 이벤트 처리기에서 다음과 같은 타이머를 추가:\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen.show\n\n시작 화면을 표시합니다.\n\n    navigator.splashscreen.show();\n    \n\n응용 프로그램 시작 및 `deviceready` 이벤트는 발생 될 때까지 응용 프로그램이 `navigator.splashscreen.show()`을 호출할 수 없습니다. 하지만 그 스플래시 스크린의 목적 것 같다 일반적으로 시작 화면이 당신의 애플 리 케이 션 시작 하기 전에 표시 될 운명이 다, 이후. `config.xml에서` 몇 가지 구성을 제공 하 자동으로 스플래시 `표시` 화면 애플 리 케이 션 출시 직후와 그것은 완벽 하 게 시작 하 고 `deviceready` 이벤트를 받은 전에. 이 구성 하 고 자세한 내용은 [아이콘 및 시작 화면을](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html) 참조 하십시오. 이러한 이유로, 그것은 가능성이 시작 화면은 응용 프로그램 시작에 대 한 표시 되도록 `navigator.splashscreen.show()`를 호출 해야입니다."
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/ko/index.md",
    "content": "<!---\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n-->\n\n# cordova-plugin-splashscreen\n\n이 플러그인은 표시 하 고 응용 프로그램 실행 하는 동안 시작 화면을 숨깁니다.\n\n## 설치\n\n    cordova plugin add cordova-plugin-splashscreen\n    \n\n## 지원 되는 플랫폼\n\n*   아마존 화재 운영 체제\n*   안 드 로이드\n*   블랙베리 10\n*   iOS\n*   Windows Phone 7과 8\n*   윈도우 8\n\n## 메서드\n\n*   splashscreen.show\n*   splashscreen.hide\n\n### 안 드 로이드 단점\n\n당신의 config.xml에 다음 환경 설정에 추가 해야 합니다.\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    \n\n여기서 foo splashscreen 파일, 선호 9 패치 파일의 이름입니다. 적절 한 폴더 아래 res/xml 디렉토리에 splashcreen 파일을 추가 해야 합니다. 두 번째 매개 변수는 splashscreen 얼마나 밀리초 단위로 표시 됩니다 나타냅니다. 3000 ms 기본값으로 사용 됩니다. 자세한 내용은 [아이콘 및 시작 화면을][1] 참조 하십시오.\n\n [1]: http://cordova.apache.org/docs/en/edge/config_ref_images.md.html\n\n## splashscreen.hide\n\n시작 화면을 닫습니다.\n\n    navigator.splashscreen.hide();\n    \n\n### 블랙베리 10, WP8, iOS 특질\n\n`config.xml` 파일의 `AutoHideSplashScreen` 설정을 `false` 여야 합니다. 2 초 동안 시작 화면을 숨기고 지연, `deviceready` 이벤트 처리기에서 다음과 같은 타이머를 추가:\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen.show\n\n시작 화면을 표시합니다.\n\n    navigator.splashscreen.show();\n    \n\n응용 프로그램 시작 및 `deviceready` 이벤트는 발생 될 때까지 응용 프로그램이 `navigator.splashscreen.show()`을 호출할 수 없습니다. 하지만 그 스플래시 스크린의 목적 것 같다 일반적으로 시작 화면이 당신의 애플 리 케이 션 시작 하기 전에 표시 될 운명이 다, 이후. `config.xml에서` 몇 가지 구성을 제공 하 자동으로 스플래시 `표시` 화면 애플 리 케이 션 출시 직후와 그것은 완벽 하 게 시작 하 고 `deviceready` 이벤트를 받은 전에. 이 구성 하 고 자세한 내용은 [아이콘 및 시작 화면을][1] 참조 하십시오. 이러한 이유로, 그것은 가능성이 시작 화면은 응용 프로그램 시작에 대 한 표시 되도록 `navigator.splashscreen.show()`를 호출 해야입니다.\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/pl/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-splashscreen\n\n[![Build Status](https://travis-ci.org/apache/cordova-plugin-splashscreen.svg)](https://travis-ci.org/apache/cordova-plugin-splashscreen)\n\nTen plugin wyświetla i ukrywa ekran powitalny podczas uruchamiania aplikacji.\n\n## Instalacja\n\n    // npm hosted (new) id\n    cordova plugin add cordova-plugin-splashscreen\n    // you may also install directly from this repo\n    cordova plugin add https://github.com/apache/cordova-plugin-splashscreen.git\n    \n\n## Obsługiwane platformy\n\n  * Amazon Fire OS\n  * Android\n  * BlackBerry 10\n  * iOS\n  * Windows Phone 7 i 8\n  * Windows 8\n  * Windows\n  * Przeglądarka\n\n## Metody\n\n  * splashscreen.show\n  * splashscreen.Hide\n\n### Dziwactwa Androida\n\nW pliku `config.xml`musisz dodać następujące preferencje:\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    <preference name=\"SplashMaintainAspectRatio\" value=\"true|false\" />\n    \n\nGdzie foo jest nazwą pliku ekranu powitalnego, najlepiej 9 łatce. Upewnij się dodać pliki splashcreen do katalogu res/xml w odpowiednich folderach. Drugi parametr reprezentuje, jak długo ekranu powitalnego pojawi się w milisekundach. Domyślnie 3000 ms. Aby uzyskać więcej informacji, zobacz [ikony i ekrany powitalne w aplikacjach](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html).\n\n\"SplashMaintainAspectRatio\" preferencji jest opcjonalne. Jeśli zestaw na wartość true, ekran powitalny dolarowe nie jest rozciągnięty do ekranów, ale zamiast po prostu \"obejmuje\" ekranu, jak CSS \"tło-rozmiar: okładka\". Jest to bardzo przydatne, kiedy opryskać tęcza obrazy nie zniekształcony w jakikolwiek sposób, na przykład, gdy zawierają one dekoracje lub tekst. To ustawienie działa najlepiej z obrazów, które mają duże marginesy (bezpiecznych obszarów), które mogą być bezpiecznie przycięte na ekrany z różnych proporcji.\n\nPlugin ładuje rozchlapać dolarowe, gdy zmienia orientację, tak można określić różnych drawables do orientacji pionowej i poziomej.\n\n### Quirks przeglądarki\n\nW pliku `config.xml`można użyć następujące preferencje:\n\n    <platform name=\"browser\">\n        <preference name=\"SplashScreen\" value=\"images/browser/splashscreen.jpg\" /> <!-- defaults to \"img/logo.png\" -->\n        <preference name=\"SplashScreenDelay\" value=\"10000\" /> <!-- defaults to \"3000\" -->\n        <preference name=\"SplashScreenBackgroundColor\" value=\"green\" /> <!-- defaults to \"#464646\" -->\n        <preference name=\"ShowSplashScreen\" value=\"false\" /> <!-- defaults to \"true\" -->\n        <preference name=\"SplashScreenWidth\" value=\"600\" /> <!-- defaults to \"170\" -->\n        <preference name=\"SplashScreenHeight\" value=\"300\" /> <!-- defaults to \"200\" -->\n    </platform>\n    \n\n### Dziwactwa iOS\n\n  * `FadeSplashScreen` (wartość logiczna, domyślnie `true`): zestaw na `false` , aby zapobiec Znikająca i odkładane po zmianie stanu wyświetlania ekranu powitalnego.\n    \n        <preference name=\"FadeSplashScreen\" value=\"false\"/>\n        \n\n  * `FadeSplashScreenDuration` (float, domyślnie `2`): określa liczbę sekund dla ekranu powitalnego zanikanie efekt do wykonać.\n    \n        <preference name=\"FadeSplashScreenDuration\" value=\"4\"/>\n        \n\n  * `ShowSplashScreenSpinner` (wartość logiczna, domyślnie `true`): zestaw na `false` , aby ukryć pokrętła ekran powitalny.\n    \n        <preference name=\"ShowSplashScreenSpinner\" value=\"false\"/>\n        \n\n## splashscreen.Hide\n\nOdrzucić ten opryskaæ têcza.\n\n    navigator.splashscreen.hide();\n    \n\n### Jeżyna 10, WP8, iOS dziwactwo\n\nPlik `config.xml` `AutoHideSplashScreen` ustawienie musi być `false`. Opóźnienia, ukrywanie ekranu powitalnego przez dwie sekundy, dodać timer następujących w `deviceready` obsługa zdarzeń:\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen.show\n\nWyświetla ekran powitalny.\n\n    navigator.splashscreen.show();\n    \n\nAplikacja nie można wywołać `navigator.splashscreen.show()`, aż aplikacja została uruchomiona i zdarzenie `deviceready` został zwolniony. Ale ponieważ zazwyczaj opryskać tęcza ma być widoczne przed rozpoczęciem aplikacji, wydaje się sprzeczne z celem ekranu powitalnego. Dostarczanie niektórych konfiguracji w `pliku config.xml` będzie automatycznie `show` splash na ekranie natychmiast po uruchomienie aplikacji i przed pełni rozpoczął i odebrał zdarzenie `deviceready`. Aby uzyskać więcej informacji na robienie tej konfiguracji, zobacz [ikony i ekrany powitalne w aplikacjach](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html). Z tego powodu jest mało prawdopodobne, należy zadzwonić `navigator.splashscreen.show()`, aby wyświetlić ekran powitalny dla uruchamiania aplikacji."
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/pl/index.md",
    "content": "<!---\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n-->\n\n# cordova-plugin-splashscreen\n\nTen plugin wyświetla i ukrywa ekran powitalny podczas uruchamiania aplikacji.\n\n## Instalacja\n\n    cordova plugin add cordova-plugin-splashscreen\n    \n\n## Obsługiwane platformy\n\n*   Amazon Fire OS\n*   Android\n*   BlackBerry 10\n*   iOS\n*   Windows Phone 7 i 8\n*   Windows 8\n\n## Metody\n\n*   splashscreen.show\n*   splashscreen.Hide\n\n### Dziwactwa Androida\n\nW pliku config.xml musisz dodać następujące preferencje:\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    \n\nGdzie foo jest nazwą pliku ekranu powitalnego, najlepiej 9 łatce. Upewnij się dodać pliki splashcreen do katalogu res/xml w odpowiednich folderach. Drugi parametr reprezentuje, jak długo ekranu powitalnego pojawi się w milisekundach. Domyślnie 3000 ms. Aby uzyskać więcej informacji, zobacz [ikony i ekrany powitalne w aplikacjach][1].\n\n [1]: http://cordova.apache.org/docs/en/edge/config_ref_images.md.html\n\n## splashscreen.Hide\n\nOdrzucić ten opryskaæ têcza.\n\n    navigator.splashscreen.hide();\n    \n\n### Jeżyna 10, WP8, iOS dziwactwo\n\nPlik `config.xml` `AutoHideSplashScreen` ustawienie musi być `false`. Opóźnienia, ukrywanie ekranu powitalnego przez dwie sekundy, dodać timer następujących w `deviceready` obsługa zdarzeń:\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen.show\n\nWyświetla ekran powitalny.\n\n    navigator.splashscreen.show();\n    \n\nAplikacja nie można wywołać `navigator.splashscreen.show()`, aż aplikacja została uruchomiona i zdarzenie `deviceready` został zwolniony. Ale ponieważ zazwyczaj opryskać tęcza ma być widoczne przed rozpoczęciem aplikacji, wydaje się sprzeczne z celem ekranu powitalnego. Dostarczanie niektórych konfiguracji w `pliku config.xml` będzie automatycznie `show` splash na ekranie natychmiast po uruchomienie aplikacji i przed pełni rozpoczął i odebrał zdarzenie `deviceready`. Aby uzyskać więcej informacji na robienie tej konfiguracji, zobacz [ikony i ekrany powitalne w aplikacjach][1]. Z tego powodu jest mało prawdopodobne, należy zadzwonić `navigator.splashscreen.show()`, aby wyświetlić ekran powitalny dla uruchamiania aplikacji.\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/ru/index.md",
    "content": "<!---\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n-->\n\n# cordova-plugin-splashscreen\n\nЭтот плагин отображает и скрывает экран-заставку при запуске приложения.\n\n## Установка\n\n    cordova plugin add cordova-plugin-splashscreen\n    \n\n## Поддерживаемые платформы\n\n*   Amazon Fire OS\n*   Android\n*   BlackBerry 10\n*   iOS\n*   Windows Phone 7 и 8\n*   Windows 8\n\n## Методы\n\n*   splashscreen.show\n*   splashscreen.hide\n\n### Особенности Android\n\nВ вашем файле config.xml необходимо добавить следующие настройки:\n\n`<preference name=\"SplashScreen\" value=\"foo\" />` `<preference name=\"SplashScreenDelay\" value=\"10000\" />`\n\nГде foo это имя файла splashscreen, желательно 9 заплатку. Убедитесь в том добавить ваши splashcreen файлы в папку res/xml в соответствующие папки. Второй параметр представляет, как долго splashscreen появится в миллисекундах. По умолчанию он 3000 МС. Увидеть [иконки и заставки][1] для получения дополнительной информации.\n\n [1]: http://cordova.apache.org/docs/en/edge/config_ref_images.md.html\n\n## splashscreen.hide\n\nЗакройте экран-заставка.\n\n    Navigator.SplashScreen.Hide();\n    \n\n### Особенности BlackBerry 10, WP8, iOS\n\n`config.xml`Файла `AutoHideSplashScreen` должен быть `false` . Для задержки скрытия заставки на две секунды, добавить таймер, например в `deviceready` обработчик событий:\n\n        setTimeout(function() {navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen.show\n\nОтображает экран-заставку.\n\n    Navigator.SplashScreen.Show();\n    \n\nВаше приложение не может вызвать `navigator.splashscreen.show()` до тех пор, пока приложение началась и `deviceready` событие инициировано. Но поскольку обычно экран-заставка должен быть видимым до начала вашего приложения, что казалось бы поражение цели экрана-заставки. Предоставление некоторых конфигурации в `config.xml` будет автоматически `show` экран-заставку сразу же после запуска вашего приложения и перед его полностью запущен и получил `deviceready` событие. Увидеть [иконки и заставки][1] для получения дополнительной информации на делать этой конфигурации. По этой причине маловероятно, вам нужно вызвать `navigator.splashscreen.show()` для отображения экрана-заставки для запуска приложения.\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/zh/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-splashscreen\n\n[![Build Status](https://travis-ci.org/apache/cordova-plugin-splashscreen.svg)](https://travis-ci.org/apache/cordova-plugin-splashscreen)\n\n這個外掛程式顯示和隱藏在應用程式啟動期間的初始螢幕。\n\n## 安裝\n\n    // npm hosted (new) id\n    cordova plugin add cordova-plugin-splashscreen\n    // you may also install directly from this repo\n    cordova plugin add https://github.com/apache/cordova-plugin-splashscreen.git\n    \n\n## 支援的平臺\n\n  * 亞馬遜火 OS\n  * Android 系統\n  * 黑莓 10\n  * iOS\n  * Windows Phone 7 和 8\n  * Windows 8\n  * Windows\n  * 瀏覽器\n\n## 方法\n\n  * splashscreen.show\n  * splashscreen.hide\n\n### Android 的怪癖\n\n在你的`config.xml`，您需要添加以下優惠:\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    <preference name=\"SplashMaintainAspectRatio\" value=\"true|false\" />\n    \n\n美孚在哪裡閃屏檔，最好是 9 修補程式檔的名稱。 請確保您的 splashcreen 檔添加到 res/xml 目錄下相應的資料夾。 第二個參數表示多久閃屏會顯示以毫秒為單位。 它將預設為 3000 毫秒。 有關更多資訊，請參見 [圖示和啟動畫面](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html)。\n\n\"SplashMaintainAspectRatio\"首選項是可選的。 如果設置為 true，可繪製的初始螢幕不會拉伸以適合螢幕，但相反只是\"覆蓋\"螢幕，像 CSS\"背景-大小: 蓋\"。 這是非常有用的不能以任何方式，例如當他們包含文本或風景畸變閃屏圖像時。 此設置適用于有大利潤 (安全區)，可以安全地裁剪不同長寬比與螢幕上的圖像。\n\n該外掛程式重新載入初始可繪製只要方向發生變化，所以您可以指定不同的畫板為縱向和橫向方向。\n\n### 瀏覽器的怪癖\n\n你可以用你的`config.xml`下列優先選項:\n\n    <platform name=\"browser\">\n        <preference name=\"SplashScreen\" value=\"images/browser/splashscreen.jpg\" /> <!-- defaults to \"img/logo.png\" -->\n        <preference name=\"SplashScreenDelay\" value=\"10000\" /> <!-- defaults to \"3000\" -->\n        <preference name=\"SplashScreenBackgroundColor\" value=\"green\" /> <!-- defaults to \"#464646\" -->\n        <preference name=\"ShowSplashScreen\" value=\"false\" /> <!-- defaults to \"true\" -->\n        <preference name=\"SplashScreenWidth\" value=\"600\" /> <!-- defaults to \"170\" -->\n        <preference name=\"SplashScreenHeight\" value=\"300\" /> <!-- defaults to \"200\" -->\n    </platform>\n    \n\n### iOS 的怪癖\n\n  * `FadeSplashScreen`(預設為`true`的布林值): 設置為`false` ，以防止出現閃屏衰落和退出其顯示狀態發生變化時。\n    \n        <preference name=\"FadeSplashScreen\" value=\"false\"/>\n        \n\n  * `FadeSplashScreenDuration`(float，預設為`2`): 指定的閃屏秒數淡出效果來執行。\n    \n        <preference name=\"FadeSplashScreenDuration\" value=\"4\"/>\n        \n\n  * `ShowSplashScreenSpinner`(boolean, `true`的布林值): 設置為`false`來隱藏初始螢幕微調框。\n    \n        <preference name=\"ShowSplashScreenSpinner\" value=\"false\"/>\n        \n\n## splashscreen.hide\n\n解雇的閃屏。\n\n    navigator.splashscreen.hide();\n    \n\n### 黑莓 10，WP8，iOS 怪癖\n\n`config.xml` 檔 `AutoHideSplashScreen` 設置必須是 `假` 的。 若要延遲兩秒鐘隱藏的閃屏，`deviceready` 事件處理常式中添加一個計時器，如下所示：\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen.show\n\n顯示初始螢幕。\n\n    navigator.splashscreen.show();\n    \n\n您的應用程式無法調用 `navigator.splashscreen.show()`，直到該應用程式已啟動，且觸發了 `deviceready` 事件。 但是，由於通常的閃屏為了是可見的在您的應用程式啟動之前，這似乎會打敗閃屏的目的。 提供一些配置在 `config.xml` 中的會自動 `show` 初始螢幕您的應用程式啟動後立即和之前它已經完全起步並收到 `deviceready` 事件。 做這種配置的詳細資訊，請參閱 [圖示和啟動畫面](http://cordova.apache.org/docs/en/edge/config_ref_images.md.html)。 出於此原因，不太可能您需要調用 `navigator.splashscreen.show()`，使初始螢幕可見為應用程式啟動。"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/doc/zh/index.md",
    "content": "<!---\n    Licensed to the Apache Software Foundation (ASF) under one\n    or more contributor license agreements.  See the NOTICE file\n    distributed with this work for additional information\n    regarding copyright ownership.  The ASF licenses this file\n    to you under the Apache License, Version 2.0 (the\n    \"License\"); you may not use this file except in compliance\n    with the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing,\n    software distributed under the License is distributed on an\n    \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n    KIND, either express or implied.  See the License for the\n    specific language governing permissions and limitations\n    under the License.\n-->\n\n# cordova-plugin-splashscreen\n\n這個外掛程式顯示和隱藏在應用程式啟動期間的初始螢幕。\n\n## 安裝\n\n    cordova plugin add cordova-plugin-splashscreen\n    \n\n## 支援的平臺\n\n*   亞馬遜火 OS\n*   Android 系統\n*   黑莓 10\n*   iOS\n*   Windows Phone 7 和 8\n*   Windows 8\n\n## 方法\n\n*   splashscreen.show\n*   splashscreen.hide\n\n### Android 的怪癖\n\n在你的 config.xml，您需要添加以下優惠：\n\n    <preference name=\"SplashScreen\" value=\"foo\" />\n    <preference name=\"SplashScreenDelay\" value=\"10000\" />\n    \n\n美孚在哪裡閃屏檔，最好是 9 修補程式檔的名稱。 請確保您的 splashcreen 檔添加到 res/xml 目錄下相應的資料夾。 第二個參數表示多久閃屏會顯示以毫秒為單位。 它將預設為 3000 毫秒。 有關更多資訊，請參見 [圖示和啟動畫面][1]。\n\n [1]: http://cordova.apache.org/docs/en/edge/config_ref_images.md.html\n\n## splashscreen.hide\n\n解雇的閃屏。\n\n    navigator.splashscreen.hide();\n    \n\n### 黑莓 10，WP8，iOS 怪癖\n\n`config.xml` 檔 `AutoHideSplashScreen` 設置必須是 `假` 的。 若要延遲兩秒鐘隱藏的閃屏，`deviceready` 事件處理常式中添加一個計時器，如下所示：\n\n        setTimeout(function() {\n            navigator.splashscreen.hide();\n        }, 2000);\n    \n\n## splashscreen.show\n\n顯示初始螢幕。\n\n    navigator.splashscreen.show();\n    \n\n您的應用程式無法調用 `navigator.splashscreen.show()`，直到該應用程式已啟動，且觸發了 `deviceready` 事件。 但是，由於通常的閃屏為了是可見的在您的應用程式啟動之前，這似乎會打敗閃屏的目的。 提供一些配置在 `config.xml` 中的會自動 `show` 初始螢幕您的應用程式啟動後立即和之前它已經完全起步並收到 `deviceready` 事件。 做這種配置的詳細資訊，請參閱 [圖示和啟動畫面][1]。 出於此原因，不太可能您需要調用 `navigator.splashscreen.show()`，使初始螢幕可見為應用程式啟動。\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/package.json",
    "content": "{\n  \"name\": \"cordova-plugin-splashscreen\",\n  \"version\": \"4.0.1\",\n  \"description\": \"Cordova Splashscreen Plugin\",\n  \"cordova\": {\n    \"id\": \"cordova-plugin-splashscreen\",\n    \"platforms\": [\n      \"android\",\n      \"amazon-fireos\",\n      \"ubuntu\",\n      \"ios\",\n      \"blackberry10\",\n      \"wp8\",\n      \"windows8\",\n      \"windows\",\n      \"tizen\"\n    ]\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/apache/cordova-plugin-splashscreen\"\n  },\n  \"keywords\": [\n    \"cordova\",\n    \"splashscreen\",\n    \"ecosystem:cordova\",\n    \"cordova-android\",\n    \"cordova-amazon-fireos\",\n    \"cordova-ubuntu\",\n    \"cordova-ios\",\n    \"cordova-blackberry10\",\n    \"cordova-wp8\",\n    \"cordova-windows8\",\n    \"cordova-windows\",\n    \"cordova-tizen\"\n  ],\n  \"scripts\": {\n    \"test\": \"npm run jshint\",\n    \"jshint\": \"node node_modules/jshint/bin/jshint www && node node_modules/jshint/bin/jshint src && node node_modules/jshint/bin/jshint tests\"\n  },\n  \"engines\": {\n    \"cordovaDependencies\": {\n      \"2.0.0\": {\n        \"cordova-android\": \">=3.6.0\"\n      },\n      \"4.0.0\": {\n        \"cordova-android\": \">=3.6.0\",\n        \"cordova-windows\": \">=4.4.0\"\n      },\n      \"5.0.0\": {\n        \"cordova\": \">100\"\n      }\n    }\n  },\n  \"author\": \"Apache Software Foundation\",\n  \"license\": \"Apache-2.0\",\n  \"devDependencies\": {\n    \"jshint\": \"^2.6.0\"\n  }\n}\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/plugin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one\n  or more contributor license agreements.  See the NOTICE file\n  distributed with this work for additional information\n  regarding copyright ownership.  The ASF licenses this file\n  to you under the Apache License, Version 2.0 (the\n  \"License\"); you may not use this file except in compliance\n  with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an\n  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n  KIND, either express or implied.  See the License for the\n  specific language governing permissions and limitations\n  under the License.\n-->\n\n<plugin xmlns=\"http://apache.org/cordova/ns/plugins/1.0\"\n           id=\"cordova-plugin-splashscreen\"\n      version=\"4.0.1\">\n    <name>Splashscreen</name>\n    <description>Cordova Splashscreen Plugin</description>\n    <license>Apache 2.0</license>\n    <keywords>cordova,splashscreen</keywords>\n    <repo>https://git-wip-us.apache.org/repos/asf/cordova-plugin-splashscreen.git</repo>\n    <issue>https://issues.apache.org/jira/browse/CB/component/12320653</issue>\n\n    <engines>\n        <engine name=\"cordova-android\" version=\">=3.6.0\" /><!-- Requires CordovaPlugin.preferences -->\n        <engine name=\"cordova-windows\" version=\">=4.4.0\" />\n    </engines>\n\n    <js-module src=\"www/splashscreen.js\" name=\"SplashScreen\">\n        <clobbers target=\"navigator.splashscreen\" />\n    </js-module>\n\n    <!-- android -->\n    <platform name=\"android\">\n        <config-file target=\"res/xml/config.xml\" parent=\"/*\">\n            <feature name=\"SplashScreen\">\n                <param name=\"android-package\" value=\"org.apache.cordova.splashscreen.SplashScreen\"/>\n                <param name=\"onload\" value=\"true\"/>\n            </feature>\n        </config-file>\n\n        <source-file src=\"src/android/SplashScreen.java\" target-dir=\"src/org/apache/cordova/splashscreen\" />\n    </platform>\n\n    <!-- amazon-fireos -->\n    <platform name=\"amazon-fireos\">\n        <config-file target=\"res/xml/config.xml\" parent=\"/*\">\n            <feature name=\"SplashScreen\">\n            <param name=\"android-package\" value=\"org.apache.cordova.splashscreen.SplashScreen\"/>\n            </feature>\n        </config-file>\n\n        <source-file src=\"src/android/SplashScreen.java\" target-dir=\"src/org/apache/cordova/splashscreen\" />\n    </platform>\n\n    <!-- ubuntu -->\n    <platform name=\"ubuntu\">\n        <header-file src=\"src/ubuntu/splashscreen.h\" />\n        <source-file src=\"src/ubuntu/splashscreen.cpp\" />\n    </platform>\n\n    <!-- ios -->\n    <platform name=\"ios\">\n        <config-file target=\"config.xml\" parent=\"/*\">\n\t\t    <feature name=\"SplashScreen\">\n\t\t\t    <param name=\"ios-package\" value=\"CDVSplashScreen\"/>\n\t\t\t    <param name=\"onload\" value=\"true\"/>\n\t\t    </feature>\n        </config-file>\n\n        <header-file src=\"src/ios/CDVSplashScreen.h\" />\n        <source-file src=\"src/ios/CDVSplashScreen.m\" />\n        <header-file src=\"src/ios/CDVViewController+SplashScreen.h\" />\n        <source-file src=\"src/ios/CDVViewController+SplashScreen.m\" />\n\n\t    <framework src=\"CoreGraphics.framework\" />\n    </platform>\n\n    <!-- blackberry10 -->\n    <platform name=\"blackberry10\">\n        <source-file src=\"src/blackberry10/index.js\" target-dir=\"SplashScreen\" />\n        <config-file target=\"www/config.xml\" parent=\"/widget\">\n            <feature name=\"SplashScreen\" value=\"SplashScreen\"/>\n        </config-file>\n    </platform>\n\n    <!-- wp8 -->\n    <platform name=\"wp8\">\n        <config-file target=\"config.xml\" parent=\"/*\">\n            <feature name=\"SplashScreen\">\n                <param name=\"wp-package\" value=\"SplashScreen\"/>\n                <param name=\"onload\" value=\"true\"/>\n            </feature>\n        </config-file>\n\n        <source-file src=\"src/wp/SplashScreen.cs\" />\n        <source-file src=\"src/wp/ResolutionHelper.cs\" />\n\n    </platform>\n\n    <!-- windows8 -->\n    <platform name=\"windows8\">\n        <js-module src=\"www/windows/SplashScreenProxy.js\" name=\"SplashScreenProxy\">\n            <merges target=\"\" />\n        </js-module>\n    </platform>\n\n    <!-- windows -->\n    <platform name=\"windows\">\n        <js-module src=\"www/windows/SplashScreenProxy.js\" name=\"SplashScreenProxy\">\n            <merges target=\"\" />\n        </js-module>\n    </platform>\n\n    <!-- tizen -->\n    <platform name=\"tizen\">\n        <js-module src=\"src/tizen/SplashScreenProxy.js\" name=\"SplashScreenProxy\">\n            <runs />\n        </js-module>\n    </platform>\n\n    <!-- browser -->\n    <platform name=\"browser\">\n        <js-module src=\"src/browser/SplashScreenProxy.js\" name=\"SplashScreenProxy\">\n            <runs />\n        </js-module>\n    </platform>\n</plugin>\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/src/android/SplashScreen.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova.splashscreen;\n\nimport android.app.Dialog;\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.res.Configuration;\nimport android.graphics.Color;\nimport android.graphics.drawable.ColorDrawable;\nimport android.os.Handler;\nimport android.view.Display;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewGroup.LayoutParams;\nimport android.view.WindowManager;\nimport android.view.animation.Animation;\nimport android.view.animation.AlphaAnimation;\nimport android.view.animation.DecelerateInterpolator;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.ProgressBar;\nimport android.widget.RelativeLayout;\n\nimport org.apache.cordova.CallbackContext;\nimport org.apache.cordova.CordovaPlugin;\nimport org.apache.cordova.CordovaWebView;\nimport org.json.JSONArray;\nimport org.json.JSONException;\n\npublic class SplashScreen extends CordovaPlugin {\n    private static final String LOG_TAG = \"SplashScreen\";\n    // Cordova 3.x.x has a copy of this plugin bundled with it (SplashScreenInternal.java).\n    // Enable functionality only if running on 4.x.x.\n    private static final boolean HAS_BUILT_IN_SPLASH_SCREEN = Integer.valueOf(CordovaWebView.CORDOVA_VERSION.split(\"\\\\.\")[0]) < 4;\n    private static final int DEFAULT_SPLASHSCREEN_DURATION = 3000;\n    private static final int DEFAULT_FADE_DURATION = 500;\n    private static Dialog splashDialog;\n    private static ProgressDialog spinnerDialog;\n    private static boolean firstShow = true;\n    private static boolean lastHideAfterDelay; // https://issues.apache.org/jira/browse/CB-9094\n\n    /**\n     * Displays the splash drawable.\n     */\n    private ImageView splashImageView;\n\n    /**\n     * Remember last device orientation to detect orientation changes.\n     */\n    private int orientation;\n\n    // Helper to be compile-time compatible with both Cordova 3.x and 4.x.\n    private View getView() {\n        try {\n            return (View)webView.getClass().getMethod(\"getView\").invoke(webView);\n        } catch (Exception e) {\n            return (View)webView;\n        }\n    }\n\n    @Override\n    protected void pluginInitialize() {\n        if (HAS_BUILT_IN_SPLASH_SCREEN) {\n            return;\n        }\n        // Make WebView invisible while loading URL\n        // CB-11326 Ensure we're calling this on UI thread\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                getView().setVisibility(View.INVISIBLE);\n            }\n        });\n        int drawableId = preferences.getInteger(\"SplashDrawableId\", 0);\n        if (drawableId == 0) {\n            String splashResource = preferences.getString(\"SplashScreen\", \"screen\");\n            if (splashResource != null) {\n                drawableId = cordova.getActivity().getResources().getIdentifier(splashResource, \"drawable\", cordova.getActivity().getClass().getPackage().getName());\n                if (drawableId == 0) {\n                    drawableId = cordova.getActivity().getResources().getIdentifier(splashResource, \"drawable\", cordova.getActivity().getPackageName());\n                }\n                preferences.set(\"SplashDrawableId\", drawableId);\n            }\n        }\n\n        // Save initial orientation.\n        orientation = cordova.getActivity().getResources().getConfiguration().orientation;\n\n        if (firstShow) {\n            boolean autoHide = preferences.getBoolean(\"AutoHideSplashScreen\", true);\n            showSplashScreen(autoHide);\n        }\n\n        if (preferences.getBoolean(\"SplashShowOnlyFirstTime\", true)) {\n            firstShow = false;\n        }\n    }\n\n    /**\n     * Shorter way to check value of \"SplashMaintainAspectRatio\" preference.\n     */\n    private boolean isMaintainAspectRatio () {\n        return preferences.getBoolean(\"SplashMaintainAspectRatio\", false);\n    }\n\n    private int getFadeDuration () {\n        int fadeSplashScreenDuration = preferences.getBoolean(\"FadeSplashScreen\", true) ?\n            preferences.getInteger(\"FadeSplashScreenDuration\", DEFAULT_FADE_DURATION) : 0;\n\n        if (fadeSplashScreenDuration < 30) {\n            // [CB-9750] This value used to be in decimal seconds, so we will assume that if someone specifies 10\n            // they mean 10 seconds, and not the meaningless 10ms\n            fadeSplashScreenDuration *= 1000;\n        }\n\n        return fadeSplashScreenDuration;\n    }\n\n    @Override\n    public void onPause(boolean multitasking) {\n        if (HAS_BUILT_IN_SPLASH_SCREEN) {\n            return;\n        }\n        // hide the splash screen to avoid leaking a window\n        this.removeSplashScreen(true);\n    }\n\n    @Override\n    public void onDestroy() {\n        if (HAS_BUILT_IN_SPLASH_SCREEN) {\n            return;\n        }\n        // hide the splash screen to avoid leaking a window\n        this.removeSplashScreen(true);\n        // If we set this to true onDestroy, we lose track when we go from page to page!\n        //firstShow = true;\n    }\n\n    @Override\n    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {\n        if (action.equals(\"hide\")) {\n            cordova.getActivity().runOnUiThread(new Runnable() {\n                public void run() {\n                    webView.postMessage(\"splashscreen\", \"hide\");\n                }\n            });\n        } else if (action.equals(\"show\")) {\n            cordova.getActivity().runOnUiThread(new Runnable() {\n                public void run() {\n                    webView.postMessage(\"splashscreen\", \"show\");\n                }\n            });\n        } else {\n            return false;\n        }\n\n        callbackContext.success();\n        return true;\n    }\n\n    @Override\n    public Object onMessage(String id, Object data) {\n        if (HAS_BUILT_IN_SPLASH_SCREEN) {\n            return null;\n        }\n        if (\"splashscreen\".equals(id)) {\n            if (\"hide\".equals(data.toString())) {\n                this.removeSplashScreen(false);\n            } else {\n                this.showSplashScreen(false);\n            }\n        } else if (\"spinner\".equals(id)) {\n            if (\"stop\".equals(data.toString())) {\n                getView().setVisibility(View.VISIBLE);\n            }\n        } else if (\"onReceivedError\".equals(id)) {\n            this.spinnerStop();\n        }\n        return null;\n    }\n\n    // Don't add @Override so that plugin still compiles on 3.x.x for a while\n    public void onConfigurationChanged(Configuration newConfig) {\n        if (newConfig.orientation != orientation) {\n            orientation = newConfig.orientation;\n\n            // Splash drawable may change with orientation, so reload it.\n            if (splashImageView != null) {\n                int drawableId = preferences.getInteger(\"SplashDrawableId\", 0);\n                if (drawableId != 0) {\n                    splashImageView.setImageDrawable(cordova.getActivity().getResources().getDrawable(drawableId));\n                }\n            }\n        }\n    }\n\n    private void removeSplashScreen(final boolean forceHideImmediately) {\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            public void run() {\n                if (splashDialog != null && splashDialog.isShowing()) {\n                    final int fadeSplashScreenDuration = getFadeDuration();\n                    // CB-10692 If the plugin is being paused/destroyed, skip the fading and hide it immediately\n                    if (fadeSplashScreenDuration > 0 && forceHideImmediately == false) {\n                        AlphaAnimation fadeOut = new AlphaAnimation(1, 0);\n                        fadeOut.setInterpolator(new DecelerateInterpolator());\n                        fadeOut.setDuration(fadeSplashScreenDuration);\n\n                        splashImageView.setAnimation(fadeOut);\n                        splashImageView.startAnimation(fadeOut);\n\n                        fadeOut.setAnimationListener(new Animation.AnimationListener() {\n                            @Override\n                            public void onAnimationStart(Animation animation) {\n                                spinnerStop();\n                            }\n\n                            @Override\n                            public void onAnimationEnd(Animation animation) {\n                                if (splashDialog != null && splashDialog.isShowing()) {\n                                    splashDialog.dismiss();\n                                    splashDialog = null;\n                                    splashImageView = null;\n                                }\n                            }\n\n                            @Override\n                            public void onAnimationRepeat(Animation animation) {\n                            }\n                        });\n                    } else {\n                        spinnerStop();\n                        splashDialog.dismiss();\n                        splashDialog = null;\n                        splashImageView = null;\n                    }\n                }\n            }\n        });\n    }\n\n    /**\n     * Shows the splash screen over the full Activity\n     */\n    @SuppressWarnings(\"deprecation\")\n    private void showSplashScreen(final boolean hideAfterDelay) {\n        final int splashscreenTime = preferences.getInteger(\"SplashScreenDelay\", DEFAULT_SPLASHSCREEN_DURATION);\n        final int drawableId = preferences.getInteger(\"SplashDrawableId\", 0);\n\n        final int fadeSplashScreenDuration = getFadeDuration();\n        final int effectiveSplashDuration = Math.max(0, splashscreenTime - fadeSplashScreenDuration);\n\n        lastHideAfterDelay = hideAfterDelay;\n\n        // If the splash dialog is showing don't try to show it again\n        if (splashDialog != null && splashDialog.isShowing()) {\n            return;\n        }\n        if (drawableId == 0 || (splashscreenTime <= 0 && hideAfterDelay)) {\n            return;\n        }\n\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            public void run() {\n                // Get reference to display\n                Display display = cordova.getActivity().getWindowManager().getDefaultDisplay();\n                Context context = webView.getContext();\n\n                // Use an ImageView to render the image because of its flexible scaling options.\n                splashImageView = new ImageView(context);\n                splashImageView.setImageResource(drawableId);\n                LayoutParams layoutParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);\n                splashImageView.setLayoutParams(layoutParams);\n\n                splashImageView.setMinimumHeight(display.getHeight());\n                splashImageView.setMinimumWidth(display.getWidth());\n\n                // TODO: Use the background color of the webView's parent instead of using the preference.\n                splashImageView.setBackgroundColor(preferences.getInteger(\"backgroundColor\", Color.BLACK));\n\n                if (isMaintainAspectRatio()) {\n                    // CENTER_CROP scale mode is equivalent to CSS \"background-size:cover\"\n                    splashImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);\n                }\n                else {\n                    // FIT_XY scales image non-uniformly to fit into image view.\n                    splashImageView.setScaleType(ImageView.ScaleType.FIT_XY);\n                }\n\n                // Create and show the dialog\n                splashDialog = new Dialog(context, android.R.style.Theme_Translucent_NoTitleBar);\n                // check to see if the splash screen should be full screen\n                if ((cordova.getActivity().getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN)\n                        == WindowManager.LayoutParams.FLAG_FULLSCREEN) {\n                    splashDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,\n                            WindowManager.LayoutParams.FLAG_FULLSCREEN);\n                }\n                splashDialog.setContentView(splashImageView);\n                splashDialog.setCancelable(false);\n                splashDialog.show();\n\n                if (preferences.getBoolean(\"ShowSplashScreenSpinner\", true)) {\n                    spinnerStart();\n                }\n\n                // Set Runnable to remove splash screen just in case\n                if (hideAfterDelay) {\n                    final Handler handler = new Handler();\n                    handler.postDelayed(new Runnable() {\n                        public void run() {\n                            if (lastHideAfterDelay) {\n                                removeSplashScreen(false);\n                            }\n                        }\n                    }, effectiveSplashDuration);\n                }\n            }\n        });\n    }\n\n    // Show only spinner in the center of the screen\n    private void spinnerStart() {\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            public void run() {\n                spinnerStop();\n\n                spinnerDialog = new ProgressDialog(webView.getContext());\n                spinnerDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {\n                    public void onCancel(DialogInterface dialog) {\n                        spinnerDialog = null;\n                    }\n                });\n\n                spinnerDialog.setCancelable(false);\n                spinnerDialog.setIndeterminate(true);\n\n                RelativeLayout centeredLayout = new RelativeLayout(cordova.getActivity());\n                centeredLayout.setGravity(Gravity.CENTER);\n                centeredLayout.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));\n\n                ProgressBar progressBar = new ProgressBar(webView.getContext());\n                RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);\n                layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);\n                progressBar.setLayoutParams(layoutParams);\n\n                centeredLayout.addView(progressBar);\n\n                spinnerDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);\n                spinnerDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));\n\n                spinnerDialog.show();\n                spinnerDialog.setContentView(centeredLayout);\n            }\n        });\n    }\n\n    private void spinnerStop() {\n        cordova.getActivity().runOnUiThread(new Runnable() {\n            public void run() {\n                if (spinnerDialog != null && spinnerDialog.isShowing()) {\n                    spinnerDialog.dismiss();\n                    spinnerDialog = null;\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/src/blackberry10/index.js",
    "content": "/*\n * Copyright 2013 Research In Motion Limited.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/* global PluginResult */\n\nmodule.exports = {\n    show: function (success, fail, args, env) {\n        var result = new PluginResult(args, env);\n        result.error(\"Not supported on platform\", false);\n    },\n\n    hide: function (success, fail, args, env) {\n        var result = new PluginResult(args, env);\n        window.qnx.webplatform.getApplication().windowVisible = true;\n        result.ok(undefined, false);\n    }\n};\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/src/browser/SplashScreenProxy.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n// Default parameter values including image size can be changed in `config.xml`\nvar splashImageWidth = 170;\nvar splashImageHeight = 200;\nvar position = { x: 0, y: 0, width: splashImageWidth, height: splashImageHeight }; \nvar localSplash; // the image to display\nvar localSplashImage;\nvar bgColor = \"#464646\";\nvar imageSrc = '/img/logo.png';\nvar splashScreenDelay = 3000; // in milliseconds\nvar showSplashScreen = true; // show splashcreen by default\nvar cordova = require('cordova');\nvar configHelper = cordova.require('cordova/confighelper');\n\nfunction updateImageLocation() {\n    position.width = Math.min(splashImageWidth, window.innerWidth);\n    position.height = position.width * (splashImageHeight / splashImageWidth);\n\n    localSplash.style.width = window.innerWidth + \"px\";\n    localSplash.style.height = window.innerHeight + \"px\";\n    localSplash.style.top = \"0px\";\n    localSplash.style.left = \"0px\";\n\n    localSplashImage.style.top = \"50%\";\n    localSplashImage.style.left = \"50%\";\n    localSplashImage.style.height = position.height + \"px\";\n    localSplashImage.style.width = position.width + \"px\";\n    localSplashImage.style.marginTop = (-position.height / 2) + \"px\";\n    localSplashImage.style.marginLeft = (-position.width / 2) + \"px\";\n}\n\nfunction onResize() {\n    updateImageLocation();\n}\n\nvar SplashScreen = {\n    setBGColor: function (cssBGColor) {\n        bgColor = cssBGColor;\n        if (localSplash) {\n            localSplash.style.backgroundColor = bgColor;\n        }\n    },\n    show: function () {\n        if(!localSplash) {\n            window.addEventListener(\"resize\", onResize, false);\n            localSplash = document.createElement(\"div\");\n            localSplash.style.backgroundColor = bgColor;\n            localSplash.style.position = \"absolute\";\n\n            localSplashImage = document.createElement(\"img\");\n            localSplashImage.src = imageSrc;\n            localSplashImage.style.position = \"absolute\";\n\n            updateImageLocation();\n\n            localSplash.appendChild(localSplashImage);\n            document.body.appendChild(localSplash);\n        }\n    },\n    hide: function () {\n        if(localSplash) {\n            window.removeEventListener(\"resize\", onResize, false);\n            document.body.removeChild(localSplash);\n            localSplash = null;\n        }\n    }\n};\n\n/**\n * Reads preferences via ConfigHelper and substitutes default parameters.\n */\nfunction readPreferencesFromCfg(cfg) {\n    try {\n        var value = cfg.getPreferenceValue('ShowSplashScreen');\n        if(typeof value != 'undefined') {\n            showSplashScreen = value === 'true';\n        }\n\n        splashScreenDelay = cfg.getPreferenceValue('SplashScreenDelay') || splashScreenDelay;\n        imageSrc = cfg.getPreferenceValue('SplashScreen') || imageSrc;\n        bgColor = cfg.getPreferenceValue('SplashScreenBackgroundColor') || bgColor;\n        splashImageWidth = cfg.getPreferenceValue('SplashScreenWidth') || splashImageWidth;\n        splashImageHeight = cfg.getPreferenceValue('SplashScreenHeight') || splashImageHeight;\n    } catch(e) {\n        var msg = '[Browser][SplashScreen] Error occured on loading preferences from config.xml: ' + JSON.stringify(e);\n        console.error(msg);\n    }\n}\n\n/**\n * Shows and hides splashscreen if it is enabled, with a delay according the current preferences.\n */\nfunction showAndHide() {\n    if(showSplashScreen) {\n        SplashScreen.show();\n\n        window.setTimeout(function() {\n            SplashScreen.hide();\n        }, splashScreenDelay);\n    }\n}\n\n/**\n * Tries to read config.xml and override default properties and then shows and hides splashcreen if it is enabled.\n */\n(function initAndShow() {\n    configHelper.readConfig(function(config) {\n        readPreferencesFromCfg(config);\n        showAndHide();\n    }, function(err) {\n        console.error(err);\n    });\n})();\n\nmodule.exports = SplashScreen;\n\nrequire(\"cordova/exec/proxy\").add(\"SplashScreen\", SplashScreen);\n\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/src/cordova-plugin-splashscreen.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/android\" isTestSource=\"false\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"classes9\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"classes6\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"classes3\" level=\"project\" />\n    <orderEntry type=\"module\" module-name=\"cordova-plugin-compat\" />\n    <orderEntry type=\"module\" module-name=\"android\" />\n    <orderEntry type=\"module\" module-name=\"buildConfig\" />\n    <orderEntry type=\"module\" module-name=\"CordovaLib\" />\n  </component>\n</module>"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/src/ios/CDVSplashScreen.h",
    "content": "/*\n Licensed to the Apache Software Foundation (ASF) under one\n or more contributor license agreements.  See the NOTICE file\n distributed with this work for additional information\n regarding copyright ownership.  The ASF licenses this file\n to you under the Apache License, Version 2.0 (the\n \"License\"); you may not use this file except in compliance\n with the License.  You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing,\n software distributed under the License is distributed on an\n \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n KIND, either express or implied.  See the License for the\n specific language governing permissions and limitations\n under the License.\n */\n\n#import <Foundation/Foundation.h>\n#import <Cordova/CDVPlugin.h>\n\ntypedef struct {\n    BOOL iPhone;\n    BOOL iPad;\n    BOOL iPhone4;\n    BOOL iPhone5;\n    BOOL iPhone6;\n    BOOL iPhone6Plus;\n    BOOL retina;\n    \n} CDV_iOSDevice;\n\n@interface CDVSplashScreen : CDVPlugin {\n    UIActivityIndicatorView* _activityView;\n    UIImageView* _imageView;\n    NSString* _curImageName;\n    BOOL _visible;\n    BOOL _destroyed;\n}\n\n- (void)show:(CDVInvokedUrlCommand*)command;\n- (void)hide:(CDVInvokedUrlCommand*)command;\n\n@end\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/src/ios/CDVSplashScreen.m",
    "content": "/*\n Licensed to the Apache Software Foundation (ASF) under one\n or more contributor license agreements.  See the NOTICE file\n distributed with this work for additional information\n regarding copyright ownership.  The ASF licenses this file\n to you under the Apache License, Version 2.0 (the\n \"License\"); you may not use this file except in compliance\n with the License.  You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing,\n software distributed under the License is distributed on an\n \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n KIND, either express or implied.  See the License for the\n specific language governing permissions and limitations\n under the License.\n */\n\n#import \"CDVSplashScreen.h\"\n#import <Cordova/CDVViewController.h>\n#import <Cordova/CDVScreenOrientationDelegate.h>\n#import \"CDVViewController+SplashScreen.h\"\n\n#define kSplashScreenDurationDefault 3000.0f\n#define kFadeDurationDefault 500.0f\n\n\n@implementation CDVSplashScreen\n\n- (void)pluginInitialize\n{\n    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad) name:CDVPageDidLoadNotification object:nil];\n\n    [self setVisible:YES];\n}\n\n- (void)show:(CDVInvokedUrlCommand*)command\n{\n    [self setVisible:YES];\n}\n\n- (void)hide:(CDVInvokedUrlCommand*)command\n{\n    [self setVisible:NO andForce:YES];\n}\n\n- (void)pageDidLoad\n{\n    id autoHideSplashScreenValue = [self.commandDelegate.settings objectForKey:[@\"AutoHideSplashScreen\" lowercaseString]];\n\n    // if value is missing, default to yes\n    if ((autoHideSplashScreenValue == nil) || [autoHideSplashScreenValue boolValue]) {\n        [self setVisible:NO];\n    }\n}\n\n- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context\n{\n    [self updateImage];\n}\n\n- (void)createViews\n{\n    /*\n     * The Activity View is the top spinning throbber in the status/battery bar. We init it with the default Grey Style.\n     *\n     *     whiteLarge = UIActivityIndicatorViewStyleWhiteLarge\n     *     white      = UIActivityIndicatorViewStyleWhite\n     *     gray       = UIActivityIndicatorViewStyleGray\n     *\n     */\n\n    // Determine whether rotation should be enabled for this device\n    // Per iOS HIG, landscape is only supported on iPad and iPhone 6+\n    CDV_iOSDevice device = [self getCurrentDevice];\n    BOOL autorotateValue = (device.iPad || device.iPhone6Plus) ?\n        [(CDVViewController *)self.viewController shouldAutorotateDefaultValue] :\n        NO;\n\n    [(CDVViewController *)self.viewController setEnabledAutorotation:autorotateValue];\n\n    NSString* topActivityIndicator = [self.commandDelegate.settings objectForKey:[@\"TopActivityIndicator\" lowercaseString]];\n    UIActivityIndicatorViewStyle topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;\n\n    if ([topActivityIndicator isEqualToString:@\"whiteLarge\"])\n    {\n        topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhiteLarge;\n    }\n    else if ([topActivityIndicator isEqualToString:@\"white\"])\n    {\n        topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhite;\n    }\n    else if ([topActivityIndicator isEqualToString:@\"gray\"])\n    {\n        topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;\n    }\n\n    UIView* parentView = self.viewController.view;\n    parentView.userInteractionEnabled = NO;  // disable user interaction while splashscreen is shown\n    _activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:topActivityIndicatorStyle];\n    _activityView.center = CGPointMake(parentView.bounds.size.width / 2, parentView.bounds.size.height / 2);\n    _activityView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin\n        | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin;\n    [_activityView startAnimating];\n\n    // Set the frame & image later.\n    _imageView = [[UIImageView alloc] init];\n    [parentView addSubview:_imageView];\n\n    id showSplashScreenSpinnerValue = [self.commandDelegate.settings objectForKey:[@\"ShowSplashScreenSpinner\" lowercaseString]];\n    // backwards compatibility - if key is missing, default to true\n    if ((showSplashScreenSpinnerValue == nil) || [showSplashScreenSpinnerValue boolValue])\n    {\n        [parentView addSubview:_activityView];\n    }\n\n    // Frame is required when launching in portrait mode.\n    // Bounds for landscape since it captures the rotation.\n    [parentView addObserver:self forKeyPath:@\"frame\" options:0 context:nil];\n    [parentView addObserver:self forKeyPath:@\"bounds\" options:0 context:nil];\n\n    [self updateImage];\n    _destroyed = NO;\n}\n\n- (void)hideViews\n{\n    [_imageView setAlpha:0];\n    [_activityView setAlpha:0];\n}\n\n- (void)destroyViews\n{\n    _destroyed = YES;\n    [(CDVViewController *)self.viewController setEnabledAutorotation:[(CDVViewController *)self.viewController shouldAutorotateDefaultValue]];\n\n    [_imageView removeFromSuperview];\n    [_activityView removeFromSuperview];\n    _imageView = nil;\n    _activityView = nil;\n    _curImageName = nil;\n\n    self.viewController.view.userInteractionEnabled = YES;  // re-enable user interaction upon completion\n    @try {\n        [self.viewController.view removeObserver:self forKeyPath:@\"frame\"];\n        [self.viewController.view removeObserver:self forKeyPath:@\"bounds\"];\n    }\n    @catch (NSException *exception) {\n        // When reloading the page from a remotely connected Safari, there\n        // are no observers, so the removeObserver method throws an exception,\n        // that we can safely ignore.\n        // Alternatively we can check whether there are observers before calling removeObserver\n    }\n}\n\n- (CDV_iOSDevice) getCurrentDevice\n{\n    CDV_iOSDevice device;\n\n    UIScreen* mainScreen = [UIScreen mainScreen];\n    CGFloat mainScreenHeight = mainScreen.bounds.size.height;\n    CGFloat mainScreenWidth = mainScreen.bounds.size.width;\n\n    int limit = MAX(mainScreenHeight,mainScreenWidth);\n\n    device.iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);\n    device.iPhone = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone);\n    device.retina = ([mainScreen scale] == 2.0);\n    device.iPhone4 = (device.iPhone && limit == 480.0);\n    device.iPhone5 = (device.iPhone && limit == 568.0);\n    // note these below is not a true device detect, for example if you are on an\n    // iPhone 6/6+ but the app is scaled it will prob set iPhone5 as true, but\n    // this is appropriate for detecting the runtime screen environment\n    device.iPhone6 = (device.iPhone && limit == 667.0);\n    device.iPhone6Plus = (device.iPhone && limit == 736.0);\n\n    return device;\n}\n\n- (BOOL) isUsingCDVLaunchScreen {\n    NSString* launchStoryboardName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@\"UILaunchStoryboardName\"];\n    if (launchStoryboardName) {\n        return ([launchStoryboardName isEqualToString:@\"CDVLaunchScreen\"]);\n    } else {\n        return NO;\n    }\n}\n\n- (NSString*)getImageName:(UIInterfaceOrientation)currentOrientation delegate:(id<CDVScreenOrientationDelegate>)orientationDelegate device:(CDV_iOSDevice)device\n{\n    // Use UILaunchImageFile if specified in plist.  Otherwise, use Default.\n    NSString* imageName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@\"UILaunchImageFile\"];\n\n    // detect if we are using CB-9762 Launch Storyboard; if so, return the associated image instead\n    if ([self isUsingCDVLaunchScreen]) {\n        imageName = @\"LaunchStoryboard\";\n        return imageName;\n    }\n\n    NSUInteger supportedOrientations = [orientationDelegate supportedInterfaceOrientations];\n\n    // Checks to see if the developer has locked the orientation to use only one of Portrait or Landscape\n    BOOL supportsLandscape = (supportedOrientations & UIInterfaceOrientationMaskLandscape);\n    BOOL supportsPortrait = (supportedOrientations & UIInterfaceOrientationMaskPortrait || supportedOrientations & UIInterfaceOrientationMaskPortraitUpsideDown);\n    // this means there are no mixed orientations in there\n    BOOL isOrientationLocked = !(supportsPortrait && supportsLandscape);\n\n    if (imageName)\n    {\n        imageName = [imageName stringByDeletingPathExtension];\n    }\n    else\n    {\n        imageName = @\"Default\";\n    }\n\n    // Add Asset Catalog specific prefixes\n    if ([imageName isEqualToString:@\"LaunchImage\"])\n    {\n        if (device.iPhone4 || device.iPhone5 || device.iPad) {\n            imageName = [imageName stringByAppendingString:@\"-700\"];\n        } else if(device.iPhone6) {\n            imageName = [imageName stringByAppendingString:@\"-800\"];\n        } else if(device.iPhone6Plus) {\n            imageName = [imageName stringByAppendingString:@\"-800\"];\n            if (currentOrientation == UIInterfaceOrientationPortrait || currentOrientation == UIInterfaceOrientationPortraitUpsideDown)\n            {\n                imageName = [imageName stringByAppendingString:@\"-Portrait\"];\n            }\n        }\n    }\n\n    if (device.iPhone5)\n    { // does not support landscape\n        imageName = [imageName stringByAppendingString:@\"-568h\"];\n    }\n    else if (device.iPhone6)\n    { // does not support landscape\n        imageName = [imageName stringByAppendingString:@\"-667h\"];\n    }\n    else if (device.iPhone6Plus)\n    { // supports landscape\n        if (isOrientationLocked)\n        {\n            imageName = [imageName stringByAppendingString:(supportsLandscape ? @\"-Landscape\" : @\"\")];\n        }\n        else\n        {\n            switch (currentOrientation)\n            {\n                case UIInterfaceOrientationLandscapeLeft:\n                case UIInterfaceOrientationLandscapeRight:\n                        imageName = [imageName stringByAppendingString:@\"-Landscape\"];\n                    break;\n                default:\n                    break;\n            }\n        }\n        imageName = [imageName stringByAppendingString:@\"-736h\"];\n\n    }\n    else if (device.iPad)\n    {   // supports landscape\n        if (isOrientationLocked)\n        {\n            imageName = [imageName stringByAppendingString:(supportsLandscape ? @\"-Landscape\" : @\"-Portrait\")];\n        }\n        else\n        {\n            switch (currentOrientation)\n            {\n                case UIInterfaceOrientationLandscapeLeft:\n                case UIInterfaceOrientationLandscapeRight:\n                    imageName = [imageName stringByAppendingString:@\"-Landscape\"];\n                    break;\n\n                case UIInterfaceOrientationPortrait:\n                case UIInterfaceOrientationPortraitUpsideDown:\n                default:\n                    imageName = [imageName stringByAppendingString:@\"-Portrait\"];\n                    break;\n            }\n        }\n    }\n\n    return imageName;\n}\n\n- (UIInterfaceOrientation)getCurrentOrientation\n{\n    UIInterfaceOrientation iOrientation = [UIApplication sharedApplication].statusBarOrientation;\n    UIDeviceOrientation dOrientation = [UIDevice currentDevice].orientation;\n\n    bool landscape;\n\n    if (dOrientation == UIDeviceOrientationUnknown || dOrientation == UIDeviceOrientationFaceUp || dOrientation == UIDeviceOrientationFaceDown) {\n        // If the device is laying down, use the UIInterfaceOrientation based on the status bar.\n        landscape = UIInterfaceOrientationIsLandscape(iOrientation);\n    } else {\n        // If the device is not laying down, use UIDeviceOrientation.\n        landscape = UIDeviceOrientationIsLandscape(dOrientation);\n\n        // There's a bug in iOS!!!! http://openradar.appspot.com/7216046\n        // So values needs to be reversed for landscape!\n        if (dOrientation == UIDeviceOrientationLandscapeLeft)\n        {\n            iOrientation = UIInterfaceOrientationLandscapeRight;\n        }\n        else if (dOrientation == UIDeviceOrientationLandscapeRight)\n        {\n            iOrientation = UIInterfaceOrientationLandscapeLeft;\n        }\n        else if (dOrientation == UIDeviceOrientationPortrait)\n        {\n            iOrientation = UIInterfaceOrientationPortrait;\n        }\n        else if (dOrientation == UIDeviceOrientationPortraitUpsideDown)\n        {\n            iOrientation = UIInterfaceOrientationPortraitUpsideDown;\n        }\n    }\n\n    return iOrientation;\n}\n\n// Sets the view's frame and image.\n- (void)updateImage\n{\n    NSString* imageName = [self getImageName:[self getCurrentOrientation] delegate:(id<CDVScreenOrientationDelegate>)self.viewController device:[self getCurrentDevice]];\n\n    if (![imageName isEqualToString:_curImageName])\n    {\n        UIImage* img = [UIImage imageNamed:imageName];\n        _imageView.image = img;\n        _curImageName = imageName;\n    }\n\n    // Check that splash screen's image exists before updating bounds\n    if (_imageView.image)\n    {\n        [self updateBounds];\n    }\n    else\n    {\n        NSLog(@\"WARNING: The splashscreen image named %@ was not found\", imageName);\n    }\n}\n\n- (void)updateBounds\n{\n    if ([self isUsingCDVLaunchScreen]) {\n        // CB-9762's launch screen expects the image to fill the screen and be scaled using AspectFill.\n        CGSize viewportSize = [UIApplication sharedApplication].delegate.window.bounds.size;\n        _imageView.frame = CGRectMake(0, 0, viewportSize.width, viewportSize.height);\n        _imageView.contentMode = UIViewContentModeScaleAspectFill;\n        return; \n    }\n\n    UIImage* img = _imageView.image;\n    CGRect imgBounds = (img) ? CGRectMake(0, 0, img.size.width, img.size.height) : CGRectZero;\n\n    CGSize screenSize = [self.viewController.view convertRect:[UIScreen mainScreen].bounds fromView:nil].size;\n    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;\n    CGAffineTransform imgTransform = CGAffineTransformIdentity;\n\n    /* If and only if an iPhone application is landscape-only as per\n     * UISupportedInterfaceOrientations, the view controller's orientation is\n     * landscape. In this case the image must be rotated in order to appear\n     * correctly.\n     */\n    CDV_iOSDevice device = [self getCurrentDevice];\n    if (UIInterfaceOrientationIsLandscape(orientation) && !device.iPhone6Plus && !device.iPad)\n    {\n        imgTransform = CGAffineTransformMakeRotation(M_PI / 2);\n        imgBounds.size = CGSizeMake(imgBounds.size.height, imgBounds.size.width);\n    }\n\n    // There's a special case when the image is the size of the screen.\n    if (CGSizeEqualToSize(screenSize, imgBounds.size))\n    {\n        CGRect statusFrame = [self.viewController.view convertRect:[UIApplication sharedApplication].statusBarFrame fromView:nil];\n        if (!(IsAtLeastiOSVersion(@\"7.0\")))\n        {\n            imgBounds.origin.y -= statusFrame.size.height;\n        }\n    }\n    else if (imgBounds.size.width > 0)\n    {\n        CGRect viewBounds = self.viewController.view.bounds;\n        CGFloat imgAspect = imgBounds.size.width / imgBounds.size.height;\n        CGFloat viewAspect = viewBounds.size.width / viewBounds.size.height;\n        // This matches the behaviour of the native splash screen.\n        CGFloat ratio;\n        if (viewAspect > imgAspect)\n        {\n            ratio = viewBounds.size.width / imgBounds.size.width;\n        }\n        else\n        {\n            ratio = viewBounds.size.height / imgBounds.size.height;\n        }\n        imgBounds.size.height *= ratio;\n        imgBounds.size.width *= ratio;\n    }\n\n    _imageView.transform = imgTransform;\n    _imageView.frame = imgBounds;\n}\n\n- (void)setVisible:(BOOL)visible\n{\n    [self setVisible:visible andForce:NO];\n}\n\n- (void)setVisible:(BOOL)visible andForce:(BOOL)force\n{\n    if (visible != _visible || force)\n    {\n        _visible = visible;\n\n        id fadeSplashScreenValue = [self.commandDelegate.settings objectForKey:[@\"FadeSplashScreen\" lowercaseString]];\n        id fadeSplashScreenDuration = [self.commandDelegate.settings objectForKey:[@\"FadeSplashScreenDuration\" lowercaseString]];\n\n        float fadeDuration = fadeSplashScreenDuration == nil ? kFadeDurationDefault : [fadeSplashScreenDuration floatValue];\n\n        id splashDurationString = [self.commandDelegate.settings objectForKey: [@\"SplashScreenDelay\" lowercaseString]];\n        float splashDuration = splashDurationString == nil ? kSplashScreenDurationDefault : [splashDurationString floatValue];\n\n        id autoHideSplashScreenValue = [self.commandDelegate.settings objectForKey:[@\"AutoHideSplashScreen\" lowercaseString]];\n        BOOL autoHideSplashScreen = true;\n\n        if (autoHideSplashScreenValue != nil) {\n            autoHideSplashScreen = [autoHideSplashScreenValue boolValue];\n        }\n\n        if (!autoHideSplashScreen) {\n            // CB-10412 SplashScreenDelay does not make sense if the splashscreen is hidden manually\n            splashDuration = 0;\n        }\n\n\n        if (fadeSplashScreenValue == nil)\n        {\n            fadeSplashScreenValue = @\"true\";\n        }\n\n        if (![fadeSplashScreenValue boolValue])\n        {\n            fadeDuration = 0;\n        }\n        else if (fadeDuration < 30)\n        {\n            // [CB-9750] This value used to be in decimal seconds, so we will assume that if someone specifies 10\n            // they mean 10 seconds, and not the meaningless 10ms\n            fadeDuration *= 1000;\n        }\n\n        if (_visible)\n        {\n            if (_imageView == nil)\n            {\n                [self createViews];\n            }\n        }\n        else if (fadeDuration == 0 && splashDuration == 0)\n        {\n            [self destroyViews];\n        }\n        else\n        {\n            __weak __typeof(self) weakSelf = self;\n            float effectiveSplashDuration;\n\n            // [CB-10562] AutoHideSplashScreen may be \"true\" but we should still be able to hide the splashscreen manually.\n            if (!autoHideSplashScreen || force) {\n                effectiveSplashDuration = (fadeDuration) / 1000;\n            } else {\n                effectiveSplashDuration = (splashDuration - fadeDuration) / 1000;\n            }\n\n            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (uint64_t) effectiveSplashDuration * NSEC_PER_SEC), dispatch_get_main_queue(), CFBridgingRelease(CFBridgingRetain(^(void) {\n                if (!_destroyed) {\n                    [UIView transitionWithView:self.viewController.view\n                                    duration:(fadeDuration / 1000)\n                                    options:UIViewAnimationOptionTransitionNone\n                                    animations:^(void) {\n                                        [weakSelf hideViews];\n                                    }\n                                    completion:^(BOOL finished) {\n                                        // Always destroy views, otherwise you could have an\n                                        // invisible splashscreen that is overlayed over your active views\n                                        // which causes that no touch events are passed\n                                        if (!_destroyed) {\n                                            [weakSelf destroyViews];\n                                            // TODO: It might also be nice to have a js event happen here -jm\n                                        }\n                                    }\n                    ];\n                }\n            })));\n        }\n    }\n}\n\n@end\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/src/ios/CDVViewController+SplashScreen.h",
    "content": "/*\n Licensed to the Apache Software Foundation (ASF) under one\n or more contributor license agreements.  See the NOTICE file\n distributed with this work for additional information\n regarding copyright ownership.  The ASF licenses this file\n to you under the Apache License, Version 2.0 (the\n \"License\"); you may not use this file except in compliance\n with the License.  You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing,\n software distributed under the License is distributed on an\n \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n KIND, either express or implied.  See the License for the\n specific language governing permissions and limitations\n under the License.\n */\n\n#import <Cordova/CDVViewController.h>\n\n@interface CDVViewController (SplashScreen)\n\n@property (nonatomic, assign) BOOL enabledAutorotation;\n@property (nonatomic, readonly) BOOL shouldAutorotateDefaultValue;\n\n\n@end\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/src/ios/CDVViewController+SplashScreen.m",
    "content": "/*\n Licensed to the Apache Software Foundation (ASF) under one\n or more contributor license agreements.  See the NOTICE file\n distributed with this work for additional information\n regarding copyright ownership.  The ASF licenses this file\n to you under the Apache License, Version 2.0 (the\n \"License\"); you may not use this file except in compliance\n with the License.  You may obtain a copy of the License at\n \n http://www.apache.org/licenses/LICENSE-2.0\n \n Unless required by applicable law or agreed to in writing,\n software distributed under the License is distributed on an\n \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n KIND, either express or implied.  See the License for the\n specific language governing permissions and limitations\n under the License.\n */\n\n#import \"CDVViewController+SplashScreen.h\"\n#import <objc/runtime.h>\n\n@implementation CDVViewController (SplashScreen)\n\n@dynamic enabledAutorotation;\n\n- (void)setEnabledAutorotation:(BOOL)value\n{\n    objc_setAssociatedObject(self,\n                             @selector(enabledAutorotation),\n                             [NSNumber numberWithBool:value],\n                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);\n}\n\n- (BOOL)enabledAutorotation\n{\n    NSNumber *number =  (NSNumber *)objc_getAssociatedObject(self, @selector(enabledAutorotation));\n\n    // Defaulting to YES to correspond parent CDVViewController behavior\n    if (number == nil)\n    {\n        return YES;\n    }\n\n    return [number boolValue];\n}\n\n+ (void)load\n{\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        Class class = [self class];\n        \n        SEL originalSelector = @selector(shouldAutorotate);\n        SEL swizzledSelector = @selector(splash_shouldAutorotate);\n        \n        Method originalMethod = class_getInstanceMethod(class, originalSelector);\n        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);\n        \n        BOOL didAddMethod = class_addMethod(class,\n                                            originalSelector,\n                                            method_getImplementation(swizzledMethod),\n                                            method_getTypeEncoding(swizzledMethod));\n        \n        if (didAddMethod) {\n            class_replaceMethod(class,\n                                swizzledSelector,\n                                method_getImplementation(originalMethod),\n                                method_getTypeEncoding(originalMethod));\n        } else {\n            method_exchangeImplementations(originalMethod, swizzledMethod);\n        }\n    });\n}\n\n#pragma mark - Method Swizzling\n\n- (BOOL)splash_shouldAutorotate\n{\n    return self.enabledAutorotation;\n}\n\n\n- (BOOL)shouldAutorotateDefaultValue\n{\n    return [self splash_shouldAutorotate];\n}\n\n@end\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/src/tizen/SplashScreenProxy.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n( function() {\n\nvar win = null;\n\nmodule.exports = {\n    show: function() {\n        if ( win === null ) {\n            win = window.open('splashscreen.html');\n        }\n    },\n\n    hide: function() {\n        if ( win !== null ) {\n            win.close();\n            win = null;\n        }\n    }\n};\n\nrequire(\"cordova/tizen/commandProxy\").add(\"SplashScreen\", module.exports);\n\n})();\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/src/ubuntu/splashscreen.cpp",
    "content": "/*\n *\n * Copyright 2013 Canonical Ltd.\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n#include <QQuickItem>\n\n#include \"splashscreen.h\"\n#include <cordova.h>\n\n#define SPLASHSCREEN_STATE_NAME \"splashscreen\"\n\nSplashscreen::Splashscreen(Cordova *cordova): CPlugin(cordova) {\n}\n\nvoid Splashscreen::show(int, int) {\n    m_cordova->rootObject()->setProperty(\"splashscreenPath\", m_cordova->getSplashscreenPath());\n\n    m_cordova->pushViewState(SPLASHSCREEN_STATE_NAME);\n}\n\nvoid Splashscreen::hide(int, int) {\n    m_cordova->popViewState(SPLASHSCREEN_STATE_NAME);\n}\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/src/ubuntu/splashscreen.h",
    "content": "/*\n *\n * Copyright 2013 Canonical Ltd.\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n#ifndef SPLASHSCREEN_H\n#define SPLASHSCREEN_H\n\n#include <QtCore>\n#include <cplugin.h>\n\nclass Splashscreen: public CPlugin {\n    Q_OBJECT\npublic:\n    explicit Splashscreen(Cordova *cordova);\n\n    virtual const QString fullName() override {\n        return Splashscreen::fullID();\n    }\n\n    virtual const QString shortName() override {\n        return \"SplashScreen\";\n    }\n\n    static const QString fullID() {\n        return \"SplashScreen\";\n    }\n\npublic slots:\n    void show(int, int);\n    void hide(int, int);\n};\n\n#endif // SPLASHSCREEN_H\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/src/wp/ResolutionHelper.cs",
    "content": "/*\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n*/\n\nusing Microsoft.Phone.Info;\nusing System;\nusing System.Windows;\n\nnamespace WPCordovaClassLib.Cordova.Commands\n{\n    public enum Resolutions { WVGA, WXGA, HD };\n\n    public static class ResolutionHelper\n    { \n       public static Resolutions CurrentResolution\n        {\n            get\n            {\n                switch (Application.Current.Host.Content.ScaleFactor) \n                {\n                    case 100: return Resolutions.WVGA;\n                    case 160: return Resolutions.WXGA;\n                    case 150: return Resolutions.HD;\n                }\n                throw new InvalidOperationException(\"Unknown resolution\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/src/wp/SplashScreen.cs",
    "content": "/*\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n*/\n\nusing System;\nusing System.Net;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Documents;\nusing System.Windows.Ink;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing System.Windows.Media.Animation;\nusing System.Windows.Shapes;\nusing Microsoft.Phone.Info;\nusing System.Windows.Controls.Primitives;\nusing System.Diagnostics;\nusing System.Windows.Media.Imaging;\nusing System.Windows.Resources;\nusing System.IO;\nusing System.Xml.Linq;\nusing System.Linq;\nusing System.Windows.Threading;\n\nnamespace WPCordovaClassLib.Cordova.Commands\n{\n    /// <summary>\n    /// Listens for changes to the state of the battery on the device.\n    /// Currently only the \"isPlugged\" parameter available via native APIs.\n    /// </summary>\n    public class SplashScreen : BaseCommand\n    {\n        private Popup popup;\n\n        // Time until we dismiss the splashscreen\n        private int prefDelay = 3000;\n\n        // Whether we hide it by default\n        private bool prefAutoHide = true;\n\n        // Path to image to use\n        private string prefImagePath = \"SplashScreenImage.jpg\";\n\n        // static because autodismiss is only ever applied once, at app launch\n        // subsequent page loads should not cause the SplashScreen to be shown.\n        private static bool WasShown = false;\n\n        public SplashScreen()\n        {\n            LoadConfigPrefs();\n\n            Image SplashScreen = new Image()\n            {\n                Height = Application.Current.Host.Content.ActualHeight,\n                Width = Application.Current.Host.Content.ActualWidth,\n                Stretch = Stretch.Fill\n            };\n\n            var imageResource = GetSplashScreenImageResource();\n            if (imageResource != null)\n            {\n                BitmapImage splash_image = new BitmapImage();\n                splash_image.SetSource(imageResource.Stream);\n                SplashScreen.Source = splash_image;\n            }\n\n            // Instansiate the popup and set the Child property of Popup to SplashScreen\n            popup = new Popup() { IsOpen = false,\n                                  Child = SplashScreen,\n                                  HorizontalAlignment = HorizontalAlignment.Stretch,\n                                  VerticalAlignment = VerticalAlignment.Center\n\n            };\n        }\n\n        public override void OnInit()\n        {\n            // we only want to autoload on the first page load.\n            // but OnInit is called for every page load.\n            if (!SplashScreen.WasShown)\n            {\n                SplashScreen.WasShown = true;\n                show();\n            }\n        }\n\n        private void LoadConfigPrefs()\n        {\n            StreamResourceInfo streamInfo = Application.GetResourceStream(new Uri(\"config.xml\", UriKind.Relative));\n            if (streamInfo != null)\n            {\n                using (StreamReader sr = new StreamReader(streamInfo.Stream))\n                {\n                    //This will Read Keys Collection for the xml file\n                    XDocument configFile = XDocument.Parse(sr.ReadToEnd());\n\n                    string configAutoHide = configFile.Descendants()\n                                        .Where(x => x.Name.LocalName == \"preference\")\n                                        .Where(x => (string)x.Attribute(\"name\") == \"AutoHideSplashScreen\")\n                                        .Select(x => (string)x.Attribute(\"value\"))\n                                        .FirstOrDefault();\n\n                    bool bVal;\n                    prefAutoHide = bool.TryParse(configAutoHide, out bVal) ? bVal : prefAutoHide;\n\n                    string configDelay = configFile.Descendants()\n                                      .Where(x => x.Name.LocalName == \"preference\")\n                                      .Where(x => (string)x.Attribute(\"name\") == \"SplashScreenDelay\")\n                                      .Select(x => (string)x.Attribute(\"value\"))\n                                      .FirstOrDefault();\n                    int nVal;\n                    prefDelay = int.TryParse(configDelay, out nVal) ? nVal : prefDelay;\n\n                    string configImage = configFile.Descendants()\n                                        .Where(x => x.Name.LocalName == \"preference\")\n                                        .Where(x => (string)x.Attribute(\"name\") == \"SplashScreen\")\n                                        .Select(x => (string)x.Attribute(\"value\"))\n                                        .FirstOrDefault();\n\n                    if (!String.IsNullOrEmpty(configImage))\n                    {\n                        prefImagePath = configImage;\n                    }\n                }\n            }\n        }\n\n        private StreamResourceInfo GetSplashScreenImageResource()\n        {\n            // Get the base filename for the splash screen images\n            string imageName = System.IO.Path.GetFileNameWithoutExtension(prefImagePath);\n            Uri imageUri = null;\n            StreamResourceInfo imageResource = null;\n\n            // First, try to get a resolution-specific splashscreen\n            try\n            {\n                // Determine the device's resolution\n                switch (ResolutionHelper.CurrentResolution)\n                {\n                    case Resolutions.HD:\n                        imageUri = new Uri(imageName + \".screen-720p.jpg\", UriKind.Relative);\n                        break;\n\n                    case Resolutions.WVGA:\n                        imageUri = new Uri(imageName + \".screen-WVGA.jpg\", UriKind.Relative);\n                        break;\n\n                    case Resolutions.WXGA:\n                    default:\n                        imageUri = new Uri(imageName + \".screen-WXGA.jpg\", UriKind.Relative);\n                        break;\n                }\n\n                imageResource = Application.GetResourceStream(imageUri);\n            }\n            catch (Exception)\n            {\n                // It's OK if we didn't get a resolution-specific image\n            }\n\n            // Fallback to the default image name without decoration\n            if (imageResource == null)\n            {\n                imageUri = new Uri(prefImagePath, UriKind.Relative);\n                imageResource = Application.GetResourceStream(imageUri);\n            }\n\n            if (imageUri != null) Debug.WriteLine(\"INFO :: SplashScreen: using image {0}\", imageUri.OriginalString);\n\n            return imageResource;\n        }\n\n        public void show(string options = null)\n        {\n            Deployment.Current.Dispatcher.BeginInvoke(() =>\n            {\n                if (!popup.IsOpen)\n                {\n                    popup.Child.Opacity = 0;\n\n                    Storyboard story = new Storyboard();\n                    DoubleAnimation animation = new DoubleAnimation()\n                                                    {\n                                                        From = 0.0,\n                                                        To = 1.0,\n                                                        Duration = new Duration(TimeSpan.FromSeconds(0.2))\n                                                    };\n\n                    Storyboard.SetTarget(animation, popup.Child);\n                    Storyboard.SetTargetProperty(animation, new PropertyPath(\"Opacity\"));\n                    story.Children.Add(animation);\n\n                    story.Begin();\n\n                    popup.IsOpen = true;\n\n                    if (prefAutoHide)\n                    {\n                        StartAutoHideTimer();\n                    }\n                }\n            });\n        }\n\n        public void hide(string options = null)\n        {\n            Deployment.Current.Dispatcher.BeginInvoke(() =>\n            {\n                if (popup.IsOpen)\n                {\n                    popup.Child.Opacity = 1.0;\n\n                    Storyboard story = new Storyboard();\n                    DoubleAnimation animation = new DoubleAnimation()\n                                                    {\n                                                        From = 1.0,\n                                                        To = 0.0,\n                                                        Duration = new Duration(TimeSpan.FromSeconds(0.4))\n                                                    };\n\n                    Storyboard.SetTarget(animation, popup.Child);\n                    Storyboard.SetTargetProperty(animation, new PropertyPath(\"Opacity\"));\n                    story.Children.Add(animation);\n                    story.Completed += (object sender, EventArgs e) =>\n                    {\n                        popup.IsOpen = false;\n                    };\n                    story.Begin();\n                }\n            });\n        }\n\n        private void StartAutoHideTimer()\n        {\n            var timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(prefDelay) };\n            timer.Tick += (object sender, EventArgs e) =>\n            {\n                hide();\n                timer.Stop();\n            };\n            timer.Start();\n        }\n    }\n}\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/CDVSplashScreenTest/.npmignore",
    "content": "build"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/CDVSplashScreenTest/CDVSplashScreenLibTests/ImageNameTest.m",
    "content": "/*\n Licensed to the Apache Software Foundation (ASF) under one\n or more contributor license agreements.  See the NOTICE file\n distributed with this work for additional information\n regarding copyright ownership.  The ASF licenses this file\n to you under the Apache License, Version 2.0 (the\n \"License\"); you may not use this file except in compliance\n with the License.  You may obtain a copy of the License at\n \n http://www.apache.org/licenses/LICENSE-2.0\n \n Unless required by applicable law or agreed to in writing,\n software distributed under the License is distributed on an\n \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n KIND, either express or implied.  See the License for the\n specific language governing permissions and limitations\n under the License.\n */\n\n#import <UIKit/UIKit.h>\n#import <XCTest/XCTest.h>\n#import <Cordova/CDVScreenOrientationDelegate.h>\n#import \"CDVSplashScreen.h\"\n#import \"ImageNameTestDelegates.h\"\n\nconst CDV_iOSDevice CDV_iOSDeviceZero = { 0, 0, 0, 0, 0, 0 };\n\n@interface ImageNameTest : XCTestCase\n\n@property (nonatomic, strong) CDVSplashScreen* plugin;\n\n@end\n\n@interface CDVSplashScreen ()\n\n// expose private interface\n- (NSString*)getImageName:(UIInterfaceOrientation)currentOrientation delegate:(id<CDVScreenOrientationDelegate>)orientationDelegate device:(CDV_iOSDevice)device;\n\n@end\n\n@implementation ImageNameTest\n\n- (void)setUp {\n    [super setUp];\n    // Put setup code here. This method is called before the invocation of each test method in the class.\n    \n    self.plugin = [[CDVSplashScreen alloc] init];\n}\n\n- (void)tearDown {\n    // Put teardown code here. This method is called after the invocation of each test method in the class.\n    [super tearDown];\n}\n\n- (void) orientationHelper:(id<CDVScreenOrientationDelegate>)delegate expectedImageNameDictionary:(NSDictionary*)expectedImageNameDictionary device:(CDV_iOSDevice)device{\n    \n    NSString* name = nil;\n    NSString* expectedImageName = nil;\n    UIInterfaceOrientation currentOrientation;\n    NSString* deviceName = device.iPad? @\"iPad\" : device.iPhone6Plus? @\"iPhone6Plus\": device.iPhone6? @\"iPhone6\": device.iPhone5? @\"iPhone5\" : @\"iPhone\";\n    \n    // LandscapeLeft, should always return expectedImageName\n    currentOrientation = UIInterfaceOrientationLandscapeLeft;\n    name = [self.plugin getImageName:currentOrientation delegate:delegate device:device];\n    expectedImageName = [expectedImageNameDictionary objectForKey:@\"landscapeLeft\"];\n    XCTAssertTrue([expectedImageName isEqualToString:name], @\"%@ - %@ failed (%@)\", @\"Landscape\", deviceName, name);\n    \n    // LandscapeRight - should always return expectedImageName\n    currentOrientation = UIInterfaceOrientationLandscapeRight;\n    name = [self.plugin getImageName:currentOrientation delegate:delegate device:device];\n    expectedImageName = [expectedImageNameDictionary objectForKey:@\"landscapeRight\"];\n    XCTAssertTrue([expectedImageName isEqualToString:name], @\"%@ - %@ failed (%@)\", @\"Landscape\", deviceName, name);\n    \n    // Portrait - should always return expectedImageName\n    currentOrientation = UIInterfaceOrientationPortrait;\n    name = [self.plugin getImageName:currentOrientation delegate:delegate device:device];\n    expectedImageName = [expectedImageNameDictionary objectForKey:@\"portrait\"];\n    XCTAssertTrue([expectedImageName isEqualToString:name], @\"%@ - %@ failed (%@)\", @\"Portrait\", deviceName, name);\n    \n    // PortraitUpsideDown - should always return expectedImageName\n    currentOrientation = UIInterfaceOrientationPortraitUpsideDown;\n    name = [self.plugin getImageName:currentOrientation delegate:delegate device:device];\n    expectedImageName = [expectedImageNameDictionary objectForKey:@\"portraitUpsideDown\"];\n    XCTAssertTrue([expectedImageName isEqualToString:name], @\"%@ - %@ failed (%@)\", @\"Portrait\", deviceName, name);\n}\n\n- (void)testiPadOrientation {\n    \n    CDV_iOSDevice device = CDV_iOSDeviceZero;\n    device.iPad = YES;\n    \n    // One orientation\n    \n    PortraitOnly* delegate = [[PortraitOnly alloc] init];\n    [self orientationHelper:delegate expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Portrait\",\n                                                                    @\"landscapeRight\" : @\"Default-Portrait\",\n                                                                    @\"portrait\" : @\"Default-Portrait\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-Portrait\"\n                                                                    }\n                     device:device];\n    \n    PortraitUpsideDownOnly* delegate2 = [[PortraitUpsideDownOnly alloc] init];\n    [self orientationHelper:delegate2 expectedImageNameDictionary:@{\n                                                                   @\"landscapeLeft\" : @\"Default-Portrait\",\n                                                                   @\"landscapeRight\" : @\"Default-Portrait\",\n                                                                   @\"portrait\" : @\"Default-Portrait\",\n                                                                   @\"portraitUpsideDown\" : @\"Default-Portrait\"\n                                                                   }\n                     device:device];\n    \n    LandscapeLeftOnly* delegate3 = [[LandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate3 expectedImageNameDictionary:@{\n                                                                   @\"landscapeLeft\" : @\"Default-Landscape\",\n                                                                   @\"landscapeRight\" : @\"Default-Landscape\",\n                                                                   @\"portrait\" : @\"Default-Landscape\",\n                                                                   @\"portraitUpsideDown\" : @\"Default-Landscape\"\n                                                                   }\n                     device:device];\n    \n    LandscapeRightOnly* delegate4 = [[LandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate4 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Landscape\",\n                                                                    @\"landscapeRight\" : @\"Default-Landscape\",\n                                                                    @\"portrait\" : @\"Default-Landscape\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-Landscape\"\n                                                                    }\n                     device:device];\n\n    // All Portrait\n\n    AllPortraitOnly* delegate5 = [[AllPortraitOnly alloc] init];\n    [self orientationHelper:delegate5 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Portrait\",\n                                                                    @\"landscapeRight\" : @\"Default-Portrait\",\n                                                                    @\"portrait\" : @\"Default-Portrait\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-Portrait\"\n                                                                    }\n                     device:device];\n\n    // All Landscape\n    \n    AllLandscapeOnly* delegate6 = [[AllLandscapeOnly alloc] init];\n    [self orientationHelper:delegate6 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Landscape\",\n                                                                    @\"landscapeRight\" : @\"Default-Landscape\",\n                                                                    @\"portrait\" : @\"Default-Landscape\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-Landscape\"\n                                                                    }\n                     device:device];\n    \n    \n    // All orientations\n    \n    AllOrientations* delegate7 = [[AllOrientations alloc] init];\n    [self orientationHelper:delegate7 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Landscape\",\n                                                                    @\"landscapeRight\" : @\"Default-Landscape\",\n                                                                    @\"portrait\" : @\"Default-Portrait\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-Portrait\"\n                                                                    }\n                     device:device];\n\n    // Portrait and Landscape Left\n    \n    PortraitAndLandscapeLeftOnly* delegate8 = [[PortraitAndLandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate8 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Landscape\",\n                                                                    @\"landscapeRight\" : @\"Default-Landscape\",\n                                                                    @\"portrait\" : @\"Default-Portrait\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-Portrait\"\n                                                                    }\n                     device:device];\n\n    // Portrait and Landscape Right\n    \n    PortraitAndLandscapeRightOnly* delegate9 = [[PortraitAndLandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate9 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Landscape\",\n                                                                    @\"landscapeRight\" : @\"Default-Landscape\",\n                                                                    @\"portrait\" : @\"Default-Portrait\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-Portrait\"\n                                                                    }\n                     device:device];\n\n    // PortraitUpsideDown and Landscape Left\n    \n    PortraitUpsideDownAndLandscapeLeftOnly* delegate10 = [[PortraitUpsideDownAndLandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate10 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Landscape\",\n                                                                    @\"landscapeRight\" : @\"Default-Landscape\",\n                                                                    @\"portrait\" : @\"Default-Portrait\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-Portrait\"\n                                                                    }\n                     device:device];\n\n    // PortraitUpsideDown and Landscape Right\n    \n    PortraitUpsideDownAndLandscapeRightOnly* delegate11 = [[PortraitUpsideDownAndLandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate11 expectedImageNameDictionary:@{\n                                                                     @\"landscapeLeft\" : @\"Default-Landscape\",\n                                                                     @\"landscapeRight\" : @\"Default-Landscape\",\n                                                                     @\"portrait\" : @\"Default-Portrait\",\n                                                                     @\"portraitUpsideDown\" : @\"Default-Portrait\"\n                                                                     }\n                     device:device];\n}\n\n- (void)testiPhoneOrientation {\n    \n    CDV_iOSDevice device = CDV_iOSDeviceZero;\n    device.iPhone = YES;\n    \n    // One orientation\n    \n    PortraitOnly* delegate = [[PortraitOnly alloc] init];\n    [self orientationHelper:delegate expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default\",\n                                                                    @\"landscapeRight\" : @\"Default\",\n                                                                    @\"portrait\" : @\"Default\",\n                                                                    @\"portraitUpsideDown\" : @\"Default\"\n                                                                    }\n                     device:device];\n    \n    PortraitUpsideDownOnly* delegate2 = [[PortraitUpsideDownOnly alloc] init];\n    [self orientationHelper:delegate2 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default\",\n                                                                    @\"landscapeRight\" : @\"Default\",\n                                                                    @\"portrait\" : @\"Default\",\n                                                                    @\"portraitUpsideDown\" : @\"Default\"\n                                                                    }\n                     device:device];\n    \n    LandscapeLeftOnly* delegate3 = [[LandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate3 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default\",\n                                                                    @\"landscapeRight\" : @\"Default\",\n                                                                    @\"portrait\" : @\"Default\",\n                                                                    @\"portraitUpsideDown\" : @\"Default\"\n                                                                    }\n                     device:device];\n    \n    LandscapeRightOnly* delegate4 = [[LandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate4 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default\",\n                                                                    @\"landscapeRight\" : @\"Default\",\n                                                                    @\"portrait\" : @\"Default\",\n                                                                    @\"portraitUpsideDown\" : @\"Default\"\n                                                                    }\n                     device:device];\n    \n    // All Portrait\n    \n    AllPortraitOnly* delegate5 = [[AllPortraitOnly alloc] init];\n    [self orientationHelper:delegate5 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default\",\n                                                                    @\"landscapeRight\" : @\"Default\",\n                                                                    @\"portrait\" : @\"Default\",\n                                                                    @\"portraitUpsideDown\" : @\"Default\"\n                                                                    }\n                     device:device];\n    \n    // All Landscape\n    \n    AllLandscapeOnly* delegate6 = [[AllLandscapeOnly alloc] init];\n    [self orientationHelper:delegate6 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default\",\n                                                                    @\"landscapeRight\" : @\"Default\",\n                                                                    @\"portrait\" : @\"Default\",\n                                                                    @\"portraitUpsideDown\" : @\"Default\"\n                                                                    }\n                     device:device];\n    \n    \n    // All orientations\n    \n    AllOrientations* delegate7 = [[AllOrientations alloc] init];\n    [self orientationHelper:delegate7 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default\",\n                                                                    @\"landscapeRight\" : @\"Default\",\n                                                                    @\"portrait\" : @\"Default\",\n                                                                    @\"portraitUpsideDown\" : @\"Default\"\n                                                                    }\n                     device:device];\n    \n    // Portrait and Landscape Left\n    \n    PortraitAndLandscapeLeftOnly* delegate8 = [[PortraitAndLandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate8 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default\",\n                                                                    @\"landscapeRight\" : @\"Default\",\n                                                                    @\"portrait\" : @\"Default\",\n                                                                    @\"portraitUpsideDown\" : @\"Default\"\n                                                                    }\n                     device:device];\n    \n    // Portrait and Landscape Right\n    \n    PortraitAndLandscapeRightOnly* delegate9 = [[PortraitAndLandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate9 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default\",\n                                                                    @\"landscapeRight\" : @\"Default\",\n                                                                    @\"portrait\" : @\"Default\",\n                                                                    @\"portraitUpsideDown\" : @\"Default\"\n                                                                    }\n                     device:device];\n    \n    // PortraitUpsideDown and Landscape Left\n    \n    PortraitUpsideDownAndLandscapeLeftOnly* delegate10 = [[PortraitUpsideDownAndLandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate10 expectedImageNameDictionary:@{\n                                                                     @\"landscapeLeft\" : @\"Default\",\n                                                                     @\"landscapeRight\" : @\"Default\",\n                                                                     @\"portrait\" : @\"Default\",\n                                                                     @\"portraitUpsideDown\" : @\"Default\"\n                                                                     }\n                     device:device];\n    \n    // PortraitUpsideDown and Landscape Right\n    \n    PortraitUpsideDownAndLandscapeRightOnly* delegate11 = [[PortraitUpsideDownAndLandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate11 expectedImageNameDictionary:@{\n                                                                     @\"landscapeLeft\" : @\"Default\",\n                                                                     @\"landscapeRight\" : @\"Default\",\n                                                                     @\"portrait\" : @\"Default\",\n                                                                     @\"portraitUpsideDown\" : @\"Default\"\n                                                                     }\n                     device:device];\n}\n\n- (void)testiPhone5Orientation {\n    \n    CDV_iOSDevice device = CDV_iOSDeviceZero;\n    device.iPhone = YES;\n    device.iPhone5 = YES;\n    \n    // One orientation\n    \n    PortraitOnly* delegate = [[PortraitOnly alloc] init];\n    [self orientationHelper:delegate expectedImageNameDictionary:@{\n                                                                   @\"landscapeLeft\" : @\"Default-568h\",\n                                                                   @\"landscapeRight\" : @\"Default-568h\",\n                                                                   @\"portrait\" : @\"Default-568h\",\n                                                                   @\"portraitUpsideDown\" : @\"Default-568h\"\n                                                                   }\n                     device:device];\n    \n    PortraitUpsideDownOnly* delegate2 = [[PortraitUpsideDownOnly alloc] init];\n    [self orientationHelper:delegate2 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-568h\",\n                                                                    @\"landscapeRight\" : @\"Default-568h\",\n                                                                    @\"portrait\" : @\"Default-568h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-568h\"\n                                                                    }\n                     device:device];\n    \n    LandscapeLeftOnly* delegate3 = [[LandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate3 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-568h\",\n                                                                    @\"landscapeRight\" : @\"Default-568h\",\n                                                                    @\"portrait\" : @\"Default-568h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-568h\"\n                                                                    }\n                     device:device];\n    \n    LandscapeRightOnly* delegate4 = [[LandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate4 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-568h\",\n                                                                    @\"landscapeRight\" : @\"Default-568h\",\n                                                                    @\"portrait\" : @\"Default-568h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-568h\"\n                                                                    }\n                     device:device];\n    \n    // All Portrait\n    \n    AllPortraitOnly* delegate5 = [[AllPortraitOnly alloc] init];\n    [self orientationHelper:delegate5 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-568h\",\n                                                                    @\"landscapeRight\" : @\"Default-568h\",\n                                                                    @\"portrait\" : @\"Default-568h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-568h\"\n                                                                    }\n                     device:device];\n    \n    // All Landscape\n    \n    AllLandscapeOnly* delegate6 = [[AllLandscapeOnly alloc] init];\n    [self orientationHelper:delegate6 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-568h\",\n                                                                    @\"landscapeRight\" : @\"Default-568h\",\n                                                                    @\"portrait\" : @\"Default-568h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-568h\"\n                                                                    }\n                     device:device];\n    \n    \n    // All orientations\n    \n    AllOrientations* delegate7 = [[AllOrientations alloc] init];\n    [self orientationHelper:delegate7 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-568h\",\n                                                                    @\"landscapeRight\" : @\"Default-568h\",\n                                                                    @\"portrait\" : @\"Default-568h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-568h\"\n                                                                    }\n                     device:device];\n    \n    // Portrait and Landscape Left\n    \n    PortraitAndLandscapeLeftOnly* delegate8 = [[PortraitAndLandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate8 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-568h\",\n                                                                    @\"landscapeRight\" : @\"Default-568h\",\n                                                                    @\"portrait\" : @\"Default-568h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-568h\"\n                                                                    }\n                     device:device];\n    \n    // Portrait and Landscape Right\n    \n    PortraitAndLandscapeRightOnly* delegate9 = [[PortraitAndLandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate9 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-568h\",\n                                                                    @\"landscapeRight\" : @\"Default-568h\",\n                                                                    @\"portrait\" : @\"Default-568h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-568h\"\n                                                                    }\n                     device:device];\n    \n    // PortraitUpsideDown and Landscape Left\n    \n    PortraitUpsideDownAndLandscapeLeftOnly* delegate10 = [[PortraitUpsideDownAndLandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate10 expectedImageNameDictionary:@{\n                                                                     @\"landscapeLeft\" : @\"Default-568h\",\n                                                                     @\"landscapeRight\" : @\"Default-568h\",\n                                                                     @\"portrait\" : @\"Default-568h\",\n                                                                     @\"portraitUpsideDown\" : @\"Default-568h\"\n                                                                     }\n                     device:device];\n    \n    // PortraitUpsideDown and Landscape Right\n    \n    PortraitUpsideDownAndLandscapeRightOnly* delegate11 = [[PortraitUpsideDownAndLandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate11 expectedImageNameDictionary:@{\n                                                                     @\"landscapeLeft\" : @\"Default-568h\",\n                                                                     @\"landscapeRight\" : @\"Default-568h\",\n                                                                     @\"portrait\" : @\"Default-568h\",\n                                                                     @\"portraitUpsideDown\" : @\"Default-568h\"\n                                                                     }\n                     device:device];\n}\n\n- (void)testiPhone6Orientation {\n    \n    CDV_iOSDevice device = CDV_iOSDeviceZero;\n    device.iPhone = YES;\n    device.iPhone6 = YES;\n    \n    // One orientation\n    \n    PortraitOnly* delegate = [[PortraitOnly alloc] init];\n    [self orientationHelper:delegate expectedImageNameDictionary:@{\n                                                                   @\"landscapeLeft\" : @\"Default-667h\",\n                                                                   @\"landscapeRight\" : @\"Default-667h\",\n                                                                   @\"portrait\" : @\"Default-667h\",\n                                                                   @\"portraitUpsideDown\" : @\"Default-667h\"\n                                                                   }\n                     device:device];\n    \n    PortraitUpsideDownOnly* delegate2 = [[PortraitUpsideDownOnly alloc] init];\n    [self orientationHelper:delegate2 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-667h\",\n                                                                    @\"landscapeRight\" : @\"Default-667h\",\n                                                                    @\"portrait\" : @\"Default-667h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-667h\"\n                                                                    }\n                     device:device];\n    \n    LandscapeLeftOnly* delegate3 = [[LandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate3 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-667h\",\n                                                                    @\"landscapeRight\" : @\"Default-667h\",\n                                                                    @\"portrait\" : @\"Default-667h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-667h\"\n                                                                    }\n                     device:device];\n    \n    LandscapeRightOnly* delegate4 = [[LandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate4 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-667h\",\n                                                                    @\"landscapeRight\" : @\"Default-667h\",\n                                                                    @\"portrait\" : @\"Default-667h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-667h\"\n                                                                    }\n                     device:device];\n    \n    // All Portrait\n    \n    AllPortraitOnly* delegate5 = [[AllPortraitOnly alloc] init];\n    [self orientationHelper:delegate5 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-667h\",\n                                                                    @\"landscapeRight\" : @\"Default-667h\",\n                                                                    @\"portrait\" : @\"Default-667h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-667h\"\n                                                                    }\n                     device:device];\n    \n    // All Landscape\n    \n    AllLandscapeOnly* delegate6 = [[AllLandscapeOnly alloc] init];\n    [self orientationHelper:delegate6 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-667h\",\n                                                                    @\"landscapeRight\" : @\"Default-667h\",\n                                                                    @\"portrait\" : @\"Default-667h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-667h\"\n                                                                    }\n                     device:device];\n    \n    \n    // All orientations\n    \n    AllOrientations* delegate7 = [[AllOrientations alloc] init];\n    [self orientationHelper:delegate7 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-667h\",\n                                                                    @\"landscapeRight\" : @\"Default-667h\",\n                                                                    @\"portrait\" : @\"Default-667h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-667h\"\n                                                                    }\n                     device:device];\n    \n    // Portrait and Landscape Left\n    \n    PortraitAndLandscapeLeftOnly* delegate8 = [[PortraitAndLandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate8 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-667h\",\n                                                                    @\"landscapeRight\" : @\"Default-667h\",\n                                                                    @\"portrait\" : @\"Default-667h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-667h\"\n                                                                    }\n                     device:device];\n    \n    // Portrait and Landscape Right\n    \n    PortraitAndLandscapeRightOnly* delegate9 = [[PortraitAndLandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate9 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-667h\",\n                                                                    @\"landscapeRight\" : @\"Default-667h\",\n                                                                    @\"portrait\" : @\"Default-667h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-667h\"\n                                                                    }\n                     device:device];\n    \n    // PortraitUpsideDown and Landscape Left\n    \n    PortraitUpsideDownAndLandscapeLeftOnly* delegate10 = [[PortraitUpsideDownAndLandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate10 expectedImageNameDictionary:@{\n                                                                     @\"landscapeLeft\" : @\"Default-667h\",\n                                                                     @\"landscapeRight\" : @\"Default-667h\",\n                                                                     @\"portrait\" : @\"Default-667h\",\n                                                                     @\"portraitUpsideDown\" : @\"Default-667h\"\n                                                                     }\n                     device:device];\n    \n    // PortraitUpsideDown and Landscape Right\n    \n    PortraitUpsideDownAndLandscapeRightOnly* delegate11 = [[PortraitUpsideDownAndLandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate11 expectedImageNameDictionary:@{\n                                                                     @\"landscapeLeft\" : @\"Default-667h\",\n                                                                     @\"landscapeRight\" : @\"Default-667h\",\n                                                                     @\"portrait\" : @\"Default-667h\",\n                                                                     @\"portraitUpsideDown\" : @\"Default-667h\"\n                                                                     }\n                     device:device];\n}\n\n- (void)testiPhone6PlusOrientation {\n    \n    CDV_iOSDevice device = CDV_iOSDeviceZero;\n    device.iPhone = YES;\n    device.iPhone6Plus = YES;\n    \n    // One orientation\n    \n    PortraitOnly* delegate = [[PortraitOnly alloc] init];\n    [self orientationHelper:delegate expectedImageNameDictionary:@{\n                                                                   @\"landscapeLeft\" : @\"Default-736h\",\n                                                                   @\"landscapeRight\" : @\"Default-736h\",\n                                                                   @\"portrait\" : @\"Default-736h\",\n                                                                   @\"portraitUpsideDown\" : @\"Default-736h\"\n                                                                   }\n                     device:device];\n    \n    PortraitUpsideDownOnly* delegate2 = [[PortraitUpsideDownOnly alloc] init];\n    [self orientationHelper:delegate2 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-736h\",\n                                                                    @\"landscapeRight\" : @\"Default-736h\",\n                                                                    @\"portrait\" : @\"Default-736h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-736h\"\n                                                                    }\n                     device:device];\n    \n    LandscapeLeftOnly* delegate3 = [[LandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate3 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Landscape-736h\",\n                                                                    @\"landscapeRight\" : @\"Default-Landscape-736h\",\n                                                                    @\"portrait\" : @\"Default-Landscape-736h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-Landscape-736h\"\n                                                                    }\n                     device:device];\n    \n    LandscapeRightOnly* delegate4 = [[LandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate4 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Landscape-736h\",\n                                                                    @\"landscapeRight\" : @\"Default-Landscape-736h\",\n                                                                    @\"portrait\" : @\"Default-Landscape-736h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-Landscape-736h\"\n                                                                    }\n                     device:device];\n    \n    // All Portrait\n    \n    AllPortraitOnly* delegate5 = [[AllPortraitOnly alloc] init];\n    [self orientationHelper:delegate5 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-736h\",\n                                                                    @\"landscapeRight\" : @\"Default-736h\",\n                                                                    @\"portrait\" : @\"Default-736h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-736h\"\n                                                                    }\n                     device:device];\n    \n    // All Landscape\n    \n    AllLandscapeOnly* delegate6 = [[AllLandscapeOnly alloc] init];\n    [self orientationHelper:delegate6 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Landscape-736h\",\n                                                                    @\"landscapeRight\" : @\"Default-Landscape-736h\",\n                                                                    @\"portrait\" : @\"Default-Landscape-736h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-Landscape-736h\"\n                                                                    }\n                     device:device];\n    \n    \n    // All orientations\n    \n    AllOrientations* delegate7 = [[AllOrientations alloc] init];\n    [self orientationHelper:delegate7 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Landscape-736h\",\n                                                                    @\"landscapeRight\" : @\"Default-Landscape-736h\",\n                                                                    @\"portrait\" : @\"Default-736h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-736h\"\n                                                                    }\n                     device:device];\n    \n    // Portrait and Landscape Left\n    \n    PortraitAndLandscapeLeftOnly* delegate8 = [[PortraitAndLandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate8 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Landscape-736h\",\n                                                                    @\"landscapeRight\" : @\"Default-Landscape-736h\",\n                                                                    @\"portrait\" : @\"Default-736h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-736h\"\n                                                                    }\n                     device:device];\n    \n    // Portrait and Landscape Right\n    \n    PortraitAndLandscapeRightOnly* delegate9 = [[PortraitAndLandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate9 expectedImageNameDictionary:@{\n                                                                    @\"landscapeLeft\" : @\"Default-Landscape-736h\",\n                                                                    @\"landscapeRight\" : @\"Default-Landscape-736h\",\n                                                                    @\"portrait\" : @\"Default-736h\",\n                                                                    @\"portraitUpsideDown\" : @\"Default-736h\"\n                                                                    }\n                     device:device];\n    \n    // PortraitUpsideDown and Landscape Left\n    \n    PortraitUpsideDownAndLandscapeLeftOnly* delegate10 = [[PortraitUpsideDownAndLandscapeLeftOnly alloc] init];\n    [self orientationHelper:delegate10 expectedImageNameDictionary:@{\n                                                                     @\"landscapeLeft\" : @\"Default-Landscape-736h\",\n                                                                     @\"landscapeRight\" : @\"Default-Landscape-736h\",\n                                                                     @\"portrait\" : @\"Default-736h\",\n                                                                     @\"portraitUpsideDown\" : @\"Default-736h\"\n                                                                     }\n                     device:device];\n    \n    // PortraitUpsideDown and Landscape Right\n    \n    PortraitUpsideDownAndLandscapeRightOnly* delegate11 = [[PortraitUpsideDownAndLandscapeRightOnly alloc] init];\n    [self orientationHelper:delegate11 expectedImageNameDictionary:@{\n                                                                     @\"landscapeLeft\" : @\"Default-Landscape-736h\",\n                                                                     @\"landscapeRight\" : @\"Default-Landscape-736h\",\n                                                                     @\"portrait\" : @\"Default-736h\",\n                                                                     @\"portraitUpsideDown\" : @\"Default-736h\"\n                                                                     }\n                     device:device];\n}\n\n\n\n@end\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/CDVSplashScreenTest/CDVSplashScreenLibTests/ImageNameTestDelegates.h",
    "content": "/*\n Licensed to the Apache Software Foundation (ASF) under one\n or more contributor license agreements.  See the NOTICE file\n distributed with this work for additional information\n regarding copyright ownership.  The ASF licenses this file\n to you under the Apache License, Version 2.0 (the\n \"License\"); you may not use this file except in compliance\n with the License.  You may obtain a copy of the License at\n \n http://www.apache.org/licenses/LICENSE-2.0\n \n Unless required by applicable law or agreed to in writing,\n software distributed under the License is distributed on an\n \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n KIND, either express or implied.  See the License for the\n specific language governing permissions and limitations\n under the License.\n */\n\n#import <Foundation/Foundation.h>\n#import <Cordova/CDVScreenOrientationDelegate.h>\n\n@interface PortraitOnly : NSObject <CDVScreenOrientationDelegate>\n@end\n\n@interface PortraitUpsideDownOnly : NSObject <CDVScreenOrientationDelegate>\n@end\n\n@interface AllPortraitOnly : NSObject <CDVScreenOrientationDelegate>\n@end\n\n\n@interface LandscapeLeftOnly : NSObject <CDVScreenOrientationDelegate>\n@end\n\n@interface LandscapeRightOnly : NSObject <CDVScreenOrientationDelegate>\n@end\n\n@interface AllLandscapeOnly : NSObject <CDVScreenOrientationDelegate>\n@end\n\n\n@interface AllOrientations : NSObject <CDVScreenOrientationDelegate>\n@end\n\n@interface PortraitAndLandscapeLeftOnly : NSObject <CDVScreenOrientationDelegate>\n@end\n\n@interface PortraitAndLandscapeRightOnly : NSObject <CDVScreenOrientationDelegate>\n@end\n\n@interface PortraitUpsideDownAndLandscapeLeftOnly : NSObject <CDVScreenOrientationDelegate>\n@end\n\n@interface PortraitUpsideDownAndLandscapeRightOnly : NSObject <CDVScreenOrientationDelegate>\n@end\n\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/CDVSplashScreenTest/CDVSplashScreenLibTests/ImageNameTestDelegates.m",
    "content": "/*\n Licensed to the Apache Software Foundation (ASF) under one\n or more contributor license agreements.  See the NOTICE file\n distributed with this work for additional information\n regarding copyright ownership.  The ASF licenses this file\n to you under the Apache License, Version 2.0 (the\n \"License\"); you may not use this file except in compliance\n with the License.  You may obtain a copy of the License at\n \n http://www.apache.org/licenses/LICENSE-2.0\n \n Unless required by applicable law or agreed to in writing,\n software distributed under the License is distributed on an\n \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n KIND, either express or implied.  See the License for the\n specific language governing permissions and limitations\n under the License.\n */\n\n#import <UIKit/UIKit.h>\n#import \"ImageNameTestDelegates.h\"\n\n@implementation PortraitOnly\n\n- (NSUInteger)supportedInterfaceOrientations {\n    return UIInterfaceOrientationMaskPortrait;\n}\n\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {\n    return [self supportedInterfaceOrientations] & (1 << interfaceOrientation) ;\n}\n\n- (BOOL)shouldAutorotate {\n    return YES;\n}\n\n@end\n\n@implementation PortraitUpsideDownOnly\n\n- (NSUInteger)supportedInterfaceOrientations {\n    return UIInterfaceOrientationMaskPortraitUpsideDown;\n}\n\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {\n    return [self supportedInterfaceOrientations] & (1 << interfaceOrientation) ;\n}\n\n- (BOOL)shouldAutorotate {\n    return YES;\n}\n\n@end\n\n@implementation AllPortraitOnly\n\n- (NSUInteger)supportedInterfaceOrientations {\n    return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;\n}\n\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {\n    return [self supportedInterfaceOrientations] & (1 << interfaceOrientation) ;\n}\n\n- (BOOL)shouldAutorotate {\n    return YES;\n}\n\n@end\n\n\n@implementation LandscapeLeftOnly\n\n- (NSUInteger)supportedInterfaceOrientations {\n    return UIInterfaceOrientationMaskLandscapeLeft;\n}\n\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {\n    return [self supportedInterfaceOrientations] & (1 << interfaceOrientation) ;\n}\n\n- (BOOL)shouldAutorotate {\n    return YES;\n}\n\n@end\n\n@implementation LandscapeRightOnly\n\n- (NSUInteger)supportedInterfaceOrientations {\n    return UIInterfaceOrientationMaskLandscapeRight;\n}\n\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {\n    return [self supportedInterfaceOrientations] & (1 << interfaceOrientation) ;\n}\n\n- (BOOL)shouldAutorotate {\n    return YES;\n}\n\n@end\n\n@implementation AllLandscapeOnly\n\n- (NSUInteger)supportedInterfaceOrientations {\n    return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;\n}\n\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {\n    return [self supportedInterfaceOrientations] & (1 << interfaceOrientation) ;\n}\n\n- (BOOL)shouldAutorotate {\n    return YES;\n}\n\n@end\n\n\n@implementation AllOrientations\n\n- (NSUInteger)supportedInterfaceOrientations {\n    return UIInterfaceOrientationMaskAll;\n}\n\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {\n    return [self supportedInterfaceOrientations] & (1 << interfaceOrientation) ;\n}\n\n- (BOOL)shouldAutorotate {\n    return YES;\n}\n\n@end\n\n@implementation PortraitAndLandscapeLeftOnly\n\n- (NSUInteger)supportedInterfaceOrientations {\n    return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;\n}\n\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {\n    return [self supportedInterfaceOrientations] & (1 << interfaceOrientation) ;\n}\n\n- (BOOL)shouldAutorotate {\n    return YES;\n}\n\n@end\n\n@implementation PortraitAndLandscapeRightOnly\n\n- (NSUInteger)supportedInterfaceOrientations {\n    return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeRight;\n}\n\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {\n    return [self supportedInterfaceOrientations] & (1 << interfaceOrientation) ;\n}\n\n- (BOOL)shouldAutorotate {\n    return YES;\n}\n\n@end\n\n@implementation PortraitUpsideDownAndLandscapeLeftOnly\n\n- (NSUInteger)supportedInterfaceOrientations {\n    return UIInterfaceOrientationMaskPortraitUpsideDown | UIInterfaceOrientationMaskLandscapeLeft;\n}\n\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {\n    return [self supportedInterfaceOrientations] & (1 << interfaceOrientation) ;\n}\n\n- (BOOL)shouldAutorotate {\n    return YES;\n}\n\n@end\n\n@implementation PortraitUpsideDownAndLandscapeRightOnly\n\n- (NSUInteger)supportedInterfaceOrientations {\n    return UIInterfaceOrientationMaskPortraitUpsideDown | UIInterfaceOrientationMaskLandscapeRight;\n}\n\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {\n    return [self supportedInterfaceOrientations] & (1 << interfaceOrientation) ;\n}\n\n- (BOOL)shouldAutorotate {\n    return YES;\n}\n\n@end\n\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/CDVSplashScreenTest/CDVSplashScreenLibTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#  KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n#\n-->\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>org.apache.cordova.$(PRODUCT_NAME:rfc1034identifier)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/CDVSplashScreenTest/CDVSplashScreenTest.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t7E9F51AB19DA10AE00DA31AC /* CDVSplashScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E9F51A919DA10AE00DA31AC /* CDVSplashScreen.m */; };\n\t\t7E9F51B119DA114400DA31AC /* ImageNameTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E9F51B019DA114400DA31AC /* ImageNameTest.m */; };\n\t\t7E9F51B319DA116500DA31AC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E9F51B219DA116500DA31AC /* Foundation.framework */; };\n\t\t7E9F51B519DA127E00DA31AC /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E9F51B419DA127E00DA31AC /* UIKit.framework */; };\n\t\t7E9F51B819DA14FD00DA31AC /* ImageNameTestDelegates.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E9F51B719DA14FD00DA31AC /* ImageNameTestDelegates.m */; };\n\t\t7E9F51B919DA1B1600DA31AC /* libCDVSplashScreenLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E9F519519DA102000DA31AC /* libCDVSplashScreenLib.a */; };\n\t\t7E9F51BA19DA1B2000DA31AC /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E9F519019DA0F8300DA31AC /* libCordova.a */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t7E9F518F19DA0F8300DA31AC /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 68A32D7114102E1C006B237C;\n\t\t\tremoteInfo = CordovaLib;\n\t\t};\n\t\t7E9F51AC19DA10DE00DA31AC /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 7E9F517219DA09CE00DA31AC /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 7E9F519419DA102000DA31AC;\n\t\t\tremoteInfo = CDVSplashScreenLib;\n\t\t};\n\t\t7E9F51AE19DA10E100DA31AC /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = D2AAC07D0554694100DB518D;\n\t\t\tremoteInfo = CordovaLib;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t7E9F519319DA102000DA31AC /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"include/$(PRODUCT_NAME)\";\n\t\t\tdstSubfolderSpec = 16;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = CordovaLib.xcodeproj; path = \"../node_modules/cordova-ios/CordovaLib/CordovaLib.xcodeproj\"; sourceTree = \"<group>\"; };\n\t\t7E9F519519DA102000DA31AC /* libCDVSplashScreenLib.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCDVSplashScreenLib.a; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t7E9F519F19DA102000DA31AC /* CDVSplashScreenLibTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CDVSplashScreenLibTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t7E9F51A219DA102000DA31AC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t7E9F51A919DA10AE00DA31AC /* CDVSplashScreen.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVSplashScreen.m; path = ../../../src/ios/CDVSplashScreen.m; sourceTree = SOURCE_ROOT; };\n\t\t7E9F51AA19DA10AE00DA31AC /* CDVSplashScreen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVSplashScreen.h; path = ../../../src/ios/CDVSplashScreen.h; sourceTree = SOURCE_ROOT; };\n\t\t7E9F51B019DA114400DA31AC /* ImageNameTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageNameTest.m; sourceTree = \"<group>\"; };\n\t\t7E9F51B219DA116500DA31AC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };\n\t\t7E9F51B419DA127E00DA31AC /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };\n\t\t7E9F51B619DA12C600DA31AC /* ImageNameTestDelegates.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageNameTestDelegates.h; sourceTree = \"<group>\"; };\n\t\t7E9F51B719DA14FD00DA31AC /* ImageNameTestDelegates.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageNameTestDelegates.m; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t7E9F519219DA102000DA31AC /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t7E9F519C19DA102000DA31AC /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t7E9F51BA19DA1B2000DA31AC /* libCordova.a in Frameworks */,\n\t\t\t\t7E9F51B919DA1B1600DA31AC /* libCDVSplashScreenLib.a in Frameworks */,\n\t\t\t\t7E9F51B519DA127E00DA31AC /* UIKit.framework in Frameworks */,\n\t\t\t\t7E9F51B319DA116500DA31AC /* Foundation.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t7E9F517119DA09CE00DA31AC = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7E9F51B419DA127E00DA31AC /* UIKit.framework */,\n\t\t\t\t7E9F51B219DA116500DA31AC /* Foundation.framework */,\n\t\t\t\t7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */,\n\t\t\t\t7E9F519619DA102000DA31AC /* CDVSplashScreenLib */,\n\t\t\t\t7E9F51A019DA102000DA31AC /* CDVSplashScreenLibTests */,\n\t\t\t\t7E9F517D19DA0A0A00DA31AC /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t7E9F517D19DA0A0A00DA31AC /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7E9F519519DA102000DA31AC /* libCDVSplashScreenLib.a */,\n\t\t\t\t7E9F519F19DA102000DA31AC /* CDVSplashScreenLibTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t7E9F518C19DA0F8300DA31AC /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7E9F519019DA0F8300DA31AC /* libCordova.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t7E9F519619DA102000DA31AC /* CDVSplashScreenLib */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7E9F51A919DA10AE00DA31AC /* CDVSplashScreen.m */,\n\t\t\t\t7E9F51AA19DA10AE00DA31AC /* CDVSplashScreen.h */,\n\t\t\t);\n\t\t\tpath = CDVSplashScreenLib;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t7E9F51A019DA102000DA31AC /* CDVSplashScreenLibTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7E9F51A119DA102000DA31AC /* Supporting Files */,\n\t\t\t\t7E9F51B019DA114400DA31AC /* ImageNameTest.m */,\n\t\t\t\t7E9F51B619DA12C600DA31AC /* ImageNameTestDelegates.h */,\n\t\t\t\t7E9F51B719DA14FD00DA31AC /* ImageNameTestDelegates.m */,\n\t\t\t);\n\t\t\tpath = CDVSplashScreenLibTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t7E9F51A119DA102000DA31AC /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7E9F51A219DA102000DA31AC /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t7E9F519419DA102000DA31AC /* CDVSplashScreenLib */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 7E9F51A319DA102000DA31AC /* Build configuration list for PBXNativeTarget \"CDVSplashScreenLib\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t7E9F519119DA102000DA31AC /* Sources */,\n\t\t\t\t7E9F519219DA102000DA31AC /* Frameworks */,\n\t\t\t\t7E9F519319DA102000DA31AC /* CopyFiles */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = CDVSplashScreenLib;\n\t\t\tproductName = CDVSplashScreenLib;\n\t\t\tproductReference = 7E9F519519DA102000DA31AC /* libCDVSplashScreenLib.a */;\n\t\t\tproductType = \"com.apple.product-type.library.static\";\n\t\t};\n\t\t7E9F519E19DA102000DA31AC /* CDVSplashScreenLibTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 7E9F51A619DA102000DA31AC /* Build configuration list for PBXNativeTarget \"CDVSplashScreenLibTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t7E9F519B19DA102000DA31AC /* Sources */,\n\t\t\t\t7E9F519C19DA102000DA31AC /* Frameworks */,\n\t\t\t\t7E9F519D19DA102000DA31AC /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t7E9F51AF19DA10E100DA31AC /* PBXTargetDependency */,\n\t\t\t\t7E9F51AD19DA10DE00DA31AC /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = CDVSplashScreenLibTests;\n\t\t\tproductName = CDVSplashScreenLibTests;\n\t\t\tproductReference = 7E9F519F19DA102000DA31AC /* CDVSplashScreenLibTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t7E9F517219DA09CE00DA31AC /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 0600;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t7E9F519419DA102000DA31AC = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.0;\n\t\t\t\t\t};\n\t\t\t\t\t7E9F519E19DA102000DA31AC = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.0;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 7E9F517519DA09CE00DA31AC /* Build configuration list for PBXProject \"CDVSplashScreenTest\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t);\n\t\t\tmainGroup = 7E9F517119DA09CE00DA31AC;\n\t\t\tproductRefGroup = 7E9F517D19DA0A0A00DA31AC /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectReferences = (\n\t\t\t\t{\n\t\t\t\t\tProductGroup = 7E9F518C19DA0F8300DA31AC /* Products */;\n\t\t\t\t\tProjectRef = 7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */;\n\t\t\t\t},\n\t\t\t);\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t7E9F519419DA102000DA31AC /* CDVSplashScreenLib */,\n\t\t\t\t7E9F519E19DA102000DA31AC /* CDVSplashScreenLibTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXReferenceProxy section */\n\t\t7E9F519019DA0F8300DA31AC /* libCordova.a */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = archive.ar;\n\t\t\tpath = libCordova.a;\n\t\t\tremoteRef = 7E9F518F19DA0F8300DA31AC /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n/* End PBXReferenceProxy section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t7E9F519D19DA102000DA31AC /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t7E9F519119DA102000DA31AC /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t7E9F51AB19DA10AE00DA31AC /* CDVSplashScreen.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t7E9F519B19DA102000DA31AC /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t7E9F51B119DA114400DA31AC /* ImageNameTest.m in Sources */,\n\t\t\t\t7E9F51B819DA14FD00DA31AC /* ImageNameTestDelegates.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t7E9F51AD19DA10DE00DA31AC /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 7E9F519419DA102000DA31AC /* CDVSplashScreenLib */;\n\t\t\ttargetProxy = 7E9F51AC19DA10DE00DA31AC /* PBXContainerItemProxy */;\n\t\t};\n\t\t7E9F51AF19DA10E100DA31AC /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\tname = CordovaLib;\n\t\t\ttargetProxy = 7E9F51AE19DA10E100DA31AC /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\t7E9F517619DA09CE00DA31AC /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t7E9F517719DA09CE00DA31AC /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t7E9F51A419DA102000DA31AC /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"\\\"$(TARGET_BUILD_DIR)/usr/local/lib/include\\\"\",\n\t\t\t\t\t\"\\\"$(OBJROOT)/UninstalledProducts/include\\\"\",\n\t\t\t\t\t\"\\\"$(BUILT_PRODUCTS_DIR)\\\"\",\n\t\t\t\t);\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tOTHER_LDFLAGS = \"-ObjC\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t7E9F51A519DA102000DA31AC /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"\\\"$(TARGET_BUILD_DIR)/usr/local/lib/include\\\"\",\n\t\t\t\t\t\"\\n\\\"$(OBJROOT)/UninstalledProducts/include\\\"\\n\\\"$(BUILT_PRODUCTS_DIR)\\\"\",\n\t\t\t\t);\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tOTHER_LDFLAGS = \"-ObjC\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t7E9F51A719DA102000DA31AC /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)/Developer/Library/Frameworks\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tINFOPLIST_FILE = CDVSplashScreenLibTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t7E9F51A819DA102000DA31AC /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)/Developer/Library/Frameworks\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tINFOPLIST_FILE = CDVSplashScreenLibTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t7E9F517519DA09CE00DA31AC /* Build configuration list for PBXProject \"CDVSplashScreenTest\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t7E9F517619DA09CE00DA31AC /* Debug */,\n\t\t\t\t7E9F517719DA09CE00DA31AC /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t7E9F51A319DA102000DA31AC /* Build configuration list for PBXNativeTarget \"CDVSplashScreenLib\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t7E9F51A419DA102000DA31AC /* Debug */,\n\t\t\t\t7E9F51A519DA102000DA31AC /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t7E9F51A619DA102000DA31AC /* Build configuration list for PBXNativeTarget \"CDVSplashScreenLibTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t7E9F51A719DA102000DA31AC /* Debug */,\n\t\t\t\t7E9F51A819DA102000DA31AC /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 7E9F517219DA09CE00DA31AC /* Project object */;\n}\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/CDVSplashScreenTest/CDVSplashScreenTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:CDVSplashScreenTest.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/CDVSplashScreenTest/CDVSplashScreenTest.xcodeproj/project.xcworkspace/xcshareddata/CDVSplashScreenTest.xccheckout",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDESourceControlProjectFavoriteDictionaryKey</key>\n\t<false/>\n\t<key>IDESourceControlProjectIdentifier</key>\n\t<string>6BE9AD73-1B9F-4362-98D7-DC631BEC6185</string>\n\t<key>IDESourceControlProjectName</key>\n\t<string>CDVSplashScreenTest</string>\n\t<key>IDESourceControlProjectOriginsDictionary</key>\n\t<dict>\n\t\t<key>BEF5A5D0FF64801E558286389440357A9233D7DB</key>\n\t\t<string>https://git-wip-us.apache.org/repos/asf/cordova-plugin-splashscreen.git</string>\n\t</dict>\n\t<key>IDESourceControlProjectPath</key>\n\t<string>tests/ios/CDVSplashScreenTest/CDVSplashScreenTest.xcodeproj</string>\n\t<key>IDESourceControlProjectRelativeInstallPathDictionary</key>\n\t<dict>\n\t\t<key>BEF5A5D0FF64801E558286389440357A9233D7DB</key>\n\t\t<string>../../../../..</string>\n\t</dict>\n\t<key>IDESourceControlProjectURL</key>\n\t<string>https://git-wip-us.apache.org/repos/asf/cordova-plugin-splashscreen.git</string>\n\t<key>IDESourceControlProjectVersion</key>\n\t<integer>111</integer>\n\t<key>IDESourceControlProjectWCCIdentifier</key>\n\t<string>BEF5A5D0FF64801E558286389440357A9233D7DB</string>\n\t<key>IDESourceControlProjectWCConfigurations</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>IDESourceControlRepositoryExtensionIdentifierKey</key>\n\t\t\t<string>public.vcs.git</string>\n\t\t\t<key>IDESourceControlWCCIdentifierKey</key>\n\t\t\t<string>BEF5A5D0FF64801E558286389440357A9233D7DB</string>\n\t\t\t<key>IDESourceControlWCCName</key>\n\t\t\t<string>cordova-plugin-splashscreen</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/CDVSplashScreenTest/CDVSplashScreenTest.xcodeproj/xcshareddata/xcschemes/CDVSplashScreenLib.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0600\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"7E9F519419DA102000DA31AC\"\n               BuildableName = \"libCDVSplashScreenLib.a\"\n               BlueprintName = \"CDVSplashScreenLib\"\n               ReferencedContainer = \"container:CDVSplashScreenTest.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      buildConfiguration = \"Debug\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      buildConfiguration = \"Debug\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"7E9F519419DA102000DA31AC\"\n            BuildableName = \"libCDVSplashScreenLib.a\"\n            BlueprintName = \"CDVSplashScreenLib\"\n            ReferencedContainer = \"container:CDVSplashScreenTest.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      buildConfiguration = \"Release\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"7E9F519419DA102000DA31AC\"\n            BuildableName = \"libCDVSplashScreenLib.a\"\n            BlueprintName = \"CDVSplashScreenLib\"\n            ReferencedContainer = \"container:CDVSplashScreenTest.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/CDVSplashScreenTest/CDVSplashScreenTest.xcodeproj/xcshareddata/xcschemes/CDVSplashScreenLibTests.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0600\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"7E9F519E19DA102000DA31AC\"\n               BuildableName = \"CDVSplashScreenLibTests.xctest\"\n               BlueprintName = \"CDVSplashScreenLibTests\"\n               ReferencedContainer = \"container:CDVSplashScreenTest.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      buildConfiguration = \"Debug\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"7E9F519E19DA102000DA31AC\"\n               BuildableName = \"CDVSplashScreenLibTests.xctest\"\n               BlueprintName = \"CDVSplashScreenLibTests\"\n               ReferencedContainer = \"container:CDVSplashScreenTest.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"7E9F519E19DA102000DA31AC\"\n            BuildableName = \"CDVSplashScreenLibTests.xctest\"\n            BlueprintName = \"CDVSplashScreenLibTests\"\n            ReferencedContainer = \"container:CDVSplashScreenTest.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </TestAction>\n   <LaunchAction\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      buildConfiguration = \"Debug\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"7E9F519E19DA102000DA31AC\"\n            BuildableName = \"CDVSplashScreenLibTests.xctest\"\n            BlueprintName = \"CDVSplashScreenLibTests\"\n            ReferencedContainer = \"container:CDVSplashScreenTest.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      buildConfiguration = \"Release\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"7E9F519E19DA102000DA31AC\"\n            BuildableName = \"CDVSplashScreenLibTests.xctest\"\n            BlueprintName = \"CDVSplashScreenLibTests\"\n            ReferencedContainer = \"container:CDVSplashScreenTest.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/CDVSplashScreenTest.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"container:CDVSplashScreenTest/CDVSplashScreenTest.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/CDVSplashScreenTest.xcworkspace/xcshareddata/CDVSplashScreenTest.xccheckout",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDESourceControlProjectFavoriteDictionaryKey</key>\n\t<false/>\n\t<key>IDESourceControlProjectIdentifier</key>\n\t<string>6BE9AD73-1B9F-4362-98D7-DC631BEC6185</string>\n\t<key>IDESourceControlProjectName</key>\n\t<string>CDVSplashScreenTest</string>\n\t<key>IDESourceControlProjectOriginsDictionary</key>\n\t<dict>\n\t\t<key>BEF5A5D0FF64801E558286389440357A9233D7DB</key>\n\t\t<string>https://git-wip-us.apache.org/repos/asf/cordova-plugin-splashscreen.git</string>\n\t</dict>\n\t<key>IDESourceControlProjectPath</key>\n\t<string>tests/ios/CDVSplashScreenTest/CDVSplashScreenTest.xcodeproj</string>\n\t<key>IDESourceControlProjectRelativeInstallPathDictionary</key>\n\t<dict>\n\t\t<key>BEF5A5D0FF64801E558286389440357A9233D7DB</key>\n\t\t<string>../../../../..</string>\n\t</dict>\n\t<key>IDESourceControlProjectURL</key>\n\t<string>https://git-wip-us.apache.org/repos/asf/cordova-plugin-splashscreen.git</string>\n\t<key>IDESourceControlProjectVersion</key>\n\t<integer>111</integer>\n\t<key>IDESourceControlProjectWCCIdentifier</key>\n\t<string>BEF5A5D0FF64801E558286389440357A9233D7DB</string>\n\t<key>IDESourceControlProjectWCConfigurations</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>IDESourceControlRepositoryExtensionIdentifierKey</key>\n\t\t\t<string>public.vcs.git</string>\n\t\t\t<key>IDESourceControlWCCIdentifierKey</key>\n\t\t\t<string>BEF5A5D0FF64801E558286389440357A9233D7DB</string>\n\t\t\t<key>IDESourceControlWCCName</key>\n\t\t\t<string>cordova-plugin-splashscreen</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/CDVSplashScreenTest.xcworkspace/xcshareddata/xcschemes/CordovaLib.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0600\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"D2AAC07D0554694100DB518D\"\n               BuildableName = \"libCordova.a\"\n               BlueprintName = \"CordovaLib\"\n               ReferencedContainer = \"container:node_modules/cordova-ios/CordovaLib/CordovaLib.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      buildConfiguration = \"Debug\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      buildConfiguration = \"Debug\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"D2AAC07D0554694100DB518D\"\n            BuildableName = \"libCordova.a\"\n            BlueprintName = \"CordovaLib\"\n            ReferencedContainer = \"container:node_modules/cordova-ios/CordovaLib/CordovaLib.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      buildConfiguration = \"Release\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"D2AAC07D0554694100DB518D\"\n            BuildableName = \"libCordova.a\"\n            BlueprintName = \"CordovaLib\"\n            ReferencedContainer = \"container:node_modules/cordova-ios/CordovaLib/CordovaLib.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# iOS Tests for CDVSplashScreen\n\nYou need to install `node.js` to pull in `cordova-ios`.\n\nFirst install cordova-ios:\n\n    npm install\n\n... in the current folder.\n\n\n# Testing from Xcode\n\n1. Launch the `CDVSplashScreenTest.xcworkspace` file.\n2. Choose \"CDVSplashScreenLibTests\" from the scheme drop-down menu\n3. Click and hold on the `Play` button, and choose the `Wrench` icon to run the tests\n\n\n# Testing from the command line\n\n    npm test\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/doc/de/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# iOS-Tests für CDVSplashScreen\n\nSie müssen installieren `node.js` in `Cordova-Ios` zu ziehen.\n\nInstallieren Sie Cordova-Ios zum ersten Mal:\n\n    npm install\n    \n\n... im aktuellen Ordner.\n\n# Testen von Xcode\n\n  1. Starten Sie die Datei `CDVSplashScreenTest.xcworkspace` .\n  2. Wählen Sie im Dropdown-Schema \"CDVSplashScreenLibTests\"\n  3. Klicken Sie und halten Sie auf den `Play` -Button und wählen Sie das `Schraubenschlüssel` -Symbol zum Ausführen der tests\n\n# Tests von der Befehlszeile aus\n\n    npm test\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/doc/es/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# Pruebas de iOS para CDVSplashScreen\n\nNecesita instalar `node.js` en `Córdoba-ios`.\n\nPrimero instalar cordova-ios:\n\n    npm install\n    \n\n... en la carpeta actual.\n\n# Prueba de Xcode\n\n  1. Iniciar el archivo `CDVSplashScreenTest.xcworkspace` .\n  2. Elija \"CDVSplashScreenLibTests\" en el menú de lista desplegable esquema\n  3. Haga clic y mantenga el botón de `Play` y elegir el icono de `llave inglesa` para ejecutar las pruebas\n\n# Pruebas desde la línea de comandos\n\n    npm test\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/doc/fr/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# Tests d'iOS pour CDVSplashScreen\n\nVous devez installer `node.js` à `cordova-ios`.\n\nCommencez par installer cordova-ios :\n\n    npm install\n    \n\n... dans le dossier actuel.\n\n# Tests de Xcode\n\n  1. Lancez le fichier `CDVSplashScreenTest.xcworkspace` .\n  2. Choisissez « CDVSplashScreenLibTests » dans le menu déroulant de régime\n  3. Cliquez et maintenez sur la touche `Play` et cliquez sur l'icône de `clé` pour exécuter les tests\n\n# Test de la ligne de commande\n\n    npm test\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/doc/it/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# Test di iOS per CDVSplashScreen\n\nÈ necessario installare `node. js` per tirare in `cordova-ios`.\n\nIn primo luogo installare cordova-ios:\n\n    npm install\n    \n\n... nella cartella corrente.\n\n# Test da Xcode\n\n  1. Lanciare il file `CDVSplashScreenTest.xcworkspace` .\n  2. Scegli \"CDVSplashScreenLibTests\" dal menu a discesa Schema\n  3. Fare clic e tenere premuto il pulsante `Play` e scegliere l'icona della `chiave inglese` per eseguire i test\n\n# Test dalla riga di comando\n\n    npm test\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/doc/ja/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# CDVSplashScreen の iOS のテスト\n\n`Node.js` `コルドバ`ios をプルするをインストールする必要があります。.\n\nコルドバ ios をインストールします。\n\n    npm install\n    \n\n現在のフォルダーに.\n\n# Xcode からテスト\n\n  1. `CDVSplashScreenTest.xcworkspace`ファイルを起動します。\n  2. スキーム] ドロップダウン メニューから\"CDVSplashScreenLibTests\"を選択します。\n  3. クリックし、`再生`ボタンを押し、テストを実行する`レンチ`のアイコンを選択\n\n# コマンドラインからテスト\n\n    npm test\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/doc/ko/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# CDVSplashScreen에 대 한 iOS 테스트\n\n`Node.js` `코르도바` ios에서를 설치 해야.\n\n코르도바-ios를 설치 하는 첫번째는:\n\n    npm install\n    \n\n현재 폴더에....\n\n# Xcode에서 테스트\n\n  1. `CDVSplashScreenTest.xcworkspace` 파일을 시작 합니다.\n  2. 구성표 드롭 다운 메뉴에서 \"CDVSplashScreenLibTests\"를 선택\n  3. 클릭 하 고 `재생` 버튼에는 테스트를 실행 하려면 `공구 모양` 아이콘을 선택\n\n# 명령줄에서 테스트\n\n    npm test\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/doc/pl/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# iOS testy dla CDVSplashScreen\n\nMusisz zainstalować `node.js` ciągnąć w `cordova-ios`.\n\nNajpierw zainstalować cordova-ios:\n\n    npm install\n    \n\n... w folderze bieżącym.\n\n# Badania z Xcode\n\n  1. Uruchom plik `CDVSplashScreenTest.xcworkspace` .\n  2. Wybierz z menu rozwijanego systemu \"CDVSplashScreenLibTests\"\n  3. Kliknij i przytrzymaj przycisk `Play` i wybrać ikonę `klucz` do testów\n\n# Badania z wiersza polecenia\n\n    npm test\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/doc/zh/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# CDVSplashScreen 的 iOS 測試\n\n您需要安裝`node.js`拉`科爾多瓦 ios`中.\n\n第一次安裝科爾多瓦 ios:\n\n    npm install\n    \n\n在當前資料夾中。\n\n# 從 Xcode 測試\n\n  1. 啟動`CDVSplashScreenTest.xcworkspace`檔。\n  2. 從方案下拉式功能表中選擇\"CDVSplashScreenLibTests\"\n  3. 按一下並堅持`播放`按鈕，然後選擇要運行的測試的`扳手`圖示\n\n# 從命令列測試\n\n    npm test\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/ios/package.json",
    "content": "{\n    \"name\": \"cordova-plugin-splashscreen-test-ios\",\n    \"version\": \"1.0.0\",\n    \"description\": \"iOS Unit Tests for Splashscreen Plugin\",\n    \"author\": \"Apache Software Foundation\",\n    \"license\": \"Apache Version 2.0\",\n    \"dependencies\": {\n        \"cordova-ios\": \"*\"\n    },\n    \"scripts\": {\n        \"test\": \"xcodebuild test -workspace CDVSplashScreenTest.xcworkspace -scheme CDVSplashScreenLibTests -destination 'platform=iOS Simulator,name=iPhone 5' CONFIGURATION_BUILD_DIR='/tmp' HEADER_SEARCH_PATHS='$(OBJROOT)/UninstalledProducts/$(PLATFORM_NAME)/include'\"\n    }\n}\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/plugin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one\n  or more contributor license agreements.  See the NOTICE file\n  distributed with this work for additional information\n  regarding copyright ownership.  The ASF licenses this file\n  to you under the Apache License, Version 2.0 (the\n  \"License\"); you may not use this file except in compliance\n  with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an\n  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n  KIND, either express or implied.  See the License for the\n  specific language governing permissions and limitations\n  under the License.\n-->\n\n<plugin xmlns=\"http://apache.org/cordova/ns/plugins/1.0\"\n    id=\"cordova-plugin-splashscreen-tests\"\n    version=\"4.0.1\">\n    <name>Cordova Splashscreen Plugin Tests</name>\n    <license>Apache 2.0</license>\n\n    <js-module src=\"tests.js\" name=\"tests\">\n    </js-module>\n</plugin>\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/tests/tests.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n/* jshint jasmine: true */\n\nexports.defineAutoTests = function () {\n    describe('Splashscreen (cordova)', function () {\n        it(\"splashscreen.spec.1 should exist\", function () {\n            expect(navigator.splashscreen).toBeDefined();\n        });\n\n        it(\"splashscreen.spec.2 show method should exist\", function () {\n            expect(navigator.splashscreen.show).toBeDefined();\n            expect(typeof navigator.splashscreen.show).toBe('function');\n        });\n\n        it(\"splashscreen.spec.3 hide method should exist\", function () {\n            expect(navigator.splashscreen.hide).toBeDefined();\n            expect(typeof navigator.splashscreen.hide).toBe('function');\n        });\n    });\n};\n\nexports.defineManualTests = function (contentEl, createActionButton) {\n    function showFor(duration) {\n        navigator.splashscreen.show();\n        window.setTimeout(function () {\n            navigator.splashscreen.hide();\n        }, 1000 * duration);\n    }\n\n    contentEl.innerHTML = '<h1>Splashscreen Tests</h1>' +\n        '<h3>Note for WP: AutoHideSplashScreen must be set to false in config.xml</h3>' +\n        '<div id=\"show1\"></div>' +\n        'Expected result: Will show the Cordova splashscreen for 1 second' +\n        '</p> <div id=\"show5\"></div>' +\n        'Expected result: Will show the Cordova splashscreen for 5 seconds';\n\n    createActionButton('Show for 1 second', function () {\n        showFor(1);\n    }, 'show1');\n\n    createActionButton('Show for 5 seconds', function () {\n        showFor(5);\n    }, 'show5');\n};\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/www/splashscreen.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\nvar exec = require('cordova/exec');\n\nvar splashscreen = {\n    show:function() {\n        exec(null, null, \"SplashScreen\", \"show\", []);\n    },\n    hide:function() {\n        exec(null, null, \"SplashScreen\", \"hide\", []);\n    }\n};\n\nmodule.exports = splashscreen;\n"
  },
  {
    "path": "plugins/cordova-plugin-splashscreen/www/windows/SplashScreenProxy.js",
    "content": "﻿/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\n\n/*jslint sloppy:true */\n\nvar splash = require('cordova/splashscreen');\n\nvar SplashScreen = {\n    show: function () {\n        splash.show();\n    },\n    hide: function () {\n        splash.hide();\n    }\n};\n\nmodule.exports = SplashScreen;\n\nrequire(\"cordova/exec/proxy\").add(\"SplashScreen\", SplashScreen);\n"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/CONTRIBUTING.md",
    "content": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#  KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n#\n-->\n\n# Contributing to Apache Cordova\n\nAnyone can contribute to Cordova. And we need your contributions.\n\nThere are multiple ways to contribute: report bugs, improve the docs, and\ncontribute code.\n\nFor instructions on this, start with the\n[contribution overview](http://cordova.apache.org/contribute/).\n\nThe details are explained there, but the important items are:\n - Sign and submit an Apache ICLA (Contributor License Agreement).\n - Have a Jira issue open that corresponds to your contribution.\n - Run the tests so your patch doesn't break existing functionality.\n\nWe look forward to your contributions!\n"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "plugins/cordova-plugin-whitelist/NOTICE",
    "content": "Apache Cordova\nCopyright 2012 The Apache Software Foundation\n\nThis product includes software developed at\nThe Apache Software Foundation (http://www.apache.org/).\n"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/README.md",
    "content": "---\ntitle: Whitelist\ndescription: Whitelist external content accessible by your app.\n---\n<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-whitelist\n\nThis plugin implements a whitelist policy for navigating the application webview on Cordova 4.0\n\n:warning: Report issues on the [Apache Cordova issue tracker](https://issues.apache.org/jira/issues/?jql=project%20%3D%20CB%20AND%20status%20in%20%28Open%2C%20%22In%20Progress%22%2C%20Reopened%29%20AND%20resolution%20%3D%20Unresolved%20AND%20component%20%3D%20%22Plugin%20Whitelist%22%20ORDER%20BY%20priority%20DESC%2C%20summary%20ASC%2C%20updatedDate%20DESC)\n\n## Installation\n\nYou can install whitelist plugin with Cordova CLI, from npm:\n\n```\n$ cordova plugin add cordova-plugin-whitelist\n$ cordova prepare\n```\n\n## Supported Cordova Platforms\n\n* Android 4.0.0 or above\n\n## Navigation Whitelist\nControls which URLs the WebView itself can be navigated to. Applies to\ntop-level navigations only.\n\nQuirks: on Android it also applies to iframes for non-http(s) schemes.\n\nBy default, navigations only to `file://` URLs, are allowed. To allow others URLs, you must add `<allow-navigation>` tags to your `config.xml`:\n\n    <!-- Allow links to example.com -->\n    <allow-navigation href=\"http://example.com/*\" />\n\n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-navigation href=\"*://*.example.com/*\" />\n\n    <!-- A wildcard can be used to whitelist the entire network,\n         over HTTP and HTTPS.\n         *NOT RECOMMENDED* -->\n    <allow-navigation href=\"*\" />\n\n    <!-- The above is equivalent to these three declarations -->\n    <allow-navigation href=\"http://*/*\" />\n    <allow-navigation href=\"https://*/*\" />\n    <allow-navigation href=\"data:*\" />\n\n## Intent Whitelist\nControls which URLs the app is allowed to ask the system to open.\nBy default, no external URLs are allowed.\n\nOn Android, this equates to sending an intent of type BROWSEABLE.\n\nThis whitelist does not apply to plugins, only hyperlinks and calls to `window.open()`.\n\nIn `config.xml`, add `<allow-intent>` tags, like this:\n\n    <!-- Allow links to web pages to open in a browser -->\n    <allow-intent href=\"http://*/*\" />\n    <allow-intent href=\"https://*/*\" />\n\n    <!-- Allow links to example.com to open in a browser -->\n    <allow-intent href=\"http://example.com/*\" />\n\n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-intent href=\"*://*.example.com/*\" />\n\n    <!-- Allow SMS links to open messaging app -->\n    <allow-intent href=\"sms:*\" />\n\n    <!-- Allow tel: links to open the dialer -->\n    <allow-intent href=\"tel:*\" />\n\n    <!-- Allow geo: links to open maps -->\n    <allow-intent href=\"geo:*\" />\n\n    <!-- Allow all unrecognized URLs to open installed apps\n         *NOT RECOMMENDED* -->\n    <allow-intent href=\"*\" />\n\n## Network Request Whitelist\nControls which network requests (images, XHRs, etc) are allowed to be made (via cordova native hooks).\n\nNote: We suggest you use a Content Security Policy (see below), which is more secure.  This whitelist is mostly historical for webviews which do not support CSP.\n\nIn `config.xml`, add `<access>` tags, like this:\n\n    <!-- Allow images, xhrs, etc. to google.com -->\n    <access origin=\"http://google.com\" />\n    <access origin=\"https://google.com\" />\n\n    <!-- Access to the subdomain maps.google.com -->\n    <access origin=\"http://maps.google.com\" />\n\n    <!-- Access to all the subdomains on google.com -->\n    <access origin=\"http://*.google.com\" />\n\n    <!-- Enable requests to content: URLs -->\n    <access origin=\"content:///*\" />\n\n    <!-- Don't block any requests -->\n    <access origin=\"*\" />\n\nWithout any `<access>` tags, only requests to `file://` URLs are allowed. However, the default Cordova application includes `<access origin=\"*\">` by default.\n\n\nNote: Whitelist cannot block network redirects from a whitelisted remote website (i.e. http or https) to a non-whitelisted website. Use CSP rules to mitigate redirects to non-whitelisted websites for webviews that support CSP.\n\nQuirk: Android also allows requests to https://ssl.gstatic.com/accessibility/javascript/android/ by default, since this is required for TalkBack to function properly.\n\n### Content Security Policy\nControls which network requests (images, XHRs, etc) are allowed to be made (via webview directly).\n\nOn Android and iOS, the network request whitelist (see above) is not able to filter all types of requests (e.g. `<video>` & WebSockets are not blocked). So, in addition to the whitelist, you should use a [Content Security Policy](http://content-security-policy.com/) `<meta>` tag on all of your pages.\n\nOn Android, support for CSP within the system webview starts with KitKat (but is available on all versions using Crosswalk WebView).\n\nHere are some example CSP declarations for your `.html` pages:\n\n    <!-- Good default declaration:\n        * gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication\n        * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly\n        * Disables use of eval() and inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:\n            * Enable inline JS: add 'unsafe-inline' to default-src\n            * Enable eval(): add 'unsafe-eval' to default-src\n    -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' data: gap: https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; media-src *\">\n\n    <!-- Allow everything but only from the same origin and foo.com -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' foo.com\">\n\n    <!-- This policy allows everything (eg CSS, AJAX, object, frame, media, etc) except that \n        * CSS only from the same origin and inline styles,\n        * scripts only from the same origin and inline styles, and eval()\n    -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">\n\n    <!-- Allows XHRs only over HTTPS on the same domain. -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' https:\">\n\n    <!-- Allow iframe to https://cordova.apache.org/ -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'; frame-src 'self' https://cordova.apache.org\">\n"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/RELEASENOTES.md",
    "content": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#  KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n#\n-->\n# Release Notes\n\n### 1.3.1 (Dec 07, 2016)\n* [CB-11917](https://issues.apache.org/jira/browse/CB-11917) - Remove pull request template checklist item: \"iCLA has been submitted…\"\n* Edit package.json license to match SPDX id\n* [CB-11832](https://issues.apache.org/jira/browse/CB-11832) Incremented plugin version.\n\n### 1.3.0 (Sep 08, 2016)\n* [CB-11795](https://issues.apache.org/jira/browse/CB-11795) Add 'protective' entry to cordovaDependencies\n* Updated installation section\n* Plugin uses `Android Log class` and not `Cordova LOG class`\n* Add pull request template.\n* [CB-10866](https://issues.apache.org/jira/browse/CB-10866) Adding engine info to `package.json`\n* [CB-10996](https://issues.apache.org/jira/browse/CB-10996) Adding front matter to README.md\n\n### 1.2.2 (Apr 15, 2016)\n* add note about redirects\n* [CB-10624](https://issues.apache.org/jira/browse/CB-10624) remove error message from `whitelist.js`, which leaves it empty\n\n### 1.2.1 (Jan 15, 2016)\n* [CB-10194](https://issues.apache.org/jira/browse/CB-10194) info tag prints for ios when not applicable\n\n### 1.2.0 (Nov 18, 2015)\n* removed **iOS** engine check from `plugin.xml`\n* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Updated `RELEASENOTES` to be newest to oldest\n* [CB-9972](https://issues.apache.org/jira/browse/CB-9972) - Remove **iOS** whitelist\n* Updated the text, it should read 4.0.x and greater, since this plugin will be required for `cordova-android 5.0`\n* Fixing contribute link.\n* Updated `plugin.xml <info>` tag to remove warning about not needing this plugin if you are using the **iOS 9 SDK**\n* [CB-9738](https://issues.apache.org/jira/browse/CB-9738) - Disable whitelist use when runtime environment is **iOS 9**\n* [CB-9740](https://issues.apache.org/jira/browse/CB-9740) - Add `<info>` tag describing whitelist plugin not needed on `cordova-ios` and cordova-android 3.x`\n* [CB-9568](https://issues.apache.org/jira/browse/CB-9568) - Update whitelist plugin to allow all network access by default\n* [CB-9337](https://issues.apache.org/jira/browse/CB-9337) - enable use of `<access>` tags for native code network requests\n\n### 1.1.0 (Jun 17, 2015)\n* [CB-9128](https://issues.apache.org/jira/browse/CB-9128) cordova-plugin-whitelist documentation translation: cordova-plugin-whitelist\n* fix npm md issue\n* Usage of CDVURLRequestFilter protocol.\n* [CB-9089](https://issues.apache.org/jira/browse/CB-9089) - iOS whitelist plugin does not compile\n* [CB-9090](https://issues.apache.org/jira/browse/CB-9090) - Enable whitelist plugin for cordova-ios 4.0.0\n* Fixed error in Content-Security-Policy example\n\n### 1.0.0 (Mar 25, 2015)\n* [CB-8739](https://issues.apache.org/jira/browse/CB-8739) added missing license headers\n* Add @Override to CustomConfigXmlParser methods\n* Change ID to cordova-plugin-whitelist rather than reverse-DNS-style\n* Tweak CSP examples in README\n* [CB-8660](https://issues.apache.org/jira/browse/CB-8660) remove extra commas from package.json\n"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/doc/de/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-whitelist\n\nDieses Plugin implementiert eine Whitelist-Politik für die Navigation in der Anwendung Webview Cordova 4.0\n\n## Cordova unterstützte Plattformen\n\n  * Android 4.0.0 oder höher\n  * iOS 4.0.0 oder höher\n\n## Navigation-Whitelist\n\nSteuert, welche URLs die WebView selbst zu navigiert werden kann. Bezieht sich auf der obersten Ebene Navigationen nur.\n\nMacken: auf Android es gilt auch für Iframes für nicht-http(s) Systeme.\n\nIn der Standardeinstellung Navigationen nur auf `file://` URLs, sind zulässig. Wenn andere andere URLs zulassen möchten, müssen Sie Ihre `\"config.xml\"` `<allow-navigation>` Markierungen hinzufügen:\n\n    <!-- Allow links to example.com -->\n    <allow-navigation href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-navigation href=\"*://*.example.com/*\" />\n    \n    <!-- A wildcard can be used to whitelist the entire network,\n         over HTTP and HTTPS.\n         *NOT RECOMMENDED* -->\n    <allow-navigation href=\"*\" />\n    \n    <!-- The above is equivalent to these three declarations -->\n    <allow-navigation href=\"http://*/*\" />\n    <allow-navigation href=\"https://*/*\" />\n    <allow-navigation href=\"data:*\" />\n    \n\n## Vorsatz-Whitelist\n\nSteuert, welche URLs die app zulässig ist, um das System zu öffnen Fragen. Standardmäßig dürfen keine externe URLs.\n\nDas entspricht auf Android eine Absicht des Typs BROWSEABLE senden.\n\nDiese Whitelist gilt nicht für Plugins, nur Hyperlinks und Aufrufe von `window.open()`.\n\nFügen Sie in `\"config.xml\"` `<allow-intent>` Tags hinzu, wie folgt:\n\n    <!-- Allow links to web pages to open in a browser -->\n    <allow-intent href=\"http://*/*\" />\n    <allow-intent href=\"https://*/*\" />\n    \n    <!-- Allow links to example.com to open in a browser -->\n    <allow-intent href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-intent href=\"*://*.example.com/*\" />\n    \n    <!-- Allow SMS links to open messaging app -->\n    <allow-intent href=\"sms:*\" />\n    \n    <!-- Allow tel: links to open the dialer -->\n    <allow-intent href=\"tel:*\" />\n    \n    <!-- Allow geo: links to open maps -->\n    <allow-intent href=\"geo:*\" />\n    \n    <!-- Allow all unrecognized URLs to open installed apps\n         *NOT RECOMMENDED* -->\n    <allow-intent href=\"*\" />\n    \n\n## Netzwerk-Anforderung-Whitelist\n\nSteuert, welche-Anforderungen Netzwerk (Bilder, XHRs, etc.) dürfen (über Cordova native Haken) erfolgen.\n\nHinweis: Wir empfehlen Ihnen eine Content Security Policy (siehe unten), das ist sicherer. Diese Whitelist ist vor allem historisch für Webansichten für die CSP nicht unterstützen.\n\nFügen Sie in `\"config.xml\"` `<access>` Tags hinzu, wie folgt:\n\n    <!-- Allow images, xhrs, etc. to google.com -->\n    <access origin=\"http://google.com\" />\n    <access origin=\"https://google.com\" />\n    \n    <!-- Access to the subdomain maps.google.com -->\n    <access origin=\"http://maps.google.com\" />\n    \n    <!-- Access to all the subdomains on google.com -->\n    <access origin=\"http://*.google.com\" />\n    \n    <!-- Enable requests to content: URLs -->\n    <access origin=\"content:///*\" />\n    \n    <!-- Don't block any requests -->\n    <access origin=\"*\" />\n    \n\nOhne `<access>` -Tags dürfen nur Anforderungen an `file://` URLs. Enthält jedoch die Standardanwendung Cordova `<access origin=\"*\">` standardmäßig.\n\nEigenart: Android kann auch Anforderungen an https://ssl.gstatic.com/accessibility/javascript/android/ standardmäßig, da dies für TalkBack ordnungsgemäß erforderlich ist.\n\n### Content-Security-Policy\n\nSteuert, welche-Anforderungen Netzwerk (Bilder, XHRs, etc.) dürfen (über Webview direkt) erfolgen.\n\nAuf Android und iOS ist die Netzwerk Anfrage Whitelist (s.o.) nicht in der Lage, alle Arten von Anfragen (z.B. `< video >` & WebSockets nicht blockiert) filtern. Also, sollten Sie neben der Whitelist, [Content Security Policy](http://content-security-policy.com/) `< Meta >` -Tags auf allen Ihren Seiten verwenden.\n\nAuf Android Unterstützung für CSP innerhalb der System-Webview beginnt mit KitKat (aber ist in allen Versionen mit Crosswalk WebView verfügbar).\n\nHier sind einige Beispiel-CSP-Deklarationen für Ihre `HTML` -Seiten:\n\n    <!-- Good default declaration:\n        * gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication\n        * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly\n        * Disables use of eval() and inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:\n            * Enable inline JS: add 'unsafe-inline' to default-src\n            * Enable eval(): add 'unsafe-eval' to default-src\n    -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' data: gap: https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; media-src *\">\n    \n    <!-- Allow requests to foo.com -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' foo.com\">\n    \n    <!-- Enable all requests, inline styles, and eval() -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">\n    \n    <!-- Allow XHRs via https only -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' https:\">\n    \n    <!-- Allow iframe to https://cordova.apache.org/ -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'; frame-src 'self' https://cordova.apache.org\">"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/doc/es/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-whitelist\n\nEste plugin implementa una política de lista blanca para navegar la aplicación webview en Cordova 4.0\n\n## Plataformas soportadas Cordova\n\n  * Android 4.0 o superior\n  * iOS 4.0.0 o superior\n\n## Lista blanca de navegación\n\nControla que las URLs del WebView se puede navegar a. Se aplica a nivel superior navegaciones solo.\n\nPeculiaridades: en Android también se aplica a iframes para esquemas que son de http (s).\n\nPor defecto, navegaciones solo a direcciones URL `file://` , son permitidas. Para permitir que otros otras URL, debe agregar `< allow-navegación >` etiquetas en el `archivo config.xml`:\n\n    <!-- Allow links to example.com -->\n    <allow-navigation href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-navigation href=\"*://*.example.com/*\" />\n    \n    <!-- A wildcard can be used to whitelist the entire network,\n         over HTTP and HTTPS.\n         *NOT RECOMMENDED* -->\n    <allow-navigation href=\"*\" />\n    \n    <!-- The above is equivalent to these three declarations -->\n    <allow-navigation href=\"http://*/*\" />\n    <allow-navigation href=\"https://*/*\" />\n    <allow-navigation href=\"data:*\" />\n    \n\n## Intención de lista blanca\n\nControla qué URLs de la aplicación se permite hacer el sistema para abrir. De forma predeterminada, se permiten ninguÌ n external URLs.\n\nEn Android, esto equivale a enviar una intención de tipo BROWSEABLE.\n\nEsta lista blanca no se aplica a plugins, sólo los hipervínculos y las llamadas a `window.Open)`.\n\nEn `config.xml`, agregar etiquetas `< allow-intent >` , como este:\n\n    <!-- Allow links to web pages to open in a browser -->\n    <allow-intent href=\"http://*/*\" />\n    <allow-intent href=\"https://*/*\" />\n    \n    <!-- Allow links to example.com to open in a browser -->\n    <allow-intent href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-intent href=\"*://*.example.com/*\" />\n    \n    <!-- Allow SMS links to open messaging app -->\n    <allow-intent href=\"sms:*\" />\n    \n    <!-- Allow tel: links to open the dialer -->\n    <allow-intent href=\"tel:*\" />\n    \n    <!-- Allow geo: links to open maps -->\n    <allow-intent href=\"geo:*\" />\n    \n    <!-- Allow all unrecognized URLs to open installed apps\n         *NOT RECOMMENDED* -->\n    <allow-intent href=\"*\" />\n    \n\n## Solicitud de red blanca\n\nControles que las peticiones de la red (imágenes, XHRs, etc.) se les permite hacer (a través de ganchos nativa de Córdoba).\n\nNota: Le sugerimos que utilice una política de seguridad de contenido (véase abajo), que es más seguro. Esta lista blanca es sobre todo histórico para webviews que no admiten la CSP.\n\nEn `config.xml`, agregue etiquetas de `< access >` , como este:\n\n    <!-- Allow images, xhrs, etc. to google.com -->\n    <access origin=\"http://google.com\" />\n    <access origin=\"https://google.com\" />\n    \n    <!-- Access to the subdomain maps.google.com -->\n    <access origin=\"http://maps.google.com\" />\n    \n    <!-- Access to all the subdomains on google.com -->\n    <access origin=\"http://*.google.com\" />\n    \n    <!-- Enable requests to content: URLs -->\n    <access origin=\"content:///*\" />\n    \n    <!-- Don't block any requests -->\n    <access origin=\"*\" />\n    \n\nSin las etiquetas `< access >` , se admiten sólo las solicitudes a direcciones URL `file://` . Sin embargo, la aplicación por defecto de Cordova incluye `< access origin = \"*\" >` por defecto.\n\nQuirk: Android también permite las solicitudes de https://ssl.gstatic.com/accessibility/javascript/android/ por defecto, puesto que es necesario para TalkBack funcionar correctamente.\n\n### Política de seguridad de contenido\n\nControles que las peticiones de la red (imágenes, XHRs, etc.) se les permite hacer (vía webview directamente).\n\nEn iOS y Android, la red solicitud lista blanca (véase arriba) no es capaz de filtrar todos los tipos de solicitudes (por ejemplo, `< video >` y WebSockets no estén bloqueadas). Así, además de la lista blanca, usted debe utilizar una etiqueta `< meta >` de [Contenido la política de seguridad](http://content-security-policy.com/) en todas las páginas.\n\nEn Android, soporte para CSP en el sistema webview comienza con KitKat (pero está disponible en todas las versiones con WebView de paso de peatones).\n\nAquí están algunas declaraciones de CSP de ejemplo para las páginas `.html` :\n\n    <!-- Good default declaration:\n        * gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication\n        * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly\n        * Disables use of eval() and inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:\n            * Enable inline JS: add 'unsafe-inline' to default-src\n            * Enable eval(): add 'unsafe-eval' to default-src\n    -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' data: gap: https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; media-src *\">\n    \n    <!-- Allow requests to foo.com -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' foo.com\">\n    \n    <!-- Enable all requests, inline styles, and eval() -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">\n    \n    <!-- Allow XHRs via https only -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' https:\">\n    \n    <!-- Allow iframe to https://cordova.apache.org/ -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'; frame-src 'self' https://cordova.apache.org\">"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/doc/fr/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-whitelist\n\nCe plugin met en œuvre une politique de liste blanche pour naviguer le webview application sur Cordova 4.0\n\n## Plates-formes prises en charge Cordova\n\n  * 4.0.0 Android ou supérieur\n  * iOS 4.0.0 ou supérieur\n\n## Navigation liste blanche\n\nContrôle quels URL le WebView lui-même peut être parcourus à. S'applique à des navigations niveau supérieur seulement.\n\nParticularités : sur Android il s'applique également aux iframes pour non-schémas http (s).\n\nPar défaut, navigations qu'aux URL `file://` , sont autorisés. Pour permettre aux autres d'autres URL, vous devez ajouter des balises `<allow-navigation>` à votre `fichier config.xml`:\n\n    <!-- Allow links to example.com -->\n    <allow-navigation href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-navigation href=\"*://*.example.com/*\" />\n    \n    <!-- A wildcard can be used to whitelist the entire network,\n         over HTTP and HTTPS.\n         *NOT RECOMMENDED* -->\n    <allow-navigation href=\"*\" />\n    \n    <!-- The above is equivalent to these three declarations -->\n    <allow-navigation href=\"http://*/*\" />\n    <allow-navigation href=\"https://*/*\" />\n    <allow-navigation href=\"data:*\" />\n    \n\n## Intent Whitelist\n\nContrôle quels URL l'app n'est autorisé à poser le système d'ouverture. Par défaut, aucun external URL est autorisés.\n\nSur Android, cela équivaut à envoyer une intention de type BROWSEABLE.\n\nCette autorisation ne s'applique pas aux plugins, uniquement les liens hypertexte et les appels à `window.open()`.\n\nDans le `fichier config.xml`, ajouter des balises `<allow-intent>` , comme ceci :\n\n    <!-- Allow links to web pages to open in a browser -->\n    <allow-intent href=\"http://*/*\" />\n    <allow-intent href=\"https://*/*\" />\n    \n    <!-- Allow links to example.com to open in a browser -->\n    <allow-intent href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-intent href=\"*://*.example.com/*\" />\n    \n    <!-- Allow SMS links to open messaging app -->\n    <allow-intent href=\"sms:*\" />\n    \n    <!-- Allow tel: links to open the dialer -->\n    <allow-intent href=\"tel:*\" />\n    \n    <!-- Allow geo: links to open maps -->\n    <allow-intent href=\"geo:*\" />\n    \n    <!-- Allow all unrecognized URLs to open installed apps\n         *NOT RECOMMENDED* -->\n    <allow-intent href=\"*\" />\n    \n\n## Réseau demande liste blanche\n\nLes contrôles dont les demandes de réseau (images, XHRs, etc.) sont autorisés à effectuer (via cordova natif crochets).\n\nRemarque : Nous vous suggérons de qu'utiliser un contenu politique de sécurité (voir ci-dessous), qui est plus sûr. Cette liste blanche est surtout historique pour webviews qui ne prennent pas en charge les CSP.\n\nDans le `fichier config.xml`, ajouter des balises `<access>` , comme ceci :\n\n    <!-- Allow images, xhrs, etc. to google.com -->\n    <access origin=\"http://google.com\" />\n    <access origin=\"https://google.com\" />\n    \n    <!-- Access to the subdomain maps.google.com -->\n    <access origin=\"http://maps.google.com\" />\n    \n    <!-- Access to all the subdomains on google.com -->\n    <access origin=\"http://*.google.com\" />\n    \n    <!-- Enable requests to content: URLs -->\n    <access origin=\"content:///*\" />\n    \n    <!-- Don't block any requests -->\n    <access origin=\"*\" />\n    \n\nSans les balises `<access>` , seules les demandes d'URL `file://` sont autorisés. Toutefois, l'application de Cordoue par défaut inclut `<access origin=\"*\" >` par défaut.\n\nBizarrerie : Android permet également aux requêtes à https://ssl.gstatic.com/accessibility/javascript/android/ par défaut, puisque c'est nécessaire pour TalkBack fonctionner correctement.\n\n### Politique de sécurité du contenu\n\nLes contrôles dont les demandes de réseau (images, XHRs, etc.) sont autorisés à effectuer (via webview directement).\n\nSur Android et iOS, la réseau demande liste blanche (voir ci-dessus) n'est pas en mesure de filtrer tous les types de demandes (p. ex. `< video >` & WebSockets ne sont pas bloquées). Ainsi, en plus de la liste blanche, vous devez utiliser une balise `< meta >` de [Contenu politique de sécurité](http://content-security-policy.com/) sur toutes vos pages.\n\nSur Android, support pour le CSP dans le système webview commence par KitKat (mais n'est disponible sur toutes les versions à l'aide du tableau de concordance WebView).\n\nVoici quelques exemples de déclarations de CSP pour vos pages `.html` :\n\n    <!-- Good default declaration:\n        * gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication\n        * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly\n        * Disables use of eval() and inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:\n            * Enable inline JS: add 'unsafe-inline' to default-src\n            * Enable eval(): add 'unsafe-eval' to default-src\n    -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' data: gap: https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; media-src *\">\n    \n    <!-- Allow requests to foo.com -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' foo.com\">\n    \n    <!-- Enable all requests, inline styles, and eval() -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">\n    \n    <!-- Allow XHRs via https only -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' https:\">\n    \n    <!-- Allow iframe to https://cordova.apache.org/ -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'; frame-src 'self' https://cordova.apache.org\">"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/doc/it/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-whitelist\n\nQuesto plugin attua una politica di whitelist per spostarsi all'interno dell'applicazione webview in Cordova 4.0\n\n## Piattaforme supportate Cordova\n\n  * Android 4.0.0 o superiore\n  * iOS 4.0.0 o superiore\n\n## Navigazione Whitelist\n\nControlla quali URL WebView stessa può essere esplorato. Si applica al solo primo livello navigazioni.\n\nStranezze: su Android vale anche per gli iframe per non-schemi di http (s).\n\nPer impostazione predefinita, navigazioni solo agli URL `file://` , sono ammessi. Per consentire altri altri URL, è necessario aggiungere `<allow-navigation>` tag per il tuo `config. XML`:\n\n    <!-- Allow links to example.com -->\n    <allow-navigation href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-navigation href=\"*://*.example.com/*\" />\n    \n    <!-- A wildcard can be used to whitelist the entire network,\n         over HTTP and HTTPS.\n         *NOT RECOMMENDED* -->\n    <allow-navigation href=\"*\" />\n    \n    <!-- The above is equivalent to these three declarations -->\n    <allow-navigation href=\"http://*/*\" />\n    <allow-navigation href=\"https://*/*\" />\n    <allow-navigation href=\"data:*\" />\n    \n\n## Whitelist intento\n\nControlla quali URL app è consentito richiedere il sistema di apertura. Per impostazione predefinita, nessun esterno URL sono ammessi.\n\nSu Android, ciò equivale all'invio di un intento di tipo BROWSEABLE.\n\nQuesta whitelist non si applica ai plugin, solo i collegamenti ipertestuali e chiamate a `Window`.\n\nIn `config. XML`, aggiungere tag `<allow-intent>` , simile al seguente:\n\n    <!-- Allow links to web pages to open in a browser -->\n    <allow-intent href=\"http://*/*\" />\n    <allow-intent href=\"https://*/*\" />\n    \n    <!-- Allow links to example.com to open in a browser -->\n    <allow-intent href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-intent href=\"*://*.example.com/*\" />\n    \n    <!-- Allow SMS links to open messaging app -->\n    <allow-intent href=\"sms:*\" />\n    \n    <!-- Allow tel: links to open the dialer -->\n    <allow-intent href=\"tel:*\" />\n    \n    <!-- Allow geo: links to open maps -->\n    <allow-intent href=\"geo:*\" />\n    \n    <!-- Allow all unrecognized URLs to open installed apps\n         *NOT RECOMMENDED* -->\n    <allow-intent href=\"*\" />\n    \n\n## Rete richiesta Whitelist\n\nControlli che le richieste di rete (immagini, XHRs, ecc.) sono consentiti (tramite ganci nativo di cordova).\n\nNota: Si consiglia di che utilizzare un criterio di protezione contenuti (Vedi sotto), che è più sicuro. La whitelist è principalmente storico per visualizzazioni Web che non supportano la CSP.\n\nIn `config. XML`, aggiungere tag `< access >` , simile al seguente:\n\n    <!-- Allow images, xhrs, etc. to google.com -->\n    <access origin=\"http://google.com\" />\n    <access origin=\"https://google.com\" />\n    \n    <!-- Access to the subdomain maps.google.com -->\n    <access origin=\"http://maps.google.com\" />\n    \n    <!-- Access to all the subdomains on google.com -->\n    <access origin=\"http://*.google.com\" />\n    \n    <!-- Enable requests to content: URLs -->\n    <access origin=\"content:///*\" />\n    \n    <!-- Don't block any requests -->\n    <access origin=\"*\" />\n    \n\nSenza qualsiasi tag `< access >` , sono consentite solo le richieste di URL `file://` . Tuttavia, l'applicazione di Cordova predefinito include `< access origin = \"*\" >` per impostazione predefinita.\n\nStranezza: Android consente anche alle richieste di https://ssl.gstatic.com/accessibility/javascript/android/ per impostazione predefinita, poiché questa operazione è necessaria per TalkBack funzionare correttamente.\n\n### Politica di sicurezza del contenuto\n\nControlli che le richieste di rete (immagini, XHRs, ecc.) possono essere effettuate (via webview direttamente).\n\nSu Android e iOS, la rete richiesta whitelist (Vedi sopra) non è in grado di filtrare tutti i tipi di richieste (ad esempio non sono bloccate `< video >` & WebSockets). Così, oltre alla whitelist, è necessario utilizzare un tag `< meta >` [Content Security Policy](http://content-security-policy.com/) su tutte le pagine.\n\nSu Android, supporto per CSP all'interno webview sistema inizia con KitKat (ma è disponibile su tutte le versioni usando Crosswalk WebView).\n\nEcco alcuni esempi di dichiarazioni di CSP per le pagine `HTML` :\n\n    <!-- Good default declaration:\n        * gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication\n        * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly\n        * Disables use of eval() and inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:\n            * Enable inline JS: add 'unsafe-inline' to default-src\n            * Enable eval(): add 'unsafe-eval' to default-src\n    -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' data: gap: https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; media-src *\">\n    \n    <!-- Allow requests to foo.com -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' foo.com\">\n    \n    <!-- Enable all requests, inline styles, and eval() -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">\n    \n    <!-- Allow XHRs via https only -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' https:\">\n    \n    <!-- Allow iframe to https://cordova.apache.org/ -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'; frame-src 'self' https://cordova.apache.org\">"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/doc/ja/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-whitelist\n\nこのプラグイン実装コルドバ 4.0 アプリケーション webview をナビゲートするためのホワイト リスト ポリシー\n\n## サポートされているコルドバのプラットフォーム\n\n  * アンドロイド 4.0.0 以上\n  * iOS 4.0.0 以上\n\n## ナビゲーションのホワイト リスト\n\nWebView 自体に移動に Url を制御します。最上位ナビゲーションのみに適用されます。\n\n癖: Android にもに適用されますの iframe 非-[http スキーム。\n\n既定では、ナビゲーション、 `file://`の Url にのみ許可されます。その他の他の Url を許可するように、 `config.xml`に`<allow-navigation>`タグを追加する必要があります。\n\n    <!-- Allow links to example.com -->\n    <allow-navigation href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-navigation href=\"*://*.example.com/*\" />\n    \n    <!-- A wildcard can be used to whitelist the entire network,\n         over HTTP and HTTPS.\n         *NOT RECOMMENDED* -->\n    <allow-navigation href=\"*\" />\n    \n    <!-- The above is equivalent to these three declarations -->\n    <allow-navigation href=\"http://*/*\" />\n    <allow-navigation href=\"https://*/*\" />\n    <allow-navigation href=\"data:*\" />\n    \n\n## インテントのホワイト リスト\n\nどの Url を開くようにシステムを聞いて、アプリに許可を制御します。 既定では、外部 Url 許可されません。\n\n人造人間、これは型 BROWSEABLE の意図を送信することに相当します。\n\nこのホワイト リストはプラグインのみハイパーリンクおよび`window.open()`への呼び出しには適用されません。.\n\n`Config.xml`内の`<allow-intent>`タグは、このようなを追加します。\n\n    <!-- Allow links to web pages to open in a browser -->\n    <allow-intent href=\"http://*/*\" />\n    <allow-intent href=\"https://*/*\" />\n    \n    <!-- Allow links to example.com to open in a browser -->\n    <allow-intent href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-intent href=\"*://*.example.com/*\" />\n    \n    <!-- Allow SMS links to open messaging app -->\n    <allow-intent href=\"sms:*\" />\n    \n    <!-- Allow tel: links to open the dialer -->\n    <allow-intent href=\"tel:*\" />\n    \n    <!-- Allow geo: links to open maps -->\n    <allow-intent href=\"geo:*\" />\n    \n    <!-- Allow all unrecognized URLs to open installed apps\n         *NOT RECOMMENDED* -->\n    <allow-intent href=\"*\" />\n    \n\n## ネットワーク要求のホワイト リスト\n\nネットワーク要求コントロール (画像、XHRs 等) (コルドバ ネイティブ フック) を介して行われることが。\n\n注: より安全なコンテンツ セキュリティ ポリシー (下記参照) を使用してお勧めします。 このホワイト リストほとんどの CSP をサポートしていない web 表示のために歴史的です。\n\n`Config.xml`内のこのような`<access>`タグを追加します。\n\n    <!-- Allow images, xhrs, etc. to google.com -->\n    <access origin=\"http://google.com\" />\n    <access origin=\"https://google.com\" />\n    \n    <!-- Access to the subdomain maps.google.com -->\n    <access origin=\"http://maps.google.com\" />\n    \n    <!-- Access to all the subdomains on google.com -->\n    <access origin=\"http://*.google.com\" />\n    \n    <!-- Enable requests to content: URLs -->\n    <access origin=\"content:///*\" />\n    \n    <!-- Don't block any requests -->\n    <access origin=\"*\" />\n    \n\n`<access>`タグ、なし`file://` Url に要求のみを許可します。 ただし、既定のコルドバ アプリケーションが含まれています`<access origin=\"*\">`デフォルトで。\n\n気まぐれ: アンドロイドも要求できます https://ssl.gstatic.com/accessibility/javascript/android/デフォルトでは、トークが正常に機能するために必要ですので。\n\n### コンテンツのセキュリティ ポリシー\n\nネットワーク要求コントロール (画像、XHRs 等) (直接 webview) を介して行われることが。\n\nAndroid と iOS は、ネットワーク要求ホワイト リスト (上記参照) はすべての種類の要求 (例: `< ビデオ >` & Websocket がふさがれていない) をフィルター処理できません。 だから、ホワイト リストに加えてすべてのページに[コンテンツ セキュリティ ポリシー](http://content-security-policy.com/) `< meta >`タグを使用する必要があります。\n\nAndroid 上システム webview 内 CSP サポート キットカットから始まります (しかし横断歩道 WebView を使用してすべてのバージョンで利用可能です)。\n\n`.Html`ページのいくつかの例 CSP の宣言は次のとおりです。\n\n    <!-- Good default declaration:\n        * gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication\n        * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly\n        * Disables use of eval() and inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:\n            * Enable inline JS: add 'unsafe-inline' to default-src\n            * Enable eval(): add 'unsafe-eval' to default-src\n    -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' data: gap: https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; media-src *\">\n    \n    <!-- Allow requests to foo.com -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' foo.com\">\n    \n    <!-- Enable all requests, inline styles, and eval() -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">\n    \n    <!-- Allow XHRs via https only -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' https:\">\n    \n    <!-- Allow iframe to https://cordova.apache.org/ -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'; frame-src 'self' https://cordova.apache.org\">"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/doc/ko/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-whitelist\n\n이 플러그인 구현 코르도바 4.0 응용 프로그램 webview를 탐색에 대 한 허용 정책\n\n## 지원된 코르도바 플랫폼\n\n  * 안 드 로이드 4.0.0 이상\n  * iOS 4.0.0 이상\n\n## 탐색 허용\n\nWebView 자체가 탐색할 수 있는 Url을 제어 합니다. 최상위 탐색에만 적용 됩니다.\n\n단점: 안 드 로이드에도 적용 됩니다 iframe에 대 한 비-프로토콜인 계획.\n\n기본적으로 탐색 `file://` Url에만 사용할 수 있습니다. 다른 다른 Url을 허용 하려면 `config.xml`에 `< allow-navigation >` 태그를 추가 해야 합니다.\n\n    <!-- Allow links to example.com -->\n    <allow-navigation href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-navigation href=\"*://*.example.com/*\" />\n    \n    <!-- A wildcard can be used to whitelist the entire network,\n         over HTTP and HTTPS.\n         *NOT RECOMMENDED* -->\n    <allow-navigation href=\"*\" />\n    \n    <!-- The above is equivalent to these three declarations -->\n    <allow-navigation href=\"http://*/*\" />\n    <allow-navigation href=\"https://*/*\" />\n    <allow-navigation href=\"data:*\" />\n    \n\n## 의도 허용\n\nApp 시스템 열을 게 허용 되는 Url을 제어 합니다. 기본적으로 외부 Url은 사용할 수 있습니다.\n\n안 드 로이드에이 형식의 BROWSEABLE 의도 보내는 것 같습니다.\n\n이 허용 된 플러그인, 하이퍼링크 및 `window.open ()` 호출에 적용 되지 않습니다..\n\n`Config.xml`에이 같은 `< allow-intent >` 태그를 추가 합니다.\n\n    <!-- Allow links to web pages to open in a browser -->\n    <allow-intent href=\"http://*/*\" />\n    <allow-intent href=\"https://*/*\" />\n    \n    <!-- Allow links to example.com to open in a browser -->\n    <allow-intent href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-intent href=\"*://*.example.com/*\" />\n    \n    <!-- Allow SMS links to open messaging app -->\n    <allow-intent href=\"sms:*\" />\n    \n    <!-- Allow tel: links to open the dialer -->\n    <allow-intent href=\"tel:*\" />\n    \n    <!-- Allow geo: links to open maps -->\n    <allow-intent href=\"geo:*\" />\n    \n    <!-- Allow all unrecognized URLs to open installed apps\n         *NOT RECOMMENDED* -->\n    <allow-intent href=\"*\" />\n    \n\n## 네트워크 요청 허용\n\n요청을 네트워크 컨트롤 (이미지, XHRs, 등) (코르도바 네이티브 후크)를 통해 할 수 있습니다.\n\n참고: 당신이 사용 콘텐츠 보안 정책 (아래 참조), 더 안전한 것이 좋습니다. 이 허용은 CSP를 지원 하지 않는 webviews에 대 한 역사적.\n\n`Config.xml`에이 같은 `< access >` 태그를 추가 합니다.\n\n    <!-- Allow images, xhrs, etc. to google.com -->\n    <access origin=\"http://google.com\" />\n    <access origin=\"https://google.com\" />\n    \n    <!-- Access to the subdomain maps.google.com -->\n    <access origin=\"http://maps.google.com\" />\n    \n    <!-- Access to all the subdomains on google.com -->\n    <access origin=\"http://*.google.com\" />\n    \n    <!-- Enable requests to content: URLs -->\n    <access origin=\"content:///*\" />\n    \n    <!-- Don't block any requests -->\n    <access origin=\"*\" />\n    \n\n어떤 `< access >` 태그 없이 요청 `file://` Url 사용할 수 있습니다. 그러나 기본 코르도바 응용 프로그램을 포함 하는, `< access origin=\"*\" >` 기본적으로.\n\n특질: 안 드 로이드 또한 수 있습니다 요청을 https://ssl.gstatic.com/accessibility/javascript/android/ 기본적으로 필요 제대로 작동 하려면 의견 이므로.\n\n### 콘텐츠 보안 정책\n\n요청을 네트워크 컨트롤 (이미지, XHRs, 등) (webview 직접)를 통해 할 수 있습니다.\n\n안 드 로이드와 iOS에 네트워크 요청 허용 (위 참조)는 모든 종류의 요청 (예: `< 비디오 >` & WebSockets 차단 되지 않습니다)를 필터링 할 수 없습니다. 그래서, 허용, 뿐만 아니라 귀하의 모든 페이지에 [콘텐츠 보안 정책](http://content-security-policy.com/) `< meta >` 태그를 사용 해야 합니다.\n\n안 드 로이드, 시스템 webview 내에서 CSP에 대 한 지원을 KitKat 시작 (하지만 횡단 보도 WebView를 사용 하 여 모든 버전에서 사용할 수).\n\n다음은 `.html` 페이지에 대 한 몇 가지 예제 CSP 선언입니다.\n\n    <!-- Good default declaration:\n        * gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication\n        * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly\n        * Disables use of eval() and inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:\n            * Enable inline JS: add 'unsafe-inline' to default-src\n            * Enable eval(): add 'unsafe-eval' to default-src\n    -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' data: gap: https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; media-src *\">\n    \n    <!-- Allow requests to foo.com -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' foo.com\">\n    \n    <!-- Enable all requests, inline styles, and eval() -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">\n    \n    <!-- Allow XHRs via https only -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' https:\">\n    \n    <!-- Allow iframe to https://cordova.apache.org/ -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'; frame-src 'self' https://cordova.apache.org\">"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/doc/pl/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-whitelist\n\nTen plugin wdraża polityki białej nawigacja widoku sieci Web aplikacji na Cordova 4.0\n\n## Cordova obsługiwanych platform\n\n  * Android 4.0.0 lub powyżej\n  * iOS 4.0.0 lub powyżej\n\n## Biała lista nawigacji\n\nKontroluje, których adresy URL widoku sieci Web, samej można nawigować do. Dotyczy tylko najwyższego poziomu nawigacje.\n\nDziwactwa: na Android to dotyczy także IFRAME do nie-http (s) systemów.\n\nDomyślnie, nawigacje tylko do URLi `file://` , są dozwolone. Aby zezwolić na inne adresy URL, należy dodać Tagi `< allow-navigation >` do pliku `config.xml`:\n\n    <!-- Allow links to example.com -->\n    <allow-navigation href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-navigation href=\"*://*.example.com/*\" />\n    \n    <!-- A wildcard can be used to whitelist the entire network,\n         over HTTP and HTTPS.\n         *NOT RECOMMENDED* -->\n    <allow-navigation href=\"*\" />\n    \n    <!-- The above is equivalent to these three declarations -->\n    <allow-navigation href=\"http://*/*\" />\n    <allow-navigation href=\"https://*/*\" />\n    <allow-navigation href=\"data:*\" />\n    \n\n## Zamiarem biała\n\nKontroluje, których adresy URL aplikacji jest możliwość zapytać systemem otwierania. Domyślnie nie ma zewnętrznych adresów URL są dozwolone.\n\nNa Android to przyrównuje do wysyłania zamiarem typu BROWSEABLE.\n\nTa biała nie ma zastosowania do pluginów, tylko hiperłącza i wywołania `window.open()`.\n\nW `pliku config.xml`dodawanie tagów `< allow-intent >` , jak to:\n\n    <!-- Allow links to web pages to open in a browser -->\n    <allow-intent href=\"http://*/*\" />\n    <allow-intent href=\"https://*/*\" />\n    \n    <!-- Allow links to example.com to open in a browser -->\n    <allow-intent href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-intent href=\"*://*.example.com/*\" />\n    \n    <!-- Allow SMS links to open messaging app -->\n    <allow-intent href=\"sms:*\" />\n    \n    <!-- Allow tel: links to open the dialer -->\n    <allow-intent href=\"tel:*\" />\n    \n    <!-- Allow geo: links to open maps -->\n    <allow-intent href=\"geo:*\" />\n    \n    <!-- Allow all unrecognized URLs to open installed apps\n         *NOT RECOMMENDED* -->\n    <allow-intent href=\"*\" />\n    \n\n## Sieci wniosek biała\n\nFormanty, które sieci żądań (obrazy, XHRs, itp.) mogą być wykonane (za pośrednictwem cordova rodzimych haki).\n\nUwaga: Zalecamy, że używasz treści polityki bezpieczeństwa (patrz poniżej), który jest bardziej bezpieczne. Ta Biała jest głównie historyczne dla webviews, które nie obsługują CSP.\n\nW `pliku config.xml`dodawanie tagów `< access >` , jak to:\n\n    <!-- Allow images, xhrs, etc. to google.com -->\n    <access origin=\"http://google.com\" />\n    <access origin=\"https://google.com\" />\n    \n    <!-- Access to the subdomain maps.google.com -->\n    <access origin=\"http://maps.google.com\" />\n    \n    <!-- Access to all the subdomains on google.com -->\n    <access origin=\"http://*.google.com\" />\n    \n    <!-- Enable requests to content: URLs -->\n    <access origin=\"content:///*\" />\n    \n    <!-- Don't block any requests -->\n    <access origin=\"*\" />\n    \n\nBez żadnych tagów `< access >` dozwolone są tylko żądania do URLi `file://` . Jednak domyślnie Cordova aplikacja zawiera `< access origin = \"*\" >` domyślnie.\n\nCokół: Android pozwala również żądania do https://ssl.gstatic.com/accessibility/javascript/android/ domyślnie, ponieważ jest to wymagane dla TalkBack wobec funkcja poprawnie.\n\n### Zasady zabezpieczeń zawartości\n\nFormanty, które sieci żądań (obrazy, XHRs, itp.) mogą być wykonane (za pomocą widoku sieci Web bezpośrednio).\n\nNa Androida i iOS biała żądanie sieci (patrz wyżej) nie jest w stanie filtrować wszystkie rodzaje wniosków (np. `< video >` & WebSockets nie są zablokowane). Tak oprócz białej listy, należy użyć tagu `< meta >` [Treści polityki bezpieczeństwa](http://content-security-policy.com/) na wszystkich stronach.\n\nNa Android wsparcie dla CSP w ramach systemu widoku sieci Web zaczyna KitKat (ale jest dostępne we wszystkich wersjach przy użyciu widoku sieci Web przejście dla pieszych).\n\nOto niektóre przykład CSP deklaracje dla strony `HTML` :\n\n    <!-- Good default declaration:\n        * gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication\n        * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly\n        * Disables use of eval() and inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:\n            * Enable inline JS: add 'unsafe-inline' to default-src\n            * Enable eval(): add 'unsafe-eval' to default-src\n    -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' data: gap: https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; media-src *\">\n    \n    <!-- Allow requests to foo.com -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' foo.com\">\n    \n    <!-- Enable all requests, inline styles, and eval() -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">\n    \n    <!-- Allow XHRs via https only -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' https:\">\n    \n    <!-- Allow iframe to https://cordova.apache.org/ -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'; frame-src 'self' https://cordova.apache.org\">"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/doc/zh/README.md",
    "content": "<!--\n# license: Licensed to the Apache Software Foundation (ASF) under one\n#         or more contributor license agreements.  See the NOTICE file\n#         distributed with this work for additional information\n#         regarding copyright ownership.  The ASF licenses this file\n#         to you under the Apache License, Version 2.0 (the\n#         \"License\"); you may not use this file except in compliance\n#         with the License.  You may obtain a copy of the License at\n#\n#           http://www.apache.org/licenses/LICENSE-2.0\n#\n#         Unless required by applicable law or agreed to in writing,\n#         software distributed under the License is distributed on an\n#         \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#         KIND, either express or implied.  See the License for the\n#         specific language governing permissions and limitations\n#         under the License.\n-->\n\n# cordova-plugin-whitelist\n\n這個外掛程式實現一個用於導航在科爾多瓦 4.0 應用程式 web 視圖的白名單策略\n\n## 支援的科爾多瓦平臺\n\n  * Android 4.0.0 或以上\n  * iOS 4.0.0 或以上\n\n## 導航白名單\n\n控制 web 視圖本身可以導航到的 Url。適用于頂級導航只。\n\n怪癖: 在 Android 上它也適用于 iframe 的非-結計畫。\n\n預設情況下，只有到`file://` Url 導航允許。若要允許其他其他 Url，必須將`<allow-navigation>`標籤添加到您的`config.xml`:\n\n    <!-- Allow links to example.com -->\n    <allow-navigation href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-navigation href=\"*://*.example.com/*\" />\n    \n    <!-- A wildcard can be used to whitelist the entire network,\n         over HTTP and HTTPS.\n         *NOT RECOMMENDED* -->\n    <allow-navigation href=\"*\" />\n    \n    <!-- The above is equivalent to these three declarations -->\n    <allow-navigation href=\"http://*/*\" />\n    <allow-navigation href=\"https://*/*\" />\n    <allow-navigation href=\"data:*\" />\n    \n\n## 科爾多瓦-外掛程式-白名單\n\n控制應用程式允許讓系統打開的 Url。 預設情況下，沒有外部 Url 允許。\n\n在 android 系統，這相當於發送類型 BROWSEABLE 的意圖。\n\n此白名單並不適用于只超連結和對`window.open ()`調用的外掛程式.\n\n在`config.xml`中添加`<allow-intent>`標籤，像這樣:\n\n    <!-- Allow links to web pages to open in a browser -->\n    <allow-intent href=\"http://*/*\" />\n    <allow-intent href=\"https://*/*\" />\n    \n    <!-- Allow links to example.com to open in a browser -->\n    <allow-intent href=\"http://example.com/*\" />\n    \n    <!-- Wildcards are allowed for the protocol, as a prefix\n         to the host, or as a suffix to the path -->\n    <allow-intent href=\"*://*.example.com/*\" />\n    \n    <!-- Allow SMS links to open messaging app -->\n    <allow-intent href=\"sms:*\" />\n    \n    <!-- Allow tel: links to open the dialer -->\n    <allow-intent href=\"tel:*\" />\n    \n    <!-- Allow geo: links to open maps -->\n    <allow-intent href=\"geo:*\" />\n    \n    <!-- Allow all unrecognized URLs to open installed apps\n         *NOT RECOMMENDED* -->\n    <allow-intent href=\"*\" />\n    \n\n## 網路請求白名單\n\n網路請求的控制項 (圖像，XHRs 等) 允許 (通過科爾多瓦本機掛鉤)。\n\n注意: 我們建議你使用內容的安全性原則 (見下文)，這是更安全。 此白名單大多是為 webviews 不支援 CSP 的歷史。\n\n在`config.xml`中添加`<access>`標記，像這樣:\n\n    <!-- Allow images, xhrs, etc. to google.com -->\n    <access origin=\"http://google.com\" />\n    <access origin=\"https://google.com\" />\n    \n    <!-- Access to the subdomain maps.google.com -->\n    <access origin=\"http://maps.google.com\" />\n    \n    <!-- Access to all the subdomains on google.com -->\n    <access origin=\"http://*.google.com\" />\n    \n    <!-- Enable requests to content: URLs -->\n    <access origin=\"content:///*\" />\n    \n    <!-- Don't block any requests -->\n    <access origin=\"*\" />\n    \n\n沒有任何`<access>`標籤，只到`file://` Url 允許請求。 但是，預設的科爾多瓦應用程式包括`<access origin=\"*\">` ，預設情況。\n\n怪癖: Android 還允許對 HTTPs://ssl.gstatic.com/accessibility/javascript/android/ 請求預設情況下，因為這是對講正常所需。\n\n### 內容安全政策\n\n網路請求的控制項 (圖像，XHRs 等) 允許 (通過 web 視圖直接)。\n\n對 Android 和 iOS，網路請求白名單 (見上文) 是不能夠過濾所有類型的請求 (例如`<video>` & Websocket 未被阻止)。 那麼，除了白名單中，你應使用[內容安全性原則](http://content-security-policy.com/) `< 元 >`標記您的所有頁面。\n\n在 android 系統，對 CSP 系統 web 視圖的支援開始奇巧 (但是是上使用 web 視圖人行橫道上的所有版本可用)。\n\n下面是一些示例 CSP 聲明為`.html`頁面:\n\n    <!-- Good default declaration:\n        * gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication\n        * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly\n        * Disables use of eval() and inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:\n            * Enable inline JS: add 'unsafe-inline' to default-src\n            * Enable eval(): add 'unsafe-eval' to default-src\n    -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' data: gap: https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; media-src *\">\n    \n    <!-- Allow requests to foo.com -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' foo.com\">\n    \n    <!-- Enable all requests, inline styles, and eval() -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">\n    \n    <!-- Allow XHRs via https only -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self' https:\">\n    \n    <!-- Allow iframe to https://cordova.apache.org/ -->\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'; frame-src 'self' https://cordova.apache.org\">"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/package.json",
    "content": "{\n  \"name\": \"cordova-plugin-whitelist\",\n  \"version\": \"1.3.1\",\n  \"description\": \"Cordova Whitelist Plugin\",\n  \"cordova\": {\n    \"platforms\": [\n      \"android\"\n    ]\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/apache/cordova-plugin-whitelist\"\n  },\n  \"keywords\": [\n    \"cordova\",\n    \"whitelist\",\n    \"ecosystem:cordova\",\n    \"cordova-android\"\n  ],\n  \"engines\": {\n    \"cordovaDependencies\": {\n      \"0.0.0\": {\n        \"cordova-android\": \">=4.0.0\"\n      },\n      \"2.0.0\": {\n        \"cordova\": \">100\"\n      }\n    }\n  },\n  \"author\": \"Apache Software Foundation\",\n  \"license\": \"Apache-2.0\"\n}\n"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/plugin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one\n  or more contributor license agreements.  See the NOTICE file\n  distributed with this work for additional information\n  regarding copyright ownership.  The ASF licenses this file\n  to you under the Apache License, Version 2.0 (the\n  \"License\"); you may not use this file except in compliance\n  with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an\n  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n  KIND, either express or implied.  See the License for the\n  specific language governing permissions and limitations\n  under the License.\n-->\n\n<plugin xmlns=\"http://apache.org/cordova/ns/plugins/1.0\"\n           id=\"cordova-plugin-whitelist\"\n      version=\"1.3.1\">\n    <name>Whitelist</name>\n    <description>Cordova Network Whitelist Plugin</description>\n    <license>Apache 2.0</license>\n    <keywords>cordova,whitelist,policy</keywords>\n\n    <engines>\n      <engine name=\"cordova-android\" version=\">=4.0.0\" />\n    </engines>\n\n    <platform name=\"android\">\n        <config-file target=\"res/xml/config.xml\" parent=\"/*\">\n            <feature name=\"Whitelist\" >\n                <param name=\"android-package\" value=\"org.apache.cordova.whitelist.WhitelistPlugin\"/>\n                <param name=\"onload\" value=\"true\" />\n            </feature>\n        </config-file>\n\n        <source-file src=\"src/android/WhitelistPlugin.java\" target-dir=\"src/org/apache/cordova/whitelist\" />\n\n        \t<info>\n               This plugin is only applicable for versions of cordova-android greater than 4.0. If you have a previous platform version, you do *not* need this plugin since the whitelist will be built in.\n          </info>\n    </platform>\n\t\n\n\n</plugin>\n"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/src/android/WhitelistPlugin.java",
    "content": "/*\n       Licensed to the Apache Software Foundation (ASF) under one\n       or more contributor license agreements.  See the NOTICE file\n       distributed with this work for additional information\n       regarding copyright ownership.  The ASF licenses this file\n       to you under the Apache License, Version 2.0 (the\n       \"License\"); you may not use this file except in compliance\n       with the License.  You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n       Unless required by applicable law or agreed to in writing,\n       software distributed under the License is distributed on an\n       \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n       KIND, either express or implied.  See the License for the\n       specific language governing permissions and limitations\n       under the License.\n*/\n\npackage org.apache.cordova.whitelist;\n\nimport org.apache.cordova.CordovaPlugin;\nimport org.apache.cordova.ConfigXmlParser;\nimport org.apache.cordova.LOG;\nimport org.apache.cordova.Whitelist;\nimport org.xmlpull.v1.XmlPullParser;\n\nimport android.content.Context;\n\npublic class WhitelistPlugin extends CordovaPlugin {\n    private static final String LOG_TAG = \"WhitelistPlugin\";\n    private Whitelist allowedNavigations;\n    private Whitelist allowedIntents;\n    private Whitelist allowedRequests;\n\n    // Used when instantiated via reflection by PluginManager\n    public WhitelistPlugin() {\n    }\n    // These can be used by embedders to allow Java-configuration of whitelists.\n    public WhitelistPlugin(Context context) {\n        this(new Whitelist(), new Whitelist(), null);\n        new CustomConfigXmlParser().parse(context);\n    }\n    public WhitelistPlugin(XmlPullParser xmlParser) {\n        this(new Whitelist(), new Whitelist(), null);\n        new CustomConfigXmlParser().parse(xmlParser);\n    }\n    public WhitelistPlugin(Whitelist allowedNavigations, Whitelist allowedIntents, Whitelist allowedRequests) {\n        if (allowedRequests == null) {\n            allowedRequests = new Whitelist();\n            allowedRequests.addWhiteListEntry(\"file:///*\", false);\n            allowedRequests.addWhiteListEntry(\"data:*\", false);\n        }\n        this.allowedNavigations = allowedNavigations;\n        this.allowedIntents = allowedIntents;\n        this.allowedRequests = allowedRequests;\n    }\n    @Override\n    public void pluginInitialize() {\n        if (allowedNavigations == null) {\n            allowedNavigations = new Whitelist();\n            allowedIntents = new Whitelist();\n            allowedRequests = new Whitelist();\n            new CustomConfigXmlParser().parse(webView.getContext());\n        }\n    }\n\n    private class CustomConfigXmlParser extends ConfigXmlParser {\n        @Override\n        public void handleStartTag(XmlPullParser xml) {\n            String strNode = xml.getName();\n            if (strNode.equals(\"content\")) {\n                String startPage = xml.getAttributeValue(null, \"src\");\n                allowedNavigations.addWhiteListEntry(startPage, false);\n            } else if (strNode.equals(\"allow-navigation\")) {\n                String origin = xml.getAttributeValue(null, \"href\");\n                if (\"*\".equals(origin)) {\n                    allowedNavigations.addWhiteListEntry(\"http://*/*\", false);\n                    allowedNavigations.addWhiteListEntry(\"https://*/*\", false);\n                    allowedNavigations.addWhiteListEntry(\"data:*\", false);\n                } else {\n                    allowedNavigations.addWhiteListEntry(origin, false);\n                }\n            } else if (strNode.equals(\"allow-intent\")) {\n                String origin = xml.getAttributeValue(null, \"href\");\n                allowedIntents.addWhiteListEntry(origin, false);\n            } else if (strNode.equals(\"access\")) {\n                String origin = xml.getAttributeValue(null, \"origin\");\n                String subdomains = xml.getAttributeValue(null, \"subdomains\");\n                boolean external = (xml.getAttributeValue(null, \"launch-external\") != null);\n                if (origin != null) {\n                    if (external) {\n                        LOG.w(LOG_TAG, \"Found <access launch-external> within config.xml. Please use <allow-intent> instead.\");\n                        allowedIntents.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase(\"true\") == 0));\n                    } else {\n                        if (\"*\".equals(origin)) {\n                            allowedRequests.addWhiteListEntry(\"http://*/*\", false);\n                            allowedRequests.addWhiteListEntry(\"https://*/*\", false);\n                        } else {\n                            allowedRequests.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase(\"true\") == 0));\n                        }\n                    }\n                }\n            }\n        }\n        @Override\n        public void handleEndTag(XmlPullParser xml) {\n        }\n    }\n\n    @Override\n    public Boolean shouldAllowNavigation(String url) {\n        if (allowedNavigations.isUrlWhiteListed(url)) {\n            return true;\n        }\n        return null; // Default policy\n    }\n\n    @Override\n    public Boolean shouldAllowRequest(String url) {\n        if (Boolean.TRUE == shouldAllowNavigation(url)) {\n            return true;\n        }\n        if (allowedRequests.isUrlWhiteListed(url)) {\n            return true;\n        }\n        return null; // Default policy\n    }\n\n    @Override\n    public Boolean shouldOpenExternalUrl(String url) {\n        if (allowedIntents.isUrlWhiteListed(url)) {\n            return true;\n        }\n        return null; // Default policy\n    }\n\n    public Whitelist getAllowedNavigations() {\n        return allowedNavigations;\n    }\n\n    public void setAllowedNavigations(Whitelist allowedNavigations) {\n        this.allowedNavigations = allowedNavigations;\n    }\n\n    public Whitelist getAllowedIntents() {\n        return allowedIntents;\n    }\n\n    public void setAllowedIntents(Whitelist allowedIntents) {\n        this.allowedIntents = allowedIntents;\n    }\n\n    public Whitelist getAllowedRequests() {\n        return allowedRequests;\n    }\n\n    public void setAllowedRequests(Whitelist allowedRequests) {\n        this.allowedRequests = allowedRequests;\n    }\n}\n"
  },
  {
    "path": "plugins/cordova-plugin-whitelist/src/cordova-plugin-whitelist.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/android\" isTestSource=\"false\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"classes9\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"classes6\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"classes3\" level=\"project\" />\n    <orderEntry type=\"module\" module-name=\"cordova-plugin-compat\" />\n    <orderEntry type=\"module\" module-name=\"android\" />\n    <orderEntry type=\"module\" module-name=\"buildConfig\" />\n    <orderEntry type=\"module\" module-name=\"CordovaLib\" />\n  </component>\n</module>"
  },
  {
    "path": "plugins/fetch.json",
    "content": "{\n    \"cordova-plugin-whitelist\": {\n        \"source\": {\n            \"type\": \"registry\",\n            \"id\": \"cordova-plugin-whitelist@1\"\n        },\n        \"is_top_level\": true,\n        \"variables\": {}\n    },\n    \"cordova-plugin-splashscreen\": {\n        \"source\": {\n            \"type\": \"registry\",\n            \"id\": \"cordova-plugin-splashscreen@4.0.1\"\n        },\n        \"is_top_level\": true,\n        \"variables\": {}\n    },\n    \"cordova-plugin-compat\": {\n        \"source\": {\n            \"type\": \"registry\",\n            \"id\": \"cordova-plugin-compat\"\n        },\n        \"is_top_level\": false,\n        \"variables\": {}\n    },\n    \"phonegap-plugin-barcodescanner\": {\n        \"source\": {\n            \"type\": \"registry\",\n            \"id\": \"phonegap-plugin-barcodescanner\"\n        },\n        \"is_top_level\": true,\n        \"variables\": {}\n    }\n}"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/CHANGELOG.md",
    "content": "# Change Log\n\n[6.0.5](https://github.com/phonegap/phonegap-plugin-barcodescanner/tree/6.0.5) (2016-12-22)\n[Full Changelog](https://github.com/phonegap/phonegap-plugin-barcodescanner/compare/6.0.4...6.0.5)\n\n- Flashlight default value #385, Turning off found plain text #259, Remove Result Prompt #234, Custom Result Messages #219 [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/fee66a7d1b4c3bca845beb3fa8c99365b4c15ce2)\n- Flipping orientation on Android crashes app [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/72ae2c75d3d66df24c124a6da9c26e48f7ad36a0)\n- Focus improvements [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/52a23b0f42d454d6a9f2e29a693b5e984c0bb13f)\n- Crash on iOS on low memory devices [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6e3718c2db03fda3d8ea439a9471b3a08e121f21)\n- Disable Animation [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f9960f9b81aef35bd85ecba856c63058bc109ac1)\n- Flashlight option [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/a7ed6890d4e5e2cb386c8754aca081fad559ba1a)\n- Merge pull request #343 from cepm-nate/master [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/77622ca92f5607a8d22131f62f2dea720857a5ed)\n- Merge pull request #334 from lucatorella/patch-1 [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/10f94bc81aff5329291272a4922837e04569a339)\n- Merge pull request #346 from kunder-lab/master [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1cdbf871c9d290630e4535e8ed9db0804b413f74)\n- Catch Class not registered exception in case of missing Media Player [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d43964f06c8eb57fc168d7b19027462e957ba23d)\n- Adds promise scan .done particularly to handle \"No cameras\" error [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/68b6fd14a95f34b32ea2bb651f9715ff880e4ade)\n- Merge pull request #358 from vladimir-kotikov/explicit_intent [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/75cffc3282f09f6973d078d8ce9b306bff210bd5)\n- Use explicit intent to launch scan activity [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/4c046898543dee838b259997a5ec360240e26354)\n- Merge pull request #338 from jlowe234/master [view commit](https://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7f4e4daf19951692873a490c845446cfa0fbda68)\n- 6.0.2 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/18f958796ee9587d5bc21e6229f40139dd4f0c8a)\n- Bumping plugin version to 6.0.2 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/8728015c06d6d201cbd421621384cd19857f6720)\n- Update pluginpub [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/ca4973214b3f99a135d3844d52f40a086022ddcb)\n- Merge pull request #303 from vladimir-kotikov/memory_consumption_fix [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/631ab8fabe16266fb8ea6168d96250be11b8efd1)\n- Merge pull request #318 from vladimir-kotikov/surface3_crash [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/4fffc8d187ddd7ee8df90ba285a5ae6eaac980fe)\n- Add contribution doc, issue and pull request templates [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/31d9badd9b9b3278a78650bcccd105a95a7b4c78)\n- Add editorconfig [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c33c2ab4d63f476bc63c3dd8a5b18f0301baf30f)\n- Setup CHANGELOG [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1c2491db0f3e15322e543e87def64159cc4b3bb9)\n- Setup regression tests [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/4d6ee25e8f1ca3b2589c979a23f987afa60bb701)\n- Issue #270: OS 10 requires Camera permission reason [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/380a56a0b5236bf867bd11d10ceaa185351ea892)\n- Merge pull request #302 from jcesarmobile/add-permission-check [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7dd0e8404394b1bcb14fef49cf0301f5b32503c4)\n- Merge pull request #271 from EddyVerbruggen/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/8004584a8f266fc4715ffc69fb7148a0a83724ae)\n- Merge pull request #307 from timkim/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d775cc7995c4ef6935c127a02d2d8164243bb795)\n- Avoid crash on Surface3 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1473daa0a8d2a4c9a0a7b5330be771acaf5a295a)\n- Merge pull request #314 from ben-8409/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/2af63247c8f379bedbfb323734995b7420005367)\n- only set cdvMinSdkVersion if not set or smaller then 15. Fixes #275 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5513f5c99d9363582e5e77a77b0b6fd3ac8f85c9)\n- Merge pull request #183 from stigok/readme-update [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/97a29911c49ad7aa4406ae99a9b74219212ee608)\n- Require camera [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5e58c0a1b8dabb301836440d6765f2423b3a9482)\n- [#277] - fix for crash on iOS switching cameras [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6c3d74dcbde681a464ba0abc29c5a3d084b09739)\n- Crash fix [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7841f6deba953121bc6d74bbf60d3380a466d73f)\n- Reduce memory consumption by using smaller video resolution [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/89a9c69f6d2ba2d0e3d5ae25d937d3772c48b67c)\n- iOS: Added permission ckeck and fail if it's not permited [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/59301afe045509f53d44c2f17bc7cd9927c357c1)\n- Updated version to 6.0.1 for release [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/3cf975bda01cdddd71b03d74ce31c97595ae98af)\n- Merge pull request #285 from daserge/visibilitychange [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/9d4a96123030f71f2f85676c61a4bfb8b3846592)\n- [Windows] Handled visibilitychange to avoid camera freeze on minimize [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/005c30309d3c0b371c5fc4ceceb2ab8f7f2ffb40)\n- Merge pull request #284 from daserge/version-bump [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/11dd6b5ad2d3528df57a63f3b6ff093452e3bfb9)\n- Updated version to 6.0.0 for release [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/0f534db7e2dcee9348a2e707c7f47ebd0df48b8c)\n- https://github.com/phonegap/phonegap-plugin-barcodescanner/issues/270 iOS 10 requires Camera permission reason [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/2895b3b85506dd7dd91c93a741e1cc13acc59f09)\n- Merge pull request #263 from daserge/check-arch [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/dd85e2530d9638ecac2774c2a00a7b9ec2a573b3)\n- Adds a windows pre compile/run hook to ensure an arch is specified [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/49e33a85a08cfe0b1c5559d24d7f6f42a60334b5)\n- Merge pull request #269 from daserge/win8-deprecation [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/865e1b678fd93b1f712084d65140f41f6ebc4a29)\n- Merge pull request #256 from daserge/cleanup-on-events [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d3344f2d0a0666357a2e9bc4230902227cdd039d)\n- Retargeted WinRTBarcodeReader component, deprecated windows8 platform support [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/eba7eb3a4cc9f558feed571ed589134fd3a7cfa4)\n- Merge pull request #170 from jcesarmobile/callback-with-blocks [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/ae9f6e2a2e14aa0b16d86c039ea50ae1183f7bbe)\n- send callbacks on dismissViewControllerAnimated completion [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/21152cf42978623ae6c67488124fb6474342f9bc)\n- Merge pull request #266 from daserge/multiple-focus-3 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d92af72bd1ce76eb2f40b6fbb0a32292b4fa8817)\n- Merge pull request #267 from daserge/multiple-scan [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/78a53459d3c0b9abd6fa510571a422e279dfadde)\n- [Windows] Focus fails on multiple taps [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f18ed1a78c3b720ee88497b84734bcd77699ea2d)\n- Prevent multiple calls to scanner [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/2aa5bdcda508bd4164326298da18638f955e0873)\n- [Windows] Cleanup camera on app suspension Save/restore scanning state on suspend/resume [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/49489db0678e6e80a3b0744533d432681b9cfdb7)\n- Merge pull request #260 from Telerik-Verified-Plugins/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/55e693843e3a556ee9ba9f2dab13fd9ca652396f)\n- Stable plugin id [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/363335c13b96f7f2c5a728d99a8be137b6601e34)\n- Stable plugin id - revert after PR [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/be3e490b95b99078740f473466b60cb0c7348796)\n- Stable plugin id for PR [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/73c32f4e62467694ecf725e5d9d307d3ed94a3e1)\n- Merge remote-tracking branch 'upstream/master' [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c0546f71e60991ff2dcbbde2d1e23443db5d19a7)\n- https://github.com/phonegap/phonegap-plugin-barcodescanner/issues/40 https://github.com/phonegap/phonegap-plugin-barcodescanner/pull/171 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/e9f1b1bfe18edfae2db087f91c9112b82909bd83)\n- Scanning crashes on Windows phone on device rotation [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c3bcd87e1c66dc0fca7c04a2bbbd405ea9fbed2f)\n- Merge pull request #257 from daserge/multiple-focus-2 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/45ec98fb46e4f5d18bbc5fb4d6627065cccac248)\n- Added missing CHECK_PLAYING_TIMEOUT Added a timeout before initial focus to prevent focusAsync hang on slow devices [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/eb31d2e3416f64bb3312ed639f2fa046b4551414)\n- Merge pull request #250 from daserge/multipleFocus [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/e65272ad4536bc49200d4ca8b23cd970d7a118db)\n- [Windows] Focus fails on multiple taps, this closes #249 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b836297ed5139d495bd0f0b4aeabaaa9734e4154)\n- Merge pull request #251 from daserge/close-button [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/128c80f63ae2aa490adbe0c27250598fdabdd722)\n- Merge pull request #253 from daserge/win10-CameraStreamState [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5161af4c7f92d7b0edc71230f6b43127502e3568)\n- Windows Mobile 10 - Close button does not work, this fixes #196 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/942d1ed199ec0ea7488bcf3d8ec0a9d6b711ec82)\n- [Windows10] Fix The request is invalid in the current state [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/2a3e4fd532fba820979046b85e573529742f3b62)\n- Merge pull request #252 from daserge/css-fixes [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/a3d4dfa18adeeb6ecb62a40ac0492d9825372458)\n- [Windows] CSS fixes - no-select, no-zoom, no-scroll [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5364553b1e00d4515dfc5293f4baae3629d8c48b)\n- Added a note about PGB [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b20c04648b4cfcd1170e098c257e535cd6762f72)\n- Merge remote-tracking branch 'upstream/master' [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/ce0cf94603c526a261cb80654be19652eae9d239)\n- Merge remote-tracking branch 'upstream/master' [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d4b22bb0094fc216a7837f61ddfabb91b4f3450d)\n- #221 updated version to 5.0.0 for release [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/27227e9d2b00174e816869bc6123071d470ade87)\n- stable plugin id [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/762dea0958937ee2cc1b76831312733bb59a401f)\n- Merge pull request #217 from Telerik-Verified-Plugins/merge-phonegap-official [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/bd6c295908a22a23d1a473f39db39956e6bc62bf)\n- Bump plugin version to 4.2.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/0cda49bfe1229977d6bec855942c199d5357c7ee)\n- Fix iOS issues after merge [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/06f4a7d04bec902ffa2109b79602f3955175a17a)\n- Fixing Android after merge [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5641c8ea17d036f806fd2f15763ce16cc79ada3c)\n- Re-added old platform files we removed after forking Wildabeast [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/172f164b68d620699ac14bcf6468a21a65a57ada)\n- Merge remote-tracking branch 'upstream/master' into merge-phonegap-official [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6a7d7208b15000e004b894184860cc0f298b6e32)\n- fix Android M permission [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/29d3308b7d46a94fbda10945d3ecb78a7d6d1c08)\n- merge [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f0ad027425313f3edbfb9350ab81068ed4898894)\n- #28 Plugin renaming my app [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/55b716ad8e6dd4bfad1921d2efa00eec45fd414b)\n- #28 Plugin renaming my app [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1778bee6b028081ff4761c32748eca0c939b4368)\n- #10 Warnings on IOS 8.4 when using library [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/57babcc2beb1f6f2d45b738b126e4588b1b1643e)\n- #26 App crashes if the CordovaActivity is stopped during scanning - Moved `scan` to a background thread so it won't block the UI for about 50ms while initiating the scanner [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d0bf407951f13759484a8fd2a77e6c3d1fb8ecc1)\n- Documented the new \"orientation\" feature for Android [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/8dea274bb72d01039173c305cc4a276a9985a5c2)\n- This fixes a few issues in our fork: Image upside down on tablet #20 Android UI doesn't support Portrait and is small #4 Prebuilt Zebra Crossing (xzing) Library #3 Forcing landscape on camera android #17 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/25e00cd9e2d3a6789663ef9c0b9210f5ebf6776b)\n- Merge pull request #206 from sarangan12/Windows10Fix [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/2a5e289085e8a9a11b4863d7ddbdfcea58b22510)\n- Fix for the crash in Windows 10 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/8e46fcb76d49c76f4598be195e489cd81fc29217)\n- #25 iOS app scans randomly UPC and other EAN formats when scanning EAN-13 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/dde3c197026412811e719e016d2adad14330ad78)\n- #14 Cannot read code_128 barcodes in iOS [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c0673038124e623e2c6f6558b87f75dd611d3171)\n- Update README.md [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b8ea34e5ac4b4e7b34b991e4e1065ef8619f776b)\n- Fixes Windows Mobile - Issue with Orientation [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/383406708e265ef4eddea28a3c07163fc4787519)\n- Merge pull request #168 from MSOpenTech/escape_fix [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d1dcfe0763cfdb24d0fc1f5c5811dcd05bfa74d8)\n- Fix plugin installation failure in VS2015 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/4c0dcf4b27e9c6c4851f0b642a9436ab1c85bde9)\n- Merge pull request #135 from MSOpenTech/windows_refactor [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/e22581cb56e9c6a147860ee6e6f4ce4991186493)\n- Refactor windows implementation in promise manner [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/0d01bde3a6ce1e499099d051d3fb54111537cf9c)\n- Merge pull request #134 from MSOpenTech/orientation_change [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/02c67a20d9f6c59388a1be8f71fa568358f984b2)\n- Add support for orientation change from #62 and #97 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/51216ff3dd0375a694eb4f9352bb78046ae47505)\n- Resolve merge conflicts and address feedback for #62 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/cabb67e6425e23366ebed47b58ddbcd93c6925ee)\n- fixing issues for windows platform [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d68cdce6f920c3db0bf7a1345f60a6fdabedde95)\n- Merge pull request #132 from MSOpenTech/windows_barcode_format_fix [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/8b5739fc692ab30e807feb7530d618ec7ba7ac8e)\n- Correct scan result to expose format name instead of format code. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/dc84cac7844d3fdf64d3bfbdf0765930bc0a6b9e)\n- Add information about windows 10 support to README [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b25d71061693f716658f0769c9be789b58b2b65e)\n- Removes intermediate winmd component from Win10 implementation [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/521d427ed418d2288a1b31a11398b99f54fb1f5d)\n- Add Windows 10 Support [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/9c2da016e4ddbd973a596568c750b7bb48ea4409)\n- Merge pull request #131 from MSOpenTech/backbutton-fix [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/9dec84ced0050f7f7221bb49d0fad4f39ccb819b)\n- Improve native look and feel for windows platform [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/23b4343483104b21ce501f481e0001827f7f994b)\n- Merge pull request #128 from MSOpenTech/autofocus-fix [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/4606ac6d2465e83742d436cf351902f2f09854b7)\n- Rework autofocus logic for windows. This fixes #41 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/a905251130a5a956d28ed849bef69a3d6df6dee9)\n- Merge pull request #127 from timwindsor/barcodeEncodeBB [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f4d5d5c638085169c10d54dde887b6203332a6ec)\n- Merge branch 'master' into barcodeEncodeBB [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d9f47951442cefe939a61d1f9c5ee72316d82863)\n- comments [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/2219f194a6c4b5d87a1fb7d5bec2e60b91f41c07)\n- added data type check, and uri prepending for encode method [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1cf63768bf5b3e991b2b62d9f34f1f1283f92ef8)\n- error checking, data validation [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d5e84c9f09480a0f5f2782e206c61b0cf92c8c37)\n- qrcode encode working [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/2830a6d85c8be6f07aa503931c702e5f7444c879)\n- encode method or blackberry [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c662c85c9db8b43bc259e966a40203b74b8552f5)\n- Use maven reference to android-support-v4 library [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/fb0a4f80092ab173366c98c6a1555bbed0ad864f)\n- bump [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/df1210276412c72d428d13d382141a200e811986)\n- fixes #162 button bar not working in ios8 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1f51bb9561c92be3abf676dd56b82c86f207b204)\n- #15 Android M (6) compatibility [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/82bd97ef65b4b609a8d7a8be5a8068a5961b7cac)\n- #15 Android M (6) compatibility [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f028ec469a60031e31033fc2d44fd69358d95be0)\n- 4.1.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6b5f7fb7626f24b45fb643dcdd841e3fa0e5361f)\n- updated to version 4.1.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6452c9802f0e0a4b686e5b94f043cc23d2380acd)\n- Ignore linting [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/64845f4cf4726f1b50610463daa703b7a3a7f649)\n- Removing custom strings [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/607efeb158f12e651e8555eec9abdd8d9480010a)\n- Merge pull request #78 from timwindsor/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/940e98babdcc27e8dea6120a42412a3b8161e9ca)\n- Merge remote-tracking branch 'phonegap/master' [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/28174b118447b86bdf4acebbc24913775db3fc7c)\n- revert obsolete workaround. Fixes delayed error. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b8f2fa5c4efcc72732ebadb8bb304cc46465e93e)\n- Parses result so it's consistent with other platforms. Removes obsolete, unused file. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/0632e345a63b22e4a52b250cac427f9649ab9858)\n- #13 Cordova-iOS 4 support [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/de5700cc233cc845453bb98356e7b2cce67b6d92)\n- #11 PDF417 support on Android. Version bump. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/009175b0ac39f8eea71c928708af97226a636d44)\n- #11 PDF417 support on Android [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/e413345fa765c61d46c8c5437eb08d754b9c4dd1)\n- updated version in plugin.xml [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/74f33d5d14107915c357753684e9276eb37a3f66)\n- 4.0.2 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/07322cb29310ad1f5b19f43472de8b86c558d19f)\n- Merge pull request #66 from olimortimer/patch-1 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/346472ff22b94f94cef25dea9f6f7eb851974c43)\n- Merge pull request #52 from nlsdg/patch-1 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/001a1be747183e5b727d367236ae477dc9b49613)\n- Fixed iPhone / iPod scanning issue [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c92bc8ac49e72a064093e83da4597aba2e68dab7)\n- Add BlackBerry namespace [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7175796244403b9b3de42ac5c1df2ca576606678)\n- Update README.md [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/49571fbb7b79742481c230daa7b146cc7b2d9e7c)\n- 4.0.1 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f72bc48f7508c84a52a2cbe9e31c31408063def9)\n- #48 fixed version in plugin.xml [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7b7c4c6d8751005a0ac762d29f179244dbe68866)\n- 4.0.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b005d77852b22073c1b618ddec0d713453f5b69a)\n- Merge pull request #32 from timwindsor/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7bbc73c82eb3dfb41c285103771d11451a1ae666)\n- Adds blackberry10 to package.json [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/0ecd01e1104b4a89efee38ec598f89a6a1b51cd8)\n- Merge pull request #1 from timwindsor/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/30196b3dfc2ef0f36c30253f6765cfbde283127b)\n- Completes merge of BB10 implementation into phonegap API [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/52b5adb8d40e6116c20df2416cf1a78ec24f4b7e)\n- Unifying API for BlackBerry10 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/02c5ba86d5752df841359ba42df32db0b74ff10b)\n- Restore location of BlackBerry repo [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/8cf9df1c65d047d61b3dc6a59c30f1dbda4f7f54)\n- Restore location of iOS and Android repositories [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d801b7687dcb7b02ce7114e166d0cddf82adf12f)\n- Merge in BlackBerry 10 support [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6043674b179295489936ba81b8fd5ff1ff2fdfa8)\n- indentation fix [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/cce09e379351065a303ad9af93dd463fc049da53)\n- stopRead error handling [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/66e572e3eb3f0febfa52b5ac2b334bfde11f2557)\n- Merges in BlackBerry 10 support [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7b320e1dfe3216937dc0bb77a4ba65d790169bf9)\n- Android 'encode' crashes [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1feb36d34313077c2dd145c59d9009088542d347)\n- bump [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c484e0a754d67e2136ade27b9a3e4a4d115253e6)\n- Android 'encode' crashes [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/3632edc0cd0aa85b6a04d3f6671005a6215f6a82)\n- Ugh, AB build errors because of lint config [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/31a7ebfcc2159e5c5075668bba508e67bd00db30)\n- Ugh, AB build errors because of lint config [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c5cf295c7207ea3433f21b7319f1e29d538911a2)\n- V3.1.2 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/70ca00be45a675b1b1d6963ad6f72430e579788e)\n- Merge pull request #7 from mlaponder/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/3d96f565e450f50fe0d36fb6d119c4e0d0268147)\n- Update version to 3.1.1 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/405c00b616a41dd6041c5daf359795dd7e4831a4)\n- 3.1.1 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b58323f54c72c0e93089d1e1fb81592a708309b4)\n- Merge pull request #6 from mlaponder/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/9d12d19f9af5ae9379b8c11b658079e234b39d9d)\n- Fix incorrect uri for wp8 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5f1fb8865264576b8be8b6bdce7a4e34d40ee8ce)\n- 3.1.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/78cc3fbcdf6f21e35614578409494d767193786b)\n- updated to version 3.1.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/4647c48c2ee683437f36589a3ad27868698840e7)\n- Merge pull request #4 from komola/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/41c6e8c475b5028883478f22ed6694502e1b6b9d)\n- fixed issue with readme [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5fbee99fc7bf561f99f7fcbb90ad8b41669797a3)\n- added travis-ci support [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/616a2700f60e3789505737330bc6446acc42c7c9)\n- fixed tests, made compatible with cordova-test-framework and paramedic [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/652d50967a8754a623e3a9de04b8b9565b4aa06d)\n- Merge pull request #5 from stevengill/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b17891c002a04dc31c24e66ca5a50f31254d0e98)\n- updated ID to phonegap-plugin-barcodescanner, V3.0.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/50d3f0a23bb1313d128c00d9634f8ef6f4d7cc3d)\n- removed cordova.define from js [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/729f2caddd96041dc671188cae95648927fcb860)\n- Merge pull request #1 from trongrg/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/262ef2b03b906043c05ca4f2283300eaa0fdff8c)\n- Updated src/android/com.google.zxing.client.android.captureactivity.jar [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/fa13720cf7cf664f6cc7a6d5721038d4f0e92ad1)\n- Remove unnecessary retain calls [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5fce7a4d78c767e2e32e1d6173743c138e230406)\n- [#4] Android UI doesn't support Portrait and is small - support for tablets with default landscape orientation [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/408adbf364c4336901d017d5176d27721271a439)\n- [#4] Android UI doesn't support Portrait and is small - support for tablets with default landscape orientation [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f412fbc0db37cba9d96df3b6502715150794a70d)\n- [#4] Android UI doesn't support Portrait and is small - support for 320x240 screens [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6c120b984c2adb86cfd8c2cddc55cf2719e17731)\n- [#4] Android UI doesn't support Portrait and is small - portrait scanning of non-QR codes didn't work [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/e197d222cd6b6c879eb0fed79316ee960674736f)\n- [#4] Android UI doesn't support Portrait and is small - support Android projects which have not set targetSDK (crashed without it) [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f74da676341aaa9a9cfbcb23440408e35449fbd2)\n- [#4] Android UI doesn't support Portrait and is small [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/a250540bec7b179820af584f3b714cc7920b1eda)\n- Restore MultiFormat Reader [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/bd459f4b9c5aea7e7d20b7e7aaf7d61847ab48bb)\n- Merge pull request #1 from MSOpenTech/2.1-windows [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/4e5af0ca1b782fe4c54f9f849495d5678edc95b8)\n- Include winmd source as subproject instead of prebuilt winmd [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/21083d4974e471e9233f66ed8b84f53df74b6eea)\n- Merge pull request #2 from MSOpenTech/2.0-wp8 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/47aa58873097ad763c932c2fa2d7e0e0aa442ae5)\n- Check if the last n scans returned the same result  and only then accept the code [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1d264dae30895a3edb07938c95c9902ef0ad69c3)\n- windows: fixes \"class not registered\" error [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/96284b34430dd8824c517a24eef8fd23046b6de2)\n- #616 Use single proxy for both windows8 and windows [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/eabae9e10be2e21f8c5f917748bd769c9fe11b43)\n- #616 Adds support for windows platform [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/aa80367059e1a6c68a0947d56a7f6d63e896177b)\n- Windows Phone 8.0 improvements and bugfixes: [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d0b2b27a77e02af5afec0cfd6c3566d1a3f65d62)\n- v2.2.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c74e37a40cbf5ecbec5be8f6677e3bf01f0920bf)\n- added support for adding config parameter which is passed to barcode scanner activity [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7773e4dae0afbe85ee50e3681df9ffbe7611a04e)\n- Restrict to EAN13 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f70288d7b27cbe96d134db68c5bf517f85ce8e92)\n- v2.1.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7b3302282215b4d41e1168cbef8af9a3abf122a6)\n- Played beep sound after scan succeeded. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b1bb4fa2fad9d27bf5d25b8aa2f7872c92ffcf2b)\n- iOS update encode method return format [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f04a2a0e4c8bc9c09d76a725ee771423e042837e)\n- Add QR code encoder implementation for IOS [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/8b10b8ae33fb672018fa9230079d8c6f096c4b13)\n- fixes #162 button bar not working in ios8 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/a1f216d4413596ca18251c3fe543f862acf972a5)\n- fixed size to int conversion and cordova 3.6 deprecation warnings for iOS [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c2dcd871d25b480dfaf65b2eab878bc5a4775746)\n- Removed ARC code [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/22a23b171a89322709bb1020fbdc02e90a079c21)\n- Version bump [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/30236cda293f6e4de564e3adfc7fb847e1dbc0ba)\n- Merge pull request #9 from galexandrov/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/35ad6da69b10f8107ad90491b4afb25ca9f5d971)\n- Remove unnecessary retain calls [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/a44f7403649e7727b2b65a72585e631d703386e1)\n- up version to 2.0.1 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/fb600c1710ff2f786a1c3a31cd135d69846817fe)\n- [#4] Android UI doesn't support Portrait and is small - support for tablets with default landscape orientation [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/044de265661e17abb0aefcdf8230d9e357b6cfc0)\n- [#4] Android UI doesn't support Portrait and is small - support for tablets with default landscape orientation [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d0aa7d75ee35fc951d66b3b094deba00ef17db97)\n- [#4] Android UI doesn't support Portrait and is small - support for 320x240 screens [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7e60c7c1e830113b34673784ce0764ae450e7dfd)\n- Support browser. encode is NOT ready yet. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/116a3bb4e797b75292867900b626b8f2bae10fb9)\n- [#4] Android UI doesn't support Portrait and is small - portrait scanning of non-QR codes didn't work [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/fe7746456defcb7f6d16ce4b023712c515bdb748)\n- [#4] Android UI doesn't support Portrait and is small - support Android projects which have not set targetSDK (crashed without it) [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/20799f14ade1e2a1399428377fdea2f608c84b49)\n- [#4] Android UI doesn't support Portrait and is small [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b163ab694f1e49ae1667a2e4635f43a1bd6de74d)\n- Documented new features [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/8b9d6a5835b5c1a7f487b9ba38a5cb4e4d323dd9)\n- Merge pull request #2 from EddyVerbruggen/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5f37fb12c6081809aa237b7896a5e7b26b32eeca)\n- Added option to select choose to show a 'flip camera' button (default: false) [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/9f194201327ed4cbe0eee21f67ed38496e2a5003)\n- Added option to select frontcamera via JS api [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/80a828516c1512964a85e0f2fdd44e09d206e418)\n- added repo + issue tags [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5268a02fd7f6c96aa2c2bc022ab777e89ae6cc23)\n- Upped version to 2.0.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c3090dcf5347c1cc10caaeff225bb2c0a0deeede)\n- [readme] fix encode example code [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/3a0978076fab0c5180d4c2989a4a3844a980fbe2)\n- Enabled ITF support [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/740aa3a33b55c5d51ae07dbb8bf40620bdd7b7b6)\n- Added support for front face camera.  Signed-off-by: Emil Marashliev <marashliev@gmail.com> [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/a209c6d396a53c6304582f89f59300066ad56149)\n- Updated link to Cordova plugin spec to fix 404 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5a7aa5c29d98679513209247e5c65559cd2e275d)\n- Updated README links to the original iOS and Android repos to fix 404 errors [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/a8c2a2609399cee2799c873863257b9ce870ac80)\n- avoid calling other apps activity [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/84af3e9f72bd12f172853f6c091b08eb556572cf)\n- [plugin.xml] updated description [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f766ba2536b93cae56875060bf25af55cf80c178)\n- [plugin-xml] upped version to 1.2.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/552974245e156960bc48b991520f82d696d125b5)\n- Adds documentation for Windows Phone 8 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/602dad12e506ec0f8601d144d1fde716d021814f)\n- Adds support for Windows phone 8.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b94b4f67c417d431094da193f2a40da7876b498b)\n- Adds documentation for Windows8. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/74f78db8ac7fb6b5aec25584a5a9518286a1de9d)\n- Adds Windows8 implementation (scan method only) [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/3a7d7610ab8b2c0c94feecbaff854c564018ba9d)\n- [1.1.0] upped version [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/2a2fc654bcc2a68598d04d417a84c5a64fe3fb24)\n- [js] plugin.xml asset backwards compat [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/a6ed222163792190ce5b4b684b6ad746bfd7662d)\n- Compiled jar [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c93d7569c4fb88baa8a2546e5c278249f7961887)\n- Added a flip-camera button for Android - missing icon [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/332f12fe9c79a7a8210914f747ce8353368c1266)\n- Added a flip-camera button for Android - missing icon [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/48be871057bac642724de63c1c3707c99f9976ab)\n- Added a flip-camera button for Android [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1a2b8c6126f9d61ff229bbee2f9f8109a78e806d)\n- Front camera scanning for iOS ([#108]) deserves a version bump [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/98f158aa4dde990c6d2bc89ff418039c77b6e15c)\n- Added support for front face camera.  Signed-off-by: Emil Marashliev <marashliev@gmail.com> [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d3c8ad2df92743bc8fd038ec37d89e0bce2053f9)\n- avoid calling other apps activity [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/ef1155d09d53856b4d8dfd6326c734e05e702885)\n- [plugin.xml] updated description [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/cfa698d93773fa7d737fc1adf02d6a2e46538d09)\n- Change plugin.xml to use framework element [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/619f6984c3db640c14fa2505d06b659913018137)\n- Change barcode scanner to work similar to the iOS and Android versions. In plugin.xml added reference to ZXing.Net so it is refered as plugin is installed. Similar to other platforms' versions, there is a focus area - only this area is scanned for barcodes. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/3a377ef883d0e5db138ed40f5e5f6838d1407f3a)\n- removed unused reference [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/05a5a17eceed4e377faa9674b2f3564ca37b422e)\n- [1.2.0] upped version [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/53ad095e86434adc7694b8a26bdf16d6c381238d)\n- ignore Intellij module files [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1654970ac5b5b89c4e5008d71f93a755df71add0)\n- Updated Plugin, refactored some library parts, added description to read me [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/719f19d3f003a19313d29f81c8d668030980db7e)\n- added windows phone version [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/039d1d0ea45d75902c748ba9f7f115a9b94887c7)\n- window.plugins is not defined anymore, replaced it with cordova.plugins [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7d831d83ed3967ce438551bed1b8a86ec2f7fb84)\n- Add missing iOS framework \"QuartzCore\" to plugin.xml [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/ec4de624ae9f68a59557f21a1a5a4e18d3cfa425)\n- [plugin.xml] corrected supported cordova versions [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/24acf29896fa39578238a0269c9b1a3d643c6a3b)\n- delete plugin.xml.generate.php [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/a310fda2d7d55e650a65b9d0327eff87356c0818)\n- Use <js-module> in favour of <asset> for the JS [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/8bf3cce0737f7435b979b55433c87657dab792a1)\n- [readme] fixed encode syntax typo [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/2d8701634f4d761f3c3cc961d8eb337b44de79e5)\n- [android][0.7.2] remove busted menu items + fixes #11 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7880bf7b5c4a619acaff8e8b905e0710eb3f41b5)\n- [0.7.1] upped version [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/12a31b76b015d3218874437a37d9a78fe710b161)\n- [README] fix typo [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/a2857ba5f8ed2a4ef7277fae8dc108239a2f15ee)\n- Merge branch 'ios_warnings' of https://github.com/agrieve/BarcodeScanner into agrive-ios_warnings [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f046f651ceb06e35a6867e3e3df0cbb2c58a0f13)\n- Use <js-module> in favour of <asset> for the JS. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6ad6dafc1169d62871663d013d49312df64acb2b)\n- Fix plugin for iOS on Cordova 3.0 by disabling ARC and using newer plugin signature. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/14d63e35ac9d1333f178cb3ae95a88b530d73538)\n- Fix some compile warnings on iOS [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d901977064078efec335f3309c30bc8038372447)\n- [0.7.0] upped version [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7094cc6eda5ef8a225c550e463bc49907c36ac40)\n- Cordova 2.8 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/fc3dcd56d1558415043aaa538c724426b6caa726)\n- minor [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/50a2f8bf5236e643635caf8cabba5e0d2df8ba69)\n- Merge remote-tracking branch 'upstream/master' [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/8966e5207fdf506f5c94a9dee9f9e25b847aa5c7)\n- ident [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/8fa142ca9d1d400ca91d651865b6eb5d9f79d204)\n- Encode object access fix. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6fd905a8e60a0341fc4a4453f594222eb7cd0b8d)\n- 3.0 fixed README.md [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/32880fc1fa78dd0911a66c86895303d7479a2be5)\n- typo [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/903b02f142534057cb02d79772d874c37fdbd553)\n- Fix for https://issues.apache.org/jira/browse/CB-4379 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6fdac151eb089043c6147e6822e46ebea4604375)\n- Changes for crodova 3.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c84bf0e66d0ac14b44283261a2a3c9813e4750db)\n- PG 3.0 changes [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/e728d331554837a3c905e569a579f290125d4717)\n- [readme] correct ios supported formats [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1242c551424e31270035929c024b4d7de55ae9ef)\n- [readme] plugman not pluginstall [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/3b1ad506b2a4e387405f62263ec3b5dd550775bc)\n- [0.6.0] upped version [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/fab895ab3002da39e3fdaf0f11eee2a3f8ad4e9d)\n- app_name fix [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c5c60c88568b78898bd08a042b5e0087053cc9b1)\n- Update README.md [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5b01acb999fcc9f5316212a8887fcd29ebbf78a5)\n- minor refactoring ;-) [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/db30964d5113d4ac4a63fe8997165d07e7bb9e20)\n- plugin spec. update [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6e29489982aae3f761195647b18c8c1ccd2ff850)\n- Update to 4.3.1 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/8c50a121e87425ffcf4c09f7c4a08669c7bb7a71)\n- [plugin.xml] update license tag [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/e2cef45cb8b2a85f6979eee17dc96a6ec55d01e5)\n- [plugin.xml] license tag [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c24882311fc880f4881dc02bcb14f9816d1808cc)\n- Merge branch 'master' of https://github.com/Eccenux/BarcodeScanner [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5833a1fa9e5adcd1f823e86b76a28800af1980ae)\n- app_name fix [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/9ed602fdacd4da7e8b083946089a4d04b51a46fd)\n- Update README.md [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/06b05fc6c98fae2b7c45502d6bd1ee315a339265)\n- minor refactoring ;-) [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/2f86c728e5953a35efe236e293a0eca48353be2a)\n- plugin spec. update [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/01a74e4c6c198750dc9149c8e90bd363dc0670ff)\n- [0.5.4] upped version [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/18f2f7a9fe67ac42a1deafb11992050009df2ea2)\n- Update to 4.3.1 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/cf2be813cb3fb28b61fd2fedf4803ed70d2d5c16)\n- Merge branch 'master' of github.com:wildabeast/BarcodeScanner [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/10d66a4e67221957a8c5b02e7cd05b25539c4970)\n- [readme] reference plugman not pluginstall [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/27d6d653fc51e6cb2eca1a7e610934d7f0a140a4)\n- [plugin-xml] added engines [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/4efcc86a24144c40fd60e372f0a4a6d02ce8578a)\n- [plugin-xml] Add description [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/4d38047b41fe4bed48b63249c1ce12b85f252089)\n- [readme] reference plugman not pluginstall [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/af21cd20f6c14bbd803e83f904573c9af9de225d)\n- [plugin-xml] added engines [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/e38147f27f661137240b6ff673a08ca6e10c9c6d)\n- [0.5.3] upped version [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b45ce29fec8f2c062661670a5651684234545b12)\n- [spec] update specs to cordova.require/define [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/77d4a3dda27a10ec956c1e9e5f3281c76c54a25a)\n- [plugman] plugman don't like spec/config.xml [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6f4e09be4f2e0fe17a3372bec5cb2309372395d7)\n- [plugin-xml] Add description [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b0747cadcef11fd1fd90fd94d0ffc8729e8256d3)\n- [0.5.3] upped version [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/3332885acd3072085dbbee8bc6389d83ff18dfcb)\n- [spec] update specs to cordova.require/define [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/2331218b5a597d1c5888e66461a2d4bd7358a8ae)\n- [plugman] plugman don't like spec/config.xml [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7ec3d477c208d7476eede4959f8675c6be1cc5f3)\n- [js] cordova.require instead of PhoneGap.require [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/3ab188539c8529d4fa79497abb84f509d1411318)\n- [readme] formatting [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/d9f9f2dc9bf5ede06df8b5d9f407456b8c938582)\n- [js] cordova.require instead of PhoneGap.require [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/ea1586b0ffbf9a6774bcedab1f988c4f3d8c7fcf)\n- [readme] formatting [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/10f8e6b1164da3e108f3e8e52ca8953e7980c0c4)\n- [spec] FIXED IT [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6cf71f0a3ea1bbfa06806ba1d447a96321eec02f)\n- [spec] 2.5.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6d95b33987c1ee5d903ee51dd1ea496d8d786ae5)\n- [spec] removing a maybe bunk spec [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/ec5e1dc843cf6f9c4090d597efc03a33a50373b0)\n- [spec] removing filsystem init [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/507c726215846a56c30cb85d309588166ab95ab9)\n- [spec] more specs [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/fceafa235a14a3f4d783c02e9529a1f96ecd64c3)\n- [spec] formatting for medic [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/666387e132148cf332d5dd7cb3e379a735bca23d)\n- [spec] app id [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/eb557c48279ebcc5147e474e73c4f374c1b9ec63)\n- [spec] Fixed spec [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/33b2e914a4420024fde9cb2206ac2f9e32bf7931)\n- [spec] app id, title [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/657ec4512268e56d5478bcc93c8a018da026dd32)\n- [spec] fixing spec app [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/52ce70de60d6ad83b05e9639777cf8fa1f9126cd)\n- [spec] add barcodescanner.js [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/ab95b1342d0ccabcd006f5691c39875c54c68c19)\n- [spec] Initial version of spec [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7e7c39dda69bd64359a8963b3cb5aa679b6047c9)\n- Do not copy the scanned barcode to the clipboard. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5c46e8d93f0b711963e88248f71a7be6babe6b75)\n- readme fix [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/3bc65ebbaa3f0e7f96948b7a3484b9e4e9b3ea7b)\n- Update for Cordova/PhoneGap 2.0 plugins (http://simonmacdonald.blogspot.ca/2012/08/so-you-wanna-write-phonegap-200-android.html) [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5d6f0d52f9e495aa34f9d6fec9c77743b2ea6c9a)\n- fix for a java ref [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f26cde76f54f3377d2e385c9fa97ebc65886d50c)\n- full paths for android [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/5d452348dabed181cb3a8b970d94c9deead44be3)\n- fully qualified paths [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/4d8646e26d9ac7008b6b1ba75c24de40960b6ef8)\n- Merge pull request #3 from filmaj/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b1f643f6f48c0dd7909c1e45da3807b35b2769f5)\n- fix for a java ref [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/9c533da17ed0554394fee2aa98f79b4caf56a574)\n- full paths for android [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f568cc6d3e63837ecaa057b666d1913cad2b0e43)\n- fully qualified paths [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/215e077510b26981007500af27e503cc3f6211ae)\n- [spec] FIXED IT [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/cc0f7d82a1723616033be2b25ad554fc614b1fe6)\n- [spec] 2.5.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f94c6129ae6c336660a240458b3371a1c501dfa9)\n- [spec] removing a maybe bunk spec [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/4579d40dc05964521f1e97026810d439e8e7be58)\n- [spec] removing filsystem init [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/40849d52d645ac5bda784ce44de2b18bb1cfac61)\n- [spec] more specs [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/2f7d652587b234362cc86c5205fce9ac10814c13)\n- [spec] formatting for medic [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c1d0b47929171a45df1bbe9ff095e128d4e7c74e)\n- [spec] app id [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/381ee1c6ace4ff2919ea0d33cf770700f5e70c2f)\n- [spec] Fixed spec [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/560cecc5b83c2257215398a9bee5ec12fdfea0b3)\n- [spec] app id, title [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/a0373c766fb8d9fca0c01a9b5dd1c0bd3c1161a7)\n- [spec] fixing spec app [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f9e3d0cffa88a09941aed82f515edeccd8773ad7)\n- [spec] add barcodescanner.js [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/604ebdf14485736b7d543812017812a40cada2b6)\n- [spec] Initial version of spec [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7c47973f78d6caad4b3c92709d0d82d59a4fb163)\n- update BarcodeScanner plugin for 2.5.0+ [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1661cc4387e1e4110f88b4ef561453030d795182)\n- Merge pull request #14 from jwark/do_not_copy_to_clipboard [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/15b5cb9442e1c43ce306fb91f8e2d07e42dd1244)\n- update BarcodeScanner plugin for 2.5.0+ [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/58e773af70c59d04012d51ded8ba408037142f95)\n- Do not copy the scanned barcode to the clipboard. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1d8ee5ca8d2e2878b82e4db95d7465c15c6fa5f4)\n- Merge pull request #7 from JaysonRaymond/master [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/3c73e21796118c3a97ba944e67d6a06c80ca08b4)\n- [iOS][2.3.0] add plugin to config.xml for 2.3.0+ + upped version to 0.3.0 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/bb3812c0cb7b525065101c251b211e320d76c45a)\n- readme fix [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c7158af58ee9aeb0e325ae733c4bbfd1db51e563)\n- Update for Cordova/PhoneGap 2.0 plugins (http://simonmacdonald.blogspot.ca/2012/08/so-you-wanna-write-phonegap-200-android.html) [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/3f166162a05c79782cbcf162154f16b94efa2609)\n- [0.2.2] updated version [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/029cb4de7d30953811690dba6939b88d9a9ceca7)\n- [ios] Fixes AVCaptureSession leak, thanks @markus-olsson [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/1e2535ad010e94ee0319f727e0f444035b02742d)\n- [android] syntax error, missing else [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/695f524777f9b0ea49dcfe3e980a5053da2e3e4a)\n- [0.2.1][ios] lock scanner to portrait [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/084594d86c7cafb98f0985101629fa910141fa6a)\n- [0.2.0] updated version [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/87ffa13f2c5e63e7388ef37bacf9b02ead8fc0d9)\n- [ios] lock scanner orientation to portrait [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/413b0236978186d5c2e3b2675c72997867bcee6a)\n- [0.1.2] version update [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/566c1f166a27108c995fd77d5fa20454c7311196)\n- [ios] Integrated shazron's iOS6 orientation updates [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/e0f7b9a33e647b9763934c09259be01edba88d5c)\n- [version] updated to 0.1.1 [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/f1fb499e42f31e06d1805dcdf40bd3edcb0fd384)\n- [android] Removed app_name string resource [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/b145a21012f1b997e0060f8d1c0e6fd25add1cca)\n- [readme] corrected supported types for iOS [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/7119054ce63bffdb3bfb77d97aec12307536d795)\n- [readme] [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/9211290b7656697f7b7a87a05b77286d1f85b2c8)\n- [readme] [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/89ed3727372815966fd83b2b925b51d22a18b001)\n- [0.1.0] version updated [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/3e3093969f0544ede202e6646a655da6fb22f1ac)\n- [android] Added translated resource files [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/47a8bdd29c277e69ab1750b94b3c4ac5c01ba19b)\n- [android] Modified zxing client to access resources from main package [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/9cff772bfc4f404337830a974a9593883cb81d23)\n- [android][plugin-xml] Added resource files [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/e3505aea3a65a967e7bb710f77f94d05fc556409)\n- [android] Added Zxing Library project [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/8421719edb1f7005b3a2a46a24c62d2d69479d7a)\n- [gitignore] [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/c432f127c593791aedc3008a83f7a1a818568700)\n- [readme] license [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/274b122932517ccea144d5e279c38beb4ad991aa)\n- [plugin-xml] fixed up plugin.xml [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/097548504dd6c192e26256e582882e6b5f12daec)\n- [ios] removed CORDOVA_FRAMEWORK ref [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/cb2e830ee5223076c9f126d80e07ef614ca3cff1)\n- Initial commit. Zeppelin rules. [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/92197289049bfd4aab63b6467dddb93449a8a7ef)\n- Initial commit [view commit](http://github.com/phonegap/phonegap-plugin-barcodescanner/commit/6de30878ff7ada1b43a01d1037dcee6e419a8050)\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/README.md",
    "content": "# PhoneGap Plugin BarcodeScanner\n================================\n\n[![Build Status](https://travis-ci.org/phonegap/phonegap-plugin-barcodescanner.svg)](https://travis-ci.org/phonegap/phonegap-plugin-barcodescanner)\n\nCross-platform BarcodeScanner for Cordova / PhoneGap.\n\nFollows the [Cordova Plugin spec](https://cordova.apache.org/docs/en/latest/plugin_ref/spec.html), so that it works with [Plugman](https://github.com/apache/cordova-plugman).\n\n## Installation\n\n\nThis requires phonegap 5.0+ ( current stable v3.0.0 )\n\n    phonegap plugin add phonegap-plugin-barcodescanner\n\nOlder versions of phonegap can still install via the __deprecated__ id ( stale v2.0.1 )\n\n    phonegap plugin add com.phonegap.plugins.barcodescanner\n\nIt is also possible to install via repo url directly ( unstable )\n\n    phonegap plugin add https://github.com/phonegap/phonegap-plugin-barcodescanner.git\n\n### Supported Platforms\n\n- Android\n- iOS\n- Windows (Windows/Windows Phone 8.1 and Windows 10)\n- Windows Phone 8\n- BlackBerry 10\n- Browser\n\nNote: the Android source for this project includes an Android Library Project.\nplugman currently doesn't support Library Project refs, so its been\nprebuilt as a jar library. Any updates to the Library Project should be\ncommitted with an updated jar.\n\nNote: Windows 10 applications can not be build for `AnyCPU` architecture, which is default for Windows platform. If you want to build/run Windows 10 app, you should specify target architecture explicitly, for example (Cordova CLI):\n\n```\ncordova run windows -- --archs=x86\n```\n\nNote: Since iOS 10 it's mandatory to add a `NSCameraUsageDescription` in the info.plist.\n\n`NSCameraUsageDescription` describes the reason that the app accesses the user’s camera.\nWhen the system prompts the user to allow access, this string is displayed as part of the dialog box.\n\nTo add this entry you can pass the following variable on plugin install.\n\n```\ncordova plugin add phonegap-plugin-barcodescanner --variable CAMERA_USAGE_DESCRIPTION=\"To scan barcodes\"\n```\n\n### PhoneGap Build\nIf you're using [PhoneGap Build](https://build.phonegap.com/) please make sure you specify `gradle` as your Android build tool in `config.xml`: `<preference name=\"android-build-tool\" value=\"gradle\" />`.\n\n## Using the plugin ##\nThe plugin creates the object `cordova/plugin/BarcodeScanner` with the method `scan(success, fail)`.\n\nThe following barcode types are currently supported:\n### Android\n\n* QR_CODE\n* DATA_MATRIX\n* UPC_E\n* UPC_A\n* EAN_8\n* EAN_13\n* CODE_128\n* CODE_39\n* CODE_93\n* CODABAR\n* ITF\n* RSS14\n* RSS_EXPANDED\n\nNot by default, but supported if you pass in the \"formats\" option:\n* PDF417\n* AZTEC\n\n### iOS\n\n* QR_CODE\n* DATA_MATRIX\n* UPC_E\n* UPC_A\n* EAN_8\n* EAN_13\n* CODE_128\n* CODE_39\n* ITF\n\n### Windows\n\n* UPC_A\n* UPC_E\n* EAN_8\n* EAN_13\n* CODE_39\n* CODE_93\n* CODE_128\n* ITF\n* CODABAR\n* MSI\n* RSS14\n* QR_CODE\n* DATA_MATRIX\n* AZTEC\n* PDF417\n\n### Windows Phone 8\n\n* UPC_A\n* UPC_E\n* EAN_8\n* EAN_13\n* CODE_39\n* CODE_93\n* CODE_128\n* ITF\n* CODABAR\n* MSI\n* RSS14\n* QR_CODE\n* DATA_MATRIX\n* AZTEC\n* PDF417\n\n### BlackBerry 10\n* UPC_A\n* UPC_E\n* EAN_8\n* EAN_13\n* CODE_39\n* CODE_128\n* ITF\n* DATA_MATRIX\n* AZTEC\n\n`success` and `fail` are callback functions. Success is passed an object with data, type and cancelled properties. Data is the text representation of the barcode data, type is the type of barcode detected and cancelled is whether or not the user cancelled the scan.\n\nA full example could be:\n```js\n   cordova.plugins.barcodeScanner.scan(\n      function (result) {\n          alert(\"We got a barcode\\n\" +\n                \"Result: \" + result.text + \"\\n\" +\n                \"Format: \" + result.format + \"\\n\" +\n                \"Cancelled: \" + result.cancelled);\n      },\n      function (error) {\n          alert(\"Scanning failed: \" + error);\n      },\n      {\n          preferFrontCamera : true, // iOS and Android\n          showFlipCameraButton : true, // iOS and Android\n          showTorchButton : true, // iOS and Android\n          torchOn: true, // Android, launch with the torch switched on (if available)\n          prompt : \"Place a barcode inside the scan area\", // Android\n          resultDisplayDuration: 500, // Android, display scanned text for X ms. 0 suppresses it entirely, default 1500\n          formats : \"QR_CODE,PDF_417\", // default: all but PDF_417 and RSS_EXPANDED\n          orientation : \"landscape\", // Android only (portrait|landscape), default unset so it rotates with the device\n          disableAnimations : true, // iOS\n          disableSuccessBeep: false // iOS\n      }\n   );\n```\n\n## Encoding a Barcode ##\n\nThe plugin creates the object `cordova.plugins.barcodeScanner` with the method `encode(type, data, success, fail)`.\n\nSupported encoding types:\n\n* TEXT_TYPE\n* EMAIL_TYPE\n* PHONE_TYPE\n* SMS_TYPE\n\n```\nA full example could be:\n\n   cordova.plugins.barcodeScanner.encode(cordova.plugins.barcodeScanner.Encode.TEXT_TYPE, \"http://www.nytimes.com\", function(success) {\n            alert(\"encode success: \" + success);\n          }, function(fail) {\n            alert(\"encoding failed: \" + fail);\n          }\n        );\n```\n\n## Windows quirks ##\n\n* Windows implementation currently doesn't support encode functionality.\n\n* On Windows 10 desktop ensure that you have Windows Media Player and Media Feature pack installed.\n\n## Windows Phone 8 quirks ##\nWindows Phone 8 implementation currently doesn't support encode functionality.\n\n## BlackBerry 10 quirks\nBlackBerry 10 implementation currently doesn't support encode functionality.\nCancelling a scan on BlackBerry 10 is done by touching the screen.\n\n## Thanks on Github ##\n\nSo many -- check out the original [iOS](https://github.com/phonegap/phonegap-plugins/tree/DEPRECATED/iOS/BarcodeScanner),  [Android](https://github.com/phonegap/phonegap-plugins/tree/DEPRECATED/Android/BarcodeScanner) and\n[BlackBerry 10](https://github.com/blackberry/WebWorks-Community-APIs/tree/master/BB10-Cordova/BarcodeScanner) repos.\n\n## Licence ##\n\nThe MIT License\n\nCopyright (c) 2010 Matt Kane\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/hooks/windows/check-arch.js",
    "content": "module.exports = function(ctx) {\n    if (ctx.opts && ctx.opts.platforms && ctx.opts.platforms.indexOf('windows') > -1\n        && ctx.opts.options) {\n        var path = require('path');\n        var shell = ctx.requireCordovaModule('shelljs');\n        var nopt = ctx.requireCordovaModule('nopt');\n\n        // parse and validate args\n        var args = nopt({\n            'archs': [String],\n            'appx': String,\n            'phone': Boolean,\n            'win': Boolean,\n            'bundle': Boolean,\n            'packageCertificateKeyFile': String,\n            'packageThumbprint': String,\n            'publisherId': String,\n            'buildConfig': String\n        }, {}, ctx.opts.options.argv, 0);\n\n        // Check if --appx flag is passed so that we have a project build version override:  \n        var isWin10 = args.appx && args.appx.toLowerCase() === 'uap';\n\n        // Else check \"windows-target-version\" preference:\n        if (!isWin10) {\n            var configXml = shell.ls(path.join(ctx.opts.projectRoot, 'config.xml'))[0];\n\n            var reTargetVersion = /<preference\\s+name=\"windows-target-version\"\\s+value=\"(.+)\"\\s*\\/>/i;\n            var targetVersion = shell.grep(reTargetVersion, configXml);\n\n            var result = reTargetVersion.exec(targetVersion);\n            if (result !== null) {\n                var match = result[1];\n                isWin10 = parseInt(match.split('.'), 10) > 8;\n            }\n        }\n\n        // Non-AnyCPU arch is required for Windows 10 (UWP) projects only:\n        if (isWin10) {\n            var rawArchs = ctx.opts.options.archs || args.archs;\n            var archs = rawArchs ? rawArchs.split(' ') : [];\n\n            // Avoid \"anycpu\" arch:\n            if (archs.length === 0 || archs.some(function (item) {\n                return item.toLowerCase() === 'anycpu';\n            })) {\n                throw new Error('You must specify an architecture to include the proper ZXing library version.'\n                + '\\nUse \\'cordova run windows -- --arch=\"x64\"\\' or \\'cordova run windows -- --arch=\"arm\" --phone --device\\' for example.');\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/package.json",
    "content": "{\n  \"name\": \"phonegap-plugin-barcodescanner\",\n  \"version\": \"6.0.6\",\n  \"description\": \"You can use the BarcodeScanner plugin to scan different types of barcodes (using the device's camera) and get the metadata encoded in them for processing within your application.\",\n  \"cordova\": {\n    \"id\": \"phonegap-plugin-barcodescanner\",\n    \"platforms\": [\n      \"ios\",\n      \"android\",\n      \"windows\",\n      \"wp8\",\n      \"blackberry10\",\n      \"browser\"\n    ]\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/phonegap/phonegap-plugin-barcodescanner.git\"\n  },\n  \"keywords\": [\n    \"ecosystem:cordova\",\n    \"ecosystem:phonegap\",\n    \"cordova-ios\",\n    \"cordova-android\",\n    \"cordova-windows\",\n    \"cordova-wp8\",\n    \"cordova-blackberry10\",\n    \"cordova-browser\",\n    \"cordova:plugin\"\n  ],\n  \"engines\": [\n    {\n      \"name\": \"cordova\",\n      \"version\": \">=3.0.0\"\n    }\n  ],\n  \"author\": \"Adobe PhoneGap Team\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/phonegap/phonegap-plugin-barcodescanner/issues\"\n  },\n  \"homepage\": \"https://github.com/phonegap/phonegap-plugin-barcodescanner#readme\",\n  \"scripts\": {\n    \"test\": \"jasmine-node --color spec\"\n  },\n  \"devDependencies\": {\n    \"jasmine-node\": \"1.14.5\",\n    \"pluginpub\": \"^0.0.6\"\n  }\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/plugin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<plugin xmlns=\"http://www.phonegap.com/ns/plugins/1.0\" xmlns:android=\"http://schemas.android.com/apk/res/android\" xmlns:rim=\"http://www.blackberry.com/ns/widgets\" id=\"phonegap-plugin-barcodescanner\" version=\"6.0.6\">\n  <name>BarcodeScanner</name>\n  <description>You can use the BarcodeScanner plugin to scan different types of barcodes (using the device's camera) and get the metadata encoded in them for processing within your application.</description>\n  <license>MIT</license>\n  <repo>https://github.com/phonegap/phonegap-plugin-barcodescanner</repo>\n  <issue>https://github.com/phonegap/phonegap-plugin-barcodescanner/issues</issue>\n  <engines>\n    <engine name=\"cordova\" version=\">=3.0.0\"/>\n  </engines>\n  <js-module src=\"www/barcodescanner.js\" name=\"BarcodeScanner\">\n    <clobbers target=\"cordova.plugins.barcodeScanner\"/>\n  </js-module>\n  <platform name=\"ios\">\n    <config-file target=\"config.xml\" parent=\"/*\">\n      <feature name=\"BarcodeScanner\">\n        <param name=\"ios-package\" value=\"CDVBarcodeScanner\"/>\n      </feature>\n    </config-file>\n    <config-file target=\"*-Info.plist\" parent=\"NSCameraUsageDescription\">\n      <string>$CAMERA_USAGE_DESCRIPTION</string>\n    </config-file>\n    <preference name=\"CAMERA_USAGE_DESCRIPTION\" default=\" \"/>\n    <resource-file src=\"src/ios/scannerOverlay.xib\"/>\n    <resource-file src=\"src/ios/CDVBarcodeScanner.bundle\"/>\n    <header-file src=\"src/ios/zxing-all-in-one.h\"/>\n    <source-file src=\"src/ios/CDVBarcodeScanner.mm\" compiler-flags=\"-fno-objc-arc\"/>\n    <source-file src=\"src/ios/zxing-all-in-one.cpp\"/>\n    <framework src=\"libiconv.dylib\"/>\n    <framework src=\"AVFoundation.framework\"/>\n    <framework src=\"AssetsLibrary.framework\"/>\n    <framework src=\"CoreVideo.framework\"/>\n    <framework src=\"QuartzCore.framework\"/>\n    <framework src=\"CoreGraphics.framework\"/>\n    <framework src=\"CoreImage.framework\"/>\n    <framework src=\"AudioToolbox.framework\"/>\n  </platform>\n  <platform name=\"android\">\n    <source-file src=\"src/android/com/phonegap/plugins/barcodescanner/BarcodeScanner.java\" target-dir=\"src/com/phonegap/plugins/barcodescanner\"/>\n    <config-file target=\"res/xml/config.xml\" parent=\"/*\">\n      <feature name=\"BarcodeScanner\">\n        <param name=\"android-package\" value=\"com.phonegap.plugins.barcodescanner.BarcodeScanner\"/>\n      </feature>\n    </config-file>\n    <config-file target=\"AndroidManifest.xml\" parent=\"/manifest/application\">\n      <activity android:name=\"com.google.zxing.client.android.CaptureActivity\" android:clearTaskOnLaunch=\"true\" android:configChanges=\"orientation|keyboardHidden|screenSize\" android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\" android:windowSoftInputMode=\"stateAlwaysHidden\" android:exported=\"false\"/>\n      <activity android:name=\"com.google.zxing.client.android.encode.EncodeActivity\" android:label=\"Share\"/>\n    </config-file>\n    <config-file target=\"AndroidManifest.xml\" parent=\"/manifest\">\n      <uses-permission android:name=\"android.permission.CAMERA\"/>\n      <uses-permission android:name=\"android.permission.FLASHLIGHT\"/>\n      <uses-feature android:name=\"android.hardware.camera\" android:required=\"true\"/>\n    </config-file>\n    <framework src=\"src/android/barcodescanner.gradle\" custom=\"true\" type=\"gradleReference\"/>\n    <resource-file src=\"src/android/barcodescanner-release-2.1.2.aar\" target=\"libs/barcodescanner.aar\"/>\n    <dependency id=\"cordova-plugin-compat\" version=\"^1.0.0\"/>\n  </platform>\n  <platform name=\"windows\">\n    <js-module src=\"src/windows/BarcodeScannerProxy.js\" name=\"BarcodeScannerProxy\">\n      <merges target=\"\"/>\n    </js-module>\n    <config-file target=\"package.appxmanifest\" parent=\"/Package/Capabilities\">\n      <DeviceCapability Name=\"webcam\"/>\n    </config-file>\n    <framework src=\"src/windows/lib.UW/x86/ZXing.winmd\" target-dir=\"x86\" arch=\"x86\" custom=\"true\" versions=\">8.1\"/>\n    <framework src=\"src/windows/lib.UW/x64/ZXing.winmd\" target-dir=\"x64\" arch=\"x64\" custom=\"true\" versions=\">8.1\"/>\n    <framework src=\"src/windows/lib.UW/ARM/ZXing.winmd\" target-dir=\"ARM\" arch=\"ARM\" custom=\"true\" versions=\">8.1\"/>\n    <framework src=\"src/windows/lib/WinRTBarcodeReader.csproj\" custom=\"true\" type=\"projectReference\" versions=\"&lt;=8.1\"/>\n    <asset src=\"src/windows/assets/plugin-barcodeScanner.css\" target=\"css/plugin-barcodeScanner.css\"/>\n    <hook src=\"hooks/windows/check-arch.js\" type=\"before_compile\"/>\n    <hook src=\"hooks/windows/check-arch.js\" type=\"before_run\"/>\n  </platform>\n  <platform name=\"wp8\">\n    <config-file target=\"config.xml\" parent=\"/*\">\n      <feature name=\"BarcodeScanner\">\n        <param name=\"wp-package\" value=\"BarcodeScanner\"/>\n      </feature>\n    </config-file>\n    <config-file target=\"Properties/WMAppManifest.xml\" parent=\"/Deployment/App/Capabilities\">\n      <Capability Name=\"ID_CAP_ISV_CAMERA\"/>\n    </config-file>\n    <framework src=\"src/wp8/lib/zxing.wp8.0.dll\" custom=\"true\"/>\n    <asset src=\"src/wp8/assets/cancel.png\" target=\"Images/appbar.cancel.png\"/>\n    <source-file src=\"src/wp8/BarcodeScanner.cs\"/>\n    <source-file src=\"src/wp8/BarcodeScannerTask.cs\"/>\n    <source-file src=\"src/wp8/BarcodeScannerUI.xaml\"/>\n    <source-file src=\"src/wp8/BarcodeScannerUI.xaml.cs\"/>\n  </platform>\n  <platform name=\"browser\">\n    <config-file target=\"config.xml\" parent=\"/*\">\n      <feature name=\"BarcodeScanner\">\n        <param name=\"browser-package\" value=\"BarcodeScanner\"/>\n      </feature>\n    </config-file>\n    <js-module src=\"src/browser/BarcodeScannerProxy.js\" name=\"BarcodeScannerProxy\">\n      <runs/>\n    </js-module>\n  </platform>\n  <platform name=\"blackberry10\">\n    <source-file src=\"src/blackberry10/index.js\" target-dir=\"BarcodeScanner\"/>\n    <source-file src=\"src/blackberry10/qrcode.js\" target-dir=\"BarcodeScanner\"/>\n    <lib-file src=\"src/blackberry10/native/device/libBarcodeScanner.so\" arch=\"device\"/>\n    <lib-file src=\"src/blackberry10/native/simulator/libBarcodeScanner.so\" arch=\"simulator\"/>\n    <config-file target=\"www/config.xml\" parent=\"/widget\">\n      <feature name=\"BarcodeScanner\">\n        <param name=\"blackberry-package\" value=\"phonegap-plugin-barcodescanner\"/>\n      </feature>\n    </config-file>\n    <config-file target=\"www/config.xml\" parent=\"/widget/rim:permissions\">\n      <rim:permit>use_camera</rim:permit>\n    </config-file>\n    <dependency id=\"cordova-plugin-bb-app\"/>\n  </platform>\n</plugin>"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/spec/helper/cordova.js",
    "content": "/* global cordova:true */\n\n/*!\n * Module dependencies.\n */\n\n/**\n * cordova.js for node.\n *\n * Think of this as cordova-node, which would be simliar to cordova-android\n * or cordova-browser. The purpose of this module is to enable testing\n * of a plugin's JavaScript interface.\n *\n * When this module is first required, it will insert a global cordova\n * instance, which can hijack cordova-specific commands within the pluin's\n * implementation.\n *\n * Remember to require this module before the plugin that you want to test.\n *\n * Example:\n *\n *     var cordova = require('./helper/cordova'),\n *         myPlugin = require('../www/myPlugin');\n */\n\nmodule.exports = global.cordova = cordova = {\n\n    /**\n     * cordova.require Mock.\n     *\n     * Hijacks all cordova.requires. By default, it returns an empty function.\n     * You can define your own implementation of each required module before\n     * or after it has been required.\n     *\n     * See `cordova.required` to learn how to add your own module implemtnation.\n     */\n\n    require: function(moduleId) {\n        // define a default function if it doesn't exist\n        if (!cordova.required[moduleId]) {\n            cordova.required[moduleId] = function() {};\n        }\n        // create a new module mapping between the module Id and cordova.required.\n        return new ModuleMap(moduleId);\n    },\n\n    /**\n     * Cordova module implementations.\n     *\n     * A key-value hash, where the key is the module such as 'cordova/exec'\n     * and the value is the function or object returned.\n     *\n     * For example:\n     *\n     *     var exec = require('cordova/exec');\n     *\n     * Will map to:\n     *\n     *     cordova.required['cordova/exec'];\n     */\n\n    required: {\n        // populated at runtime\n    }\n};\n\n/**\n * Module Mapper.\n *\n * Returns a function that when executed will lookup the implementation\n * in cordova.required[id].\n *\n * @param {String} moduleId is the module name/path, such as 'cordova/exec'\n * @return {Function}.\n */\n\nfunction ModuleMap(moduleId) {\n    return function() {\n        // lookup and execute the module's mock implementation, passing\n        // in any parameters that were provided.\n        return cordova.required[moduleId].apply(this, arguments);\n    };\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/spec/index.spec.js",
    "content": "/* globals require */\n\n/*!\n * Module dependencies.\n */\n\nvar cordova = require('./helper/cordova'),\n    BarcodeScanner = require('../www/barcodescanner'),\n    execSpy,\n    execWin,\n    options;\n\n/*!\n * Specification.\n */\n\ndescribe('phonegap-plugin-barcodescanner', function () {\n    beforeEach(function () {\n        execWin = jasmine.createSpy();\n        execSpy = spyOn(cordova.required, 'cordova/exec').andCallFake(execWin);\n    });\n\n    describe('BarcodeScanner', function () {\n      it(\"BarcodeScanner plugin should exist\", function() {\n          expect(BarcodeScanner).toBeDefined();\n          expect(typeof BarcodeScanner == 'object').toBe(true);\n      });\n\n      it(\"should contain a scan function\", function() {\n          expect(BarcodeScanner.scan).toBeDefined();\n          expect(typeof BarcodeScanner.scan == 'function').toBe(true);\n      });\n\n      it(\"should contain an encode function\", function() {\n          expect(BarcodeScanner.encode).toBeDefined();\n          expect(typeof BarcodeScanner.encode == 'function').toBe(true);\n      });\n\n      it(\"should contain three DestinationType constants\", function() {\n          expect(BarcodeScanner.Encode.TEXT_TYPE).toBe(\"TEXT_TYPE\");\n          expect(BarcodeScanner.Encode.EMAIL_TYPE).toBe(\"EMAIL_TYPE\");\n          expect(BarcodeScanner.Encode.PHONE_TYPE).toBe(\"PHONE_TYPE\");\n          expect(BarcodeScanner.Encode.SMS_TYPE).toBe(\"SMS_TYPE\");\n      });\n    });\n\n    describe('BarcodeScanner instance', function () {\n        describe('cordova.exec', function () {\n            it('should call cordova.exec on next process tick', function (done) {\n                BarcodeScanner.scan(function() {}, function() {}, {});\n                setTimeout(function () {\n                    expect(execSpy).toHaveBeenCalledWith(\n                        jasmine.any(Function),\n                        jasmine.any(Function),\n                        'BarcodeScanner',\n                        'scan',\n                        jasmine.any(Object)\n                    );\n                    done();\n                }, 100);\n            });\n\n            it('should call cordova.exec on next process tick', function (done) {\n                BarcodeScanner.encode(\"\", \"\",function() {}, function() {}, {});\n                setTimeout(function () {\n                    expect(execSpy).toHaveBeenCalledWith(\n                        jasmine.any(Function),\n                        jasmine.any(Function),\n                        'BarcodeScanner',\n                        'encode',\n                        jasmine.any(Object)\n                    );\n                    done();\n                }, 100);\n            });\n        });\n    });\n});\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/android/README.md",
    "content": "The Android .aar sources are [here](https://github.com/EddyVerbruggen/barcodescanner-lib-aar)."
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/android/barcodescanner.gradle",
    "content": "def DEFAULT_MIN_SDK_VERSION = 15\ndef minSdk = Math.max(DEFAULT_MIN_SDK_VERSION, cdvHelpers.getConfigPreference('android-minSdkVersion',0) as Integer);\nif (cdvMinSdkVersion == null || Integer.parseInt(cdvMinSdkVersion) < minSdk ) {\n    ext.cdvMinSdkVersion = minSdk;\n}\n\nrepositories{\n    jcenter()\n    flatDir{\n        dirs 'libs'\n    }\n}\n\ndependencies {\n    compile 'com.android.support:support-v4:+'\n    compile(name:'barcodescanner', ext:'aar')\n}\n\nandroid {\n    packagingOptions {\n        exclude 'META-INF/NOTICE'\n        exclude 'META-INF/LICENSE'\n    }\n}"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/android/com/phonegap/plugins/barcodescanner/BarcodeScanner.java",
    "content": "/**\n * PhoneGap is available under *either* the terms of the modified BSD license *or* the\n * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.\n *\n * Copyright (c) Matt Kane 2010\n * Copyright (c) 2011, IBM Corporation\n * Copyright (c) 2013, Maciej Nux Jaros\n */\npackage com.phonegap.plugins.barcodescanner;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport android.Manifest;\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.content.pm.PackageManager;\n\nimport org.apache.cordova.CordovaPlugin;\nimport org.apache.cordova.CallbackContext;\nimport org.apache.cordova.PluginResult;\nimport org.apache.cordova.PermissionHelper;\n\nimport com.google.zxing.client.android.CaptureActivity;\nimport com.google.zxing.client.android.encode.EncodeActivity;\nimport com.google.zxing.client.android.Intents;\n\n/**\n * This calls out to the ZXing barcode reader and returns the result.\n *\n * @sa https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java\n */\npublic class BarcodeScanner extends CordovaPlugin {\n    public static final int REQUEST_CODE = 0x0ba7c0de;\n\n    private static final String SCAN = \"scan\";\n    private static final String ENCODE = \"encode\";\n    private static final String CANCELLED = \"cancelled\";\n    private static final String FORMAT = \"format\";\n    private static final String TEXT = \"text\";\n    private static final String DATA = \"data\";\n    private static final String TYPE = \"type\";\n    private static final String PREFER_FRONTCAMERA = \"preferFrontCamera\";\n    private static final String ORIENTATION = \"orientation\";\n    private static final String SHOW_FLIP_CAMERA_BUTTON = \"showFlipCameraButton\";\n    private static final String RESULTDISPLAY_DURATION = \"resultDisplayDuration\";\n    private static final String SHOW_TORCH_BUTTON = \"showTorchButton\";\n    private static final String TORCH_ON = \"torchOn\";\n    private static final String FORMATS = \"formats\";\n    private static final String PROMPT = \"prompt\";\n    private static final String TEXT_TYPE = \"TEXT_TYPE\";\n    private static final String EMAIL_TYPE = \"EMAIL_TYPE\";\n    private static final String PHONE_TYPE = \"PHONE_TYPE\";\n    private static final String SMS_TYPE = \"SMS_TYPE\";\n\n    private static final String LOG_TAG = \"BarcodeScanner\";\n\n    private String [] permissions = { Manifest.permission.CAMERA };\n\n    private JSONArray requestArgs;\n    private CallbackContext callbackContext;\n\n    /**\n     * Constructor.\n     */\n    public BarcodeScanner() {\n    }\n\n    /**\n     * Executes the request.\n     *\n     * This method is called from the WebView thread. To do a non-trivial amount of work, use:\n     *     cordova.getThreadPool().execute(runnable);\n     *\n     * To run on the UI thread, use:\n     *     cordova.getActivity().runOnUiThread(runnable);\n     *\n     * @param action          The action to execute.\n     * @param args            The exec() arguments.\n     * @param callbackContext The callback context used when calling back into JavaScript.\n     * @return                Whether the action was valid.\n     *\n     * @sa https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java\n     */\n    @Override\n    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {\n        this.callbackContext = callbackContext;\n        this.requestArgs = args;\n\n        if (action.equals(ENCODE)) {\n            JSONObject obj = args.optJSONObject(0);\n            if (obj != null) {\n                String type = obj.optString(TYPE);\n                String data = obj.optString(DATA);\n\n                // If the type is null then force the type to text\n                if (type == null) {\n                    type = TEXT_TYPE;\n                }\n\n                if (data == null) {\n                    callbackContext.error(\"User did not specify data to encode\");\n                    return true;\n                }\n\n                encode(type, data);\n            } else {\n                callbackContext.error(\"User did not specify data to encode\");\n                return true;\n            }\n        } else if (action.equals(SCAN)) {\n\n            //android permission auto add\n            if(!hasPermisssion()) {\n              requestPermissions(0);\n            } else {\n              scan(args);\n            }\n        } else {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Starts an intent to scan and decode a barcode.\n     */\n    public void scan(final JSONArray args) {\n\n        final CordovaPlugin that = this;\n\n        cordova.getThreadPool().execute(new Runnable() {\n            public void run() {\n\n                Intent intentScan = new Intent(that.cordova.getActivity().getBaseContext(), CaptureActivity.class);\n                intentScan.setAction(Intents.Scan.ACTION);\n                intentScan.addCategory(Intent.CATEGORY_DEFAULT);\n\n                // add config as intent extras\n                if (args.length() > 0) {\n\n                    JSONObject obj;\n                    JSONArray names;\n                    String key;\n                    Object value;\n\n                    for (int i = 0; i < args.length(); i++) {\n\n                        try {\n                            obj = args.getJSONObject(i);\n                        } catch (JSONException e) {\n                            Log.i(\"CordovaLog\", e.getLocalizedMessage());\n                            continue;\n                        }\n\n                        names = obj.names();\n                        for (int j = 0; j < names.length(); j++) {\n                            try {\n                                key = names.getString(j);\n                                value = obj.get(key);\n\n                                if (value instanceof Integer) {\n                                    intentScan.putExtra(key, (Integer) value);\n                                } else if (value instanceof String) {\n                                    intentScan.putExtra(key, (String) value);\n                                }\n\n                            } catch (JSONException e) {\n                                Log.i(\"CordovaLog\", e.getLocalizedMessage());\n                            }\n                        }\n\n                        intentScan.putExtra(Intents.Scan.CAMERA_ID, obj.optBoolean(PREFER_FRONTCAMERA, false) ? 1 : 0);\n                        intentScan.putExtra(Intents.Scan.SHOW_FLIP_CAMERA_BUTTON, obj.optBoolean(SHOW_FLIP_CAMERA_BUTTON, false));\n                        intentScan.putExtra(Intents.Scan.SHOW_TORCH_BUTTON, obj.optBoolean(SHOW_TORCH_BUTTON, false));\n                        intentScan.putExtra(Intents.Scan.TORCH_ON, obj.optBoolean(TORCH_ON, false));\n                        if (obj.has(RESULTDISPLAY_DURATION)) {\n                            intentScan.putExtra(Intents.Scan.RESULT_DISPLAY_DURATION_MS, \"\" + obj.optLong(RESULTDISPLAY_DURATION));\n                        }\n                        if (obj.has(FORMATS)) {\n                            intentScan.putExtra(Intents.Scan.FORMATS, obj.optString(FORMATS));\n                        }\n                        if (obj.has(PROMPT)) {\n                            intentScan.putExtra(Intents.Scan.PROMPT_MESSAGE, obj.optString(PROMPT));\n                        }\n                        if (obj.has(ORIENTATION)) {\n                            intentScan.putExtra(Intents.Scan.ORIENTATION_LOCK, obj.optString(ORIENTATION));\n                        }\n                    }\n\n                }\n\n                // avoid calling other phonegap apps\n                intentScan.setPackage(that.cordova.getActivity().getApplicationContext().getPackageName());\n\n                that.cordova.startActivityForResult(that, intentScan, REQUEST_CODE);\n            }\n        });\n    }\n\n    /**\n     * Called when the barcode scanner intent completes.\n     *\n     * @param requestCode The request code originally supplied to startActivityForResult(),\n     *                       allowing you to identify who this result came from.\n     * @param resultCode  The integer result code returned by the child activity through its setResult().\n     * @param intent      An Intent, which can return result data to the caller (various data can be attached to Intent \"extras\").\n     */\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent intent) {\n        if (requestCode == REQUEST_CODE && this.callbackContext != null) {\n            if (resultCode == Activity.RESULT_OK) {\n                JSONObject obj = new JSONObject();\n                try {\n                    obj.put(TEXT, intent.getStringExtra(\"SCAN_RESULT\"));\n                    obj.put(FORMAT, intent.getStringExtra(\"SCAN_RESULT_FORMAT\"));\n                    obj.put(CANCELLED, false);\n                } catch (JSONException e) {\n                    Log.d(LOG_TAG, \"This should never happen\");\n                }\n                //this.success(new PluginResult(PluginResult.Status.OK, obj), this.callback);\n                this.callbackContext.success(obj);\n            } else if (resultCode == Activity.RESULT_CANCELED) {\n                JSONObject obj = new JSONObject();\n                try {\n                    obj.put(TEXT, \"\");\n                    obj.put(FORMAT, \"\");\n                    obj.put(CANCELLED, true);\n                } catch (JSONException e) {\n                    Log.d(LOG_TAG, \"This should never happen\");\n                }\n                //this.success(new PluginResult(PluginResult.Status.OK, obj), this.callback);\n                this.callbackContext.success(obj);\n            } else {\n                //this.error(new PluginResult(PluginResult.Status.ERROR), this.callback);\n                this.callbackContext.error(\"Unexpected error\");\n            }\n        }\n    }\n\n    /**\n     * Initiates a barcode encode.\n     *\n     * @param type Endoiding type.\n     * @param data The data to encode in the bar code.\n     */\n    public void encode(String type, String data) {\n        Intent intentEncode = new Intent(this.cordova.getActivity().getBaseContext(), EncodeActivity.class);\n        intentEncode.setAction(Intents.Encode.ACTION);\n        intentEncode.putExtra(Intents.Encode.TYPE, type);\n        intentEncode.putExtra(Intents.Encode.DATA, data);\n        // avoid calling other phonegap apps\n        intentEncode.setPackage(this.cordova.getActivity().getApplicationContext().getPackageName());\n\n        this.cordova.getActivity().startActivity(intentEncode);\n    }\n\n    /**\n     * check application's permissions\n     */\n   public boolean hasPermisssion() {\n       for(String p : permissions)\n       {\n           if(!PermissionHelper.hasPermission(this, p))\n           {\n               return false;\n           }\n       }\n       return true;\n   }\n\n    /**\n     * We override this so that we can access the permissions variable, which no longer exists in\n     * the parent class, since we can't initialize it reliably in the constructor!\n     *\n     * @param requestCode The code to get request action\n     */\n   public void requestPermissions(int requestCode)\n   {\n       PermissionHelper.requestPermissions(this, requestCode, permissions);\n   }\n\n   /**\n   * processes the result of permission request\n   *\n   * @param requestCode The code to get request action\n   * @param permissions The collection of permissions\n   * @param grantResults The result of grant\n   */\n  public void onRequestPermissionResult(int requestCode, String[] permissions,\n                                         int[] grantResults) throws JSONException\n   {\n       PluginResult result;\n       for (int r : grantResults) {\n           if (r == PackageManager.PERMISSION_DENIED) {\n               Log.d(LOG_TAG, \"Permission Denied!\");\n               result = new PluginResult(PluginResult.Status.ILLEGAL_ACCESS_EXCEPTION);\n               this.callbackContext.sendPluginResult(result);\n               return;\n           }\n       }\n\n       switch(requestCode)\n       {\n           case 0:\n               scan(this.requestArgs);\n               break;\n       }\n   }\n\n    /**\n     * This plugin launches an external Activity when the camera is opened, so we\n     * need to implement the save/restore API in case the Activity gets killed\n     * by the OS while it's in the background.\n     */\n    public void onRestoreStateForActivityResult(Bundle state, CallbackContext callbackContext) {\n        this.callbackContext = callbackContext;\n    }\n\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n-------------------------------------------------------\n*JNEXT (v1.0.8.3)\n\n                          MOZILLA PUBLIC LICENSE\n                                Version 1.1\n\n                              ---------------\n\n1. Definitions.\n\n     1.0.1. \"Commercial Use\" means distribution or otherwise making the\n     Covered Code available to a third party.\n\n     1.1. \"Contributor\" means each entity that creates or contributes to\n     the creation of Modifications.\n\n     1.2. \"Contributor Version\" means the combination of the Original\n     Code, prior Modifications used by a Contributor, and the Modifications\n     made by that particular Contributor.\n\n     1.3. \"Covered Code\" means the Original Code or Modifications or the\n     combination of the Original Code and Modifications, in each case\n     including portions thereof.\n\n     1.4. \"Electronic Distribution Mechanism\" means a mechanism generally\n     accepted in the software development community for the electronic\n     transfer of data.\n\n     1.5. \"Executable\" means Covered Code in any form other than Source\n     Code.\n\n     1.6. \"Initial Developer\" means the individual or entity identified\n     as the Initial Developer in the Source Code notice required by Exhibit\n     A.\n\n     1.7. \"Larger Work\" means a work which combines Covered Code or\n     portions thereof with code not governed by the terms of this License.\n\n     1.8. \"License\" means this document.\n\n     1.8.1. \"Licensable\" means having the right to grant, to the maximum\n     extent possible, whether at the time of the initial grant or\n     subsequently acquired, any and all of the rights conveyed herein.\n\n     1.9. \"Modifications\" means any addition to or deletion from the\n     substance or structure of either the Original Code or any previous\n     Modifications. When Covered Code is released as a series of files, a\n     Modification is:\n          A. Any addition to or deletion from the contents of a file\n          containing Original Code or previous Modifications.\n\n          B. Any new file that contains any part of the Original Code or\n          previous Modifications.\n\n     1.10. \"Original Code\" means Source Code of computer software code\n     which is described in the Source Code notice required by Exhibit A as\n     Original Code, and which, at the time of its release under this\n     License is not already Covered Code governed by this License.\n\n     1.10.1. \"Patent Claims\" means any patent claim(s), now owned or\n     hereafter acquired, including without limitation,  method, process,\n     and apparatus claims, in any patent Licensable by grantor.\n\n     1.11. \"Source Code\" means the preferred form of the Covered Code for\n     making modifications to it, including all modules it contains, plus\n     any associated interface definition files, scripts used to control\n     compilation and installation of an Executable, or source code\n     differential comparisons against either the Original Code or another\n     well known, available Covered Code of the Contributor's choice. The\n     Source Code can be in a compressed or archival form, provided the\n     appropriate decompression or de-archiving software is widely available\n     for no charge.\n\n     1.12. \"You\" (or \"Your\")  means an individual or a legal entity\n     exercising rights under, and complying with all of the terms of, this\n     License or a future version of this License issued under Section 6.1.\n     For legal entities, \"You\" includes any entity which controls, is\n     controlled by, or is under common control with You. For purposes of\n     this definition, \"control\" means (a) the power, direct or indirect,\n     to cause the direction or management of such entity, whether by\n     contract or otherwise, or (b) ownership of more than fifty percent\n     (50%) of the outstanding shares or beneficial ownership of such\n     entity.\n\n2. Source Code License.\n\n     2.1. The Initial Developer Grant.\n     The Initial Developer hereby grants You a world-wide, royalty-free,\n     non-exclusive license, subject to third party intellectual property\n     claims:\n          (a)  under intellectual property rights (other than patent or\n          trademark) Licensable by Initial Developer to use, reproduce,\n          modify, display, perform, sublicense and distribute the Original\n          Code (or portions thereof) with or without Modifications, and/or\n          as part of a Larger Work; and\n\n          (b) under Patents Claims infringed by the making, using or\n          selling of Original Code, to make, have made, use, practice,\n          sell, and offer for sale, and/or otherwise dispose of the\n          Original Code (or portions thereof).\n\n          (c) the licenses granted in this Section 2.1(a) and (b) are\n          effective on the date Initial Developer first distributes\n          Original Code under the terms of this License.\n\n          (d) Notwithstanding Section 2.1(b) above, no patent license is\n          granted: 1) for code that You delete from the Original Code; 2)\n          separate from the Original Code;  or 3) for infringements caused\n          by: i) the modification of the Original Code or ii) the\n          combination of the Original Code with other software or devices.\n\n     2.2. Contributor Grant.\n     Subject to third party intellectual property claims, each Contributor\n     hereby grants You a world-wide, royalty-free, non-exclusive license\n\n          (a)  under intellectual property rights (other than patent or\n          trademark) Licensable by Contributor, to use, reproduce, modify,\n          display, perform, sublicense and distribute the Modifications\n          created by such Contributor (or portions thereof) either on an\n          unmodified basis, with other Modifications, as Covered Code\n          and/or as part of a Larger Work; and\n\n          (b) under Patent Claims infringed by the making, using, or\n          selling of  Modifications made by that Contributor either alone\n          and/or in combination with its Contributor Version (or portions\n          of such combination), to make, use, sell, offer for sale, have\n          made, and/or otherwise dispose of: 1) Modifications made by that\n          Contributor (or portions thereof); and 2) the combination of\n          Modifications made by that Contributor with its Contributor\n          Version (or portions of such combination).\n\n          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are\n          effective on the date Contributor first makes Commercial Use of\n          the Covered Code.\n\n          (d)    Notwithstanding Section 2.2(b) above, no patent license is\n          granted: 1) for any code that Contributor has deleted from the\n          Contributor Version; 2)  separate from the Contributor Version;\n          3)  for infringements caused by: i) third party modifications of\n          Contributor Version or ii)  the combination of Modifications made\n          by that Contributor with other software  (except as part of the\n          Contributor Version) or other devices; or 4) under Patent Claims\n          infringed by Covered Code in the absence of Modifications made by\n          that Contributor.\n\n3. Distribution Obligations.\n\n     3.1. Application of License.\n     The Modifications which You create or to which You contribute are\n     governed by the terms of this License, including without limitation\n     Section 2.2. The Source Code version of Covered Code may be\n     distributed only under the terms of this License or a future version\n     of this License released under Section 6.1, and You must include a\n     copy of this License with every copy of the Source Code You\n     distribute. You may not offer or impose any terms on any Source Code\n     version that alters or restricts the applicable version of this\n     License or the recipients' rights hereunder. However, You may include\n     an additional document offering the additional rights described in\n     Section 3.5.\n\n     3.2. Availability of Source Code.\n     Any Modification which You create or to which You contribute must be\n     made available in Source Code form under the terms of this License\n     either on the same media as an Executable version or via an accepted\n     Electronic Distribution Mechanism to anyone to whom you made an\n     Executable version available; and if made available via Electronic\n     Distribution Mechanism, must remain available for at least twelve (12)\n     months after the date it initially became available, or at least six\n     (6) months after a subsequent version of that particular Modification\n     has been made available to such recipients. You are responsible for\n     ensuring that the Source Code version remains available even if the\n     Electronic Distribution Mechanism is maintained by a third party.\n\n     3.3. Description of Modifications.\n     You must cause all Covered Code to which You contribute to contain a\n     file documenting the changes You made to create that Covered Code and\n     the date of any change. You must include a prominent statement that\n     the Modification is derived, directly or indirectly, from Original\n     Code provided by the Initial Developer and including the name of the\n     Initial Developer in (a) the Source Code, and (b) in any notice in an\n     Executable version or related documentation in which You describe the\n     origin or ownership of the Covered Code.\n\n     3.4. Intellectual Property Matters\n          (a) Third Party Claims.\n          If Contributor has knowledge that a license under a third party's\n          intellectual property rights is required to exercise the rights\n          granted by such Contributor under Sections 2.1 or 2.2,\n          Contributor must include a text file with the Source Code\n          distribution titled \"LEGAL\" which describes the claim and the\n          party making the claim in sufficient detail that a recipient will\n          know whom to contact. If Contributor obtains such knowledge after\n          the Modification is made available as described in Section 3.2,\n          Contributor shall promptly modify the LEGAL file in all copies\n          Contributor makes available thereafter and shall take other steps\n          (such as notifying appropriate mailing lists or newsgroups)\n          reasonably calculated to inform those who received the Covered\n          Code that new knowledge has been obtained.\n\n          (b) Contributor APIs.\n          If Contributor's Modifications include an application programming\n          interface and Contributor has knowledge of patent licenses which\n          are reasonably necessary to implement that API, Contributor must\n          also include this information in the LEGAL file.\n\n               (c)    Representations.\n          Contributor represents that, except as disclosed pursuant to\n          Section 3.4(a) above, Contributor believes that Contributor's\n          Modifications are Contributor's original creation(s) and/or\n          Contributor has sufficient rights to grant the rights conveyed by\n          this License.\n\n     3.5. Required Notices.\n     You must duplicate the notice in Exhibit A in each file of the Source\n     Code.  If it is not possible to put such notice in a particular Source\n     Code file due to its structure, then You must include such notice in a\n     location (such as a relevant directory) where a user would be likely\n     to look for such a notice.  If You created one or more Modification(s)\n     You may add your name as a Contributor to the notice described in\n     Exhibit A.  You must also duplicate this License in any documentation\n     for the Source Code where You describe recipients' rights or ownership\n     rights relating to Covered Code.  You may choose to offer, and to\n     charge a fee for, warranty, support, indemnity or liability\n     obligations to one or more recipients of Covered Code. However, You\n     may do so only on Your own behalf, and not on behalf of the Initial\n     Developer or any Contributor. You must make it absolutely clear than\n     any such warranty, support, indemnity or liability obligation is\n     offered by You alone, and You hereby agree to indemnify the Initial\n     Developer and every Contributor for any liability incurred by the\n     Initial Developer or such Contributor as a result of warranty,\n     support, indemnity or liability terms You offer.\n\n     3.6. Distribution of Executable Versions.\n     You may distribute Covered Code in Executable form only if the\n     requirements of Section 3.1-3.5 have been met for that Covered Code,\n     and if You include a notice stating that the Source Code version of\n     the Covered Code is available under the terms of this License,\n     including a description of how and where You have fulfilled the\n     obligations of Section 3.2. The notice must be conspicuously included\n     in any notice in an Executable version, related documentation or\n     collateral in which You describe recipients' rights relating to the\n     Covered Code. You may distribute the Executable version of Covered\n     Code or ownership rights under a license of Your choice, which may\n     contain terms different from this License, provided that You are in\n     compliance with the terms of this License and that the license for the\n     Executable version does not attempt to limit or alter the recipient's\n     rights in the Source Code version from the rights set forth in this\n     License. If You distribute the Executable version under a different\n     license You must make it absolutely clear that any terms which differ\n     from this License are offered by You alone, not by the Initial\n     Developer or any Contributor. You hereby agree to indemnify the\n     Initial Developer and every Contributor for any liability incurred by\n     the Initial Developer or such Contributor as a result of any such\n     terms You offer.\n\n     3.7. Larger Works.\n     You may create a Larger Work by combining Covered Code with other code\n     not governed by the terms of this License and distribute the Larger\n     Work as a single product. In such a case, You must make sure the\n     requirements of this License are fulfilled for the Covered Code.\n\n4. Inability to Comply Due to Statute or Regulation.\n\n     If it is impossible for You to comply with any of the terms of this\n     License with respect to some or all of the Covered Code due to\n     statute, judicial order, or regulation then You must: (a) comply with\n     the terms of this License to the maximum extent possible; and (b)\n     describe the limitations and the code they affect. Such description\n     must be included in the LEGAL file described in Section 3.4 and must\n     be included with all distributions of the Source Code. Except to the\n     extent prohibited by statute or regulation, such description must be\n     sufficiently detailed for a recipient of ordinary skill to be able to\n     understand it.\n\n5. Application of this License.\n\n     This License applies to code to which the Initial Developer has\n     attached the notice in Exhibit A and to related Covered Code.\n\n6. Versions of the License.\n\n     6.1. New Versions.\n     Netscape Communications Corporation (\"Netscape\") may publish revised\n     and/or new versions of the License from time to time. Each version\n     will be given a distinguishing version number.\n\n     6.2. Effect of New Versions.\n     Once Covered Code has been published under a particular version of the\n     License, You may always continue to use it under the terms of that\n     version. You may also choose to use such Covered Code under the terms\n     of any subsequent version of the License published by Netscape. No one\n     other than Netscape has the right to modify the terms applicable to\n     Covered Code created under this License.\n\n     6.3. Derivative Works.\n     If You create or use a modified version of this License (which you may\n     only do in order to apply it to code which is not already Covered Code\n     governed by this License), You must (a) rename Your license so that\n     the phrases \"Mozilla\", \"MOZILLAPL\", \"MOZPL\", \"Netscape\",\n     \"MPL\", \"NPL\" or any confusingly similar phrase do not appear in your\n     license (except to note that your license differs from this License)\n     and (b) otherwise make it clear that Your version of the license\n     contains terms which differ from the Mozilla Public License and\n     Netscape Public License. (Filling in the name of the Initial\n     Developer, Original Code or Contributor in the notice described in\n     Exhibit A shall not of themselves be deemed to be modifications of\n     this License.)\n\n7. DISCLAIMER OF WARRANTY.\n\n     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN \"AS IS\" BASIS,\n     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,\n     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF\n     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.\n     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE\n     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,\n     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE\n     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER\n     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF\n     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.\n\n8. TERMINATION.\n\n     8.1.  This License and the rights granted hereunder will terminate\n     automatically if You fail to comply with terms herein and fail to cure\n     such breach within 30 days of becoming aware of the breach. All\n     sublicenses to the Covered Code which are properly granted shall\n     survive any termination of this License. Provisions which, by their\n     nature, must remain in effect beyond the termination of this License\n     shall survive.\n\n     8.2.  If You initiate litigation by asserting a patent infringement\n     claim (excluding declatory judgment actions) against Initial Developer\n     or a Contributor (the Initial Developer or Contributor against whom\n     You file such action is referred to as \"Participant\")  alleging that:\n\n     (a)  such Participant's Contributor Version directly or indirectly\n     infringes any patent, then any and all rights granted by such\n     Participant to You under Sections 2.1 and/or 2.2 of this License\n     shall, upon 60 days notice from Participant terminate prospectively,\n     unless if within 60 days after receipt of notice You either: (i)\n     agree in writing to pay Participant a mutually agreeable reasonable\n     royalty for Your past and future use of Modifications made by such\n     Participant, or (ii) withdraw Your litigation claim with respect to\n     the Contributor Version against such Participant.  If within 60 days\n     of notice, a reasonable royalty and payment arrangement are not\n     mutually agreed upon in writing by the parties or the litigation claim\n     is not withdrawn, the rights granted by Participant to You under\n     Sections 2.1 and/or 2.2 automatically terminate at the expiration of\n     the 60 day notice period specified above.\n\n     (b)  any software, hardware, or device, other than such Participant's\n     Contributor Version, directly or indirectly infringes any patent, then\n     any rights granted to You by such Participant under Sections 2.1(b)\n     and 2.2(b) are revoked effective as of the date You first made, used,\n     sold, distributed, or had made, Modifications made by that\n     Participant.\n\n     8.3.  If You assert a patent infringement claim against Participant\n     alleging that such Participant's Contributor Version directly or\n     indirectly infringes any patent where such claim is resolved (such as\n     by license or settlement) prior to the initiation of patent\n     infringement litigation, then the reasonable value of the licenses\n     granted by such Participant under Sections 2.1 or 2.2 shall be taken\n     into account in determining the amount or value of any payment or\n     license.\n\n     8.4.  In the event of termination under Sections 8.1 or 8.2 above,\n     all end user license agreements (excluding distributors and resellers)\n     which have been validly granted by You or any distributor hereunder\n     prior to termination shall survive termination.\n\n9. LIMITATION OF LIABILITY.\n\n     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT\n     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL\n     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,\n     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR\n     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY\n     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,\n     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER\n     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN\n     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF\n     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY\n     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW\n     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE\n     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO\n     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.\n\n10. U.S. GOVERNMENT END USERS.\n\n     The Covered Code is a \"commercial item,\" as that term is defined in\n     48 C.F.R. 2.101 (Oct. 1995), consisting of \"commercial computer\n     software\" and \"commercial computer software documentation,\" as such\n     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48\n     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),\n     all U.S. Government End Users acquire Covered Code with only those\n     rights set forth herein.\n\n11. MISCELLANEOUS.\n\n     This License represents the complete agreement concerning subject\n     matter hereof. If any provision of this License is held to be\n     unenforceable, such provision shall be reformed only to the extent\n     necessary to make it enforceable. This License shall be governed by\n     California law provisions (except to the extent applicable law, if\n     any, provides otherwise), excluding its conflict-of-law provisions.\n     With respect to disputes in which at least one party is a citizen of,\n     or an entity chartered or registered to do business in the United\n     States of America, any litigation relating to this License shall be\n     subject to the jurisdiction of the Federal Courts of the Northern\n     District of California, with venue lying in Santa Clara County,\n     California, with the losing party responsible for costs, including\n     without limitation, court costs and reasonable attorneys' fees and\n     expenses. The application of the United Nations Convention on\n     Contracts for the International Sale of Goods is expressly excluded.\n     Any law or regulation which provides that the language of a contract\n     shall be construed against the drafter shall not apply to this\n     License.\n\n12. RESPONSIBILITY FOR CLAIMS.\n\n     As between Initial Developer and the Contributors, each party is\n     responsible for claims and damages arising, directly or indirectly,\n     out of its utilization of rights under this License and You agree to\n     work with Initial Developer and Contributors to distribute such\n     responsibility on an equitable basis. Nothing herein is intended or\n     shall be deemed to constitute any admission of liability.\n\n13. MULTIPLE-LICENSED CODE.\n\n     Initial Developer may designate portions of the Covered Code as\n     \"Multiple-Licensed\".  \"Multiple-Licensed\" means that the Initial\n     Developer permits you to utilize portions of the Covered Code under\n     Your choice of the NPL or the alternative licenses, if any, specified\n     by the Initial Developer in the file described in Exhibit A.\n\nEXHIBIT A -Mozilla Public License.\n\n     ``The contents of this file are subject to the Mozilla Public License\n     Version 1.1 (the \"License\"); you may not use this file except in\n     compliance with the License. You may obtain a copy of the License at\n     http://www.mozilla.org/MPL/\n\n     Software distributed under the License is distributed on an \"AS IS\"\n     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the\n     License for the specific language governing rights and limitations\n     under the License.\n\n     The Original Code is ______________________________________.\n\n     The Initial Developer of the Original Code is ________________________.\n     Portions created by ______________________ are Copyright (C) ______\n     _______________________. All Rights Reserved.\n\n     Contributor(s): ______________________________________.\n\n     Alternatively, the contents of this file may be used under the terms\n     of the _____ license (the  \"[___] License\"), in which case the\n     provisions of [______] License are applicable instead of those\n     above.  If you wish to allow use of your version of this file only\n     under the terms of the [____] License and not to allow others to use\n     your version of this file under the MPL, indicate your decision by\n     deleting  the provisions above and replace  them with the notice and\n     other provisions required by the [___] License.  If you do not delete\n     the provisions above, a recipient may use your version of this file\n     under either the MPL or the [___] License.\"\n\n     [NOTE: The text of this Exhibit A may differ slightly from the text of\n     the notices in the Source Code files of the Original Code. You should\n     use the text of this Exhibit A rather than the text found in the\n     Original Code Source Code for Your Modifications.]\n\n-------------------------------------------------------\n\n* Tokenizer\n/************************************************************************\nThe zlib/libpng License\n\nCopyright (c) 2006 Joerg Wiedenmann\n\nThis software is provided 'as-is', without any express or implied warranty.\nIn no event will the authors be held liable for any damages arising from\nthe use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented;\n  you must not claim that you wrote the original software.\n  If you use this software in a product, an acknowledgment\n  in the product documentation would be appreciated but is\n  not required.\n\n2. Altered source versions must be plainly marked as such,\n  and must not be misrepresented as being the original software.\n\n3. This notice may not be removed or altered from any source distribution.\n\n***********************************************************************/"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/index.js",
    "content": "/*\n* Copyright 2013-2015 BlackBerry Limited.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\nvar barcodescanner,\n\tresultObjs = {},\n\treadCallback,\n\t_utils = require(\"../../lib/utils\"),\n\t_qr = require('plugin/BarcodeScanner/qrcode.js');\n\nconst SMS_URI_ONE = \"smsto:\",\n\t  SMS_URI_TWO = \"sms:\",\n\t  EMAIL_URI = \"mailto:\",\n\t  PHONE_URI = \"tel:+1\",\n\t  SMS_TYPE = \"SMS_TYPE\",\n\t  PHONE_TYPE = \"PHONE_TYPE\",\n\t  EMAIL_TYPE = \"EMAIL_TYPE\",\n\t  TEXT_TYPE = \"TEXT_TYPE\";\n\nmodule.exports = {\n\n\t// methods to start and stop scanning\n\tscan: function (success, fail, args, env) {\n\t\tvar result = new PluginResult(args, env);\n\t\tresultObjs[result.callbackId] = result;\n\t\treadCallback = result.callbackId;\n\t\tvar views = qnx.webplatform.getWebViews();\n\t\tvar handle = null;\n\t\tvar group = null;\n\t\tvar z = -1;\n\t\tfor (var i = 0; i < views.length; i++) {\n\t\t\tif (views[i].visible && views[i].zOrder > z){\n\t\t\t\tz = views[i].zOrder;\n\t\t\t\tgroup = views[i].windowGroup;\n\t\t\t\thandle = views[i].jsScreenWindowHandle;\n\t\t\t}\n\t\t}\n\t\tif (handle !== null) {\n\t\t\tvar values = { group: group, handle: handle };\n\t\t\tbarcodescanner.getInstance().startRead(result.callbackId, values);\n\t\t\tresult.noResult(true);\n\t\t} else {\n\t\t\tresult.error(\"Failed to find window handle\", false);\n\t\t}\n\t},\n\n\t/*\n\tMethod for barcode encoding. Returns base 64 image URI \n\tCurrently only creates QRcodes\n\t*/\n\tencode: function (success, fail, args, env) {\n\t\t\n\t\tvar result = new PluginResult(args, env);\n\t\tvalues = decodeURIComponent(args[0]);\n\t\tvalues = JSON.parse(values);\n\t\tdata = values[\"data\"];\n\t\ttype = values[\"type\"];\n\t\n\t\tif(data == \"\" || data == undefined){\n\t\t\tresult.error(\"Data to be encoded was not specified\", false);\n\t\t\treturn;\n\t\t}\n\t\tif(type == \"\" || type == undefined){\n\t\t\ttype = TEXT_TYPE;\n\t\t}\n\n\t\tif(type == SMS_TYPE){\n\t\t\tvar check_one = data.substring(0,6).toLowerCase();\n\t\t\tvar check_two = data.substring(0,4).toLowerCase();\n\t\t\tif(!(check_one == SMS_URI_ONE || check_two == SMS_URI_TWO)){\n\t\t\t\tdata = SMS_URI_ONE+data;\n\t\t\t} \n\t\t}else if(type == EMAIL_TYPE){\n\t\t\tvar check = data.substring(0,7).toLowerCase();\n\t\t\tif(check != EMAIL_URI){\n\t\t\t\tdata = EMAIL_URI+data;\n\t\t\t} \n\t\t}else if(type == PHONE_TYPE){\n\t\t\tvar check = data.substring(0,4).toLowerCase();\n\t\t\tif(check != PHONE_URI){\n\t\t\t\tdata = PHONE_URI+data;\n\t\t\t} \n\t\t}\n\n\t\tconsole.log(\"Type: \"+type + \" Data: \" + data);\n\n\t\t//Make QRcode using qrcode.js \n\t\tvar bdiv = document.createElement('div');\n\t\tvar options = {\n\t    \ttext: data,\n\t   \t\twidth: 256,\n\t    \theight: 256,\n\t    \tcolorDark : \"#000000\",\n\t    \tcolorLight : \"#ffffff\",\n\t\t};\n\n\t\tvar imageURI = _qr.makeQRcode(bdiv, options);\n\n\t\ttry{\n\t\t\tresult.ok(imageURI,false);\n\t\t}catch(e){\n\t\t\tresult.error(\"Failed to encode barcode\", false);\n\t\t}\n\t}\n};\n\n\nJNEXT.BarcodeScanner = function () {\n\tvar self = this,\n\t\thasInstance = false;\n\n\tself.getId = function () {\n\t\treturn self.m_id;\n\t};\n\n\tself.init = function () {\n\t\tif (!JNEXT.require(\"libBarcodeScanner\")) {\n\t\t\treturn false;\n\t\t}\n\n\t\tself.m_id = JNEXT.createObject(\"libBarcodeScanner.BarcodeScannerJS\");\n\n\t\tif (self.m_id === \"\") {\n\t\t\treturn false;\n\t\t}\n\n\t\tJNEXT.registerEvents(self);\n\t};\n\n\t// ************************\n\t// Enter your methods here\n\t// ************************\n\n\t// Fired by the Event framework (used by asynchronous callbacks)\n\n\tself.onEvent = function (strData) {\n\t\tvar arData = strData.split(\" \"),\n\t\t\tcallbackId = arData[0],\n\t\t\treceivedEvent = arData[1],\n\t\t\tdata = arData[2],\n\t\t\tresult = resultObjs[callbackId],\n\t\t\tevents = [\"community.barcodescanner.codefound.native\",\n\t\t\t\t\t  \"community.barcodescanner.errorfound.native\",\n\t\t\t\t\t  \"community.barcodescanner.started.native\",\n\t\t\t\t\t  \"community.barcodescanner.ended.native\"];\n\t\t\t\n\t\t// Restructures results when codefound has spaces\t\t  \n\t\tif(arData.length > 3){\n\t\t\tvar i;\n\t\t\tfor(i=3; i<arData.length; i++) {\n\t\t\t\tdata += \" \" + arData[i];\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (receivedEvent == \"community.barcodescanner.codefound.native\") {\n\t\t\tif (result) {\n\t\t\t\tvar parsed = JSON.parse(data);\n\t\t\t\tresult.callbackOk(parsed, false);\n\t\t\t}\n\t\t\tthis.stopRead(callbackId);\n\n\t\t}\n\t\tif (receivedEvent == \"community.barcodescanner.started.native\") {\n\t\t\tconsole.log(\"Scanning started successfully\");\n\t\t}\n\t\tif (receivedEvent == \"community.barcodescanner.errorfound.native\") {\n\t\t\tif (result) {\n\t\t\t\tresult.callbackError(data, false);\n\t\t\t}\n\t\t}\n\n\t\tif(receivedEvent == \"community.barcodescanner.ended.native\" || receivedEvent == \"community.barcodescanner.errorfound.native\") {\n\t\t\tdelete resultObjs[readCallback];\n\t\t\treadCallback = null;\n\t\t}\n\n\t};\n\n\t// Thread methods\n\tself.startRead = function (callbackId, handle) {\n\t\treturn JNEXT.invoke(self.m_id, \"startRead \" + callbackId + \" \" + JSON.stringify(handle));\n\t};\n\tself.stopRead = function (callbackId) {\n\t\treturn JNEXT.invoke(self.m_id, \"stopRead \" + callbackId);\n\t};\n\n\t// ************************\n\t// End of methods to edit\n\t// ************************\n\tself.m_id = \"\";\n\n\tself.getInstance = function () {\n\t\tif (!hasInstance) {\n\t\t\thasInstance = true;\n\t\t\tself.init();\n\t\t}\n\t\treturn self;\n\t};\n\n};\n\nbarcodescanner = new JNEXT.BarcodeScanner();"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/.cproject",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<?fileVersion 4.0.0?><cproject storage_type_id=\"org.eclipse.cdt.core.XmlProjectDescriptionStorage\">\n\t<storageModule moduleId=\"org.eclipse.cdt.core.settings\">\n\t\t<cconfiguration id=\"com.qnx.qcc.configuration.sharedLib.release.608922875.1009704567\">\n\t\t\t<storageModule buildSystemId=\"org.eclipse.cdt.managedbuilder.core.configurationDataProvider\" id=\"com.qnx.qcc.configuration.sharedLib.release.608922875.1009704567\" moduleId=\"org.eclipse.cdt.core.settings\" name=\"device\">\n\t\t\t\t<externalSettings/>\n\t\t\t\t<extensions>\n\t\t\t\t\t<extension id=\"com.qnx.tools.ide.qde.core.QDELinkerErrorParser\" point=\"org.eclipse.cdt.core.ErrorParser\"/>\n\t\t\t\t\t<extension id=\"org.eclipse.cdt.core.GCCErrorParser\" point=\"org.eclipse.cdt.core.ErrorParser\"/>\n\t\t\t\t\t<extension id=\"org.eclipse.cdt.core.GLDErrorParser\" point=\"org.eclipse.cdt.core.ErrorParser\"/>\n\t\t\t\t\t<extension id=\"com.qnx.tools.ide.qde.core.QDEBynaryParser\" point=\"org.eclipse.cdt.core.BinaryParser\"/>\n\t\t\t\t</extensions>\n\t\t\t</storageModule>\n\t\t\t<storageModule moduleId=\"cdtBuildSystem\" version=\"4.0.0\">\n\t\t\t\t<configuration artifactExtension=\"so\" artifactName=\"${ProjName}\" buildArtefactType=\"org.eclipse.cdt.build.core.buildArtefactType.sharedLib\" buildProperties=\"org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.sharedLib\" description=\"\" errorParsers=\"com.qnx.tools.ide.qde.core.QDELinkerErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GLDErrorParser\" id=\"com.qnx.qcc.configuration.sharedLib.release.608922875.1009704567\" name=\"device\" parent=\"com.qnx.qcc.configuration.sharedLib.release\" postannouncebuildStep=\"\" postbuildStep=\"\" preannouncebuildStep=\"\" prebuildStep=\"\">\n\t\t\t\t\t<folderInfo id=\"com.qnx.qcc.configuration.sharedLib.release.608922875.1009704567.\" name=\"/\" resourcePath=\"\">\n\t\t\t\t\t\t<toolChain errorParsers=\"\" id=\"com.qnx.qcc.toolChain.2215983\" name=\"QNX QCC\" superClass=\"com.qnx.qcc.toolChain\">\n\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.cpu.315540759\" name=\"Target CPU:\" superClass=\"com.qnx.qcc.option.cpu\" value=\"com.qnx.qcc.option.gen.cpu.armle-v7\" valueType=\"enumerated\"/>\n\t\t\t\t\t\t\t<targetPlatform archList=\"all\" binaryParser=\"com.qnx.tools.ide.qde.core.QDEBynaryParser\" id=\"com.qnx.qcc.targetPlatform.1359109141\" osList=\"all\" superClass=\"com.qnx.qcc.targetPlatform\"/>\n\t\t\t\t\t\t\t<builder buildPath=\"${workspace_loc:/Template/Device-Release}\" errorParsers=\"\" id=\"com.qnx.nto.938326560\" keepEnvironmentInBuildfile=\"false\" name=\"CDT Internal Builder\" superClass=\"com.qnx.nto\"/>\n\t\t\t\t\t\t\t<tool command=\"qcc\" commandLinePattern=\"${COMMAND}  ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS} ${FLAGS}\" errorParsers=\"org.eclipse.cdt.core.GCCErrorParser\" id=\"com.qnx.qcc.tool.compiler.242697771\" name=\"QCC Compiler\" superClass=\"com.qnx.qcc.tool.compiler\">\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.compiler.shared.553244928\" name=\"Shared (-shared)\" superClass=\"com.qnx.qcc.option.compiler.shared\" value=\"true\" valueType=\"boolean\"/>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.compiler.optlevel.2070537906\" name=\"Optimization Level\" superClass=\"com.qnx.qcc.option.compiler.optlevel\" value=\"com.qnx.qcc.option.compiler.optlevel.2\" valueType=\"enumerated\"/>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.compiler.includePath.1483355415\" name=\"Include Directories (-I)\" superClass=\"com.qnx.qcc.option.compiler.includePath\" valueType=\"includePath\">\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"${QNX_TARGET}/usr/include/img\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"${workspace_loc:/${ProjName}/public}\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"${QNX_TARGET}/usr/include/freetype2\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"${QNX_TARGET}/../target-override/usr/include\"/>\n\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.compiler.security.9625963\" name=\"Enhanced Security (-fstack-protector-strong)\" superClass=\"com.qnx.qcc.option.compiler.security\" value=\"true\" valueType=\"boolean\"/>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.compiler.defines.872099896\" name=\"Defines (-D)\" superClass=\"com.qnx.qcc.option.compiler.defines\" valueType=\"definedSymbols\">\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"_FORTIFY_SOURCE=2\"/>\n\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.compiler.qccoptions.1015003128\" name=\"QCC Options\" superClass=\"com.qnx.qcc.option.compiler.qccoptions\" valueType=\"stringList\">\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"-frecord-gcc-switches\"/>\n\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.compiler.warningLevel.331428330\" name=\"Warning Level (-w)\" superClass=\"com.qnx.qcc.option.compiler.warningLevel\" value=\"com.qnx.qcc.option.warningLevel.9\" valueType=\"enumerated\"/>\n\t\t\t\t\t\t\t\t<inputType id=\"com.qnx.qcc.inputType.compiler.1443568066\" superClass=\"com.qnx.qcc.inputType.compiler\"/>\n\t\t\t\t\t\t\t</tool>\n\t\t\t\t\t\t\t<tool command=\"qcc\" commandLinePattern=\"${COMMAND}  ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS} ${FLAGS}\" errorParsers=\"\" id=\"com.qnx.qcc.tool.assembler.1996828008\" name=\"QCC Assembler\" superClass=\"com.qnx.qcc.tool.assembler\">\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.assembler.warningLevel.1519589523\" name=\"Warning Level (-w)\" superClass=\"com.qnx.qcc.option.assembler.warningLevel\" value=\"com.qnx.qcc.option.warningLevel.9\" valueType=\"enumerated\"/>\n\t\t\t\t\t\t\t\t<inputType id=\"com.qnx.qcc.inputType.assembler.116798417\" superClass=\"com.qnx.qcc.inputType.assembler\"/>\n\t\t\t\t\t\t\t</tool>\n\t\t\t\t\t\t\t<tool command=\"qcc\" commandLinePattern=\"${COMMAND}  ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS} ${FLAGS}\" errorParsers=\"com.qnx.tools.ide.qde.core.QDELinkerErrorParser;org.eclipse.cdt.core.GLDErrorParser\" id=\"com.qnx.qcc.tool.linker.871546588\" name=\"QCC Linker\" superClass=\"com.qnx.qcc.tool.linker\">\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.linker.shared.915102752\" name=\"Shared (-shared)\" superClass=\"com.qnx.qcc.option.linker.shared\" value=\"true\" valueType=\"boolean\"/>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.linker.libraryPaths.1049529253\" name=\"Library Paths (-L)\" superClass=\"com.qnx.qcc.option.linker.libraryPaths\" valueType=\"libPaths\">\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"${QNX_TARGET}/../target-override/${CPUVARDIR}/lib\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"${QNX_TARGET}/../target-override/${CPUVARDIR}/usr/lib\"/>\n\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.linker.security.1157664997\" name=\"Enhanced Security (-Wl,-z,relro -Wl,-z,now)\" superClass=\"com.qnx.qcc.option.linker.security\" value=\"true\" valueType=\"boolean\"/>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.linker.libraries.1316432206\" name=\"Libraries (-l)\" superClass=\"com.qnx.qcc.option.linker.libraries\" valueType=\"libs\">\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"camapi\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"zxing\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"img\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"slog2\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"bps\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"screen\"/>\n\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.linker.warningLevel.2067914469\" name=\"Warning Level (-w)\" superClass=\"com.qnx.qcc.option.linker.warningLevel\" value=\"com.qnx.qcc.option.warningLevel.9\" valueType=\"enumerated\"/>\n\t\t\t\t\t\t\t\t<inputType id=\"com.qnx.qcc.inputType.linker.1028572887\" superClass=\"com.qnx.qcc.inputType.linker\">\n\t\t\t\t\t\t\t\t\t<additionalInput kind=\"additionalinputdependency\" paths=\"$(USER_OBJS)\"/>\n\t\t\t\t\t\t\t\t\t<additionalInput kind=\"additionalinput\" paths=\"$(LIBS)\"/>\n\t\t\t\t\t\t\t\t</inputType>\n\t\t\t\t\t\t\t</tool>\n\t\t\t\t\t\t\t<tool id=\"com.qnx.qcc.tool.archiver.1781914947\" name=\"QCC Archiver\" superClass=\"com.qnx.qcc.tool.archiver\"/>\n\t\t\t\t\t\t</toolChain>\n\t\t\t\t\t</folderInfo>\n\t\t\t\t\t<sourceEntries>\n\t\t\t\t\t\t<entry flags=\"VALUE_WORKSPACE_PATH|RESOLVED\" kind=\"sourcePath\" name=\"src\"/>\n\t\t\t\t\t\t<entry flags=\"VALUE_WORKSPACE_PATH|RESOLVED\" kind=\"sourcePath\" name=\"public\"/>\n\t\t\t\t\t</sourceEntries>\n\t\t\t\t</configuration>\n\t\t\t</storageModule>\n\t\t\t<storageModule moduleId=\"org.eclipse.cdt.core.externalSettings\"/>\n\t\t</cconfiguration>\n\t\t<cconfiguration id=\"com.qnx.qcc.configuration.sharedLib.debug.193597202.362186091\">\n\t\t\t<storageModule buildSystemId=\"org.eclipse.cdt.managedbuilder.core.configurationDataProvider\" id=\"com.qnx.qcc.configuration.sharedLib.debug.193597202.362186091\" moduleId=\"org.eclipse.cdt.core.settings\" name=\"simulator\">\n\t\t\t\t<externalSettings/>\n\t\t\t\t<extensions>\n\t\t\t\t\t<extension id=\"com.qnx.tools.ide.qde.core.QDELinkerErrorParser\" point=\"org.eclipse.cdt.core.ErrorParser\"/>\n\t\t\t\t\t<extension id=\"org.eclipse.cdt.core.GCCErrorParser\" point=\"org.eclipse.cdt.core.ErrorParser\"/>\n\t\t\t\t\t<extension id=\"org.eclipse.cdt.core.GLDErrorParser\" point=\"org.eclipse.cdt.core.ErrorParser\"/>\n\t\t\t\t\t<extension id=\"com.qnx.tools.ide.qde.core.QDEBynaryParser\" point=\"org.eclipse.cdt.core.BinaryParser\"/>\n\t\t\t\t</extensions>\n\t\t\t</storageModule>\n\t\t\t<storageModule moduleId=\"cdtBuildSystem\" version=\"4.0.0\">\n\t\t\t\t<configuration artifactExtension=\"so\" artifactName=\"${ProjName}\" buildArtefactType=\"org.eclipse.cdt.build.core.buildArtefactType.sharedLib\" buildProperties=\"org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.sharedLib\" description=\"\" id=\"com.qnx.qcc.configuration.sharedLib.debug.193597202.362186091\" name=\"simulator\" parent=\"com.qnx.qcc.configuration.sharedLib.debug\">\n\t\t\t\t\t<folderInfo id=\"com.qnx.qcc.configuration.sharedLib.debug.193597202.362186091.\" name=\"/\" resourcePath=\"\">\n\t\t\t\t\t\t<toolChain id=\"com.qnx.qcc.toolChain.688026907\" name=\"QNX QCC\" superClass=\"com.qnx.qcc.toolChain\">\n\t\t\t\t\t\t\t<targetPlatform archList=\"all\" binaryParser=\"com.qnx.tools.ide.qde.core.QDEBynaryParser\" id=\"com.qnx.qcc.targetPlatform.469207190\" osList=\"all\" superClass=\"com.qnx.qcc.targetPlatform\"/>\n\t\t\t\t\t\t\t<builder buildPath=\"${workspace_loc:/Template/Simulator-Debug}\" id=\"com.qnx.nto.2029800497\" keepEnvironmentInBuildfile=\"false\" name=\"CDT Internal Builder\" superClass=\"com.qnx.nto\"/>\n\t\t\t\t\t\t\t<tool id=\"com.qnx.qcc.tool.compiler.1028279123\" name=\"QCC Compiler\" superClass=\"com.qnx.qcc.tool.compiler\">\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.compiler.shared.235893159\" name=\"Shared (-shared)\" superClass=\"com.qnx.qcc.option.compiler.shared\" value=\"true\" valueType=\"boolean\"/>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.compiler.optlevel.1164238904\" name=\"Optimization Level\" superClass=\"com.qnx.qcc.option.compiler.optlevel\" value=\"com.qnx.qcc.option.compiler.optlevel.0\" valueType=\"enumerated\"/>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.compile.debug.3716470\" name=\"Debug (-g)\" superClass=\"com.qnx.qcc.option.compile.debug\" value=\"true\" valueType=\"boolean\"/>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.compiler.includePath.306305432\" name=\"Include Directories (-I)\" superClass=\"com.qnx.qcc.option.compiler.includePath\" valueType=\"includePath\">\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"${QNX_TARGET}/usr/include/img\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"${workspace_loc:/${ProjName}/public}\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"${QNX_TARGET}/usr/include/freetype2\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"${QNX_TARGET}/../target-override/usr/include\"/>\n\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.compiler.security.1730007887\" name=\"Enhanced Security (-fstack-protector-strong)\" superClass=\"com.qnx.qcc.option.compiler.security\" value=\"true\" valueType=\"boolean\"/>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.compiler.defines.1526896965\" name=\"Defines (-D)\" superClass=\"com.qnx.qcc.option.compiler.defines\" valueType=\"definedSymbols\">\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"_FORTIFY_SOURCE=2\"/>\n\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t<inputType id=\"com.qnx.qcc.inputType.compiler.1881183122\" superClass=\"com.qnx.qcc.inputType.compiler\"/>\n\t\t\t\t\t\t\t</tool>\n\t\t\t\t\t\t\t<tool id=\"com.qnx.qcc.tool.assembler.312168125\" name=\"QCC Assembler\" superClass=\"com.qnx.qcc.tool.assembler\">\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.assembler.debug.416544277\" name=\"Debug (-g)\" superClass=\"com.qnx.qcc.option.assembler.debug\" value=\"true\" valueType=\"boolean\"/>\n\t\t\t\t\t\t\t\t<inputType id=\"com.qnx.qcc.inputType.assembler.1722778407\" superClass=\"com.qnx.qcc.inputType.assembler\"/>\n\t\t\t\t\t\t\t</tool>\n\t\t\t\t\t\t\t<tool id=\"com.qnx.qcc.tool.linker.2130364088\" name=\"QCC Linker\" superClass=\"com.qnx.qcc.tool.linker\">\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.linker.debug.1332880614\" name=\"Debug (-g)\" superClass=\"com.qnx.qcc.option.linker.debug\" value=\"true\" valueType=\"boolean\"/>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.linker.shared.1633267255\" name=\"Shared (-shared)\" superClass=\"com.qnx.qcc.option.linker.shared\" value=\"true\" valueType=\"boolean\"/>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.linker.libraryPaths.565794953\" name=\"Library Paths (-L)\" superClass=\"com.qnx.qcc.option.linker.libraryPaths\" valueType=\"libPaths\">\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"${QNX_TARGET}/../target-override/${CPUVARDIR}/lib\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"${QNX_TARGET}/../target-override/${CPUVARDIR}/usr/lib\"/>\n\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.linker.security.9141791\" name=\"Enhanced Security (-Wl,-z,relro -Wl,-z,now)\" superClass=\"com.qnx.qcc.option.linker.security\" value=\"true\" valueType=\"boolean\"/>\n\t\t\t\t\t\t\t\t<option id=\"com.qnx.qcc.option.linker.libraries.220836649\" name=\"Libraries (-l)\" superClass=\"com.qnx.qcc.option.linker.libraries\" valueType=\"libs\">\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"zxing\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"camapi\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"img\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"slog2\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"bps\"/>\n\t\t\t\t\t\t\t\t\t<listOptionValue builtIn=\"false\" value=\"screen\"/>\n\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t<inputType id=\"com.qnx.qcc.inputType.linker.167117375\" superClass=\"com.qnx.qcc.inputType.linker\">\n\t\t\t\t\t\t\t\t\t<additionalInput kind=\"additionalinputdependency\" paths=\"$(USER_OBJS)\"/>\n\t\t\t\t\t\t\t\t\t<additionalInput kind=\"additionalinput\" paths=\"$(LIBS)\"/>\n\t\t\t\t\t\t\t\t</inputType>\n\t\t\t\t\t\t\t</tool>\n\t\t\t\t\t\t\t<tool id=\"com.qnx.qcc.tool.archiver.489682882\" name=\"QCC Archiver\" superClass=\"com.qnx.qcc.tool.archiver\"/>\n\t\t\t\t\t\t</toolChain>\n\t\t\t\t\t</folderInfo>\n\t\t\t\t\t<sourceEntries>\n\t\t\t\t\t\t<entry flags=\"VALUE_WORKSPACE_PATH|RESOLVED\" kind=\"sourcePath\" name=\"src\"/>\n\t\t\t\t\t\t<entry flags=\"VALUE_WORKSPACE_PATH|RESOLVED\" kind=\"sourcePath\" name=\"public\"/>\n\t\t\t\t\t</sourceEntries>\n\t\t\t\t</configuration>\n\t\t\t</storageModule>\n\t\t\t<storageModule moduleId=\"org.eclipse.cdt.core.externalSettings\"/>\n\t\t</cconfiguration>\n\t</storageModule>\n\t<storageModule moduleId=\"cdtBuildSystem\" version=\"4.0.0\">\n\t\t<project id=\"BarcodeScanner.null.629823540\" name=\"BarcodeScanner\"/>\n\t</storageModule>\n\t<storageModule moduleId=\"refreshScope\" versionNumber=\"2\">\n\t\t<configuration configurationName=\"Simulator-Profile\">\n\t\t\t<resource resourceType=\"PROJECT\" workspacePath=\"/BarcodeScanner\"/>\n\t\t</configuration>\n\t\t<configuration configurationName=\"Device-Profile\">\n\t\t\t<resource resourceType=\"PROJECT\" workspacePath=\"/BarcodeScanner\"/>\n\t\t</configuration>\n\t\t<configuration configurationName=\"Simulator-Coverage\">\n\t\t\t<resource resourceType=\"PROJECT\" workspacePath=\"/BarcodeScanner\"/>\n\t\t</configuration>\n\t\t<configuration configurationName=\"Device-Debug\">\n\t\t\t<resource resourceType=\"PROJECT\" workspacePath=\"/BarcodeScanner\"/>\n\t\t</configuration>\n\t\t<configuration configurationName=\"simulator\"/>\n\t\t<configuration configurationName=\"Simulator-Debug\">\n\t\t\t<resource resourceType=\"PROJECT\" workspacePath=\"/BarcodeScanner\"/>\n\t\t</configuration>\n\t\t<configuration configurationName=\"device\"/>\n\t\t<configuration configurationName=\"Device-Release\">\n\t\t\t<resource resourceType=\"PROJECT\" workspacePath=\"/BarcodeScanner\"/>\n\t\t</configuration>\n\t\t<configuration configurationName=\"Device-Coverage\">\n\t\t\t<resource resourceType=\"PROJECT\" workspacePath=\"/BarcodeScanner\"/>\n\t\t</configuration>\n\t</storageModule>\n\t<storageModule moduleId=\"org.eclipse.cdt.core.LanguageSettingsProviders\"/>\n\t<storageModule moduleId=\"scannerConfiguration\">\n\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.coverage.1963950149\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.profile.1521124627\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.profile.1662874485\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.release.1167756743\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.coverage.1920932411\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.release.274485450\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.debug.823677416\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.debug.606841429\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.profile.783070498\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.coverage.89043708\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.profile.815111702\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.debug.1815235065\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.debug.2137677126\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t\t<scannerConfigBuildInfo instanceId=\"com.qnx.qcc.configuration.sharedLib.coverage.1030515335\">\n\t\t\t<autodiscovery enabled=\"true\" problemReportingEnabled=\"true\" selectedProfileId=\"com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo\"/>\n\t\t</scannerConfigBuildInfo>\n\t</storageModule>\n\t<storageModule moduleId=\"org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings\"/>\n</cproject>\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/.settings/com.qnx.tools.ide.core.prefs",
    "content": "QNX_CURRENT_INSTALL=BlackBerry Native SDK 10.2\neclipse.preferences.version=1\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/device/.npmignore",
    "content": "/src\n/public\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/autolink.h",
    "content": "#ifndef JSON_AUTOLINK_H_INCLUDED\n# define JSON_AUTOLINK_H_INCLUDED\n\n# include \"config.h\"\n\n# ifdef JSON_IN_CPPTL\n#  include <cpptl/cpptl_autolink.h>\n# endif\n\n# if !defined(JSON_NO_AUTOLINK)  &&  !defined(JSON_DLL_BUILD)  &&  !defined(JSON_IN_CPPTL)\n#  define CPPTL_AUTOLINK_NAME \"json\"\n#  undef CPPTL_AUTOLINK_DLL\n#  ifdef JSON_DLL\n#   define CPPTL_AUTOLINK_DLL\n#  endif\n#  include \"autolink.h\"\n# endif\n\n#endif // JSON_AUTOLINK_H_INCLUDED\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/config.h",
    "content": "#ifndef JSON_CONFIG_H_INCLUDED\n# define JSON_CONFIG_H_INCLUDED\n\n/// If defined, indicates that json library is embedded in CppTL library.\n//# define JSON_IN_CPPTL 1\n\n/// If defined, indicates that json may leverage CppTL library\n//#  define JSON_USE_CPPTL 1\n/// If defined, indicates that cpptl vector based map should be used instead of std::map\n/// as Value container.\n//#  define JSON_USE_CPPTL_SMALLMAP 1\n/// If defined, indicates that Json specific container should be used\n/// (hash table & simple deque container with customizable allocator).\n/// THIS FEATURE IS STILL EXPERIMENTAL!\n//#  define JSON_VALUE_USE_INTERNAL_MAP 1\n/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.\n/// The memory pools allocator used optimization (initializing Value and ValueInternalLink\n/// as if it was a POD) that may cause some validation tool to report errors.\n/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.\n//#  define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1\n\n/// If defined, indicates that Json use exception to report invalid type manipulation\n/// instead of C assert macro.\n# define JSON_USE_EXCEPTION 1\n\n# ifdef JSON_IN_CPPTL\n#  include <cpptl/config.h>\n#  ifndef JSON_USE_CPPTL\n#   define JSON_USE_CPPTL 1\n#  endif\n# endif\n\n# ifdef JSON_IN_CPPTL\n#  define JSON_API CPPTL_API\n# elif defined(JSON_DLL_BUILD)\n#  define JSON_API __declspec(dllexport)\n# elif defined(JSON_DLL)\n#  define JSON_API __declspec(dllimport)\n# else\n#  define JSON_API\n# endif\n\n#endif // JSON_CONFIG_H_INCLUDED\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/features.h",
    "content": "#ifndef CPPTL_JSON_FEATURES_H_INCLUDED\n# define CPPTL_JSON_FEATURES_H_INCLUDED\n\n# include \"forwards.h\"\n\nnamespace Json {\n\n   /** \\brief Configuration passed to reader and writer.\n    * This configuration object can be used to force the Reader or Writer\n    * to behave in a standard conforming way.\n    */\n   class JSON_API Features\n   {\n   public:\n      /** \\brief A configuration that allows all features and assumes all strings are UTF-8.\n       * - C & C++ comments are allowed\n       * - Root object can be any JSON value\n       * - Assumes Value strings are encoded in UTF-8\n       */\n      static Features all();\n\n      /** \\brief A configuration that is strictly compatible with the JSON specification.\n       * - Comments are forbidden.\n       * - Root object must be either an array or an object value.\n       * - Assumes Value strings are encoded in UTF-8\n       */\n      static Features strictMode();\n\n      /** \\brief Initialize the configuration like JsonConfig::allFeatures;\n       */\n      Features();\n\n      /// \\c true if comments are allowed. Default: \\c true.\n      bool allowComments_;\n\n      /// \\c true if root must be either an array or an object value. Default: \\c false.\n      bool strictRoot_;\n   };\n\n} // namespace Json\n\n#endif // CPPTL_JSON_FEATURES_H_INCLUDED\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/forwards.h",
    "content": "#ifndef JSON_FORWARDS_H_INCLUDED\n# define JSON_FORWARDS_H_INCLUDED\n\n# include \"config.h\"\n\nnamespace Json {\n\n   // writer.h\n   class FastWriter;\n   class StyledWriter;\n\n   // reader.h\n   class Reader;\n\n   // features.h\n   class Features;\n\n   // value.h\n   typedef int Int;\n   typedef unsigned int UInt;\n   class StaticString;\n   class Path;\n   class PathArgument;\n   class Value;\n   class ValueIteratorBase;\n   class ValueIterator;\n   class ValueConstIterator;\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n   class ValueAllocator;\n   class ValueMapAllocator;\n   class ValueInternalLink;\n   class ValueInternalArray;\n   class ValueInternalMap;\n#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP\n\n} // namespace Json\n\n\n#endif // JSON_FORWARDS_H_INCLUDED\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/json.h",
    "content": "#ifndef JSON_JSON_H_INCLUDED\n# define JSON_JSON_H_INCLUDED\n\n# include \"autolink.h\"\n# include \"value.h\"\n# include \"reader.h\"\n# include \"writer.h\"\n# include \"features.h\"\n\n#endif // JSON_JSON_H_INCLUDED\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/reader.h",
    "content": "#ifndef CPPTL_JSON_READER_H_INCLUDED\n# define CPPTL_JSON_READER_H_INCLUDED\n\n# include \"features.h\"\n# include \"value.h\"\n# include <deque>\n# include <stack>\n# include <string>\n# include <iostream>\n\nnamespace Json {\n\n   /** \\brief Unserialize a <a HREF=\"http://www.json.org\">JSON</a> document into a Value.\n    *\n    */\n   class JSON_API Reader\n   {\n   public:\n      typedef char Char;\n      typedef const Char *Location;\n\n      /** \\brief Constructs a Reader allowing all features\n       * for parsing.\n       */\n      Reader();\n\n      /** \\brief Constructs a Reader allowing the specified feature set\n       * for parsing.\n       */\n      Reader( const Features &features );\n\n      /** \\brief Read a Value from a <a HREF=\"http://www.json.org\">JSON</a> document.\n       * \\param document UTF-8 encoded string containing the document to read.\n       * \\param root [out] Contains the root value of the document if it was\n       *             successfully parsed.\n       * \\param collectComments \\c true to collect comment and allow writing them back during\n       *                        serialization, \\c false to discard comments.\n       *                        This parameter is ignored if Features::allowComments_\n       *                        is \\c false.\n       * \\return \\c true if the document was successfully parsed, \\c false if an error occurred.\n       */\n      bool parse( const std::string &document, \n                  Value &root,\n                  bool collectComments = true );\n\n      /** \\brief Read a Value from a <a HREF=\"http://www.json.org\">JSON</a> document.\n       * \\param document UTF-8 encoded string containing the document to read.\n       * \\param root [out] Contains the root value of the document if it was\n       *             successfully parsed.\n       * \\param collectComments \\c true to collect comment and allow writing them back during\n       *                        serialization, \\c false to discard comments.\n       *                        This parameter is ignored if Features::allowComments_\n       *                        is \\c false.\n       * \\return \\c true if the document was successfully parsed, \\c false if an error occurred.\n       */\n      bool parse( const char *beginDoc, const char *endDoc, \n                  Value &root,\n                  bool collectComments = true );\n\n      /// \\brief Parse from input stream.\n      /// \\see Json::operator>>(std::istream&, Json::Value&).\n      bool parse( std::istream &is,\n                  Value &root,\n                  bool collectComments = true );\n\n      /** \\brief Returns a user friendly string that list errors in the parsed document.\n       * \\return Formatted error message with the list of errors with their location in \n       *         the parsed document. An empty string is returned if no error occurred\n       *         during parsing.\n       */\n      std::string getFormatedErrorMessages() const;\n\n   private:\n      enum TokenType\n      {\n         tokenEndOfStream = 0,\n         tokenObjectBegin,\n         tokenObjectEnd,\n         tokenArrayBegin,\n         tokenArrayEnd,\n         tokenString,\n         tokenNumber,\n         tokenTrue,\n         tokenFalse,\n         tokenNull,\n         tokenArraySeparator,\n         tokenMemberSeparator,\n         tokenComment,\n         tokenError\n      };\n\n      class Token\n      {\n      public:\n         TokenType type_;\n         Location start_;\n         Location end_;\n      };\n\n      class ErrorInfo\n      {\n      public:\n         Token token_;\n         std::string message_;\n         Location extra_;\n      };\n\n      typedef std::deque<ErrorInfo> Errors;\n\n      bool expectToken( TokenType type, Token &token, const char *message );\n      bool readToken( Token &token );\n      void skipSpaces();\n      bool match( Location pattern, \n                  int patternLength );\n      bool readComment();\n      bool readCStyleComment();\n      bool readCppStyleComment();\n      bool readString();\n      void readNumber();\n      bool readValue();\n      bool readObject( Token &token );\n      bool readArray( Token &token );\n      bool decodeNumber( Token &token );\n      bool decodeString( Token &token );\n      bool decodeString( Token &token, std::string &decoded );\n      bool decodeDouble( Token &token );\n      bool decodeUnicodeCodePoint( Token &token, \n                                   Location &current, \n                                   Location end, \n                                   unsigned int &unicode );\n      bool decodeUnicodeEscapeSequence( Token &token, \n                                        Location &current, \n                                        Location end, \n                                        unsigned int &unicode );\n      bool addError( const std::string &message, \n                     Token &token,\n                     Location extra = 0 );\n      bool recoverFromError( TokenType skipUntilToken );\n      bool addErrorAndRecover( const std::string &message, \n                               Token &token,\n                               TokenType skipUntilToken );\n      void skipUntilSpace();\n      Value &currentValue();\n      Char getNextChar();\n      void getLocationLineAndColumn( Location location,\n                                     int &line,\n                                     int &column ) const;\n      std::string getLocationLineAndColumn( Location location ) const;\n      void addComment( Location begin, \n                       Location end, \n                       CommentPlacement placement );\n      void skipCommentTokens( Token &token );\n   \n      typedef std::stack<Value *> Nodes;\n      Nodes nodes_;\n      Errors errors_;\n      std::string document_;\n      Location begin_;\n      Location end_;\n      Location current_;\n      Location lastValueEnd_;\n      Value *lastValue_;\n      std::string commentsBefore_;\n      Features features_;\n      bool collectComments_;\n   };\n\n   /** \\brief Read from 'sin' into 'root'.\n\n    Always keep comments from the input JSON.\n\n    This can be used to read a file into a particular sub-object.\n    For example:\n    \\code\n    Json::Value root;\n    cin >> root[\"dir\"][\"file\"];\n    cout << root;\n    \\endcode\n    Result:\n    \\verbatim\n    {\n\t\"dir\": {\n\t    \"file\": {\n\t\t// The input stream JSON would be nested here.\n\t    }\n\t}\n    }\n    \\endverbatim\n    \\throw std::exception on parse error.\n    \\see Json::operator<<()\n   */\n   std::istream& operator>>( std::istream&, Value& );\n\n} // namespace Json\n\n#endif // CPPTL_JSON_READER_H_INCLUDED\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/value.h",
    "content": "#ifndef CPPTL_JSON_H_INCLUDED\n# define CPPTL_JSON_H_INCLUDED\n\n# include \"forwards.h\"\n# include <string>\n# include <vector>\n\n# ifndef JSON_USE_CPPTL_SMALLMAP\n#  include <map>\n# else\n#  include <cpptl/smallmap.h>\n# endif\n# ifdef JSON_USE_CPPTL\n#  include <cpptl/forwards.h>\n# endif\n\n/** \\brief JSON (JavaScript Object Notation).\n */\nnamespace Json {\n\n   /** \\brief Type of the value held by a Value object.\n    */\n   enum ValueType\n   {\n      nullValue = 0, ///< 'null' value\n      intValue,      ///< signed integer value\n      uintValue,     ///< unsigned integer value\n      realValue,     ///< double value\n      stringValue,   ///< UTF-8 string value\n      booleanValue,  ///< bool value\n      arrayValue,    ///< array value (ordered list)\n      objectValue    ///< object value (collection of name/value pairs).\n   };\n\n   enum CommentPlacement\n   {\n      commentBefore = 0,        ///< a comment placed on the line before a value\n      commentAfterOnSameLine,   ///< a comment just after a value on the same line\n      commentAfter,             ///< a comment on the line after a value (only make sense for root value)\n      numberOfCommentPlacement\n   };\n\n//# ifdef JSON_USE_CPPTL\n//   typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;\n//   typedef CppTL::AnyEnumerator<const Value &> EnumValues;\n//# endif\n\n   /** \\brief Lightweight wrapper to tag static string.\n    *\n    * Value constructor and objectValue member assignement takes advantage of the\n    * StaticString and avoid the cost of string duplication when storing the\n    * string or the member name.\n    *\n    * Example of usage:\n    * \\code\n    * Json::Value aValue( StaticString(\"some text\") );\n    * Json::Value object;\n    * static const StaticString code(\"code\");\n    * object[code] = 1234;\n    * \\endcode\n    */\n   class JSON_API StaticString\n   {\n   public:\n      explicit StaticString( const char *czstring )\n         : str_( czstring )\n      {\n      }\n\n      operator const char *() const\n      {\n         return str_;\n      }\n\n      const char *c_str() const\n      {\n         return str_;\n      }\n\n   private:\n      const char *str_;\n   };\n\n   /** \\brief Represents a <a HREF=\"http://www.json.org\">JSON</a> value.\n    *\n    * This class is a discriminated union wrapper that can represents a:\n    * - signed integer [range: Value::minInt - Value::maxInt]\n    * - unsigned integer (range: 0 - Value::maxUInt)\n    * - double\n    * - UTF-8 string\n    * - boolean\n    * - 'null'\n    * - an ordered list of Value\n    * - collection of name/value pairs (javascript object)\n    *\n    * The type of the held value is represented by a #ValueType and \n    * can be obtained using type().\n    *\n    * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. \n    * Non const methods will automatically create the a #nullValue element \n    * if it does not exist. \n    * The sequence of an #arrayValue will be automatically resize and initialized \n    * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.\n    *\n    * The get() methods can be used to obtanis default value in the case the required element\n    * does not exist.\n    *\n    * It is possible to iterate over the list of a #objectValue values using \n    * the getMemberNames() method.\n    */\n   class JSON_API Value \n   {\n      friend class ValueIteratorBase;\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n      friend class ValueInternalLink;\n      friend class ValueInternalMap;\n# endif\n   public:\n      typedef std::vector<std::string> Members;\n      typedef ValueIterator iterator;\n      typedef ValueConstIterator const_iterator;\n      typedef Json::UInt UInt;\n      typedef Json::Int Int;\n      typedef UInt ArrayIndex;\n\n      static const Value null;\n      static const Int minInt;\n      static const Int maxInt;\n      static const UInt maxUInt;\n\n   private:\n#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n# ifndef JSON_VALUE_USE_INTERNAL_MAP\n      class CZString \n      {\n      public:\n         enum DuplicationPolicy \n         {\n            noDuplication = 0,\n            duplicate,\n            duplicateOnCopy\n         };\n         CZString( int index );\n         CZString( const char *cstr, DuplicationPolicy allocate );\n         CZString( const CZString &other );\n         ~CZString();\n         CZString &operator =( const CZString &other );\n         bool operator<( const CZString &other ) const;\n         bool operator==( const CZString &other ) const;\n         int index() const;\n         const char *c_str() const;\n         bool isStaticString() const;\n      private:\n         void swap( CZString &other );\n         const char *cstr_;\n         int index_;\n      };\n\n   public:\n#  ifndef JSON_USE_CPPTL_SMALLMAP\n      typedef std::map<CZString, Value> ObjectValues;\n#  else\n      typedef CppTL::SmallMap<CZString, Value> ObjectValues;\n#  endif // ifndef JSON_USE_CPPTL_SMALLMAP\n# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP\n#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n\n   public:\n      /** \\brief Create a default Value of the given type.\n\n        This is a very useful constructor.\n        To create an empty array, pass arrayValue.\n        To create an empty object, pass objectValue.\n        Another Value can then be set to this one by assignment.\n\tThis is useful since clear() and resize() will not alter types.\n\n        Examples:\n\t\\code\n\tJson::Value null_value; // null\n\tJson::Value arr_value(Json::arrayValue); // []\n\tJson::Value obj_value(Json::objectValue); // {}\n\t\\endcode\n      */\n      Value( ValueType type = nullValue );\n      Value( Int value );\n      Value( UInt value );\n      Value( double value );\n      Value( const char *value );\n      Value( const char *beginValue, const char *endValue );\n      /** \\brief Constructs a value from a static string.\n\n       * Like other value string constructor but do not duplicate the string for\n       * internal storage. The given string must remain alive after the call to this\n       * constructor.\n       * Example of usage:\n       * \\code\n       * Json::Value aValue( StaticString(\"some text\") );\n       * \\endcode\n       */\n      Value( const StaticString &value );\n      Value( const std::string &value );\n# ifdef JSON_USE_CPPTL\n      Value( const CppTL::ConstString &value );\n# endif\n      Value( bool value );\n      Value( const Value &other );\n      ~Value();\n\n      Value &operator=( const Value &other );\n      /// Swap values.\n      /// \\note Currently, comments are intentionally not swapped, for\n      /// both logic and efficiency.\n      void swap( Value &other );\n\n      ValueType type() const;\n\n      bool operator <( const Value &other ) const;\n      bool operator <=( const Value &other ) const;\n      bool operator >=( const Value &other ) const;\n      bool operator >( const Value &other ) const;\n\n      bool operator ==( const Value &other ) const;\n      bool operator !=( const Value &other ) const;\n\n      int compare( const Value &other );\n\n      const char *asCString() const;\n      std::string asString() const;\n# ifdef JSON_USE_CPPTL\n      CppTL::ConstString asConstString() const;\n# endif\n      Int asInt() const;\n      UInt asUInt() const;\n      double asDouble() const;\n      bool asBool() const;\n\n      bool isNull() const;\n      bool isBool() const;\n      bool isInt() const;\n      bool isUInt() const;\n      bool isIntegral() const;\n      bool isDouble() const;\n      bool isNumeric() const;\n      bool isString() const;\n      bool isArray() const;\n      bool isObject() const;\n\n      bool isConvertibleTo( ValueType other ) const;\n\n      /// Number of values in array or object\n      UInt size() const;\n\n      /// \\brief Return true if empty array, empty object, or null;\n      /// otherwise, false.\n      bool empty() const;\n\n      /// Return isNull()\n      bool operator!() const;\n\n      /// Remove all object members and array elements.\n      /// \\pre type() is arrayValue, objectValue, or nullValue\n      /// \\post type() is unchanged\n      void clear();\n\n      /// Resize the array to size elements. \n      /// New elements are initialized to null.\n      /// May only be called on nullValue or arrayValue.\n      /// \\pre type() is arrayValue or nullValue\n      /// \\post type() is arrayValue\n      void resize( UInt size );\n\n      /// Access an array element (zero based index ).\n      /// If the array contains less than index element, then null value are inserted\n      /// in the array so that its size is index+1.\n      /// (You may need to say 'value[0u]' to get your compiler to distinguish\n      ///  this from the operator[] which takes a string.)\n      Value &operator[]( UInt index );\n      /// Access an array element (zero based index )\n      /// (You may need to say 'value[0u]' to get your compiler to distinguish\n      ///  this from the operator[] which takes a string.)\n      const Value &operator[]( UInt index ) const;\n      /// If the array contains at least index+1 elements, returns the element value, \n      /// otherwise returns defaultValue.\n      Value get( UInt index, \n                 const Value &defaultValue ) const;\n      /// Return true if index < size().\n      bool isValidIndex( UInt index ) const;\n      /// \\brief Append value to array at the end.\n      ///\n      /// Equivalent to jsonvalue[jsonvalue.size()] = value;\n      Value &append( const Value &value );\n\n      /// Access an object value by name, create a null member if it does not exist.\n      Value &operator[]( const char *key );\n      /// Access an object value by name, returns null if there is no member with that name.\n      const Value &operator[]( const char *key ) const;\n      /// Access an object value by name, create a null member if it does not exist.\n      Value &operator[]( const std::string &key );\n      /// Access an object value by name, returns null if there is no member with that name.\n      const Value &operator[]( const std::string &key ) const;\n      /** \\brief Access an object value by name, create a null member if it does not exist.\n\n       * If the object as no entry for that name, then the member name used to store\n       * the new entry is not duplicated.\n       * Example of use:\n       * \\code\n       * Json::Value object;\n       * static const StaticString code(\"code\");\n       * object[code] = 1234;\n       * \\endcode\n       */\n      Value &operator[]( const StaticString &key );\n# ifdef JSON_USE_CPPTL\n      /// Access an object value by name, create a null member if it does not exist.\n      Value &operator[]( const CppTL::ConstString &key );\n      /// Access an object value by name, returns null if there is no member with that name.\n      const Value &operator[]( const CppTL::ConstString &key ) const;\n# endif\n      /// Return the member named key if it exist, defaultValue otherwise.\n      Value get( const char *key, \n                 const Value &defaultValue ) const;\n      /// Return the member named key if it exist, defaultValue otherwise.\n      Value get( const std::string &key,\n                 const Value &defaultValue ) const;\n# ifdef JSON_USE_CPPTL\n      /// Return the member named key if it exist, defaultValue otherwise.\n      Value get( const CppTL::ConstString &key,\n                 const Value &defaultValue ) const;\n# endif\n      /// \\brief Remove and return the named member.  \n      ///\n      /// Do nothing if it did not exist.\n      /// \\return the removed Value, or null.\n      /// \\pre type() is objectValue or nullValue\n      /// \\post type() is unchanged\n      Value removeMember( const char* key );\n      /// Same as removeMember(const char*)\n      Value removeMember( const std::string &key );\n\n      /// Return true if the object has a member named key.\n      bool isMember( const char *key ) const;\n      /// Return true if the object has a member named key.\n      bool isMember( const std::string &key ) const;\n# ifdef JSON_USE_CPPTL\n      /// Return true if the object has a member named key.\n      bool isMember( const CppTL::ConstString &key ) const;\n# endif\n\n      /// \\brief Return a list of the member names.\n      ///\n      /// If null, return an empty list.\n      /// \\pre type() is objectValue or nullValue\n      /// \\post if type() was nullValue, it remains nullValue\n      Members getMemberNames() const;\n\n//# ifdef JSON_USE_CPPTL\n//      EnumMemberNames enumMemberNames() const;\n//      EnumValues enumValues() const;\n//# endif\n\n      /// Comments must be //... or /* ... */\n      void setComment( const char *comment,\n                       CommentPlacement placement );\n      /// Comments must be //... or /* ... */\n      void setComment( const std::string &comment,\n                       CommentPlacement placement );\n      bool hasComment( CommentPlacement placement ) const;\n      /// Include delimiters and embedded newlines.\n      std::string getComment( CommentPlacement placement ) const;\n\n      std::string toStyledString() const;\n\n      const_iterator begin() const;\n      const_iterator end() const;\n\n      iterator begin();\n      iterator end();\n\n   private:\n      Value &resolveReference( const char *key, \n                               bool isStatic );\n\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n      inline bool isItemAvailable() const\n      {\n         return itemIsUsed_ == 0;\n      }\n\n      inline void setItemUsed( bool isUsed = true )\n      {\n         itemIsUsed_ = isUsed ? 1 : 0;\n      }\n\n      inline bool isMemberNameStatic() const\n      {\n         return memberNameIsStatic_ == 0;\n      }\n\n      inline void setMemberNameIsStatic( bool isStatic )\n      {\n         memberNameIsStatic_ = isStatic ? 1 : 0;\n      }\n# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP\n\n   private:\n      struct CommentInfo\n      {\n         CommentInfo();\n         ~CommentInfo();\n\n         void setComment( const char *text );\n\n         char *comment_;\n      };\n\n      //struct MemberNamesTransform\n      //{\n      //   typedef const char *result_type;\n      //   const char *operator()( const CZString &name ) const\n      //   {\n      //      return name.c_str();\n      //   }\n      //};\n\n      union ValueHolder\n      {\n         Int int_;\n         UInt uint_;\n         double real_;\n         bool bool_;\n         char *string_;\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n         ValueInternalArray *array_;\n         ValueInternalMap *map_;\n#else\n         ObjectValues *map_;\n# endif\n      } value_;\n      ValueType type_ : 8;\n      int allocated_ : 1;     // Notes: if declared as bool, bitfield is useless.\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n      unsigned int itemIsUsed_ : 1;      // used by the ValueInternalMap container.\n      int memberNameIsStatic_ : 1;       // used by the ValueInternalMap container.\n# endif\n      CommentInfo *comments_;\n   };\n\n\n   /** \\brief Experimental and untested: represents an element of the \"path\" to access a node.\n    */\n   class PathArgument\n   {\n   public:\n      friend class Path;\n\n      PathArgument();\n      PathArgument( UInt index );\n      PathArgument( const char *key );\n      PathArgument( const std::string &key );\n\n   private:\n      enum Kind\n      {\n         kindNone = 0,\n         kindIndex,\n         kindKey\n      };\n      std::string key_;\n      UInt index_;\n      Kind kind_;\n   };\n\n   /** \\brief Experimental and untested: represents a \"path\" to access a node.\n    *\n    * Syntax:\n    * - \".\" => root node\n    * - \".[n]\" => elements at index 'n' of root node (an array value)\n    * - \".name\" => member named 'name' of root node (an object value)\n    * - \".name1.name2.name3\"\n    * - \".[0][1][2].name1[3]\"\n    * - \".%\" => member name is provided as parameter\n    * - \".[%]\" => index is provied as parameter\n    */\n   class Path\n   {\n   public:\n      Path( const std::string &path,\n            const PathArgument &a1 = PathArgument(),\n            const PathArgument &a2 = PathArgument(),\n            const PathArgument &a3 = PathArgument(),\n            const PathArgument &a4 = PathArgument(),\n            const PathArgument &a5 = PathArgument() );\n\n      const Value &resolve( const Value &root ) const;\n      Value resolve( const Value &root, \n                     const Value &defaultValue ) const;\n      /// Creates the \"path\" to access the specified node and returns a reference on the node.\n      Value &make( Value &root ) const;\n\n   private:\n      typedef std::vector<const PathArgument *> InArgs;\n      typedef std::vector<PathArgument> Args;\n\n      void makePath( const std::string &path,\n                     const InArgs &in );\n      void addPathInArg( const std::string &path, \n                         const InArgs &in, \n                         InArgs::const_iterator &itInArg, \n                         PathArgument::Kind kind );\n      void invalidPath( const std::string &path, \n                        int location );\n\n      Args args_;\n   };\n\n   /** \\brief Experimental do not use: Allocator to customize member name and string value memory management done by Value.\n    *\n    * - makeMemberName() and releaseMemberName() are called to respectively duplicate and\n    *   free an Json::objectValue member name.\n    * - duplicateStringValue() and releaseStringValue() are called similarly to\n    *   duplicate and free a Json::stringValue value.\n    */\n   class ValueAllocator\n   {\n   public:\n      enum { unknown = (unsigned)-1 };\n\n      virtual ~ValueAllocator();\n\n      virtual char *makeMemberName( const char *memberName ) = 0;\n      virtual void releaseMemberName( char *memberName ) = 0;\n      virtual char *duplicateStringValue( const char *value, \n                                          unsigned int length = unknown ) = 0;\n      virtual void releaseStringValue( char *value ) = 0;\n   };\n\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n   /** \\brief Allocator to customize Value internal map.\n    * Below is an example of a simple implementation (default implementation actually\n    * use memory pool for speed).\n    * \\code\n      class DefaultValueMapAllocator : public ValueMapAllocator\n      {\n      public: // overridden from ValueMapAllocator\n         virtual ValueInternalMap *newMap()\n         {\n            return new ValueInternalMap();\n         }\n\n         virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )\n         {\n            return new ValueInternalMap( other );\n         }\n\n         virtual void destructMap( ValueInternalMap *map )\n         {\n            delete map;\n         }\n\n         virtual ValueInternalLink *allocateMapBuckets( unsigned int size )\n         {\n            return new ValueInternalLink[size];\n         }\n\n         virtual void releaseMapBuckets( ValueInternalLink *links )\n         {\n            delete [] links;\n         }\n\n         virtual ValueInternalLink *allocateMapLink()\n         {\n            return new ValueInternalLink();\n         }\n\n         virtual void releaseMapLink( ValueInternalLink *link )\n         {\n            delete link;\n         }\n      };\n    * \\endcode\n    */ \n   class JSON_API ValueMapAllocator\n   {\n   public:\n      virtual ~ValueMapAllocator();\n      virtual ValueInternalMap *newMap() = 0;\n      virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0;\n      virtual void destructMap( ValueInternalMap *map ) = 0;\n      virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0;\n      virtual void releaseMapBuckets( ValueInternalLink *links ) = 0;\n      virtual ValueInternalLink *allocateMapLink() = 0;\n      virtual void releaseMapLink( ValueInternalLink *link ) = 0;\n   };\n\n   /** \\brief ValueInternalMap hash-map bucket chain link (for internal use only).\n    * \\internal previous_ & next_ allows for bidirectional traversal.\n    */\n   class JSON_API ValueInternalLink\n   {\n   public:\n      enum { itemPerLink = 6 };  // sizeof(ValueInternalLink) = 128 on 32 bits architecture.\n      enum InternalFlags { \n         flagAvailable = 0,\n         flagUsed = 1\n      };\n\n      ValueInternalLink();\n\n      ~ValueInternalLink();\n\n      Value items_[itemPerLink];\n      char *keys_[itemPerLink];\n      ValueInternalLink *previous_;\n      ValueInternalLink *next_;\n   };\n\n\n   /** \\brief A linked page based hash-table implementation used internally by Value.\n    * \\internal ValueInternalMap is a tradional bucket based hash-table, with a linked\n    * list in each bucket to handle collision. There is an addional twist in that\n    * each node of the collision linked list is a page containing a fixed amount of\n    * value. This provides a better compromise between memory usage and speed.\n    * \n    * Each bucket is made up of a chained list of ValueInternalLink. The last\n    * link of a given bucket can be found in the 'previous_' field of the following bucket.\n    * The last link of the last bucket is stored in tailLink_ as it has no following bucket.\n    * Only the last link of a bucket may contains 'available' item. The last link always\n    * contains at least one element unless is it the bucket one very first link.\n    */\n   class JSON_API ValueInternalMap\n   {\n      friend class ValueIteratorBase;\n      friend class Value;\n   public:\n      typedef unsigned int HashKey;\n      typedef unsigned int BucketIndex;\n\n# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n      struct IteratorState\n      {\n         IteratorState() \n            : map_(0)\n            , link_(0)\n            , itemIndex_(0)\n            , bucketIndex_(0) \n         {\n         }\n         ValueInternalMap *map_;\n         ValueInternalLink *link_;\n         BucketIndex itemIndex_;\n         BucketIndex bucketIndex_;\n      };\n# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n\n      ValueInternalMap();\n      ValueInternalMap( const ValueInternalMap &other );\n      ValueInternalMap &operator =( const ValueInternalMap &other );\n      ~ValueInternalMap();\n\n      void swap( ValueInternalMap &other );\n\n      BucketIndex size() const;\n\n      void clear();\n\n      bool reserveDelta( BucketIndex growth );\n\n      bool reserve( BucketIndex newItemCount );\n\n      const Value *find( const char *key ) const;\n\n      Value *find( const char *key );\n\n      Value &resolveReference( const char *key, \n                               bool isStatic );\n\n      void remove( const char *key );\n\n      void doActualRemove( ValueInternalLink *link, \n                           BucketIndex index,\n                           BucketIndex bucketIndex );\n\n      ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex );\n\n      Value &setNewItem( const char *key, \n                         bool isStatic, \n                         ValueInternalLink *link, \n                         BucketIndex index );\n\n      Value &unsafeAdd( const char *key, \n                        bool isStatic, \n                        HashKey hashedKey );\n\n      HashKey hash( const char *key ) const;\n\n      int compare( const ValueInternalMap &other ) const;\n\n   private:\n      void makeBeginIterator( IteratorState &it ) const;\n      void makeEndIterator( IteratorState &it ) const;\n      static bool equals( const IteratorState &x, const IteratorState &other );\n      static void increment( IteratorState &iterator );\n      static void incrementBucket( IteratorState &iterator );\n      static void decrement( IteratorState &iterator );\n      static const char *key( const IteratorState &iterator );\n      static const char *key( const IteratorState &iterator, bool &isStatic );\n      static Value &value( const IteratorState &iterator );\n      static int distance( const IteratorState &x, const IteratorState &y );\n\n   private:\n      ValueInternalLink *buckets_;\n      ValueInternalLink *tailLink_;\n      BucketIndex bucketsSize_;\n      BucketIndex itemCount_;\n   };\n\n   /** \\brief A simplified deque implementation used internally by Value.\n   * \\internal\n   * It is based on a list of fixed \"page\", each page contains a fixed number of items.\n   * Instead of using a linked-list, a array of pointer is used for fast item look-up.\n   * Look-up for an element is as follow:\n   * - compute page index: pageIndex = itemIndex / itemsPerPage\n   * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]\n   *\n   * Insertion is amortized constant time (only the array containing the index of pointers\n   * need to be reallocated when items are appended).\n   */\n   class JSON_API ValueInternalArray\n   {\n      friend class Value;\n      friend class ValueIteratorBase;\n   public:\n      enum { itemsPerPage = 8 };    // should be a power of 2 for fast divide and modulo.\n      typedef Value::ArrayIndex ArrayIndex;\n      typedef unsigned int PageIndex;\n\n# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n      struct IteratorState // Must be a POD\n      {\n         IteratorState() \n            : array_(0)\n            , currentPageIndex_(0)\n            , currentItemIndex_(0) \n         {\n         }\n         ValueInternalArray *array_;\n         Value **currentPageIndex_;\n         unsigned int currentItemIndex_;\n      };\n# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n\n      ValueInternalArray();\n      ValueInternalArray( const ValueInternalArray &other );\n      ValueInternalArray &operator =( const ValueInternalArray &other );\n      ~ValueInternalArray();\n      void swap( ValueInternalArray &other );\n\n      void clear();\n      void resize( ArrayIndex newSize );\n\n      Value &resolveReference( ArrayIndex index );\n\n      Value *find( ArrayIndex index ) const;\n\n      ArrayIndex size() const;\n\n      int compare( const ValueInternalArray &other ) const;\n\n   private:\n      static bool equals( const IteratorState &x, const IteratorState &other );\n      static void increment( IteratorState &iterator );\n      static void decrement( IteratorState &iterator );\n      static Value &dereference( const IteratorState &iterator );\n      static Value &unsafeDereference( const IteratorState &iterator );\n      static int distance( const IteratorState &x, const IteratorState &y );\n      static ArrayIndex indexOf( const IteratorState &iterator );\n      void makeBeginIterator( IteratorState &it ) const;\n      void makeEndIterator( IteratorState &it ) const;\n      void makeIterator( IteratorState &it, ArrayIndex index ) const;\n\n      void makeIndexValid( ArrayIndex index );\n\n      Value **pages_;\n      ArrayIndex size_;\n      PageIndex pageCount_;\n   };\n\n   /** \\brief Experimental: do not use. Allocator to customize Value internal array.\n    * Below is an example of a simple implementation (actual implementation use\n    * memory pool).\n      \\code\nclass DefaultValueArrayAllocator : public ValueArrayAllocator\n{\npublic: // overridden from ValueArrayAllocator\n   virtual ~DefaultValueArrayAllocator()\n   {\n   }\n\n   virtual ValueInternalArray *newArray()\n   {\n      return new ValueInternalArray();\n   }\n\n   virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )\n   {\n      return new ValueInternalArray( other );\n   }\n\n   virtual void destruct( ValueInternalArray *array )\n   {\n      delete array;\n   }\n\n   virtual void reallocateArrayPageIndex( Value **&indexes, \n                                          ValueInternalArray::PageIndex &indexCount,\n                                          ValueInternalArray::PageIndex minNewIndexCount )\n   {\n      ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;\n      if ( minNewIndexCount > newIndexCount )\n         newIndexCount = minNewIndexCount;\n      void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );\n      if ( !newIndexes )\n         throw std::bad_alloc();\n      indexCount = newIndexCount;\n      indexes = static_cast<Value **>( newIndexes );\n   }\n   virtual void releaseArrayPageIndex( Value **indexes, \n                                       ValueInternalArray::PageIndex indexCount )\n   {\n      if ( indexes )\n         free( indexes );\n   }\n\n   virtual Value *allocateArrayPage()\n   {\n      return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );\n   }\n\n   virtual void releaseArrayPage( Value *value )\n   {\n      if ( value )\n         free( value );\n   }\n};\n      \\endcode\n    */ \n   class JSON_API ValueArrayAllocator\n   {\n   public:\n      virtual ~ValueArrayAllocator();\n      virtual ValueInternalArray *newArray() = 0;\n      virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0;\n      virtual void destructArray( ValueInternalArray *array ) = 0;\n      /** \\brief Reallocate array page index.\n       * Reallocates an array of pointer on each page.\n       * \\param indexes [input] pointer on the current index. May be \\c NULL.\n       *                [output] pointer on the new index of at least \n       *                         \\a minNewIndexCount pages. \n       * \\param indexCount [input] current number of pages in the index.\n       *                   [output] number of page the reallocated index can handle.\n       *                            \\b MUST be >= \\a minNewIndexCount.\n       * \\param minNewIndexCount Minimum number of page the new index must be able to\n       *                         handle.\n       */\n      virtual void reallocateArrayPageIndex( Value **&indexes, \n                                             ValueInternalArray::PageIndex &indexCount,\n                                             ValueInternalArray::PageIndex minNewIndexCount ) = 0;\n      virtual void releaseArrayPageIndex( Value **indexes, \n                                          ValueInternalArray::PageIndex indexCount ) = 0;\n      virtual Value *allocateArrayPage() = 0;\n      virtual void releaseArrayPage( Value *value ) = 0;\n   };\n#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP\n\n\n   /** \\brief base class for Value iterators.\n    *\n    */\n   class ValueIteratorBase\n   {\n   public:\n      typedef unsigned int size_t;\n      typedef int difference_type;\n      typedef ValueIteratorBase SelfType;\n\n      ValueIteratorBase();\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n      explicit ValueIteratorBase( const Value::ObjectValues::iterator &current );\n#else\n      ValueIteratorBase( const ValueInternalArray::IteratorState &state );\n      ValueIteratorBase( const ValueInternalMap::IteratorState &state );\n#endif\n\n      bool operator ==( const SelfType &other ) const\n      {\n         return isEqual( other );\n      }\n\n      bool operator !=( const SelfType &other ) const\n      {\n         return !isEqual( other );\n      }\n\n      difference_type operator -( const SelfType &other ) const\n      {\n         return computeDistance( other );\n      }\n\n      /// Return either the index or the member name of the referenced value as a Value.\n      Value key() const;\n\n      /// Return the index of the referenced Value. -1 if it is not an arrayValue.\n      UInt index() const;\n\n      /// Return the member name of the referenced Value. \"\" if it is not an objectValue.\n      const char *memberName() const;\n\n   protected:\n      Value &deref() const;\n\n      void increment();\n\n      void decrement();\n\n      difference_type computeDistance( const SelfType &other ) const;\n\n      bool isEqual( const SelfType &other ) const;\n\n      void copy( const SelfType &other );\n\n   private:\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n      Value::ObjectValues::iterator current_;\n      // Indicates that iterator is for a null value.\n      bool isNull_;\n#else\n      union\n      {\n         ValueInternalArray::IteratorState array_;\n         ValueInternalMap::IteratorState map_;\n      } iterator_;\n      bool isArray_;\n#endif\n   };\n\n   /** \\brief const iterator for object and array value.\n    *\n    */\n   class ValueConstIterator : public ValueIteratorBase\n   {\n      friend class Value;\n   public:\n      typedef unsigned int size_t;\n      typedef int difference_type;\n      typedef const Value &reference;\n      typedef const Value *pointer;\n      typedef ValueConstIterator SelfType;\n\n      ValueConstIterator();\n   private:\n      /*! \\internal Use by Value to create an iterator.\n       */\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n      explicit ValueConstIterator( const Value::ObjectValues::iterator &current );\n#else\n      ValueConstIterator( const ValueInternalArray::IteratorState &state );\n      ValueConstIterator( const ValueInternalMap::IteratorState &state );\n#endif\n   public:\n      SelfType &operator =( const ValueIteratorBase &other );\n\n      SelfType operator++( int )\n      {\n         SelfType temp( *this );\n         ++*this;\n         return temp;\n      }\n\n      SelfType operator--( int )\n      {\n         SelfType temp( *this );\n         --*this;\n         return temp;\n      }\n\n      SelfType &operator--()\n      {\n         decrement();\n         return *this;\n      }\n\n      SelfType &operator++()\n      {\n         increment();\n         return *this;\n      }\n\n      reference operator *() const\n      {\n         return deref();\n      }\n   };\n\n\n   /** \\brief Iterator for object and array value.\n    */\n   class ValueIterator : public ValueIteratorBase\n   {\n      friend class Value;\n   public:\n      typedef unsigned int size_t;\n      typedef int difference_type;\n      typedef Value &reference;\n      typedef Value *pointer;\n      typedef ValueIterator SelfType;\n\n      ValueIterator();\n      ValueIterator( const ValueConstIterator &other );\n      ValueIterator( const ValueIterator &other );\n   private:\n      /*! \\internal Use by Value to create an iterator.\n       */\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n      explicit ValueIterator( const Value::ObjectValues::iterator &current );\n#else\n      ValueIterator( const ValueInternalArray::IteratorState &state );\n      ValueIterator( const ValueInternalMap::IteratorState &state );\n#endif\n   public:\n\n      SelfType &operator =( const SelfType &other );\n\n      SelfType operator++( int )\n      {\n         SelfType temp( *this );\n         ++*this;\n         return temp;\n      }\n\n      SelfType operator--( int )\n      {\n         SelfType temp( *this );\n         --*this;\n         return temp;\n      }\n\n      SelfType &operator--()\n      {\n         decrement();\n         return *this;\n      }\n\n      SelfType &operator++()\n      {\n         increment();\n         return *this;\n      }\n\n      reference operator *() const\n      {\n         return deref();\n      }\n   };\n\n\n} // namespace Json\n\n\n#endif // CPPTL_JSON_H_INCLUDED\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json/writer.h",
    "content": "#ifndef JSON_WRITER_H_INCLUDED\n# define JSON_WRITER_H_INCLUDED\n\n# include \"value.h\"\n# include <vector>\n# include <string>\n# include <iostream>\n\nnamespace Json {\n\n   class Value;\n\n   /** \\brief Abstract class for writers.\n    */\n   class JSON_API Writer\n   {\n   public:\n      virtual ~Writer();\n\n      virtual std::string write( const Value &root ) = 0;\n   };\n\n   /** \\brief Outputs a Value in <a HREF=\"http://www.json.org\">JSON</a> format without formatting (not human friendly).\n    *\n    * The JSON document is written in a single line. It is not intended for 'human' consumption,\n    * but may be usefull to support feature such as RPC where bandwith is limited.\n    * \\sa Reader, Value\n    */\n   class JSON_API FastWriter : public Writer\n   {\n   public:\n      FastWriter();\n      virtual ~FastWriter(){}\n\n      void enableYAMLCompatibility();\n\n   public: // overridden from Writer\n      virtual std::string write( const Value &root );\n\n   private:\n      void writeValue( const Value &value );\n\n      std::string document_;\n      bool yamlCompatiblityEnabled_;\n   };\n\n   /** \\brief Writes a Value in <a HREF=\"http://www.json.org\">JSON</a> format in a human friendly way.\n    *\n    * The rules for line break and indent are as follow:\n    * - Object value:\n    *     - if empty then print {} without indent and line break\n    *     - if not empty the print '{', line break & indent, print one value per line\n    *       and then unindent and line break and print '}'.\n    * - Array value:\n    *     - if empty then print [] without indent and line break\n    *     - if the array contains no object value, empty array or some other value types,\n    *       and all the values fit on one lines, then print the array on a single line.\n    *     - otherwise, it the values do not fit on one line, or the array contains\n    *       object or non empty array, then print one value per line.\n    *\n    * If the Value have comments then they are outputed according to their #CommentPlacement.\n    *\n    * \\sa Reader, Value, Value::setComment()\n    */\n   class JSON_API StyledWriter: public Writer\n   {\n   public:\n      StyledWriter();\n      virtual ~StyledWriter(){}\n\n   public: // overridden from Writer\n      /** \\brief Serialize a Value in <a HREF=\"http://www.json.org\">JSON</a> format.\n       * \\param root Value to serialize.\n       * \\return String containing the JSON document that represents the root value.\n       */\n      virtual std::string write( const Value &root );\n\n   private:\n      void writeValue( const Value &value );\n      void writeArrayValue( const Value &value );\n      bool isMultineArray( const Value &value );\n      void pushValue( const std::string &value );\n      void writeIndent();\n      void writeWithIndent( const std::string &value );\n      void indent();\n      void unindent();\n      void writeCommentBeforeValue( const Value &root );\n      void writeCommentAfterValueOnSameLine( const Value &root );\n      bool hasCommentForValue( const Value &value );\n      static std::string normalizeEOL( const std::string &text );\n\n      typedef std::vector<std::string> ChildValues;\n\n      ChildValues childValues_;\n      std::string document_;\n      std::string indentString_;\n      int rightMargin_;\n      int indentSize_;\n      bool addChildValues_;\n   };\n\n   /** \\brief Writes a Value in <a HREF=\"http://www.json.org\">JSON</a> format in a human friendly way,\n        to a stream rather than to a string.\n    *\n    * The rules for line break and indent are as follow:\n    * - Object value:\n    *     - if empty then print {} without indent and line break\n    *     - if not empty the print '{', line break & indent, print one value per line\n    *       and then unindent and line break and print '}'.\n    * - Array value:\n    *     - if empty then print [] without indent and line break\n    *     - if the array contains no object value, empty array or some other value types,\n    *       and all the values fit on one lines, then print the array on a single line.\n    *     - otherwise, it the values do not fit on one line, or the array contains\n    *       object or non empty array, then print one value per line.\n    *\n    * If the Value have comments then they are outputed according to their #CommentPlacement.\n    *\n    * \\param indentation Each level will be indented by this amount extra.\n    * \\sa Reader, Value, Value::setComment()\n    */\n   class JSON_API StyledStreamWriter\n   {\n   public:\n      StyledStreamWriter( std::string indentation=\"\\t\" );\n      ~StyledStreamWriter(){}\n\n   public:\n      /** \\brief Serialize a Value in <a HREF=\"http://www.json.org\">JSON</a> format.\n       * \\param out Stream to write to. (Can be ostringstream, e.g.)\n       * \\param root Value to serialize.\n       * \\note There is no point in deriving from Writer, since write() should not return a value.\n       */\n      void write( std::ostream &out, const Value &root );\n\n   private:\n      void writeValue( const Value &value );\n      void writeArrayValue( const Value &value );\n      bool isMultineArray( const Value &value );\n      void pushValue( const std::string &value );\n      void writeIndent();\n      void writeWithIndent( const std::string &value );\n      void indent();\n      void unindent();\n      void writeCommentBeforeValue( const Value &root );\n      void writeCommentAfterValueOnSameLine( const Value &root );\n      bool hasCommentForValue( const Value &value );\n      static std::string normalizeEOL( const std::string &text );\n\n      typedef std::vector<std::string> ChildValues;\n\n      ChildValues childValues_;\n      std::ostream* document_;\n      std::string indentString_;\n      int rightMargin_;\n      std::string indentation_;\n      bool addChildValues_;\n   };\n\n   std::string JSON_API valueToString( Int value );\n   std::string JSON_API valueToString( UInt value );\n   std::string JSON_API valueToString( double value );\n   std::string JSON_API valueToString( bool value );\n   std::string JSON_API valueToQuotedString( const char *value );\n\n   /// \\brief Output using the StyledStreamWriter.\n   /// \\see Json::operator>>()\n   std::ostream& operator<<( std::ostream&, const Value &root );\n\n} // namespace Json\n\n\n\n#endif // JSON_WRITER_H_INCLUDED\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_batchallocator.h",
    "content": "#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED\n# define JSONCPP_BATCHALLOCATOR_H_INCLUDED\n\n# include <stdlib.h>\n# include <assert.h>\n\n# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n\nnamespace Json {\n\n/* Fast memory allocator.\n *\n * This memory allocator allocates memory for a batch of object (specified by\n * the page size, the number of object in each page).\n *\n * It does not allow the destruction of a single object. All the allocated objects\n * can be destroyed at once. The memory can be either released or reused for future\n * allocation.\n * \n * The in-place new operator must be used to construct the object using the pointer\n * returned by allocate.\n */\ntemplate<typename AllocatedType\n        ,const unsigned int objectPerAllocation>\nclass BatchAllocator\n{\npublic:\n   typedef AllocatedType Type;\n\n   BatchAllocator( unsigned int objectsPerPage = 255 )\n      : freeHead_( 0 )\n      , objectsPerPage_( objectsPerPage )\n   {\n//      printf( \"Size: %d => %s\\n\", sizeof(AllocatedType), typeid(AllocatedType).name() );\n      assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.\n      assert( objectsPerPage >= 16 );\n      batches_ = allocateBatch( 0 );   // allocated a dummy page\n      currentBatch_ = batches_;\n   }\n\n   ~BatchAllocator()\n   {\n      for ( BatchInfo *batch = batches_; batch;  )\n      {\n         BatchInfo *nextBatch = batch->next_;\n         free( batch );\n         batch = nextBatch;\n      }\n   }\n\n   /// allocate space for an array of objectPerAllocation object.\n   /// @warning it is the responsability of the caller to call objects constructors.\n   AllocatedType *allocate()\n   {\n      if ( freeHead_ ) // returns node from free list.\n      {\n         AllocatedType *object = freeHead_;\n         freeHead_ = *(AllocatedType **)object;\n         return object;\n      }\n      if ( currentBatch_->used_ == currentBatch_->end_ )\n      {\n         currentBatch_ = currentBatch_->next_;\n         while ( currentBatch_  &&  currentBatch_->used_ == currentBatch_->end_ )\n            currentBatch_ = currentBatch_->next_;\n\n         if ( !currentBatch_  ) // no free batch found, allocate a new one\n         { \n            currentBatch_ = allocateBatch( objectsPerPage_ );\n            currentBatch_->next_ = batches_; // insert at the head of the list\n            batches_ = currentBatch_;\n         }\n      }\n      AllocatedType *allocated = currentBatch_->used_;\n      currentBatch_->used_ += objectPerAllocation;\n      return allocated;\n   }\n\n   /// Release the object.\n   /// @warning it is the responsability of the caller to actually destruct the object.\n   void release( AllocatedType *object )\n   {\n      assert( object != 0 );\n      *(AllocatedType **)object = freeHead_;\n      freeHead_ = object;\n   }\n\nprivate:\n   struct BatchInfo\n   {\n      BatchInfo *next_;\n      AllocatedType *used_;\n      AllocatedType *end_;\n      AllocatedType buffer_[objectPerAllocation];\n   };\n\n   // disabled copy constructor and assignement operator.\n   BatchAllocator( const BatchAllocator & );\n   void operator =( const BatchAllocator &);\n\n   static BatchInfo *allocateBatch( unsigned int objectsPerPage )\n   {\n      const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation\n                                + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;\n      BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );\n      batch->next_ = 0;\n      batch->used_ = batch->buffer_;\n      batch->end_ = batch->buffer_ + objectsPerPage;\n      return batch;\n   }\n\n   BatchInfo *batches_;\n   BatchInfo *currentBatch_;\n   /// Head of a single linked list within the allocated space of freeed object\n   AllocatedType *freeHead_;\n   unsigned int objectsPerPage_;\n};\n\n\n} // namespace Json\n\n# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION\n\n#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED\n\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_internalarray.inl",
    "content": "// included by json_value.cpp\n// everything is within Json namespace\n\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// class ValueInternalArray\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n\nValueArrayAllocator::~ValueArrayAllocator()\n{\n}\n\n// //////////////////////////////////////////////////////////////////\n// class DefaultValueArrayAllocator\n// //////////////////////////////////////////////////////////////////\n#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR\nclass DefaultValueArrayAllocator : public ValueArrayAllocator\n{\npublic: // overridden from ValueArrayAllocator\n   virtual ~DefaultValueArrayAllocator()\n   {\n   }\n\n   virtual ValueInternalArray *newArray()\n   {\n      return new ValueInternalArray();\n   }\n\n   virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )\n   {\n      return new ValueInternalArray( other );\n   }\n\n   virtual void destructArray( ValueInternalArray *array )\n   {\n      delete array;\n   }\n\n   virtual void reallocateArrayPageIndex( Value **&indexes, \n                                          ValueInternalArray::PageIndex &indexCount,\n                                          ValueInternalArray::PageIndex minNewIndexCount )\n   {\n      ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;\n      if ( minNewIndexCount > newIndexCount )\n         newIndexCount = minNewIndexCount;\n      void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );\n      if ( !newIndexes )\n         throw std::bad_alloc();\n      indexCount = newIndexCount;\n      indexes = static_cast<Value **>( newIndexes );\n   }\n   virtual void releaseArrayPageIndex( Value **indexes, \n                                       ValueInternalArray::PageIndex indexCount )\n   {\n      if ( indexes )\n         free( indexes );\n   }\n\n   virtual Value *allocateArrayPage()\n   {\n      return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );\n   }\n\n   virtual void releaseArrayPage( Value *value )\n   {\n      if ( value )\n         free( value );\n   }\n};\n\n#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR\n/// @todo make this thread-safe (lock when accessign batch allocator)\nclass DefaultValueArrayAllocator : public ValueArrayAllocator\n{\npublic: // overridden from ValueArrayAllocator\n   virtual ~DefaultValueArrayAllocator()\n   {\n   }\n\n   virtual ValueInternalArray *newArray()\n   {\n      ValueInternalArray *array = arraysAllocator_.allocate();\n      new (array) ValueInternalArray(); // placement new\n      return array;\n   }\n\n   virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )\n   {\n      ValueInternalArray *array = arraysAllocator_.allocate();\n      new (array) ValueInternalArray( other ); // placement new\n      return array;\n   }\n\n   virtual void destructArray( ValueInternalArray *array )\n   {\n      if ( array )\n      {\n         array->~ValueInternalArray();\n         arraysAllocator_.release( array );\n      }\n   }\n\n   virtual void reallocateArrayPageIndex( Value **&indexes, \n                                          ValueInternalArray::PageIndex &indexCount,\n                                          ValueInternalArray::PageIndex minNewIndexCount )\n   {\n      ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;\n      if ( minNewIndexCount > newIndexCount )\n         newIndexCount = minNewIndexCount;\n      void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );\n      if ( !newIndexes )\n         throw std::bad_alloc();\n      indexCount = newIndexCount;\n      indexes = static_cast<Value **>( newIndexes );\n   }\n   virtual void releaseArrayPageIndex( Value **indexes, \n                                       ValueInternalArray::PageIndex indexCount )\n   {\n      if ( indexes )\n         free( indexes );\n   }\n\n   virtual Value *allocateArrayPage()\n   {\n      return static_cast<Value *>( pagesAllocator_.allocate() );\n   }\n\n   virtual void releaseArrayPage( Value *value )\n   {\n      if ( value )\n         pagesAllocator_.release( value );\n   }\nprivate:\n   BatchAllocator<ValueInternalArray,1> arraysAllocator_;\n   BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_;\n};\n#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR\n\nstatic ValueArrayAllocator *&arrayAllocator()\n{\n   static DefaultValueArrayAllocator defaultAllocator;\n   static ValueArrayAllocator *arrayAllocator = &defaultAllocator;\n   return arrayAllocator;\n}\n\nstatic struct DummyArrayAllocatorInitializer {\n   DummyArrayAllocatorInitializer() \n   {\n      arrayAllocator();      // ensure arrayAllocator() statics are initialized before main().\n   }\n} dummyArrayAllocatorInitializer;\n\n// //////////////////////////////////////////////////////////////////\n// class ValueInternalArray\n// //////////////////////////////////////////////////////////////////\nbool \nValueInternalArray::equals( const IteratorState &x, \n                            const IteratorState &other )\n{\n   return x.array_ == other.array_  \n          &&  x.currentItemIndex_ == other.currentItemIndex_  \n          &&  x.currentPageIndex_ == other.currentPageIndex_;\n}\n\n\nvoid \nValueInternalArray::increment( IteratorState &it )\n{\n   JSON_ASSERT_MESSAGE( it.array_  &&\n      (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_\n      != it.array_->size_,\n      \"ValueInternalArray::increment(): moving iterator beyond end\" );\n   ++(it.currentItemIndex_);\n   if ( it.currentItemIndex_ == itemsPerPage )\n   {\n      it.currentItemIndex_ = 0;\n      ++(it.currentPageIndex_);\n   }\n}\n\n\nvoid \nValueInternalArray::decrement( IteratorState &it )\n{\n   JSON_ASSERT_MESSAGE( it.array_  &&  it.currentPageIndex_ == it.array_->pages_ \n                        &&  it.currentItemIndex_ == 0,\n      \"ValueInternalArray::decrement(): moving iterator beyond end\" );\n   if ( it.currentItemIndex_ == 0 )\n   {\n      it.currentItemIndex_ = itemsPerPage-1;\n      --(it.currentPageIndex_);\n   }\n   else\n   {\n      --(it.currentItemIndex_);\n   }\n}\n\n\nValue &\nValueInternalArray::unsafeDereference( const IteratorState &it )\n{\n   return (*(it.currentPageIndex_))[it.currentItemIndex_];\n}\n\n\nValue &\nValueInternalArray::dereference( const IteratorState &it )\n{\n   JSON_ASSERT_MESSAGE( it.array_  &&\n      (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_\n      < it.array_->size_,\n      \"ValueInternalArray::dereference(): dereferencing invalid iterator\" );\n   return unsafeDereference( it );\n}\n\nvoid \nValueInternalArray::makeBeginIterator( IteratorState &it ) const\n{\n   it.array_ = const_cast<ValueInternalArray *>( this );\n   it.currentItemIndex_ = 0;\n   it.currentPageIndex_ = pages_;\n}\n\n\nvoid \nValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const\n{\n   it.array_ = const_cast<ValueInternalArray *>( this );\n   it.currentItemIndex_ = index % itemsPerPage;\n   it.currentPageIndex_ = pages_ + index / itemsPerPage;\n}\n\n\nvoid \nValueInternalArray::makeEndIterator( IteratorState &it ) const\n{\n   makeIterator( it, size_ );\n}\n\n\nValueInternalArray::ValueInternalArray()\n   : pages_( 0 )\n   , size_( 0 )\n   , pageCount_( 0 )\n{\n}\n\n\nValueInternalArray::ValueInternalArray( const ValueInternalArray &other )\n   : pages_( 0 )\n   , pageCount_( 0 )\n   , size_( other.size_ )\n{\n   PageIndex minNewPages = other.size_ / itemsPerPage;\n   arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );\n   JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, \n                        \"ValueInternalArray::reserve(): bad reallocation\" );\n   IteratorState itOther;\n   other.makeBeginIterator( itOther );\n   Value *value;\n   for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) )\n   {\n      if ( index % itemsPerPage == 0 )\n      {\n         PageIndex pageIndex = index / itemsPerPage;\n         value = arrayAllocator()->allocateArrayPage();\n         pages_[pageIndex] = value;\n      }\n      new (value) Value( dereference( itOther ) );\n   }\n}\n\n\nValueInternalArray &\nValueInternalArray::operator =( const ValueInternalArray &other )\n{\n   ValueInternalArray temp( other );\n   swap( temp );\n   return *this;\n}\n\n\nValueInternalArray::~ValueInternalArray()\n{\n   // destroy all constructed items\n   IteratorState it;\n   IteratorState itEnd;\n   makeBeginIterator( it);\n   makeEndIterator( itEnd );\n   for ( ; !equals(it,itEnd); increment(it) )\n   {\n      Value *value = &dereference(it);\n      value->~Value();\n   }\n   // release all pages\n   PageIndex lastPageIndex = size_ / itemsPerPage;\n   for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex )\n      arrayAllocator()->releaseArrayPage( pages_[pageIndex] );\n   // release pages index\n   arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ );\n}\n\n\nvoid \nValueInternalArray::swap( ValueInternalArray &other )\n{\n   Value **tempPages = pages_;\n   pages_ = other.pages_;\n   other.pages_ = tempPages;\n   ArrayIndex tempSize = size_;\n   size_ = other.size_;\n   other.size_ = tempSize;\n   PageIndex tempPageCount = pageCount_;\n   pageCount_ = other.pageCount_;\n   other.pageCount_ = tempPageCount;\n}\n\nvoid \nValueInternalArray::clear()\n{\n   ValueInternalArray dummy;\n   swap( dummy );\n}\n\n\nvoid \nValueInternalArray::resize( ArrayIndex newSize )\n{\n   if ( newSize == 0 )\n      clear();\n   else if ( newSize < size_ )\n   {\n      IteratorState it;\n      IteratorState itEnd;\n      makeIterator( it, newSize );\n      makeIterator( itEnd, size_ );\n      for ( ; !equals(it,itEnd); increment(it) )\n      {\n         Value *value = &dereference(it);\n         value->~Value();\n      }\n      PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;\n      PageIndex lastPageIndex = size_ / itemsPerPage;\n      for ( ; pageIndex < lastPageIndex; ++pageIndex )\n         arrayAllocator()->releaseArrayPage( pages_[pageIndex] );\n      size_ = newSize;\n   }\n   else if ( newSize > size_ )\n      resolveReference( newSize );\n}\n\n\nvoid \nValueInternalArray::makeIndexValid( ArrayIndex index )\n{\n   // Need to enlarge page index ?\n   if ( index >= pageCount_ * itemsPerPage )\n   {\n      PageIndex minNewPages = (index + 1) / itemsPerPage;\n      arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );\n      JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, \"ValueInternalArray::reserve(): bad reallocation\" );\n   }\n\n   // Need to allocate new pages ?\n   ArrayIndex nextPageIndex = \n      (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage\n                                  : size_;\n   if ( nextPageIndex <= index )\n   {\n      PageIndex pageIndex = nextPageIndex / itemsPerPage;\n      PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;\n      for ( ; pageToAllocate-- > 0; ++pageIndex )\n         pages_[pageIndex] = arrayAllocator()->allocateArrayPage();\n   }\n\n   // Initialize all new entries\n   IteratorState it;\n   IteratorState itEnd;\n   makeIterator( it, size_ );\n   size_ = index + 1;\n   makeIterator( itEnd, size_ );\n   for ( ; !equals(it,itEnd); increment(it) )\n   {\n      Value *value = &dereference(it);\n      new (value) Value(); // Construct a default value using placement new\n   }\n}\n\nValue &\nValueInternalArray::resolveReference( ArrayIndex index )\n{\n   if ( index >= size_ )\n      makeIndexValid( index );\n   return pages_[index/itemsPerPage][index%itemsPerPage];\n}\n\nValue *\nValueInternalArray::find( ArrayIndex index ) const\n{\n   if ( index >= size_ )\n      return 0;\n   return &(pages_[index/itemsPerPage][index%itemsPerPage]);\n}\n\nValueInternalArray::ArrayIndex \nValueInternalArray::size() const\n{\n   return size_;\n}\n\nint \nValueInternalArray::distance( const IteratorState &x, const IteratorState &y )\n{\n   return indexOf(y) - indexOf(x);\n}\n\n\nValueInternalArray::ArrayIndex \nValueInternalArray::indexOf( const IteratorState &iterator )\n{\n   if ( !iterator.array_ )\n      return ArrayIndex(-1);\n   return ArrayIndex(\n      (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage \n      + iterator.currentItemIndex_ );\n}\n\n\nint \nValueInternalArray::compare( const ValueInternalArray &other ) const\n{\n   int sizeDiff( size_ - other.size_ );\n   if ( sizeDiff != 0 )\n      return sizeDiff;\n   \n   for ( ArrayIndex index =0; index < size_; ++index )\n   {\n      int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare( \n         other.pages_[index/itemsPerPage][index%itemsPerPage] );\n      if ( diff != 0 )\n         return diff;\n   }\n   return 0;\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_internalmap.inl",
    "content": "// included by json_value.cpp\n// everything is within Json namespace\n\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// class ValueInternalMap\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n\n/** \\internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );\n   * This optimization is used by the fast allocator.\n   */\nValueInternalLink::ValueInternalLink()\n   : previous_( 0 )\n   , next_( 0 )\n{\n}\n\nValueInternalLink::~ValueInternalLink()\n{ \n   for ( int index =0; index < itemPerLink; ++index )\n   {\n      if ( !items_[index].isItemAvailable() )\n      {\n         if ( !items_[index].isMemberNameStatic() )\n            free( keys_[index] );\n      }\n      else\n         break;\n   }\n}\n\n\n\nValueMapAllocator::~ValueMapAllocator()\n{\n}\n\n#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR\nclass DefaultValueMapAllocator : public ValueMapAllocator\n{\npublic: // overridden from ValueMapAllocator\n   virtual ValueInternalMap *newMap()\n   {\n      return new ValueInternalMap();\n   }\n\n   virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )\n   {\n      return new ValueInternalMap( other );\n   }\n\n   virtual void destructMap( ValueInternalMap *map )\n   {\n      delete map;\n   }\n\n   virtual ValueInternalLink *allocateMapBuckets( unsigned int size )\n   {\n      return new ValueInternalLink[size];\n   }\n\n   virtual void releaseMapBuckets( ValueInternalLink *links )\n   {\n      delete [] links;\n   }\n\n   virtual ValueInternalLink *allocateMapLink()\n   {\n      return new ValueInternalLink();\n   }\n\n   virtual void releaseMapLink( ValueInternalLink *link )\n   {\n      delete link;\n   }\n};\n#else\n/// @todo make this thread-safe (lock when accessign batch allocator)\nclass DefaultValueMapAllocator : public ValueMapAllocator\n{\npublic: // overridden from ValueMapAllocator\n   virtual ValueInternalMap *newMap()\n   {\n      ValueInternalMap *map = mapsAllocator_.allocate();\n      new (map) ValueInternalMap(); // placement new\n      return map;\n   }\n\n   virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )\n   {\n      ValueInternalMap *map = mapsAllocator_.allocate();\n      new (map) ValueInternalMap( other ); // placement new\n      return map;\n   }\n\n   virtual void destructMap( ValueInternalMap *map )\n   {\n      if ( map )\n      {\n         map->~ValueInternalMap();\n         mapsAllocator_.release( map );\n      }\n   }\n\n   virtual ValueInternalLink *allocateMapBuckets( unsigned int size )\n   {\n      return new ValueInternalLink[size];\n   }\n\n   virtual void releaseMapBuckets( ValueInternalLink *links )\n   {\n      delete [] links;\n   }\n\n   virtual ValueInternalLink *allocateMapLink()\n   {\n      ValueInternalLink *link = linksAllocator_.allocate();\n      memset( link, 0, sizeof(ValueInternalLink) );\n      return link;\n   }\n\n   virtual void releaseMapLink( ValueInternalLink *link )\n   {\n      link->~ValueInternalLink();\n      linksAllocator_.release( link );\n   }\nprivate:\n   BatchAllocator<ValueInternalMap,1> mapsAllocator_;\n   BatchAllocator<ValueInternalLink,1> linksAllocator_;\n};\n#endif\n\nstatic ValueMapAllocator *&mapAllocator()\n{\n   static DefaultValueMapAllocator defaultAllocator;\n   static ValueMapAllocator *mapAllocator = &defaultAllocator;\n   return mapAllocator;\n}\n\nstatic struct DummyMapAllocatorInitializer {\n   DummyMapAllocatorInitializer() \n   {\n      mapAllocator();      // ensure mapAllocator() statics are initialized before main().\n   }\n} dummyMapAllocatorInitializer;\n\n\n\n// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.\n\n/*\nuse linked list hash map. \nbuckets array is a container.\nlinked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)\nvalue have extra state: valid, available, deleted\n*/\n\n\nValueInternalMap::ValueInternalMap()\n   : buckets_( 0 )\n   , tailLink_( 0 )\n   , bucketsSize_( 0 )\n   , itemCount_( 0 )\n{\n}\n\n\nValueInternalMap::ValueInternalMap( const ValueInternalMap &other )\n   : buckets_( 0 )\n   , tailLink_( 0 )\n   , bucketsSize_( 0 )\n   , itemCount_( 0 )\n{\n   reserve( other.itemCount_ );\n   IteratorState it;\n   IteratorState itEnd;\n   other.makeBeginIterator( it );\n   other.makeEndIterator( itEnd );\n   for ( ; !equals(it,itEnd); increment(it) )\n   {\n      bool isStatic;\n      const char *memberName = key( it, isStatic );\n      const Value &aValue = value( it );\n      resolveReference(memberName, isStatic) = aValue;\n   }\n}\n\n\nValueInternalMap &\nValueInternalMap::operator =( const ValueInternalMap &other )\n{\n   ValueInternalMap dummy( other );\n   swap( dummy );\n   return *this;\n}\n\n\nValueInternalMap::~ValueInternalMap()\n{\n   if ( buckets_ )\n   {\n      for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )\n      {\n         ValueInternalLink *link = buckets_[bucketIndex].next_;\n         while ( link )\n         {\n            ValueInternalLink *linkToRelease = link;\n            link = link->next_;\n            mapAllocator()->releaseMapLink( linkToRelease );\n         }\n      }\n      mapAllocator()->releaseMapBuckets( buckets_ );\n   }\n}\n\n\nvoid \nValueInternalMap::swap( ValueInternalMap &other )\n{\n   ValueInternalLink *tempBuckets = buckets_;\n   buckets_ = other.buckets_;\n   other.buckets_ = tempBuckets;\n   ValueInternalLink *tempTailLink = tailLink_;\n   tailLink_ = other.tailLink_;\n   other.tailLink_ = tempTailLink;\n   BucketIndex tempBucketsSize = bucketsSize_;\n   bucketsSize_ = other.bucketsSize_;\n   other.bucketsSize_ = tempBucketsSize;\n   BucketIndex tempItemCount = itemCount_;\n   itemCount_ = other.itemCount_;\n   other.itemCount_ = tempItemCount;\n}\n\n\nvoid \nValueInternalMap::clear()\n{\n   ValueInternalMap dummy;\n   swap( dummy );\n}\n\n\nValueInternalMap::BucketIndex \nValueInternalMap::size() const\n{\n   return itemCount_;\n}\n\nbool \nValueInternalMap::reserveDelta( BucketIndex growth )\n{\n   return reserve( itemCount_ + growth );\n}\n\nbool \nValueInternalMap::reserve( BucketIndex newItemCount )\n{\n   if ( !buckets_  &&  newItemCount > 0 )\n   {\n      buckets_ = mapAllocator()->allocateMapBuckets( 1 );\n      bucketsSize_ = 1;\n      tailLink_ = &buckets_[0];\n   }\n//   BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;\n   return true;\n}\n\n\nconst Value *\nValueInternalMap::find( const char *key ) const\n{\n   if ( !bucketsSize_ )\n      return 0;\n   HashKey hashedKey = hash( key );\n   BucketIndex bucketIndex = hashedKey % bucketsSize_;\n   for ( const ValueInternalLink *current = &buckets_[bucketIndex]; \n         current != 0; \n         current = current->next_ )\n   {\n      for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )\n      {\n         if ( current->items_[index].isItemAvailable() )\n            return 0;\n         if ( strcmp( key, current->keys_[index] ) == 0 )\n            return &current->items_[index];\n      }\n   }\n   return 0;\n}\n\n\nValue *\nValueInternalMap::find( const char *key )\n{\n   const ValueInternalMap *constThis = this;\n   return const_cast<Value *>( constThis->find( key ) );\n}\n\n\nValue &\nValueInternalMap::resolveReference( const char *key,\n                                    bool isStatic )\n{\n   HashKey hashedKey = hash( key );\n   if ( bucketsSize_ )\n   {\n      BucketIndex bucketIndex = hashedKey % bucketsSize_;\n      ValueInternalLink **previous = 0;\n      BucketIndex index;\n      for ( ValueInternalLink *current = &buckets_[bucketIndex]; \n            current != 0; \n            previous = &current->next_, current = current->next_ )\n      {\n         for ( index=0; index < ValueInternalLink::itemPerLink; ++index )\n         {\n            if ( current->items_[index].isItemAvailable() )\n               return setNewItem( key, isStatic, current, index );\n            if ( strcmp( key, current->keys_[index] ) == 0 )\n               return current->items_[index];\n         }\n      }\n   }\n\n   reserveDelta( 1 );\n   return unsafeAdd( key, isStatic, hashedKey );\n}\n\n\nvoid \nValueInternalMap::remove( const char *key )\n{\n   HashKey hashedKey = hash( key );\n   if ( !bucketsSize_ )\n      return;\n   BucketIndex bucketIndex = hashedKey % bucketsSize_;\n   for ( ValueInternalLink *link = &buckets_[bucketIndex]; \n         link != 0; \n         link = link->next_ )\n   {\n      BucketIndex index;\n      for ( index =0; index < ValueInternalLink::itemPerLink; ++index )\n      {\n         if ( link->items_[index].isItemAvailable() )\n            return;\n         if ( strcmp( key, link->keys_[index] ) == 0 )\n         {\n            doActualRemove( link, index, bucketIndex );\n            return;\n         }\n      }\n   }\n}\n\nvoid \nValueInternalMap::doActualRemove( ValueInternalLink *link, \n                                  BucketIndex index,\n                                  BucketIndex bucketIndex )\n{\n   // find last item of the bucket and swap it with the 'removed' one.\n   // set removed items flags to 'available'.\n   // if last page only contains 'available' items, then desallocate it (it's empty)\n   ValueInternalLink *&lastLink = getLastLinkInBucket( index );\n   BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1\n   for ( ;   \n         lastItemIndex < ValueInternalLink::itemPerLink; \n         ++lastItemIndex ) // may be optimized with dicotomic search\n   {\n      if ( lastLink->items_[lastItemIndex].isItemAvailable() )\n         break;\n   }\n   \n   BucketIndex lastUsedIndex = lastItemIndex - 1;\n   Value *valueToDelete = &link->items_[index];\n   Value *valueToPreserve = &lastLink->items_[lastUsedIndex];\n   if ( valueToDelete != valueToPreserve )\n      valueToDelete->swap( *valueToPreserve );\n   if ( lastUsedIndex == 0 )  // page is now empty\n   {  // remove it from bucket linked list and delete it.\n      ValueInternalLink *linkPreviousToLast = lastLink->previous_;\n      if ( linkPreviousToLast != 0 )   // can not deleted bucket link.\n      {\n         mapAllocator()->releaseMapLink( lastLink );\n         linkPreviousToLast->next_ = 0;\n         lastLink = linkPreviousToLast;\n      }\n   }\n   else\n   {\n      Value dummy;\n      valueToPreserve->swap( dummy ); // restore deleted to default Value.\n      valueToPreserve->setItemUsed( false );\n   }\n   --itemCount_;\n}\n\n\nValueInternalLink *&\nValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )\n{\n   if ( bucketIndex == bucketsSize_ - 1 )\n      return tailLink_;\n   ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;\n   if ( !previous )\n      previous = &buckets_[bucketIndex];\n   return previous;\n}\n\n\nValue &\nValueInternalMap::setNewItem( const char *key, \n                              bool isStatic,\n                              ValueInternalLink *link, \n                              BucketIndex index )\n{\n   char *duplicatedKey = valueAllocator()->makeMemberName( key );\n   ++itemCount_;\n   link->keys_[index] = duplicatedKey;\n   link->items_[index].setItemUsed();\n   link->items_[index].setMemberNameIsStatic( isStatic );\n   return link->items_[index]; // items already default constructed.\n}\n\n\nValue &\nValueInternalMap::unsafeAdd( const char *key, \n                             bool isStatic, \n                             HashKey hashedKey )\n{\n   JSON_ASSERT_MESSAGE( bucketsSize_ > 0, \"ValueInternalMap::unsafeAdd(): internal logic error.\" );\n   BucketIndex bucketIndex = hashedKey % bucketsSize_;\n   ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );\n   ValueInternalLink *link = previousLink;\n   BucketIndex index;\n   for ( index =0; index < ValueInternalLink::itemPerLink; ++index )\n   {\n      if ( link->items_[index].isItemAvailable() )\n         break;\n   }\n   if ( index == ValueInternalLink::itemPerLink ) // need to add a new page\n   {\n      ValueInternalLink *newLink = mapAllocator()->allocateMapLink();\n      index = 0;\n      link->next_ = newLink;\n      previousLink = newLink;\n      link = newLink;\n   }\n   return setNewItem( key, isStatic, link, index );\n}\n\n\nValueInternalMap::HashKey \nValueInternalMap::hash( const char *key ) const\n{\n   HashKey hash = 0;\n   while ( *key )\n      hash += *key++ * 37;\n   return hash;\n}\n\n\nint \nValueInternalMap::compare( const ValueInternalMap &other ) const\n{\n   int sizeDiff( itemCount_ - other.itemCount_ );\n   if ( sizeDiff != 0 )\n      return sizeDiff;\n   // Strict order guaranty is required. Compare all keys FIRST, then compare values.\n   IteratorState it;\n   IteratorState itEnd;\n   makeBeginIterator( it );\n   makeEndIterator( itEnd );\n   for ( ; !equals(it,itEnd); increment(it) )\n   {\n      if ( !other.find( key( it ) ) )\n         return 1;\n   }\n\n   // All keys are equals, let's compare values\n   makeBeginIterator( it );\n   for ( ; !equals(it,itEnd); increment(it) )\n   {\n      const Value *otherValue = other.find( key( it ) );\n      int valueDiff = value(it).compare( *otherValue );\n      if ( valueDiff != 0 )\n         return valueDiff;\n   }\n   return 0;\n}\n\n\nvoid \nValueInternalMap::makeBeginIterator( IteratorState &it ) const\n{\n   it.map_ = const_cast<ValueInternalMap *>( this );\n   it.bucketIndex_ = 0;\n   it.itemIndex_ = 0;\n   it.link_ = buckets_;\n}\n\n\nvoid \nValueInternalMap::makeEndIterator( IteratorState &it ) const\n{\n   it.map_ = const_cast<ValueInternalMap *>( this );\n   it.bucketIndex_ = bucketsSize_;\n   it.itemIndex_ = 0;\n   it.link_ = 0;\n}\n\n\nbool \nValueInternalMap::equals( const IteratorState &x, const IteratorState &other )\n{\n   return x.map_ == other.map_  \n          &&  x.bucketIndex_ == other.bucketIndex_  \n          &&  x.link_ == other.link_\n          &&  x.itemIndex_ == other.itemIndex_;\n}\n\n\nvoid \nValueInternalMap::incrementBucket( IteratorState &iterator )\n{\n   ++iterator.bucketIndex_;\n   JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,\n      \"ValueInternalMap::increment(): attempting to iterate beyond end.\" );\n   if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )\n      iterator.link_ = 0;\n   else\n      iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);\n   iterator.itemIndex_ = 0;\n}\n\n\nvoid \nValueInternalMap::increment( IteratorState &iterator )\n{\n   JSON_ASSERT_MESSAGE( iterator.map_, \"Attempting to iterator using invalid iterator.\" );\n   ++iterator.itemIndex_;\n   if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )\n   {\n      JSON_ASSERT_MESSAGE( iterator.link_ != 0,\n         \"ValueInternalMap::increment(): attempting to iterate beyond end.\" );\n      iterator.link_ = iterator.link_->next_;\n      if ( iterator.link_ == 0 )\n         incrementBucket( iterator );\n   }\n   else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )\n   {\n      incrementBucket( iterator );\n   }\n}\n\n\nvoid \nValueInternalMap::decrement( IteratorState &iterator )\n{\n   if ( iterator.itemIndex_ == 0 )\n   {\n      JSON_ASSERT_MESSAGE( iterator.map_, \"Attempting to iterate using invalid iterator.\" );\n      if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )\n      {\n         JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, \"Attempting to iterate beyond beginning.\" );\n         --(iterator.bucketIndex_);\n      }\n      iterator.link_ = iterator.link_->previous_;\n      iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;\n   }\n}\n\n\nconst char *\nValueInternalMap::key( const IteratorState &iterator )\n{\n   JSON_ASSERT_MESSAGE( iterator.link_, \"Attempting to iterate using invalid iterator.\" );\n   return iterator.link_->keys_[iterator.itemIndex_];\n}\n\nconst char *\nValueInternalMap::key( const IteratorState &iterator, bool &isStatic )\n{\n   JSON_ASSERT_MESSAGE( iterator.link_, \"Attempting to iterate using invalid iterator.\" );\n   isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();\n   return iterator.link_->keys_[iterator.itemIndex_];\n}\n\n\nValue &\nValueInternalMap::value( const IteratorState &iterator )\n{\n   JSON_ASSERT_MESSAGE( iterator.link_, \"Attempting to iterate using invalid iterator.\" );\n   return iterator.link_->items_[iterator.itemIndex_];\n}\n\n\nint \nValueInternalMap::distance( const IteratorState &x, const IteratorState &y )\n{\n   int offset = 0;\n   IteratorState it = x;\n   while ( !equals( it, y ) )\n      increment( it );\n   return offset;\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_reader.cpp",
    "content": "#include <json/reader.h>\n#include <json/value.h>\n#include <utility>\n#include <cstdio>\n#include <cassert>\n#include <cstring>\n#include <iostream>\n#include <stdexcept>\n\n#if _MSC_VER >= 1400 // VC++ 8.0\n#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.\n#endif\n\nnamespace Json {\n\n// QNX is strict about declaring C symbols in the std namespace.\n#ifdef __QNXNTO__\nusing std::memcpy;\nusing std::sprintf;\nusing std::sscanf;\n#endif\n\n// Implementation of class Features\n// ////////////////////////////////\n\nFeatures::Features()\n   : allowComments_( true )\n   , strictRoot_( false )\n{\n}\n\n\nFeatures \nFeatures::all()\n{\n   return Features();\n}\n\n\nFeatures \nFeatures::strictMode()\n{\n   Features features;\n   features.allowComments_ = false;\n   features.strictRoot_ = true;\n   return features;\n}\n\n// Implementation of class Reader\n// ////////////////////////////////\n\n\nstatic inline bool \nin( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )\n{\n   return c == c1  ||  c == c2  ||  c == c3  ||  c == c4;\n}\n\nstatic inline bool \nin( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )\n{\n   return c == c1  ||  c == c2  ||  c == c3  ||  c == c4  ||  c == c5;\n}\n\n\nstatic bool \ncontainsNewLine( Reader::Location begin, \n                 Reader::Location end )\n{\n   for ( ;begin < end; ++begin )\n      if ( *begin == '\\n'  ||  *begin == '\\r' )\n         return true;\n   return false;\n}\n\nstatic std::string codePointToUTF8(unsigned int cp)\n{\n   std::string result;\n   \n   // based on description from http://en.wikipedia.org/wiki/UTF-8\n\n   if (cp <= 0x7f) \n   {\n      result.resize(1);\n      result[0] = static_cast<char>(cp);\n   } \n   else if (cp <= 0x7FF) \n   {\n      result.resize(2);\n      result[1] = static_cast<char>(0x80 | (0x3f & cp));\n      result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));\n   } \n   else if (cp <= 0xFFFF) \n   {\n      result.resize(3);\n      result[2] = static_cast<char>(0x80 | (0x3f & cp));\n      result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));\n      result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));\n   }\n   else if (cp <= 0x10FFFF) \n   {\n      result.resize(4);\n      result[3] = static_cast<char>(0x80 | (0x3f & cp));\n      result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));\n      result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));\n      result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));\n   }\n\n   return result;\n}\n\n\n// Class Reader\n// //////////////////////////////////////////////////////////////////\n\nReader::Reader()\n   : features_( Features::all() )\n{\n}\n\n\nReader::Reader( const Features &features )\n   : features_( features )\n{\n}\n\n\nbool\nReader::parse( const std::string &document, \n               Value &root,\n               bool collectComments )\n{\n   document_ = document;\n   const char *begin = document_.c_str();\n   const char *end = begin + document_.length();\n   return parse( begin, end, root, collectComments );\n}\n\n\nbool\nReader::parse( std::istream& sin,\n               Value &root,\n               bool collectComments )\n{\n   //std::istream_iterator<char> begin(sin);\n   //std::istream_iterator<char> end;\n   // Those would allow streamed input from a file, if parse() were a\n   // template function.\n\n   // Since std::string is reference-counted, this at least does not\n   // create an extra copy.\n   std::string doc;\n   std::getline(sin, doc, (char)EOF);\n   return parse( doc, root, collectComments );\n}\n\nbool \nReader::parse( const char *beginDoc, const char *endDoc, \n               Value &root,\n               bool collectComments )\n{\n   if ( !features_.allowComments_ )\n   {\n      collectComments = false;\n   }\n\n   begin_ = beginDoc;\n   end_ = endDoc;\n   collectComments_ = collectComments;\n   current_ = begin_;\n   lastValueEnd_ = 0;\n   lastValue_ = 0;\n   commentsBefore_ = \"\";\n   errors_.clear();\n   while ( !nodes_.empty() )\n      nodes_.pop();\n   nodes_.push( &root );\n   \n   bool successful = readValue();\n   Token token;\n   skipCommentTokens( token );\n   if ( collectComments_  &&  !commentsBefore_.empty() )\n      root.setComment( commentsBefore_, commentAfter );\n   if ( features_.strictRoot_ )\n   {\n      if ( !root.isArray()  &&  !root.isObject() )\n      {\n         // Set error location to start of doc, ideally should be first token found in doc\n         token.type_ = tokenError;\n         token.start_ = beginDoc;\n         token.end_ = endDoc;\n         addError( \"A valid JSON document must be either an array or an object value.\",\n                   token );\n         return false;\n      }\n   }\n   return successful;\n}\n\n\nbool\nReader::readValue()\n{\n   Token token;\n   skipCommentTokens( token );\n   bool successful = true;\n\n   if ( collectComments_  &&  !commentsBefore_.empty() )\n   {\n      currentValue().setComment( commentsBefore_, commentBefore );\n      commentsBefore_ = \"\";\n   }\n\n\n   switch ( token.type_ )\n   {\n   case tokenObjectBegin:\n      successful = readObject( token );\n      break;\n   case tokenArrayBegin:\n      successful = readArray( token );\n      break;\n   case tokenNumber:\n      successful = decodeNumber( token );\n      break;\n   case tokenString:\n      successful = decodeString( token );\n      break;\n   case tokenTrue:\n      currentValue() = true;\n      break;\n   case tokenFalse:\n      currentValue() = false;\n      break;\n   case tokenNull:\n      currentValue() = Value();\n      break;\n   default:\n      return addError( \"Syntax error: value, object or array expected.\", token );\n   }\n\n   if ( collectComments_ )\n   {\n      lastValueEnd_ = current_;\n      lastValue_ = &currentValue();\n   }\n\n   return successful;\n}\n\n\nvoid \nReader::skipCommentTokens( Token &token )\n{\n   if ( features_.allowComments_ )\n   {\n      do\n      {\n         readToken( token );\n      }\n      while ( token.type_ == tokenComment );\n   }\n   else\n   {\n      readToken( token );\n   }\n}\n\n\nbool \nReader::expectToken( TokenType type, Token &token, const char *message )\n{\n   readToken( token );\n   if ( token.type_ != type )\n      return addError( message, token );\n   return true;\n}\n\n\nbool \nReader::readToken( Token &token )\n{\n   skipSpaces();\n   token.start_ = current_;\n   Char c = getNextChar();\n   bool ok = true;\n   switch ( c )\n   {\n   case '{':\n      token.type_ = tokenObjectBegin;\n      break;\n   case '}':\n      token.type_ = tokenObjectEnd;\n      break;\n   case '[':\n      token.type_ = tokenArrayBegin;\n      break;\n   case ']':\n      token.type_ = tokenArrayEnd;\n      break;\n   case '\"':\n      token.type_ = tokenString;\n      ok = readString();\n      break;\n   case '/':\n      token.type_ = tokenComment;\n      ok = readComment();\n      break;\n   case '0':\n   case '1':\n   case '2':\n   case '3':\n   case '4':\n   case '5':\n   case '6':\n   case '7':\n   case '8':\n   case '9':\n   case '-':\n      token.type_ = tokenNumber;\n      readNumber();\n      break;\n   case 't':\n      token.type_ = tokenTrue;\n      ok = match( \"rue\", 3 );\n      break;\n   case 'f':\n      token.type_ = tokenFalse;\n      ok = match( \"alse\", 4 );\n      break;\n   case 'n':\n      token.type_ = tokenNull;\n      ok = match( \"ull\", 3 );\n      break;\n   case ',':\n      token.type_ = tokenArraySeparator;\n      break;\n   case ':':\n      token.type_ = tokenMemberSeparator;\n      break;\n   case 0:\n      token.type_ = tokenEndOfStream;\n      break;\n   default:\n      ok = false;\n      break;\n   }\n   if ( !ok )\n      token.type_ = tokenError;\n   token.end_ = current_;\n   return true;\n}\n\n\nvoid \nReader::skipSpaces()\n{\n   while ( current_ != end_ )\n   {\n      Char c = *current_;\n      if ( c == ' '  ||  c == '\\t'  ||  c == '\\r'  ||  c == '\\n' )\n         ++current_;\n      else\n         break;\n   }\n}\n\n\nbool \nReader::match( Location pattern, \n               int patternLength )\n{\n   if ( end_ - current_ < patternLength )\n      return false;\n   int index = patternLength;\n   while ( index-- )\n      if ( current_[index] != pattern[index] )\n         return false;\n   current_ += patternLength;\n   return true;\n}\n\n\nbool\nReader::readComment()\n{\n   Location commentBegin = current_ - 1;\n   Char c = getNextChar();\n   bool successful = false;\n   if ( c == '*' )\n      successful = readCStyleComment();\n   else if ( c == '/' )\n      successful = readCppStyleComment();\n   if ( !successful )\n      return false;\n\n   if ( collectComments_ )\n   {\n      CommentPlacement placement = commentBefore;\n      if ( lastValueEnd_  &&  !containsNewLine( lastValueEnd_, commentBegin ) )\n      {\n         if ( c != '*'  ||  !containsNewLine( commentBegin, current_ ) )\n            placement = commentAfterOnSameLine;\n      }\n\n      addComment( commentBegin, current_, placement );\n   }\n   return true;\n}\n\n\nvoid \nReader::addComment( Location begin, \n                    Location end, \n                    CommentPlacement placement )\n{\n   assert( collectComments_ );\n   if ( placement == commentAfterOnSameLine )\n   {\n      assert( lastValue_ != 0 );\n      lastValue_->setComment( std::string( begin, end ), placement );\n   }\n   else\n   {\n      if ( !commentsBefore_.empty() )\n         commentsBefore_ += \"\\n\";\n      commentsBefore_ += std::string( begin, end );\n   }\n}\n\n\nbool \nReader::readCStyleComment()\n{\n   while ( current_ != end_ )\n   {\n      Char c = getNextChar();\n      if ( c == '*'  &&  *current_ == '/' )\n         break;\n   }\n   return getNextChar() == '/';\n}\n\n\nbool \nReader::readCppStyleComment()\n{\n   while ( current_ != end_ )\n   {\n      Char c = getNextChar();\n      if (  c == '\\r'  ||  c == '\\n' )\n         break;\n   }\n   return true;\n}\n\n\nvoid \nReader::readNumber()\n{\n   while ( current_ != end_ )\n   {\n      if ( !(*current_ >= '0'  &&  *current_ <= '9')  &&\n           !in( *current_, '.', 'e', 'E', '+', '-' ) )\n         break;\n      ++current_;\n   }\n}\n\nbool\nReader::readString()\n{\n   Char c = 0;\n   while ( current_ != end_ )\n   {\n      c = getNextChar();\n      if ( c == '\\\\' )\n         getNextChar();\n      else if ( c == '\"' )\n         break;\n   }\n   return c == '\"';\n}\n\n\nbool \nReader::readObject( Token &tokenStart )\n{\n   Token tokenName;\n   std::string name;\n   currentValue() = Value( objectValue );\n   while ( readToken( tokenName ) )\n   {\n      bool initialTokenOk = true;\n      while ( tokenName.type_ == tokenComment  &&  initialTokenOk )\n         initialTokenOk = readToken( tokenName );\n      if  ( !initialTokenOk )\n         break;\n      if ( tokenName.type_ == tokenObjectEnd  &&  name.empty() )  // empty object\n         return true;\n      if ( tokenName.type_ != tokenString )\n         break;\n      \n      name = \"\";\n      if ( !decodeString( tokenName, name ) )\n         return recoverFromError( tokenObjectEnd );\n\n      Token colon;\n      if ( !readToken( colon ) ||  colon.type_ != tokenMemberSeparator )\n      {\n         return addErrorAndRecover( \"Missing ':' after object member name\", \n                                    colon, \n                                    tokenObjectEnd );\n      }\n      Value &value = currentValue()[ name ];\n      nodes_.push( &value );\n      bool ok = readValue();\n      nodes_.pop();\n      if ( !ok ) // error already set\n         return recoverFromError( tokenObjectEnd );\n\n      Token comma;\n      if ( !readToken( comma )\n            ||  ( comma.type_ != tokenObjectEnd  &&  \n                  comma.type_ != tokenArraySeparator &&\n\t\t  comma.type_ != tokenComment ) )\n      {\n         return addErrorAndRecover( \"Missing ',' or '}' in object declaration\", \n                                    comma, \n                                    tokenObjectEnd );\n      }\n      bool finalizeTokenOk = true;\n      while ( comma.type_ == tokenComment &&\n              finalizeTokenOk )\n         finalizeTokenOk = readToken( comma );\n      if ( comma.type_ == tokenObjectEnd )\n         return true;\n   }\n   return addErrorAndRecover( \"Missing '}' or object member name\", \n                              tokenName, \n                              tokenObjectEnd );\n}\n\n\nbool \nReader::readArray( Token &tokenStart )\n{\n   currentValue() = Value( arrayValue );\n   skipSpaces();\n   if ( *current_ == ']' ) // empty array\n   {\n      Token endArray;\n      readToken( endArray );\n      return true;\n   }\n   int index = 0;\n   while ( true )\n   {\n      Value &value = currentValue()[ index++ ];\n      nodes_.push( &value );\n      bool ok = readValue();\n      nodes_.pop();\n      if ( !ok ) // error already set\n         return recoverFromError( tokenArrayEnd );\n\n      Token token;\n      // Accept Comment after last item in the array.\n      ok = readToken( token );\n      while ( token.type_ == tokenComment  &&  ok )\n      {\n         ok = readToken( token );\n      }\n      bool badTokenType = ( token.type_ == tokenArraySeparator  &&  \n                            token.type_ == tokenArrayEnd );\n      if ( !ok  ||  badTokenType )\n      {\n         return addErrorAndRecover( \"Missing ',' or ']' in array declaration\", \n                                    token, \n                                    tokenArrayEnd );\n      }\n      if ( token.type_ == tokenArrayEnd )\n         break;\n   }\n   return true;\n}\n\n\nbool \nReader::decodeNumber( Token &token )\n{\n   bool isDouble = false;\n   for ( Location inspect = token.start_; inspect != token.end_; ++inspect )\n   {\n      isDouble = isDouble  \n                 ||  in( *inspect, '.', 'e', 'E', '+' )  \n                 ||  ( *inspect == '-'  &&  inspect != token.start_ );\n   }\n   if ( isDouble )\n      return decodeDouble( token );\n   Location current = token.start_;\n   bool isNegative = *current == '-';\n   if ( isNegative )\n      ++current;\n   Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) \n                                       : Value::maxUInt) / 10;\n   Value::UInt value = 0;\n   while ( current < token.end_ )\n   {\n      Char c = *current++;\n      if ( c < '0'  ||  c > '9' )\n         return addError( \"'\" + std::string( token.start_, token.end_ ) + \"' is not a number.\", token );\n      if ( value >= threshold )\n         return decodeDouble( token );\n      value = value * 10 + Value::UInt(c - '0');\n   }\n   if ( isNegative )\n      currentValue() = -Value::Int( value );\n   else if ( value <= Value::UInt(Value::maxInt) )\n      currentValue() = Value::Int( value );\n   else\n      currentValue() = value;\n   return true;\n}\n\n\nbool \nReader::decodeDouble( Token &token )\n{\n   double value = 0;\n   const int bufferSize = 32;\n   int count;\n   int length = int(token.end_ - token.start_);\n   if ( length <= bufferSize )\n   {\n      Char buffer[bufferSize];\n      memcpy( buffer, token.start_, length );\n      buffer[length] = 0;\n      count = sscanf( buffer, \"%lf\", &value );\n   }\n   else\n   {\n      std::string buffer( token.start_, token.end_ );\n      count = sscanf( buffer.c_str(), \"%lf\", &value );\n   }\n\n   if ( count != 1 )\n      return addError( \"'\" + std::string( token.start_, token.end_ ) + \"' is not a number.\", token );\n   currentValue() = value;\n   return true;\n}\n\n\nbool \nReader::decodeString( Token &token )\n{\n   std::string decoded;\n   if ( !decodeString( token, decoded ) )\n      return false;\n   currentValue() = decoded;\n   return true;\n}\n\n\nbool \nReader::decodeString( Token &token, std::string &decoded )\n{\n   decoded.reserve( token.end_ - token.start_ - 2 );\n   Location current = token.start_ + 1; // skip '\"'\n   Location end = token.end_ - 1;      // do not include '\"'\n   while ( current != end )\n   {\n      Char c = *current++;\n      if ( c == '\"' )\n         break;\n      else if ( c == '\\\\' )\n      {\n         if ( current == end )\n            return addError( \"Empty escape sequence in string\", token, current );\n         Char escape = *current++;\n         switch ( escape )\n         {\n         case '\"': decoded += '\"'; break;\n         case '/': decoded += '/'; break;\n         case '\\\\': decoded += '\\\\'; break;\n         case 'b': decoded += '\\b'; break;\n         case 'f': decoded += '\\f'; break;\n         case 'n': decoded += '\\n'; break;\n         case 'r': decoded += '\\r'; break;\n         case 't': decoded += '\\t'; break;\n         case 'u':\n            {\n               unsigned int unicode;\n               if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )\n                  return false;\n               decoded += codePointToUTF8(unicode);\n            }\n            break;\n         default:\n            return addError( \"Bad escape sequence in string\", token, current );\n         }\n      }\n      else\n      {\n         decoded += c;\n      }\n   }\n   return true;\n}\n\nbool\nReader::decodeUnicodeCodePoint( Token &token, \n                                     Location &current, \n                                     Location end, \n                                     unsigned int &unicode )\n{\n\n   if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )\n      return false;\n   if (unicode >= 0xD800 && unicode <= 0xDBFF)\n   {\n      // surrogate pairs\n      if (end - current < 6)\n         return addError( \"additional six characters expected to parse unicode surrogate pair.\", token, current );\n      unsigned int surrogatePair;\n      if (*(current++) == '\\\\' && *(current++)== 'u')\n      {\n         if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))\n         {\n            unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);\n         } \n         else\n            return false;\n      } \n      else\n         return addError( \"expecting another \\\\u token to begin the second half of a unicode surrogate pair\", token, current );\n   }\n   return true;\n}\n\nbool \nReader::decodeUnicodeEscapeSequence( Token &token, \n                                     Location &current, \n                                     Location end, \n                                     unsigned int &unicode )\n{\n   if ( end - current < 4 )\n      return addError( \"Bad unicode escape sequence in string: four digits expected.\", token, current );\n   unicode = 0;\n   for ( int index =0; index < 4; ++index )\n   {\n      Char c = *current++;\n      unicode *= 16;\n      if ( c >= '0'  &&  c <= '9' )\n         unicode += c - '0';\n      else if ( c >= 'a'  &&  c <= 'f' )\n         unicode += c - 'a' + 10;\n      else if ( c >= 'A'  &&  c <= 'F' )\n         unicode += c - 'A' + 10;\n      else\n         return addError( \"Bad unicode escape sequence in string: hexadecimal digit expected.\", token, current );\n   }\n   return true;\n}\n\n\nbool \nReader::addError( const std::string &message, \n                  Token &token,\n                  Location extra )\n{\n   ErrorInfo info;\n   info.token_ = token;\n   info.message_ = message;\n   info.extra_ = extra;\n   errors_.push_back( info );\n   return false;\n}\n\n\nbool \nReader::recoverFromError( TokenType skipUntilToken )\n{\n   int errorCount = int(errors_.size());\n   Token skip;\n   while ( true )\n   {\n      if ( !readToken(skip) )\n         errors_.resize( errorCount ); // discard errors caused by recovery\n      if ( skip.type_ == skipUntilToken  ||  skip.type_ == tokenEndOfStream )\n         break;\n   }\n   errors_.resize( errorCount );\n   return false;\n}\n\n\nbool \nReader::addErrorAndRecover( const std::string &message, \n                            Token &token,\n                            TokenType skipUntilToken )\n{\n   addError( message, token );\n   return recoverFromError( skipUntilToken );\n}\n\n\nValue &\nReader::currentValue()\n{\n   return *(nodes_.top());\n}\n\n\nReader::Char \nReader::getNextChar()\n{\n   if ( current_ == end_ )\n      return 0;\n   return *current_++;\n}\n\n\nvoid \nReader::getLocationLineAndColumn( Location location,\n                                  int &line,\n                                  int &column ) const\n{\n   Location current = begin_;\n   Location lastLineStart = current;\n   line = 0;\n   while ( current < location  &&  current != end_ )\n   {\n      Char c = *current++;\n      if ( c == '\\r' )\n      {\n         if ( *current == '\\n' )\n            ++current;\n         lastLineStart = current;\n         ++line;\n      }\n      else if ( c == '\\n' )\n      {\n         lastLineStart = current;\n         ++line;\n      }\n   }\n   // column & line start at 1\n   column = int(location - lastLineStart) + 1;\n   ++line;\n}\n\n\nstd::string\nReader::getLocationLineAndColumn( Location location ) const\n{\n   int line, column;\n   getLocationLineAndColumn( location, line, column );\n   char buffer[18+16+16+1];\n   sprintf( buffer, \"Line %d, Column %d\", line, column );\n   return buffer;\n}\n\n\nstd::string \nReader::getFormatedErrorMessages() const\n{\n   std::string formattedMessage;\n   for ( Errors::const_iterator itError = errors_.begin();\n         itError != errors_.end();\n         ++itError )\n   {\n      const ErrorInfo &error = *itError;\n      formattedMessage += \"* \" + getLocationLineAndColumn( error.token_.start_ ) + \"\\n\";\n      formattedMessage += \"  \" + error.message_ + \"\\n\";\n      if ( error.extra_ )\n         formattedMessage += \"See \" + getLocationLineAndColumn( error.extra_ ) + \" for detail.\\n\";\n   }\n   return formattedMessage;\n}\n\n\nstd::istream& operator>>( std::istream &sin, Value &root )\n{\n    Json::Reader reader;\n    bool ok = reader.parse(sin, root, true);\n    //JSON_ASSERT( ok );\n    if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages());\n    return sin;\n}\n\n\n} // namespace Json\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_value.cpp",
    "content": "#include <iostream>\n#include <json/value.h>\n#include <json/writer.h>\n#include <utility>\n#include <stdexcept>\n#include <cstring>\n#include <cassert>\n#ifdef JSON_USE_CPPTL\n# include <cpptl/conststring.h>\n#endif\n#include <cstddef>    // size_t\n#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR\n# include \"json_batchallocator.h\"\n#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR\n\n#define JSON_ASSERT_UNREACHABLE assert( false )\n#define JSON_ASSERT( condition ) assert( condition );  // @todo <= change this into an exception throw\n#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message );\n\nnamespace Json {\n\n// QNX is strict about declaring C symbols in the std namespace.\n#ifdef __QNXNTO__\nusing std::memcpy;\nusing std::strchr;\nusing std::strcmp;\nusing std::strlen;\n#endif\n\nconst Value Value::null;\nconst Int Value::minInt = Int( ~(UInt(-1)/2) );\nconst Int Value::maxInt = Int( UInt(-1)/2 );\nconst UInt Value::maxUInt = UInt(-1);\n\n// A \"safe\" implementation of strdup. Allow null pointer to be passed. \n// Also avoid warning on msvc80.\n//\n//inline char *safeStringDup( const char *czstring )\n//{\n//   if ( czstring )\n//   {\n//      const size_t length = (unsigned int)( strlen(czstring) + 1 );\n//      char *newString = static_cast<char *>( malloc( length ) );\n//      memcpy( newString, czstring, length );\n//      return newString;\n//   }\n//   return 0;\n//}\n//\n//inline char *safeStringDup( const std::string &str )\n//{\n//   if ( !str.empty() )\n//   {\n//      const size_t length = str.length();\n//      char *newString = static_cast<char *>( malloc( length + 1 ) );\n//      memcpy( newString, str.c_str(), length );\n//      newString[length] = 0;\n//      return newString;\n//   }\n//   return 0;\n//}\n\nValueAllocator::~ValueAllocator()\n{\n}\n\nclass DefaultValueAllocator : public ValueAllocator\n{\npublic:\n   virtual ~DefaultValueAllocator()\n   {\n   }\n\n   virtual char *makeMemberName( const char *memberName )\n   {\n      return duplicateStringValue( memberName );\n   }\n\n   virtual void releaseMemberName( char *memberName )\n   {\n      releaseStringValue( memberName );\n   }\n\n   virtual char *duplicateStringValue( const char *value, \n                                       unsigned int length = unknown )\n   {\n      //@todo invesgate this old optimization\n      //if ( !value  ||  value[0] == 0 )\n      //   return 0;\n\n      if ( length == unknown )\n         length = (unsigned int)strlen(value);\n      char *newString = static_cast<char *>( malloc( length + 1 ) );\n      memcpy( newString, value, length );\n      newString[length] = 0;\n      return newString;\n   }\n\n   virtual void releaseStringValue( char *value )\n   {\n      if ( value )\n         free( value );\n   }\n};\n\nstatic ValueAllocator *&valueAllocator()\n{\n   static DefaultValueAllocator defaultAllocator;\n   static ValueAllocator *valueAllocator = &defaultAllocator;\n   return valueAllocator;\n}\n\nstatic struct DummyValueAllocatorInitializer {\n   DummyValueAllocatorInitializer() \n   {\n      valueAllocator();      // ensure valueAllocator() statics are initialized before main().\n   }\n} dummyValueAllocatorInitializer;\n\n\n\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// ValueInternals...\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n# include \"json_internalarray.inl\"\n# include \"json_internalmap.inl\"\n#endif // JSON_VALUE_USE_INTERNAL_MAP\n\n# include \"json_valueiterator.inl\"\n\n\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// class Value::CommentInfo\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n\n\nValue::CommentInfo::CommentInfo()\n   : comment_( 0 )\n{\n}\n\nValue::CommentInfo::~CommentInfo()\n{\n   if ( comment_ )\n      valueAllocator()->releaseStringValue( comment_ );\n}\n\n\nvoid \nValue::CommentInfo::setComment( const char *text )\n{\n   if ( comment_ )\n      valueAllocator()->releaseStringValue( comment_ );\n   JSON_ASSERT( text );\n   JSON_ASSERT_MESSAGE( text[0]=='\\0' || text[0]=='/', \"Comments must start with /\");\n   // It seems that /**/ style comments are acceptable as well.\n   comment_ = valueAllocator()->duplicateStringValue( text );\n}\n\n\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// class Value::CZString\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n# ifndef JSON_VALUE_USE_INTERNAL_MAP\n\n// Notes: index_ indicates if the string was allocated when\n// a string is stored.\n\nValue::CZString::CZString( int index )\n   : cstr_( 0 )\n   , index_( index )\n{\n}\n\nValue::CZString::CZString( const char *cstr, DuplicationPolicy allocate )\n   : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr) \n                                  : cstr )\n   , index_( allocate )\n{\n}\n\nValue::CZString::CZString( const CZString &other )\n: cstr_( other.index_ != noDuplication &&  other.cstr_ != 0\n                ?  valueAllocator()->makeMemberName( other.cstr_ )\n                : other.cstr_ )\n   , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate)\n                         : other.index_ )\n{\n}\n\nValue::CZString::~CZString()\n{\n   if ( cstr_  &&  index_ == duplicate )\n      valueAllocator()->releaseMemberName( const_cast<char *>( cstr_ ) );\n}\n\nvoid \nValue::CZString::swap( CZString &other )\n{\n   std::swap( cstr_, other.cstr_ );\n   std::swap( index_, other.index_ );\n}\n\nValue::CZString &\nValue::CZString::operator =( const CZString &other )\n{\n   CZString temp( other );\n   swap( temp );\n   return *this;\n}\n\nbool \nValue::CZString::operator<( const CZString &other ) const \n{\n   if ( cstr_ )\n      return strcmp( cstr_, other.cstr_ ) < 0;\n   return index_ < other.index_;\n}\n\nbool \nValue::CZString::operator==( const CZString &other ) const \n{\n   if ( cstr_ )\n      return strcmp( cstr_, other.cstr_ ) == 0;\n   return index_ == other.index_;\n}\n\n\nint \nValue::CZString::index() const\n{\n   return index_;\n}\n\n\nconst char *\nValue::CZString::c_str() const\n{\n   return cstr_;\n}\n\nbool \nValue::CZString::isStaticString() const\n{\n   return index_ == noDuplication;\n}\n\n#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP\n\n\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// class Value::Value\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n\n/*! \\internal Default constructor initialization must be equivalent to:\n * memset( this, 0, sizeof(Value) )\n * This optimization is used in ValueInternalMap fast allocator.\n */\nValue::Value( ValueType type )\n   : type_( type )\n   , allocated_( 0 )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   switch ( type )\n   {\n   case nullValue:\n      break;\n   case intValue:\n   case uintValue:\n      value_.int_ = 0;\n      break;\n   case realValue:\n      value_.real_ = 0.0;\n      break;\n   case stringValue:\n      value_.string_ = 0;\n      break;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n   case objectValue:\n      value_.map_ = new ObjectValues();\n      break;\n#else\n   case arrayValue:\n      value_.array_ = arrayAllocator()->newArray();\n      break;\n   case objectValue:\n      value_.map_ = mapAllocator()->newMap();\n      break;\n#endif\n   case booleanValue:\n      value_.bool_ = false;\n      break;\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n}\n\n\nValue::Value( Int value )\n   : type_( intValue )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.int_ = value;\n}\n\n\nValue::Value( UInt value )\n   : type_( uintValue )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.uint_ = value;\n}\n\nValue::Value( double value )\n   : type_( realValue )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.real_ = value;\n}\n\nValue::Value( const char *value )\n   : type_( stringValue )\n   , allocated_( true )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.string_ = valueAllocator()->duplicateStringValue( value );\n}\n\n\nValue::Value( const char *beginValue, \n              const char *endValue )\n   : type_( stringValue )\n   , allocated_( true )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.string_ = valueAllocator()->duplicateStringValue( beginValue, \n                                                            UInt(endValue - beginValue) );\n}\n\n\nValue::Value( const std::string &value )\n   : type_( stringValue )\n   , allocated_( true )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(), \n                                                            (unsigned int)value.length() );\n\n}\n\nValue::Value( const StaticString &value )\n   : type_( stringValue )\n   , allocated_( false )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.string_ = const_cast<char *>( value.c_str() );\n}\n\n\n# ifdef JSON_USE_CPPTL\nValue::Value( const CppTL::ConstString &value )\n   : type_( stringValue )\n   , allocated_( true )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() );\n}\n# endif\n\nValue::Value( bool value )\n   : type_( booleanValue )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.bool_ = value;\n}\n\n\nValue::Value( const Value &other )\n   : type_( other.type_ )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   switch ( type_ )\n   {\n   case nullValue:\n   case intValue:\n   case uintValue:\n   case realValue:\n   case booleanValue:\n      value_ = other.value_;\n      break;\n   case stringValue:\n      if ( other.value_.string_ )\n      {\n         value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ );\n         allocated_ = true;\n      }\n      else\n         value_.string_ = 0;\n      break;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n   case objectValue:\n      value_.map_ = new ObjectValues( *other.value_.map_ );\n      break;\n#else\n   case arrayValue:\n      value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ );\n      break;\n   case objectValue:\n      value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ );\n      break;\n#endif\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   if ( other.comments_ )\n   {\n      comments_ = new CommentInfo[numberOfCommentPlacement];\n      for ( int comment =0; comment < numberOfCommentPlacement; ++comment )\n      {\n         const CommentInfo &otherComment = other.comments_[comment];\n         if ( otherComment.comment_ )\n            comments_[comment].setComment( otherComment.comment_ );\n      }\n   }\n}\n\n\nValue::~Value()\n{\n   switch ( type_ )\n   {\n   case nullValue:\n   case intValue:\n   case uintValue:\n   case realValue:\n   case booleanValue:\n      break;\n   case stringValue:\n      if ( allocated_ )\n         valueAllocator()->releaseStringValue( value_.string_ );\n      break;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n   case objectValue:\n      delete value_.map_;\n      break;\n#else\n   case arrayValue:\n      arrayAllocator()->destructArray( value_.array_ );\n      break;\n   case objectValue:\n      mapAllocator()->destructMap( value_.map_ );\n      break;\n#endif\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n\n   if ( comments_ )\n      delete[] comments_;\n}\n\nValue &\nValue::operator=( const Value &other )\n{\n   Value temp( other );\n   swap( temp );\n   return *this;\n}\n\nvoid \nValue::swap( Value &other )\n{\n   ValueType temp = type_;\n   type_ = other.type_;\n   other.type_ = temp;\n   std::swap( value_, other.value_ );\n   int temp2 = allocated_;\n   allocated_ = other.allocated_;\n   other.allocated_ = temp2;\n}\n\nValueType \nValue::type() const\n{\n   return type_;\n}\n\n\nint \nValue::compare( const Value &other )\n{\n   /*\n   int typeDelta = other.type_ - type_;\n   switch ( type_ )\n   {\n   case nullValue:\n\n      return other.type_ == type_;\n   case intValue:\n      if ( other.type_.isNumeric()\n   case uintValue:\n   case realValue:\n   case booleanValue:\n      break;\n   case stringValue,\n      break;\n   case arrayValue:\n      delete value_.array_;\n      break;\n   case objectValue:\n      delete value_.map_;\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   */\n   return 0;  // unreachable\n}\n\nbool \nValue::operator <( const Value &other ) const\n{\n   int typeDelta = type_ - other.type_;\n   if ( typeDelta )\n      return typeDelta < 0 ? true : false;\n   switch ( type_ )\n   {\n   case nullValue:\n      return false;\n   case intValue:\n      return value_.int_ < other.value_.int_;\n   case uintValue:\n      return value_.uint_ < other.value_.uint_;\n   case realValue:\n      return value_.real_ < other.value_.real_;\n   case booleanValue:\n      return value_.bool_ < other.value_.bool_;\n   case stringValue:\n      return ( value_.string_ == 0  &&  other.value_.string_ )\n             || ( other.value_.string_  \n                  &&  value_.string_  \n                  && strcmp( value_.string_, other.value_.string_ ) < 0 );\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n   case objectValue:\n      {\n         int delta = int( value_.map_->size() - other.value_.map_->size() );\n         if ( delta )\n            return delta < 0;\n         return (*value_.map_) < (*other.value_.map_);\n      }\n#else\n   case arrayValue:\n      return value_.array_->compare( *(other.value_.array_) ) < 0;\n   case objectValue:\n      return value_.map_->compare( *(other.value_.map_) ) < 0;\n#endif\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return 0;  // unreachable\n}\n\nbool \nValue::operator <=( const Value &other ) const\n{\n   return !(other > *this);\n}\n\nbool \nValue::operator >=( const Value &other ) const\n{\n   return !(*this < other);\n}\n\nbool \nValue::operator >( const Value &other ) const\n{\n   return other < *this;\n}\n\nbool \nValue::operator ==( const Value &other ) const\n{\n   //if ( type_ != other.type_ )\n   // GCC 2.95.3 says:\n   // attempt to take address of bit-field structure member `Json::Value::type_'\n   // Beats me, but a temp solves the problem.\n   int temp = other.type_;\n   if ( type_ != temp )\n      return false;\n   switch ( type_ )\n   {\n   case nullValue:\n      return true;\n   case intValue:\n      return value_.int_ == other.value_.int_;\n   case uintValue:\n      return value_.uint_ == other.value_.uint_;\n   case realValue:\n      return value_.real_ == other.value_.real_;\n   case booleanValue:\n      return value_.bool_ == other.value_.bool_;\n   case stringValue:\n      return ( value_.string_ == other.value_.string_ )\n             || ( other.value_.string_  \n                  &&  value_.string_  \n                  && strcmp( value_.string_, other.value_.string_ ) == 0 );\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n   case objectValue:\n      return value_.map_->size() == other.value_.map_->size()\n             && (*value_.map_) == (*other.value_.map_);\n#else\n   case arrayValue:\n      return value_.array_->compare( *(other.value_.array_) ) == 0;\n   case objectValue:\n      return value_.map_->compare( *(other.value_.map_) ) == 0;\n#endif\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return 0;  // unreachable\n}\n\nbool \nValue::operator !=( const Value &other ) const\n{\n   return !( *this == other );\n}\n\nconst char *\nValue::asCString() const\n{\n   JSON_ASSERT( type_ == stringValue );\n   return value_.string_;\n}\n\n\nstd::string \nValue::asString() const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n      return \"\";\n   case stringValue:\n      return value_.string_ ? value_.string_ : \"\";\n   case booleanValue:\n      return value_.bool_ ? \"true\" : \"false\";\n   case intValue:\n   case uintValue:\n   case realValue:\n   case arrayValue:\n   case objectValue:\n      JSON_ASSERT_MESSAGE( false, \"Type is not convertible to string\" );\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return \"\"; // unreachable\n}\n\n# ifdef JSON_USE_CPPTL\nCppTL::ConstString \nValue::asConstString() const\n{\n   return CppTL::ConstString( asString().c_str() );\n}\n# endif\n\nValue::Int \nValue::asInt() const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n      return 0;\n   case intValue:\n      return value_.int_;\n   case uintValue:\n      JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, \"integer out of signed integer range\" );\n      return value_.uint_;\n   case realValue:\n      JSON_ASSERT_MESSAGE( value_.real_ >= minInt  &&  value_.real_ <= maxInt, \"Real out of signed integer range\" );\n      return Int( value_.real_ );\n   case booleanValue:\n      return value_.bool_ ? 1 : 0;\n   case stringValue:\n   case arrayValue:\n   case objectValue:\n      JSON_ASSERT_MESSAGE( false, \"Type is not convertible to int\" );\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return 0; // unreachable;\n}\n\nValue::UInt \nValue::asUInt() const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n      return 0;\n   case intValue:\n      JSON_ASSERT_MESSAGE( value_.int_ >= 0, \"Negative integer can not be converted to unsigned integer\" );\n      return value_.int_;\n   case uintValue:\n      return value_.uint_;\n   case realValue:\n      JSON_ASSERT_MESSAGE( value_.real_ >= 0  &&  value_.real_ <= maxUInt,  \"Real out of unsigned integer range\" );\n      return UInt( value_.real_ );\n   case booleanValue:\n      return value_.bool_ ? 1 : 0;\n   case stringValue:\n   case arrayValue:\n   case objectValue:\n      JSON_ASSERT_MESSAGE( false, \"Type is not convertible to uint\" );\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return 0; // unreachable;\n}\n\ndouble \nValue::asDouble() const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n      return 0.0;\n   case intValue:\n      return value_.int_;\n   case uintValue:\n      return value_.uint_;\n   case realValue:\n      return value_.real_;\n   case booleanValue:\n      return value_.bool_ ? 1.0 : 0.0;\n   case stringValue:\n   case arrayValue:\n   case objectValue:\n      JSON_ASSERT_MESSAGE( false, \"Type is not convertible to double\" );\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return 0; // unreachable;\n}\n\nbool \nValue::asBool() const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n      return false;\n   case intValue:\n   case uintValue:\n      return value_.int_ != 0;\n   case realValue:\n      return value_.real_ != 0.0;\n   case booleanValue:\n      return value_.bool_;\n   case stringValue:\n      return value_.string_  &&  value_.string_[0] != 0;\n   case arrayValue:\n   case objectValue:\n      return value_.map_->size() != 0;\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return false; // unreachable;\n}\n\n\nbool \nValue::isConvertibleTo( ValueType other ) const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n      return true;\n   case intValue:\n      return ( other == nullValue  &&  value_.int_ == 0 )\n             || other == intValue\n             || ( other == uintValue  && value_.int_ >= 0 )\n             || other == realValue\n             || other == stringValue\n             || other == booleanValue;\n   case uintValue:\n      return ( other == nullValue  &&  value_.uint_ == 0 )\n             || ( other == intValue  && value_.uint_ <= (unsigned)maxInt )\n             || other == uintValue\n             || other == realValue\n             || other == stringValue\n             || other == booleanValue;\n   case realValue:\n      return ( other == nullValue  &&  value_.real_ == 0.0 )\n             || ( other == intValue  &&  value_.real_ >= minInt  &&  value_.real_ <= maxInt )\n             || ( other == uintValue  &&  value_.real_ >= 0  &&  value_.real_ <= maxUInt )\n             || other == realValue\n             || other == stringValue\n             || other == booleanValue;\n   case booleanValue:\n      return ( other == nullValue  &&  value_.bool_ == false )\n             || other == intValue\n             || other == uintValue\n             || other == realValue\n             || other == stringValue\n             || other == booleanValue;\n   case stringValue:\n      return other == stringValue\n             || ( other == nullValue  &&  (!value_.string_  ||  value_.string_[0] == 0) );\n   case arrayValue:\n      return other == arrayValue\n             ||  ( other == nullValue  &&  value_.map_->size() == 0 );\n   case objectValue:\n      return other == objectValue\n             ||  ( other == nullValue  &&  value_.map_->size() == 0 );\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return false; // unreachable;\n}\n\n\n/// Number of values in array or object\nValue::UInt \nValue::size() const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n   case intValue:\n   case uintValue:\n   case realValue:\n   case booleanValue:\n   case stringValue:\n      return 0;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:  // size of the array is highest index + 1\n      if ( !value_.map_->empty() )\n      {\n         ObjectValues::const_iterator itLast = value_.map_->end();\n         --itLast;\n         return (*itLast).first.index()+1;\n      }\n      return 0;\n   case objectValue:\n      return Int( value_.map_->size() );\n#else\n   case arrayValue:\n      return Int( value_.array_->size() );\n   case objectValue:\n      return Int( value_.map_->size() );\n#endif\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return 0; // unreachable;\n}\n\n\nbool \nValue::empty() const\n{\n   if ( isNull() || isArray() || isObject() )\n      return size() == 0u;\n   else\n      return false;\n}\n\n\nbool\nValue::operator!() const\n{\n   return isNull();\n}\n\n\nvoid \nValue::clear()\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue  || type_ == objectValue );\n\n   switch ( type_ )\n   {\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n   case objectValue:\n      value_.map_->clear();\n      break;\n#else\n   case arrayValue:\n      value_.array_->clear();\n      break;\n   case objectValue:\n      value_.map_->clear();\n      break;\n#endif\n   default:\n      break;\n   }\n}\n\nvoid \nValue::resize( UInt newSize )\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue );\n   if ( type_ == nullValue )\n      *this = Value( arrayValue );\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   UInt oldSize = size();\n   if ( newSize == 0 )\n      clear();\n   else if ( newSize > oldSize )\n      (*this)[ newSize - 1 ];\n   else\n   {\n      for ( UInt index = newSize; index < oldSize; ++index )\n         value_.map_->erase( index );\n      assert( size() == newSize );\n   }\n#else\n   value_.array_->resize( newSize );\n#endif\n}\n\n\nValue &\nValue::operator[]( UInt index )\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue );\n   if ( type_ == nullValue )\n      *this = Value( arrayValue );\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   CZString key( index );\n   ObjectValues::iterator it = value_.map_->lower_bound( key );\n   if ( it != value_.map_->end()  &&  (*it).first == key )\n      return (*it).second;\n\n   ObjectValues::value_type defaultValue( key, null );\n   it = value_.map_->insert( it, defaultValue );\n   return (*it).second;\n#else\n   return value_.array_->resolveReference( index );\n#endif\n}\n\n\nconst Value &\nValue::operator[]( UInt index ) const\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue );\n   if ( type_ == nullValue )\n      return null;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   CZString key( index );\n   ObjectValues::const_iterator it = value_.map_->find( key );\n   if ( it == value_.map_->end() )\n      return null;\n   return (*it).second;\n#else\n   Value *value = value_.array_->find( index );\n   return value ? *value : null;\n#endif\n}\n\n\nValue &\nValue::operator[]( const char *key )\n{\n   return resolveReference( key, false );\n}\n\n\nValue &\nValue::resolveReference( const char *key, \n                         bool isStatic )\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );\n   if ( type_ == nullValue )\n      *this = Value( objectValue );\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   CZString actualKey( key, isStatic ? CZString::noDuplication \n                                     : CZString::duplicateOnCopy );\n   ObjectValues::iterator it = value_.map_->lower_bound( actualKey );\n   if ( it != value_.map_->end()  &&  (*it).first == actualKey )\n      return (*it).second;\n\n   ObjectValues::value_type defaultValue( actualKey, null );\n   it = value_.map_->insert( it, defaultValue );\n   Value &value = (*it).second;\n   return value;\n#else\n   return value_.map_->resolveReference( key, isStatic );\n#endif\n}\n\n\nValue \nValue::get( UInt index, \n            const Value &defaultValue ) const\n{\n   const Value *value = &((*this)[index]);\n   return value == &null ? defaultValue : *value;\n}\n\n\nbool \nValue::isValidIndex( UInt index ) const\n{\n   return index < size();\n}\n\n\n\nconst Value &\nValue::operator[]( const char *key ) const\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );\n   if ( type_ == nullValue )\n      return null;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   CZString actualKey( key, CZString::noDuplication );\n   ObjectValues::const_iterator it = value_.map_->find( actualKey );\n   if ( it == value_.map_->end() )\n      return null;\n   return (*it).second;\n#else\n   const Value *value = value_.map_->find( key );\n   return value ? *value : null;\n#endif\n}\n\n\nValue &\nValue::operator[]( const std::string &key )\n{\n   return (*this)[ key.c_str() ];\n}\n\n\nconst Value &\nValue::operator[]( const std::string &key ) const\n{\n   return (*this)[ key.c_str() ];\n}\n\nValue &\nValue::operator[]( const StaticString &key )\n{\n   return resolveReference( key, true );\n}\n\n\n# ifdef JSON_USE_CPPTL\nValue &\nValue::operator[]( const CppTL::ConstString &key )\n{\n   return (*this)[ key.c_str() ];\n}\n\n\nconst Value &\nValue::operator[]( const CppTL::ConstString &key ) const\n{\n   return (*this)[ key.c_str() ];\n}\n# endif\n\n\nValue &\nValue::append( const Value &value )\n{\n   return (*this)[size()] = value;\n}\n\n\nValue \nValue::get( const char *key, \n            const Value &defaultValue ) const\n{\n   const Value *value = &((*this)[key]);\n   return value == &null ? defaultValue : *value;\n}\n\n\nValue \nValue::get( const std::string &key,\n            const Value &defaultValue ) const\n{\n   return get( key.c_str(), defaultValue );\n}\n\nValue\nValue::removeMember( const char* key )\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );\n   if ( type_ == nullValue )\n      return null;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   CZString actualKey( key, CZString::noDuplication );\n   ObjectValues::iterator it = value_.map_->find( actualKey );\n   if ( it == value_.map_->end() )\n      return null;\n   Value old(it->second);\n   value_.map_->erase(it);\n   return old;\n#else\n   Value *value = value_.map_->find( key );\n   if (value){\n      Value old(*value);\n      value_.map_.remove( key );\n      return old;\n   } else {\n      return null;\n   }\n#endif\n}\n\nValue\nValue::removeMember( const std::string &key )\n{\n   return removeMember( key.c_str() );\n}\n\n# ifdef JSON_USE_CPPTL\nValue \nValue::get( const CppTL::ConstString &key,\n            const Value &defaultValue ) const\n{\n   return get( key.c_str(), defaultValue );\n}\n# endif\n\nbool \nValue::isMember( const char *key ) const\n{\n   const Value *value = &((*this)[key]);\n   return value != &null;\n}\n\n\nbool \nValue::isMember( const std::string &key ) const\n{\n   return isMember( key.c_str() );\n}\n\n\n# ifdef JSON_USE_CPPTL\nbool \nValue::isMember( const CppTL::ConstString &key ) const\n{\n   return isMember( key.c_str() );\n}\n#endif\n\nValue::Members \nValue::getMemberNames() const\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );\n   if ( type_ == nullValue )\n       return Value::Members();\n   Members members;\n   members.reserve( value_.map_->size() );\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   ObjectValues::const_iterator it = value_.map_->begin();\n   ObjectValues::const_iterator itEnd = value_.map_->end();\n   for ( ; it != itEnd; ++it )\n      members.push_back( std::string( (*it).first.c_str() ) );\n#else\n   ValueInternalMap::IteratorState it;\n   ValueInternalMap::IteratorState itEnd;\n   value_.map_->makeBeginIterator( it );\n   value_.map_->makeEndIterator( itEnd );\n   for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) )\n      members.push_back( std::string( ValueInternalMap::key( it ) ) );\n#endif\n   return members;\n}\n//\n//# ifdef JSON_USE_CPPTL\n//EnumMemberNames\n//Value::enumMemberNames() const\n//{\n//   if ( type_ == objectValue )\n//   {\n//      return CppTL::Enum::any(  CppTL::Enum::transform(\n//         CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),\n//         MemberNamesTransform() ) );\n//   }\n//   return EnumMemberNames();\n//}\n//\n//\n//EnumValues \n//Value::enumValues() const\n//{\n//   if ( type_ == objectValue  ||  type_ == arrayValue )\n//      return CppTL::Enum::anyValues( *(value_.map_), \n//                                     CppTL::Type<const Value &>() );\n//   return EnumValues();\n//}\n//\n//# endif\n\n\nbool\nValue::isNull() const\n{\n   return type_ == nullValue;\n}\n\n\nbool \nValue::isBool() const\n{\n   return type_ == booleanValue;\n}\n\n\nbool \nValue::isInt() const\n{\n   return type_ == intValue;\n}\n\n\nbool \nValue::isUInt() const\n{\n   return type_ == uintValue;\n}\n\n\nbool \nValue::isIntegral() const\n{\n   return type_ == intValue  \n          ||  type_ == uintValue  \n          ||  type_ == booleanValue;\n}\n\n\nbool \nValue::isDouble() const\n{\n   return type_ == realValue;\n}\n\n\nbool \nValue::isNumeric() const\n{\n   return isIntegral() || isDouble();\n}\n\n\nbool \nValue::isString() const\n{\n   return type_ == stringValue;\n}\n\n\nbool \nValue::isArray() const\n{\n   return type_ == nullValue  ||  type_ == arrayValue;\n}\n\n\nbool \nValue::isObject() const\n{\n   return type_ == nullValue  ||  type_ == objectValue;\n}\n\n\nvoid \nValue::setComment( const char *comment,\n                   CommentPlacement placement )\n{\n   if ( !comments_ )\n      comments_ = new CommentInfo[numberOfCommentPlacement];\n   comments_[placement].setComment( comment );\n}\n\n\nvoid \nValue::setComment( const std::string &comment,\n                   CommentPlacement placement )\n{\n   setComment( comment.c_str(), placement );\n}\n\n\nbool \nValue::hasComment( CommentPlacement placement ) const\n{\n   return comments_ != 0  &&  comments_[placement].comment_ != 0;\n}\n\nstd::string \nValue::getComment( CommentPlacement placement ) const\n{\n   if ( hasComment(placement) )\n      return comments_[placement].comment_;\n   return \"\";\n}\n\n\nstd::string \nValue::toStyledString() const\n{\n   StyledWriter writer;\n   return writer.write( *this );\n}\n\n\nValue::const_iterator \nValue::begin() const\n{\n   switch ( type_ )\n   {\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n      if ( value_.array_ )\n      {\n         ValueInternalArray::IteratorState it;\n         value_.array_->makeBeginIterator( it );\n         return const_iterator( it );\n      }\n      break;\n   case objectValue:\n      if ( value_.map_ )\n      {\n         ValueInternalMap::IteratorState it;\n         value_.map_->makeBeginIterator( it );\n         return const_iterator( it );\n      }\n      break;\n#else\n   case arrayValue:\n   case objectValue:\n      if ( value_.map_ )\n         return const_iterator( value_.map_->begin() );\n      break;\n#endif\n   default:\n      break;\n   }\n   return const_iterator();\n}\n\nValue::const_iterator \nValue::end() const\n{\n   switch ( type_ )\n   {\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n      if ( value_.array_ )\n      {\n         ValueInternalArray::IteratorState it;\n         value_.array_->makeEndIterator( it );\n         return const_iterator( it );\n      }\n      break;\n   case objectValue:\n      if ( value_.map_ )\n      {\n         ValueInternalMap::IteratorState it;\n         value_.map_->makeEndIterator( it );\n         return const_iterator( it );\n      }\n      break;\n#else\n   case arrayValue:\n   case objectValue:\n      if ( value_.map_ )\n         return const_iterator( value_.map_->end() );\n      break;\n#endif\n   default:\n      break;\n   }\n   return const_iterator();\n}\n\n\nValue::iterator \nValue::begin()\n{\n   switch ( type_ )\n   {\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n      if ( value_.array_ )\n      {\n         ValueInternalArray::IteratorState it;\n         value_.array_->makeBeginIterator( it );\n         return iterator( it );\n      }\n      break;\n   case objectValue:\n      if ( value_.map_ )\n      {\n         ValueInternalMap::IteratorState it;\n         value_.map_->makeBeginIterator( it );\n         return iterator( it );\n      }\n      break;\n#else\n   case arrayValue:\n   case objectValue:\n      if ( value_.map_ )\n         return iterator( value_.map_->begin() );\n      break;\n#endif\n   default:\n      break;\n   }\n   return iterator();\n}\n\nValue::iterator \nValue::end()\n{\n   switch ( type_ )\n   {\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n      if ( value_.array_ )\n      {\n         ValueInternalArray::IteratorState it;\n         value_.array_->makeEndIterator( it );\n         return iterator( it );\n      }\n      break;\n   case objectValue:\n      if ( value_.map_ )\n      {\n         ValueInternalMap::IteratorState it;\n         value_.map_->makeEndIterator( it );\n         return iterator( it );\n      }\n      break;\n#else\n   case arrayValue:\n   case objectValue:\n      if ( value_.map_ )\n         return iterator( value_.map_->end() );\n      break;\n#endif\n   default:\n      break;\n   }\n   return iterator();\n}\n\n\n// class PathArgument\n// //////////////////////////////////////////////////////////////////\n\nPathArgument::PathArgument()\n   : kind_( kindNone )\n{\n}\n\n\nPathArgument::PathArgument( Value::UInt index )\n   : index_( index )\n   , kind_( kindIndex )\n{\n}\n\n\nPathArgument::PathArgument( const char *key )\n   : key_( key )\n   , kind_( kindKey )\n{\n}\n\n\nPathArgument::PathArgument( const std::string &key )\n   : key_( key.c_str() )\n   , kind_( kindKey )\n{\n}\n\n// class Path\n// //////////////////////////////////////////////////////////////////\n\nPath::Path( const std::string &path,\n            const PathArgument &a1,\n            const PathArgument &a2,\n            const PathArgument &a3,\n            const PathArgument &a4,\n            const PathArgument &a5 )\n{\n   InArgs in;\n   in.push_back( &a1 );\n   in.push_back( &a2 );\n   in.push_back( &a3 );\n   in.push_back( &a4 );\n   in.push_back( &a5 );\n   makePath( path, in );\n}\n\n\nvoid \nPath::makePath( const std::string &path,\n                const InArgs &in )\n{\n   const char *current = path.c_str();\n   const char *end = current + path.length();\n   InArgs::const_iterator itInArg = in.begin();\n   while ( current != end )\n   {\n      if ( *current == '[' )\n      {\n         ++current;\n         if ( *current == '%' )\n            addPathInArg( path, in, itInArg, PathArgument::kindIndex );\n         else\n         {\n            Value::UInt index = 0;\n            for ( ; current != end && *current >= '0'  &&  *current <= '9'; ++current )\n               index = index * 10 + Value::UInt(*current - '0');\n            args_.push_back( index );\n         }\n         if ( current == end  ||  *current++ != ']' )\n            invalidPath( path, int(current - path.c_str()) );\n      }\n      else if ( *current == '%' )\n      {\n         addPathInArg( path, in, itInArg, PathArgument::kindKey );\n         ++current;\n      }\n      else if ( *current == '.' )\n      {\n         ++current;\n      }\n      else\n      {\n         const char *beginName = current;\n         while ( current != end  &&  !strchr( \"[.\", *current ) )\n            ++current;\n         args_.push_back( std::string( beginName, current ) );\n      }\n   }\n}\n\n\nvoid \nPath::addPathInArg( const std::string &path, \n                    const InArgs &in, \n                    InArgs::const_iterator &itInArg, \n                    PathArgument::Kind kind )\n{\n   if ( itInArg == in.end() )\n   {\n      // Error: missing argument %d\n   }\n   else if ( (*itInArg)->kind_ != kind )\n   {\n      // Error: bad argument type\n   }\n   else\n   {\n      args_.push_back( **itInArg );\n   }\n}\n\n\nvoid \nPath::invalidPath( const std::string &path, \n                   int location )\n{\n   // Error: invalid path.\n}\n\n\nconst Value &\nPath::resolve( const Value &root ) const\n{\n   const Value *node = &root;\n   for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )\n   {\n      const PathArgument &arg = *it;\n      if ( arg.kind_ == PathArgument::kindIndex )\n      {\n         if ( !node->isArray()  ||  node->isValidIndex( arg.index_ ) )\n         {\n            // Error: unable to resolve path (array value expected at position...\n         }\n         node = &((*node)[arg.index_]);\n      }\n      else if ( arg.kind_ == PathArgument::kindKey )\n      {\n         if ( !node->isObject() )\n         {\n            // Error: unable to resolve path (object value expected at position...)\n         }\n         node = &((*node)[arg.key_]);\n         if ( node == &Value::null )\n         {\n            // Error: unable to resolve path (object has no member named '' at position...)\n         }\n      }\n   }\n   return *node;\n}\n\n\nValue \nPath::resolve( const Value &root, \n               const Value &defaultValue ) const\n{\n   const Value *node = &root;\n   for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )\n   {\n      const PathArgument &arg = *it;\n      if ( arg.kind_ == PathArgument::kindIndex )\n      {\n         if ( !node->isArray()  ||  node->isValidIndex( arg.index_ ) )\n            return defaultValue;\n         node = &((*node)[arg.index_]);\n      }\n      else if ( arg.kind_ == PathArgument::kindKey )\n      {\n         if ( !node->isObject() )\n            return defaultValue;\n         node = &((*node)[arg.key_]);\n         if ( node == &Value::null )\n            return defaultValue;\n      }\n   }\n   return *node;\n}\n\n\nValue &\nPath::make( Value &root ) const\n{\n   Value *node = &root;\n   for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )\n   {\n      const PathArgument &arg = *it;\n      if ( arg.kind_ == PathArgument::kindIndex )\n      {\n         if ( !node->isArray() )\n         {\n            // Error: node is not an array at position ...\n         }\n         node = &((*node)[arg.index_]);\n      }\n      else if ( arg.kind_ == PathArgument::kindKey )\n      {\n         if ( !node->isObject() )\n         {\n            // Error: node is not an object at position...\n         }\n         node = &((*node)[arg.key_]);\n      }\n   }\n   return *node;\n}\n\n\n} // namespace Json\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_valueiterator.inl",
    "content": "// included by json_value.cpp\n// everything is within Json namespace\n\n\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// class ValueIteratorBase\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n\nValueIteratorBase::ValueIteratorBase()\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   : current_()\n   , isNull_( true )\n{\n}\n#else\n   : isArray_( true )\n   , isNull_( true )\n{\n   iterator_.array_ = ValueInternalArray::IteratorState();\n}\n#endif\n\n\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\nValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator &current )\n   : current_( current )\n   , isNull_( false )\n{\n}\n#else\nValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state )\n   : isArray_( true )\n{\n   iterator_.array_ = state;\n}\n\n\nValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state )\n   : isArray_( false )\n{\n   iterator_.map_ = state;\n}\n#endif\n\nValue &\nValueIteratorBase::deref() const\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   return current_->second;\n#else\n   if ( isArray_ )\n      return ValueInternalArray::dereference( iterator_.array_ );\n   return ValueInternalMap::value( iterator_.map_ );\n#endif\n}\n\n\nvoid \nValueIteratorBase::increment()\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   ++current_;\n#else\n   if ( isArray_ )\n      ValueInternalArray::increment( iterator_.array_ );\n   ValueInternalMap::increment( iterator_.map_ );\n#endif\n}\n\n\nvoid \nValueIteratorBase::decrement()\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   --current_;\n#else\n   if ( isArray_ )\n      ValueInternalArray::decrement( iterator_.array_ );\n   ValueInternalMap::decrement( iterator_.map_ );\n#endif\n}\n\n\nValueIteratorBase::difference_type \nValueIteratorBase::computeDistance( const SelfType &other ) const\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n# ifdef JSON_USE_CPPTL_SMALLMAP\n   return current_ - other.current_;\n# else\n   // Iterator for null value are initialized using the default\n   // constructor, which initialize current_ to the default\n   // std::map::iterator. As begin() and end() are two instance \n   // of the default std::map::iterator, they can not be compared.\n   // To allow this, we handle this comparison specifically.\n   if ( isNull_  &&  other.isNull_ )\n   {\n      return 0;\n   }\n\n\n   // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL,\n   // which is the one used by default).\n   // Using a portable hand-made version for non random iterator instead:\n   //   return difference_type( std::distance( current_, other.current_ ) );\n   difference_type myDistance = 0;\n   for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it )\n   {\n      ++myDistance;\n   }\n   return myDistance;\n# endif\n#else\n   if ( isArray_ )\n      return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ );\n   return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ );\n#endif\n}\n\n\nbool \nValueIteratorBase::isEqual( const SelfType &other ) const\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   if ( isNull_ )\n   {\n      return other.isNull_;\n   }\n   return current_ == other.current_;\n#else\n   if ( isArray_ )\n      return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ );\n   return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ );\n#endif\n}\n\n\nvoid \nValueIteratorBase::copy( const SelfType &other )\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   current_ = other.current_;\n#else\n   if ( isArray_ )\n      iterator_.array_ = other.iterator_.array_;\n   iterator_.map_ = other.iterator_.map_;\n#endif\n}\n\n\nValue \nValueIteratorBase::key() const\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   const Value::CZString czstring = (*current_).first;\n   if ( czstring.c_str() )\n   {\n      if ( czstring.isStaticString() )\n         return Value( StaticString( czstring.c_str() ) );\n      return Value( czstring.c_str() );\n   }\n   return Value( czstring.index() );\n#else\n   if ( isArray_ )\n      return Value( ValueInternalArray::indexOf( iterator_.array_ ) );\n   bool isStatic;\n   const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic );\n   if ( isStatic )\n      return Value( StaticString( memberName ) );\n   return Value( memberName );\n#endif\n}\n\n\nUInt \nValueIteratorBase::index() const\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   const Value::CZString czstring = (*current_).first;\n   if ( !czstring.c_str() )\n      return czstring.index();\n   return Value::UInt( -1 );\n#else\n   if ( isArray_ )\n      return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) );\n   return Value::UInt( -1 );\n#endif\n}\n\n\nconst char *\nValueIteratorBase::memberName() const\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   const char *name = (*current_).first.c_str();\n   return name ? name : \"\";\n#else\n   if ( !isArray_ )\n      return ValueInternalMap::key( iterator_.map_ );\n   return \"\";\n#endif\n}\n\n\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// class ValueConstIterator\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n\nValueConstIterator::ValueConstIterator()\n{\n}\n\n\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\nValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator &current )\n   : ValueIteratorBase( current )\n{\n}\n#else\nValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state )\n   : ValueIteratorBase( state )\n{\n}\n\nValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state )\n   : ValueIteratorBase( state )\n{\n}\n#endif\n\nValueConstIterator &\nValueConstIterator::operator =( const ValueIteratorBase &other )\n{\n   copy( other );\n   return *this;\n}\n\n\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// class ValueIterator\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n\nValueIterator::ValueIterator()\n{\n}\n\n\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\nValueIterator::ValueIterator( const Value::ObjectValues::iterator &current )\n   : ValueIteratorBase( current )\n{\n}\n#else\nValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state )\n   : ValueIteratorBase( state )\n{\n}\n\nValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state )\n   : ValueIteratorBase( state )\n{\n}\n#endif\n\nValueIterator::ValueIterator( const ValueConstIterator &other )\n   : ValueIteratorBase( other )\n{\n}\n\nValueIterator::ValueIterator( const ValueIterator &other )\n   : ValueIteratorBase( other )\n{\n}\n\nValueIterator &\nValueIterator::operator =( const SelfType &other )\n{\n   copy( other );\n   return *this;\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/json_writer.cpp",
    "content": "#include <json/writer.h>\n#include <utility>\n#include <assert.h>\n#include <stdio.h>\n#include <string.h>\n#include <iostream>\n#include <sstream>\n#include <iomanip>\n\n#if _MSC_VER >= 1400 // VC++ 8.0\n#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.\n#endif\n\nnamespace Json {\n\nstatic bool isControlCharacter(char ch)\n{\n   return ch > 0 && ch <= 0x1F;\n}\n\nstatic bool containsControlCharacter( const char* str )\n{\n   while ( *str ) \n   {\n      if ( isControlCharacter( *(str++) ) )\n         return true;\n   }\n   return false;\n}\nstatic void uintToString( unsigned int value, \n                          char *&current )\n{\n   *--current = 0;\n   do\n   {\n      *--current = (value % 10) + '0';\n      value /= 10;\n   }\n   while ( value != 0 );\n}\n\nstd::string valueToString( Int value )\n{\n   char buffer[32];\n   char *current = buffer + sizeof(buffer);\n   bool isNegative = value < 0;\n   if ( isNegative )\n      value = -value;\n   uintToString( UInt(value), current );\n   if ( isNegative )\n      *--current = '-';\n   assert( current >= buffer );\n   return current;\n}\n\n\nstd::string valueToString( UInt value )\n{\n   char buffer[32];\n   char *current = buffer + sizeof(buffer);\n   uintToString( value, current );\n   assert( current >= buffer );\n   return current;\n}\n\nstd::string valueToString( double value )\n{\n   char buffer[32];\n#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. \n   sprintf_s(buffer, sizeof(buffer), \"%#.16g\", value); \n#else\t\n   sprintf(buffer, \"%#.16g\", value); \n#endif\n   char* ch = buffer + strlen(buffer) - 1;\n   if (*ch != '0') return buffer; // nothing to truncate, so save time\n   while(ch > buffer && *ch == '0'){\n     --ch;\n   }\n   char* last_nonzero = ch;\n   while(ch >= buffer){\n     switch(*ch){\n     case '0':\n     case '1':\n     case '2':\n     case '3':\n     case '4':\n     case '5':\n     case '6':\n     case '7':\n     case '8':\n     case '9':\n       --ch;\n       continue;\n     case '.':\n       // Truncate zeroes to save bytes in output, but keep one.\n       *(last_nonzero+2) = '\\0';\n       return buffer;\n     default:\n       return buffer;\n     }\n   }\n   return buffer;\n}\n\n\nstd::string valueToString( bool value )\n{\n   return value ? \"true\" : \"false\";\n}\n\nstd::string valueToQuotedString( const char *value )\n{\n   // Not sure how to handle unicode...\n   if (strpbrk(value, \"\\\"\\\\\\b\\f\\n\\r\\t\") == NULL && !containsControlCharacter( value ))\n      return std::string(\"\\\"\") + value + \"\\\"\";\n   // We have to walk value and escape any special characters.\n   // Appending to std::string is not efficient, but this should be rare.\n   // (Note: forward slashes are *not* rare, but I am not escaping them.)\n   unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL\n   std::string result;\n   result.reserve(maxsize); // to avoid lots of mallocs\n   result += \"\\\"\";\n   for (const char* c=value; *c != 0; ++c)\n   {\n      switch(*c)\n      {\n         case '\\\"':\n            result += \"\\\\\\\"\";\n            break;\n         case '\\\\':\n            result += \"\\\\\\\\\";\n            break;\n         case '\\b':\n            result += \"\\\\b\";\n            break;\n         case '\\f':\n            result += \"\\\\f\";\n            break;\n         case '\\n':\n            result += \"\\\\n\";\n            break;\n         case '\\r':\n            result += \"\\\\r\";\n            break;\n         case '\\t':\n            result += \"\\\\t\";\n            break;\n         //case '/':\n            // Even though \\/ is considered a legal escape in JSON, a bare\n            // slash is also legal, so I see no reason to escape it.\n            // (I hope I am not misunderstanding something.\n            // blep notes: actually escaping \\/ may be useful in javascript to avoid </ \n            // sequence.\n            // Should add a flag to allow this compatibility mode and prevent this \n            // sequence from occurring.\n         default:\n            if ( isControlCharacter( *c ) )\n            {\n               std::ostringstream oss;\n               oss << \"\\\\u\" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);\n               result += oss.str();\n            }\n            else\n            {\n               result += *c;\n            }\n            break;\n      }\n   }\n   result += \"\\\"\";\n   return result;\n}\n\n// Class Writer\n// //////////////////////////////////////////////////////////////////\nWriter::~Writer()\n{\n}\n\n\n// Class FastWriter\n// //////////////////////////////////////////////////////////////////\n\nFastWriter::FastWriter()\n   : yamlCompatiblityEnabled_( false )\n{\n}\n\n\nvoid \nFastWriter::enableYAMLCompatibility()\n{\n   yamlCompatiblityEnabled_ = true;\n}\n\n\nstd::string \nFastWriter::write( const Value &root )\n{\n   document_ = \"\";\n   writeValue( root );\n   document_ += \"\\n\";\n   return document_;\n}\n\n\nvoid \nFastWriter::writeValue( const Value &value )\n{\n   switch ( value.type() )\n   {\n   case nullValue:\n      document_ += \"null\";\n      break;\n   case intValue:\n      document_ += valueToString( value.asInt() );\n      break;\n   case uintValue:\n      document_ += valueToString( value.asUInt() );\n      break;\n   case realValue:\n      document_ += valueToString( value.asDouble() );\n      break;\n   case stringValue:\n      document_ += valueToQuotedString( value.asCString() );\n      break;\n   case booleanValue:\n      document_ += valueToString( value.asBool() );\n      break;\n   case arrayValue:\n      {\n         document_ += \"[\";\n         int size = value.size();\n         for ( int index =0; index < size; ++index )\n         {\n            if ( index > 0 )\n               document_ += \",\";\n            writeValue( value[index] );\n         }\n         document_ += \"]\";\n      }\n      break;\n   case objectValue:\n      {\n         Value::Members members( value.getMemberNames() );\n         document_ += \"{\";\n         for ( Value::Members::iterator it = members.begin(); \n               it != members.end(); \n               ++it )\n         {\n            const std::string &name = *it;\n            if ( it != members.begin() )\n               document_ += \",\";\n            document_ += valueToQuotedString( name.c_str() );\n            document_ += yamlCompatiblityEnabled_ ? \": \" \n                                                  : \":\";\n            writeValue( value[name] );\n         }\n         document_ += \"}\";\n      }\n      break;\n   }\n}\n\n\n// Class StyledWriter\n// //////////////////////////////////////////////////////////////////\n\nStyledWriter::StyledWriter()\n   : rightMargin_( 74 )\n   , indentSize_( 3 )\n{\n}\n\n\nstd::string \nStyledWriter::write( const Value &root )\n{\n   document_ = \"\";\n   addChildValues_ = false;\n   indentString_ = \"\";\n   writeCommentBeforeValue( root );\n   writeValue( root );\n   writeCommentAfterValueOnSameLine( root );\n   document_ += \"\\n\";\n   return document_;\n}\n\n\nvoid \nStyledWriter::writeValue( const Value &value )\n{\n   switch ( value.type() )\n   {\n   case nullValue:\n      pushValue( \"null\" );\n      break;\n   case intValue:\n      pushValue( valueToString( value.asInt() ) );\n      break;\n   case uintValue:\n      pushValue( valueToString( value.asUInt() ) );\n      break;\n   case realValue:\n      pushValue( valueToString( value.asDouble() ) );\n      break;\n   case stringValue:\n      pushValue( valueToQuotedString( value.asCString() ) );\n      break;\n   case booleanValue:\n      pushValue( valueToString( value.asBool() ) );\n      break;\n   case arrayValue:\n      writeArrayValue( value);\n      break;\n   case objectValue:\n      {\n         Value::Members members( value.getMemberNames() );\n         if ( members.empty() )\n            pushValue( \"{}\" );\n         else\n         {\n            writeWithIndent( \"{\" );\n            indent();\n            Value::Members::iterator it = members.begin();\n            while ( true )\n            {\n               const std::string &name = *it;\n               const Value &childValue = value[name];\n               writeCommentBeforeValue( childValue );\n               writeWithIndent( valueToQuotedString( name.c_str() ) );\n               document_ += \" : \";\n               writeValue( childValue );\n               if ( ++it == members.end() )\n               {\n                  writeCommentAfterValueOnSameLine( childValue );\n                  break;\n               }\n               document_ += \",\";\n               writeCommentAfterValueOnSameLine( childValue );\n            }\n            unindent();\n            writeWithIndent( \"}\" );\n         }\n      }\n      break;\n   }\n}\n\n\nvoid \nStyledWriter::writeArrayValue( const Value &value )\n{\n   unsigned size = value.size();\n   if ( size == 0 )\n      pushValue( \"[]\" );\n   else\n   {\n      bool isArrayMultiLine = isMultineArray( value );\n      if ( isArrayMultiLine )\n      {\n         writeWithIndent( \"[\" );\n         indent();\n         bool hasChildValue = !childValues_.empty();\n         unsigned index =0;\n         while ( true )\n         {\n            const Value &childValue = value[index];\n            writeCommentBeforeValue( childValue );\n            if ( hasChildValue )\n               writeWithIndent( childValues_[index] );\n            else\n            {\n               writeIndent();\n               writeValue( childValue );\n            }\n            if ( ++index == size )\n            {\n               writeCommentAfterValueOnSameLine( childValue );\n               break;\n            }\n            document_ += \",\";\n            writeCommentAfterValueOnSameLine( childValue );\n         }\n         unindent();\n         writeWithIndent( \"]\" );\n      }\n      else // output on a single line\n      {\n         assert( childValues_.size() == size );\n         document_ += \"[ \";\n         for ( unsigned index =0; index < size; ++index )\n         {\n            if ( index > 0 )\n               document_ += \", \";\n            document_ += childValues_[index];\n         }\n         document_ += \" ]\";\n      }\n   }\n}\n\n\nbool \nStyledWriter::isMultineArray( const Value &value )\n{\n   int size = value.size();\n   bool isMultiLine = size*3 >= rightMargin_ ;\n   childValues_.clear();\n   for ( int index =0; index < size  &&  !isMultiLine; ++index )\n   {\n      const Value &childValue = value[index];\n      isMultiLine = isMultiLine  ||\n                     ( (childValue.isArray()  ||  childValue.isObject())  &&  \n                        childValue.size() > 0 );\n   }\n   if ( !isMultiLine ) // check if line length > max line length\n   {\n      childValues_.reserve( size );\n      addChildValues_ = true;\n      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'\n      for ( int index =0; index < size  &&  !isMultiLine; ++index )\n      {\n         writeValue( value[index] );\n         lineLength += int( childValues_[index].length() );\n         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );\n      }\n      addChildValues_ = false;\n      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;\n   }\n   return isMultiLine;\n}\n\n\nvoid \nStyledWriter::pushValue( const std::string &value )\n{\n   if ( addChildValues_ )\n      childValues_.push_back( value );\n   else\n      document_ += value;\n}\n\n\nvoid \nStyledWriter::writeIndent()\n{\n   if ( !document_.empty() )\n   {\n      char last = document_[document_.length()-1];\n      if ( last == ' ' )     // already indented\n         return;\n      if ( last != '\\n' )    // Comments may add new-line\n         document_ += '\\n';\n   }\n   document_ += indentString_;\n}\n\n\nvoid \nStyledWriter::writeWithIndent( const std::string &value )\n{\n   writeIndent();\n   document_ += value;\n}\n\n\nvoid \nStyledWriter::indent()\n{\n   indentString_ += std::string( indentSize_, ' ' );\n}\n\n\nvoid \nStyledWriter::unindent()\n{\n   assert( int(indentString_.size()) >= indentSize_ );\n   indentString_.resize( indentString_.size() - indentSize_ );\n}\n\n\nvoid \nStyledWriter::writeCommentBeforeValue( const Value &root )\n{\n   if ( !root.hasComment( commentBefore ) )\n      return;\n   document_ += normalizeEOL( root.getComment( commentBefore ) );\n   document_ += \"\\n\";\n}\n\n\nvoid \nStyledWriter::writeCommentAfterValueOnSameLine( const Value &root )\n{\n   if ( root.hasComment( commentAfterOnSameLine ) )\n      document_ += \" \" + normalizeEOL( root.getComment( commentAfterOnSameLine ) );\n\n   if ( root.hasComment( commentAfter ) )\n   {\n      document_ += \"\\n\";\n      document_ += normalizeEOL( root.getComment( commentAfter ) );\n      document_ += \"\\n\";\n   }\n}\n\n\nbool \nStyledWriter::hasCommentForValue( const Value &value )\n{\n   return value.hasComment( commentBefore )\n          ||  value.hasComment( commentAfterOnSameLine )\n          ||  value.hasComment( commentAfter );\n}\n\n\nstd::string \nStyledWriter::normalizeEOL( const std::string &text )\n{\n   std::string normalized;\n   normalized.reserve( text.length() );\n   const char *begin = text.c_str();\n   const char *end = begin + text.length();\n   const char *current = begin;\n   while ( current != end )\n   {\n      char c = *current++;\n      if ( c == '\\r' ) // mac or dos EOL\n      {\n         if ( *current == '\\n' ) // convert dos EOL\n            ++current;\n         normalized += '\\n';\n      }\n      else // handle unix EOL & other char\n         normalized += c;\n   }\n   return normalized;\n}\n\n\n// Class StyledStreamWriter\n// //////////////////////////////////////////////////////////////////\n\nStyledStreamWriter::StyledStreamWriter( std::string indentation )\n   : document_(NULL)\n   , rightMargin_( 74 )\n   , indentation_( indentation )\n{\n}\n\n\nvoid\nStyledStreamWriter::write( std::ostream &out, const Value &root )\n{\n   document_ = &out;\n   addChildValues_ = false;\n   indentString_ = \"\";\n   writeCommentBeforeValue( root );\n   writeValue( root );\n   writeCommentAfterValueOnSameLine( root );\n   *document_ << \"\\n\";\n   document_ = NULL; // Forget the stream, for safety.\n}\n\n\nvoid \nStyledStreamWriter::writeValue( const Value &value )\n{\n   switch ( value.type() )\n   {\n   case nullValue:\n      pushValue( \"null\" );\n      break;\n   case intValue:\n      pushValue( valueToString( value.asInt() ) );\n      break;\n   case uintValue:\n      pushValue( valueToString( value.asUInt() ) );\n      break;\n   case realValue:\n      pushValue( valueToString( value.asDouble() ) );\n      break;\n   case stringValue:\n      pushValue( valueToQuotedString( value.asCString() ) );\n      break;\n   case booleanValue:\n      pushValue( valueToString( value.asBool() ) );\n      break;\n   case arrayValue:\n      writeArrayValue( value);\n      break;\n   case objectValue:\n      {\n         Value::Members members( value.getMemberNames() );\n         if ( members.empty() )\n            pushValue( \"{}\" );\n         else\n         {\n            writeWithIndent( \"{\" );\n            indent();\n            Value::Members::iterator it = members.begin();\n            while ( true )\n            {\n               const std::string &name = *it;\n               const Value &childValue = value[name];\n               writeCommentBeforeValue( childValue );\n               writeWithIndent( valueToQuotedString( name.c_str() ) );\n               *document_ << \" : \";\n               writeValue( childValue );\n               if ( ++it == members.end() )\n               {\n                  writeCommentAfterValueOnSameLine( childValue );\n                  break;\n               }\n               *document_ << \",\";\n               writeCommentAfterValueOnSameLine( childValue );\n            }\n            unindent();\n            writeWithIndent( \"}\" );\n         }\n      }\n      break;\n   }\n}\n\n\nvoid \nStyledStreamWriter::writeArrayValue( const Value &value )\n{\n   unsigned size = value.size();\n   if ( size == 0 )\n      pushValue( \"[]\" );\n   else\n   {\n      bool isArrayMultiLine = isMultineArray( value );\n      if ( isArrayMultiLine )\n      {\n         writeWithIndent( \"[\" );\n         indent();\n         bool hasChildValue = !childValues_.empty();\n         unsigned index =0;\n         while ( true )\n         {\n            const Value &childValue = value[index];\n            writeCommentBeforeValue( childValue );\n            if ( hasChildValue )\n               writeWithIndent( childValues_[index] );\n            else\n            {\n\t       writeIndent();\n               writeValue( childValue );\n            }\n            if ( ++index == size )\n            {\n               writeCommentAfterValueOnSameLine( childValue );\n               break;\n            }\n            *document_ << \",\";\n            writeCommentAfterValueOnSameLine( childValue );\n         }\n         unindent();\n         writeWithIndent( \"]\" );\n      }\n      else // output on a single line\n      {\n         assert( childValues_.size() == size );\n         *document_ << \"[ \";\n         for ( unsigned index =0; index < size; ++index )\n         {\n            if ( index > 0 )\n               *document_ << \", \";\n            *document_ << childValues_[index];\n         }\n         *document_ << \" ]\";\n      }\n   }\n}\n\n\nbool \nStyledStreamWriter::isMultineArray( const Value &value )\n{\n   int size = value.size();\n   bool isMultiLine = size*3 >= rightMargin_ ;\n   childValues_.clear();\n   for ( int index =0; index < size  &&  !isMultiLine; ++index )\n   {\n      const Value &childValue = value[index];\n      isMultiLine = isMultiLine  ||\n                     ( (childValue.isArray()  ||  childValue.isObject())  &&  \n                        childValue.size() > 0 );\n   }\n   if ( !isMultiLine ) // check if line length > max line length\n   {\n      childValues_.reserve( size );\n      addChildValues_ = true;\n      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'\n      for ( int index =0; index < size  &&  !isMultiLine; ++index )\n      {\n         writeValue( value[index] );\n         lineLength += int( childValues_[index].length() );\n         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );\n      }\n      addChildValues_ = false;\n      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;\n   }\n   return isMultiLine;\n}\n\n\nvoid \nStyledStreamWriter::pushValue( const std::string &value )\n{\n   if ( addChildValues_ )\n      childValues_.push_back( value );\n   else\n      *document_ << value;\n}\n\n\nvoid \nStyledStreamWriter::writeIndent()\n{\n  /*\n    Some comments in this method would have been nice. ;-)\n\n   if ( !document_.empty() )\n   {\n      char last = document_[document_.length()-1];\n      if ( last == ' ' )     // already indented\n         return;\n      if ( last != '\\n' )    // Comments may add new-line\n         *document_ << '\\n';\n   }\n  */\n   *document_ << '\\n' << indentString_;\n}\n\n\nvoid \nStyledStreamWriter::writeWithIndent( const std::string &value )\n{\n   writeIndent();\n   *document_ << value;\n}\n\n\nvoid \nStyledStreamWriter::indent()\n{\n   indentString_ += indentation_;\n}\n\n\nvoid \nStyledStreamWriter::unindent()\n{\n   assert( indentString_.size() >= indentation_.size() );\n   indentString_.resize( indentString_.size() - indentation_.size() );\n}\n\n\nvoid \nStyledStreamWriter::writeCommentBeforeValue( const Value &root )\n{\n   if ( !root.hasComment( commentBefore ) )\n      return;\n   *document_ << normalizeEOL( root.getComment( commentBefore ) );\n   *document_ << \"\\n\";\n}\n\n\nvoid \nStyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )\n{\n   if ( root.hasComment( commentAfterOnSameLine ) )\n      *document_ << \" \" + normalizeEOL( root.getComment( commentAfterOnSameLine ) );\n\n   if ( root.hasComment( commentAfter ) )\n   {\n      *document_ << \"\\n\";\n      *document_ << normalizeEOL( root.getComment( commentAfter ) );\n      *document_ << \"\\n\";\n   }\n}\n\n\nbool \nStyledStreamWriter::hasCommentForValue( const Value &value )\n{\n   return value.hasComment( commentBefore )\n          ||  value.hasComment( commentAfterOnSameLine )\n          ||  value.hasComment( commentAfter );\n}\n\n\nstd::string \nStyledStreamWriter::normalizeEOL( const std::string &text )\n{\n   std::string normalized;\n   normalized.reserve( text.length() );\n   const char *begin = text.c_str();\n   const char *end = begin + text.length();\n   const char *current = begin;\n   while ( current != end )\n   {\n      char c = *current++;\n      if ( c == '\\r' ) // mac or dos EOL\n      {\n         if ( *current == '\\n' ) // convert dos EOL\n            ++current;\n         normalized += '\\n';\n      }\n      else // handle unix EOL & other char\n         normalized += c;\n   }\n   return normalized;\n}\n\n\nstd::ostream& operator<<( std::ostream &sout, const Value &root )\n{\n   Json::StyledStreamWriter writer;\n   writer.write(sout, root);\n   return sout;\n}\n\n\n} // namespace Json\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/plugin.cpp",
    "content": "#include \"plugin.h\"\n#include \"tokenizer.h\"\n\n#ifdef _WINDOWS\n#include <windows.h>\nBOOL APIENTRY DllMain( HANDLE hModule,\n                       DWORD ul_reason_for_call,\n                       LPVOID lpReserved )\n{\n    return TRUE;\n}\n#else\n#include <errno.h>\n#include <string.h>\n\nextern int errno;\n#endif\n\nSendPluginEv SendPluginEvent;\n\nstring g_GetSysErrMsg( void )\n{\n    string strError = \"Unknown\";\n    // Problem loading\n#ifdef _WINDOWS\n    int nErrorCode = GetLastError();\n    LPTSTR s;\n    if ( ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,\n    NULL, nErrorCode, 0, ( LPTSTR ) &s, 0, NULL ) )\n    {\n        strError = s;\n    }\n    else\n    {\n        char szBuf[ 20 ];\n        _snprintf_s( szBuf, _countof(szBuf), 19, \"%d\", nErrorCode );\n        strError = szBuf;\n    }\n#else\n    char szError[80];\n    if ( strerror_r( errno, szError, sizeof(szError)  ) )\n    {\n        strError = \"no description found\";\n    }\n    else\n    {\n        strError = szError;\n    }\n#endif\n    return strError;\n}\n\nvoid g_sleep( unsigned int mseconds )\n{\n#ifdef _WINDOWS\n    Sleep( mseconds );\n#else\n    usleep( mseconds * 1000 );\n#endif\n}\n\nstring& g_trim( string& str )\n{\n    // Whitespace characters\n    char whspc[] = \" \\t\\r\\n\\v\\f\";\n\n    // Whack off first part\n    size_t pos = str.find_first_not_of( whspc );\n\n    if ( pos != string::npos )\n        str.replace( 0, pos, \"\" );\n\n    // Whack off trailing stuff\n    pos = str.find_last_not_of( whspc );\n\n    if ( pos != string::npos )\n        str.replace( pos + 1, str.length() - pos, \"\" );\n\n    return str;\n}\n\nvoid g_tokenize( const string& str, const string& delimiters, vector<string>& tokens )\n{\n    tokenize( str, tokens, delimiters );\n}\n\nchar* SetEventFunc( SendPluginEv funcPtr )\n{\n    static char * szObjList = onGetObjList();\n    SendPluginEvent = funcPtr;\n    return szObjList;\n}\n\n\nconst int nMAXSIZE = 512;\nchar* g_pszRetVal = NULL;\n\n//-----------------------------------------------------------\n// Map from an object Id to an object instance\n//-----------------------------------------------------------\ntypedef std::map<string, JSExt*> StringToJExt_T;\n\n//-----------------------------------------------------------\n// Map from a browser context to an id mapping\n//-----------------------------------------------------------\ntypedef std::map<void*, StringToJExt_T*> VoidToMap_T;\n\nVoidToMap_T g_context2Map;\n\nclass GlobalSharedModule\n{\n\npublic:\n    GlobalSharedModule( void )\n    {\n        g_pszRetVal = new char[ nMAXSIZE ];\n    }\n\n    ~GlobalSharedModule()\n    {\n        delete [] g_pszRetVal;\n\n        VoidToMap_T::iterator posMaps;\n\n        for ( posMaps = g_context2Map.begin(); posMaps != g_context2Map.end(); ++posMaps )\n        {\n            StringToJExt_T& id2Obj = *posMaps->second;\n            StringToJExt_T::iterator posMap;\n\n            for ( posMap = id2Obj.begin(); posMap != id2Obj.end(); ++posMap )\n            {\n                JSExt* pJSExt = posMap->second;\n\n                if ( pJSExt->CanDelete() )\n                {\n                    delete pJSExt;\n                }\n            }\n\n            id2Obj.erase( id2Obj.begin(), id2Obj.end() );\n        }\n\n        g_context2Map.erase( g_context2Map.begin(), g_context2Map.end() );\n    }\n};\n\nGlobalSharedModule g_sharedModule;\n\nchar* g_str2global( const string& strRetVal )\n{\n    int nLen = strRetVal.size();\n\n    if ( nLen >= nMAXSIZE )\n    {\n        delete [] g_pszRetVal;\n        g_pszRetVal = new char[ nLen + 1 ];\n    }\n\n    else\n    {\n        // To minimaize the number of memory reallocations, the assumption\n        // is that in most times this will be the case\n        delete [] g_pszRetVal;\n        g_pszRetVal = new char[ nMAXSIZE ];\n    }\n\n    strcpy( g_pszRetVal, strRetVal.c_str() );\n    return g_pszRetVal;\n}\n\nbool g_unregisterObject( const string& strObjId, void* pContext )\n{\n    // Called by the plugin extension implementation\n    // if the extension handles the deletion of its object\n\n    StringToJExt_T * pID2Obj = NULL;\n\n    VoidToMap_T::iterator iter = g_context2Map.find( pContext );\n\n    if ( iter != g_context2Map.end() )\n    {\n        pID2Obj = iter->second;\n    }\n    else\n    {\n        return false;\n    }\n\n    StringToJExt_T& mapID2Obj = *pID2Obj;\n\n    StringToJExt_T::iterator r = mapID2Obj.find( strObjId );\n\n    if ( r == mapID2Obj.end() )\n    {\n        return false;\n    }\n\n    mapID2Obj.erase( strObjId );\n    return true;\n}\n\nchar* InvokeFunction( const char* szCommand, void* pContext )\n{\n    StringToJExt_T * pID2Obj = NULL;\n\n    VoidToMap_T::iterator iter = g_context2Map.find( pContext );\n\n    if ( iter != g_context2Map.end() )\n    {\n        pID2Obj = iter->second;\n    }\n    else\n    {\n        pID2Obj = new StringToJExt_T;\n        g_context2Map[ pContext ] = pID2Obj;\n    }\n\n    StringToJExt_T& mapID2Obj = *pID2Obj;\n\n    string strFullCommand = szCommand;\n    vector<string> arParams;\n    g_tokenize( strFullCommand, \" \", arParams );\n    string strCommand = arParams[ 0 ];\n    string strRetVal = szERROR;\n\n    if ( strCommand == szCREATE )\n    {\n        string strClassName = arParams[ 1 ];\n        string strObjId = arParams[ 2 ];\n\n        StringToJExt_T::iterator r = mapID2Obj.find( strObjId );\n\n        if ( r != mapID2Obj.end() )\n        {\n            strRetVal += strObjId;\n            strRetVal += \" :Object already exists.\";\n            return g_str2global( strRetVal );\n        }\n\n        JSExt* pJSExt = onCreateObject( strClassName, strObjId );\n\n        if ( pJSExt == NULL )\n        {\n            strRetVal += strObjId;\n            strRetVal += \" :Unknown object type \";\n            strRetVal += strClassName;\n            return g_str2global( strRetVal );\n        }\n\n        pJSExt->m_pContext = pContext;\n        mapID2Obj[ strObjId ] = pJSExt;\n\n        strRetVal = szOK;\n        strRetVal += strObjId;\n        return g_str2global( strRetVal );\n    }\n    else\n    if ( strCommand == szINVOKE )\n    {\n        string strObjId = arParams[ 1 ];\n        string strMethod = arParams[ 2 ];\n\n        StringToJExt_T::iterator r = mapID2Obj.find( strObjId );\n\n        if ( r == mapID2Obj.end() )\n        {\n            strRetVal += strObjId;\n            strRetVal += \" :No object found for id.\";\n            return g_str2global( strRetVal );\n        }\n\n        JSExt* pJSExt = r->second;\n\n        size_t nLoc = strFullCommand.find( strObjId );\n\n        if ( nLoc == string::npos )\n        {\n            strRetVal += strObjId;\n            strRetVal += \" :Internal InvokeMethod error.\";\n            return g_str2global( strRetVal );\n        }\n\n        if ( strMethod == szDISPOSE )\n        {\n            StringToJExt_T::iterator r = mapID2Obj.find( strObjId );\n\n            if ( r == mapID2Obj.end() )\n            {\n                strRetVal = szERROR;\n                strRetVal += strObjId;\n                return g_str2global( strRetVal );\n            }\n\n            JSExt * pJSExt = mapID2Obj[ strObjId ];\n\n            if ( pJSExt->CanDelete() )\n            {\n                delete pJSExt;\n            }\n\n            mapID2Obj.erase( strObjId );\n            strRetVal = szOK;\n            strRetVal += strObjId;\n            return g_str2global( strRetVal );\n        }\n\n        size_t nSuffixLoc = nLoc + strObjId.size();\n        string strInvoke = strFullCommand.substr( nSuffixLoc );\n        strInvoke = g_trim( strInvoke );\n        strRetVal = pJSExt->InvokeMethod( strInvoke );\n        return g_str2global( strRetVal );\n    }\n\n    strRetVal += \" :Unknown command \";\n    strRetVal += strCommand;\n    return g_str2global( strRetVal );\n}\n\n//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/plugin.h",
    "content": "#ifndef _PLUGIN_H\n#define _PLUGIN_H\n\n#include <map>\n#include <string>\n#include <vector>\n#include <unistd.h>\n//#include \"tokenizer.h\"\n\nusing namespace std;\n\n//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n//%% Functions exported by this DLL\n//%% Should always be only SetEventFunc and InvokeFunction\n//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n// g++ requires extern \"C\" otherwise the names of SetEventFunc and InvokeFunction\n// are mangled C++ style. MS Visual Studio doesn't seem to care though.\nextern \"C\"\n{\n    typedef void (*SendPluginEv)( const char* szEvent, void* pContext );\n    char* SetEventFunc(SendPluginEv funcPtr);\n    char* InvokeFunction( const char* szCommand, void* pContext );\n}\n\n// JNEXT Framework function of the form:\n// typedef void (*SendPluginEv)( const char* szEvent );\n// used to notify JavaScript of an asynchronous event\nextern SendPluginEv SendPluginEvent;\n\n/////////////////////////////////////////////////////////////////////////\n// Constants and methods common to all JNEXT extensions types\n/////////////////////////////////////////////////////////////////////////\n#define szERROR         \"Error \"\n#define szOK            \"Ok \"\n\n#define szDISPOSE       \"Dispose\"\n#define szINVOKE        \"InvokeMethod\"\n#define szCREATE        \"CreateObj\"\n\n/////////////////////////////////////////////////////////////////////////\n// Utility functions\n/////////////////////////////////////////////////////////////////////////\nstring& g_trim( string& str );\nvoid g_tokenize(const string& str,const string& delimiters, vector<string>& tokens);\nchar* g_str2static( const string& strRetVal );\nvoid g_sleep( unsigned int mseconds );\nbool g_unregisterObject( const string& strObjId, void* pContext );\n\n\n/////////////////////////////////////////////////////////////////////////\n// Abstract extension object\n/////////////////////////////////////////////////////////////////////////\nclass JSExt\n{\npublic:\n    virtual ~JSExt() {};\n    virtual string InvokeMethod( const string& strCommand ) = 0;\n    virtual bool CanDelete( void ) = 0;\n    virtual void TryDelete( void ) {}\npublic:\n    void* m_pContext;\n};\n\n/////////////////////////////////////////////////////////////////////////\n// Callback functions to be implemented by the plugin implementation\n/////////////////////////////////////////////////////////////////////////\nextern char* onGetObjList( void );\nextern JSExt* onCreateObject( const string& strClassName, const string& strObjId );\n\n#endif\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/tokenizer.cpp",
    "content": "/************************************************************************\nThe zlib/libpng License\n\nCopyright (c) 2006 Joerg Wiedenmann\n\nThis software is provided 'as-is', without any express or implied warranty.\nIn no event will the authors be held liable for any damages arising from\nthe use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented;\nyou must not claim that you wrote the original software.\nIf you use this software in a product, an acknowledgment\nin the product documentation would be appreciated but is\nnot required.\n\n2. Altered source versions must be plainly marked as such,\nand must not be misrepresented as being the original software.\n\n3. This notice may not be removed or altered from any source distribution.\n\n***********************************************************************/\n\n/********************************************************************\n\tcreated:\t2006-01-28\n\tfilename: \ttokenizer.cpp\n\tauthor:\t\tJrg Wiedenmann\n\t\n\tpurpose:\tA tokenizer function which provides a very\n\t\t\t\tcustomizable way of breaking up strings.\n\n\thistory:\t2006-01-28, Original version\n\t\t\t\t2006-03-04, Fixed a small parsing bug, thanks Elias.\n*********************************************************************/\n\n#include \"tokenizer.h\"\n\nusing namespace std;\n\nvoid tokenize ( const string& str, vector<string>& result,\n\t\t\t   const string& delimiters, const string& delimiters_preserve,\n\t\t\t   const string& quote, const string& esc )\n{\n\t// clear the vector\n\tif ( false == result.empty() )\n\t{\n\t\tresult.clear();\n\t}\n\n\tstring::size_type pos = 0; // the current position (char) in the string\n\tchar ch = 0; // buffer for the current character\n\tchar delimiter = 0;\t// the buffer for the delimiter char which\n\t\t\t\t\t\t\t// will be added to the tokens if the delimiter\n\t\t\t\t\t\t\t// is preserved\n\tchar current_quote = 0; // the char of the current open quote\n\tbool quoted = false; // indicator if there is an open quote\n\tstring token;  // string buffer for the token\n\tbool token_complete = false; // indicates if the current token is\n\t\t\t\t\t\t\t\t // read to be added to the result vector\n\tstring::size_type len = str.length();  // length of the input-string\n\n\t// for every char in the input-string\n\twhile ( len > pos )\n\t{\n\t\t// get the character of the string and reset the delimiter buffer\n\t\tch = str.at(pos);\n\t\tdelimiter = 0;\n\n\t\t// assume ch isn't a delimiter\n\t\tbool add_char = true;\n\n\t\t// check ...\n\n\t\t// ... if the delimiter is an escaped character\n\t\tbool escaped = false; // indicates if the next char is protected\n\t\tif ( false == esc.empty() ) // check if esc-chars are  provided\n\t\t{\n\t\t\tif ( string::npos != esc.find_first_of(ch) )\n\t\t\t{\n\t\t\t\t// get the escaped char\n\t\t\t\t++pos;\n\t\t\t\tif ( pos < len ) // if there are more chars left\n\t\t\t\t{\n\t\t\t\t\t// get the next one\n\t\t\t\t\tch = str.at(pos);\n\n\t\t\t\t\t// add the escaped character to the token\n\t\t\t\t\tadd_char = true;\n\t\t\t\t}\n\t\t\t\telse // cannot get any more characters\n\t\t\t\t{\n\t\t\t\t\t// don't add the esc-char\n\t\t\t\t\tadd_char = false;\n\t\t\t\t}\n\n\t\t\t\t// ignore the remaining delimiter checks\n\t\t\t\tescaped = true;\n\t\t\t}\n\t\t}\n\n\t\t// ... if the delimiter is a quote\n\t\tif ( false == quote.empty() && false == escaped )\n\t\t{\n\t\t\t// if quote chars are provided and the char isn't protected\n\t\t\tif ( string::npos != quote.find_first_of(ch) )\n\t\t\t{\n\t\t\t\t// if not quoted, set state to open quote and set\n\t\t\t\t// the quote character\n\t\t\t\tif ( false == quoted )\n\t\t\t\t{\n\t\t\t\t\tquoted = true;\n\t\t\t\t\tcurrent_quote = ch;\n\n\t\t\t\t\t// don't add the quote-char to the token\n\t\t\t\t\tadd_char = false;\n\t\t\t\t}\n\t\t\t\telse // if quote is open already\n\t\t\t\t{\n\t\t\t\t\t// check if it is the matching character to close it\n\t\t\t\t\tif ( current_quote == ch )\n\t\t\t\t\t{\n\t\t\t\t\t\t// close quote and reset the quote character\n\t\t\t\t\t\tquoted = false;\n\t\t\t\t\t\tcurrent_quote = 0;\n\n\t\t\t\t\t\t// don't add the quote-char to the token\n\t\t\t\t\t\tadd_char = false;\n\t\t\t\t\t}\n\t\t\t\t} // else\n\t\t\t}\n\t\t}\n\n\t\t// ... if the delimiter isn't preserved\n\t\tif ( false == delimiters.empty() && false == escaped &&\n\t\t\t false == quoted )\n\t\t{\n\t\t\t// if a delimiter is provided and the char isn't protected by\n\t\t\t// quote or escape char\n\t\t\tif ( string::npos != delimiters.find_first_of(ch) )\n\t\t\t{\n\t\t\t\t// if ch is a delimiter and the token string isn't empty\n\t\t\t\t// the token is complete\n\t\t\t\tif ( false == token.empty() ) // BUGFIX: 2006-03-04\n\t\t\t\t{\n\t\t\t\t\ttoken_complete = true;\n\t\t\t\t}\n\n\t\t\t\t// don't add the delimiter to the token\n\t\t\t\tadd_char = false;\n\t\t\t}\n\t\t}\n\n\t\t// ... if the delimiter is preserved - add it as a token\n\t\tbool add_delimiter = false;\n\t\tif ( false == delimiters_preserve.empty() && false == escaped &&\n\t\t\t false == quoted )\n\t\t{\n\t\t\t// if a delimiter which will be preserved is provided and the\n\t\t\t// char isn't protected by quote or escape char\n\t\t\tif ( string::npos != delimiters_preserve.find_first_of(ch) )\n\t\t\t{\n\t\t\t\t// if ch is a delimiter and the token string isn't empty\n\t\t\t\t// the token is complete\n\t\t\t\tif ( false == token.empty() ) // BUGFIX: 2006-03-04\n\t\t\t\t{\n\t\t\t\t\ttoken_complete = true;\n\t\t\t\t}\n\n\t\t\t\t// don't add the delimiter to the token\n\t\t\t\tadd_char = false;\n\n\t\t\t\t// add the delimiter\n\t\t\t\tdelimiter = ch;\n\t\t\t\tadd_delimiter = true;\n\t\t\t}\n\t\t}\n\n\n\t\t// add the character to the token\n\t\tif ( true == add_char )\n\t\t{\n\t\t\t// add the current char\n\t\t\ttoken.push_back( ch );\n\t\t}\n\n\t\t// add the token if it is complete\n\t\tif ( true == token_complete && false == token.empty() )\n\t\t{\n\t\t\t// add the token string\n\t\t\tresult.push_back( token );\n\n\t\t\t// clear the contents\n\t\t\ttoken.clear();\n\n\t\t\t// build the next token\n\t\t\ttoken_complete = false;\n\t\t}\n\n\t\t// add the delimiter\n\t\tif ( true == add_delimiter )\n\t\t{\n\t\t\t// the next token is the delimiter\n\t\t\tstring delim_token;\n\t\t\tdelim_token.push_back( delimiter );\n\t\t\tresult.push_back( delim_token );\n\n\t\t\t// REMOVED: 2006-03-04, Bugfix\n\t\t}\n\n\t\t// repeat for the next character\n\t\t++pos;\n\t} // while\n\n\t// add the final token\n\tif ( false == token.empty() )\n\t{\n\t\tresult.push_back( token );\n\t}\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/public/tokenizer.h",
    "content": "/************************************************************************\nThe zlib/libpng License\n\nCopyright (c) 2006 Joerg Wiedenmann\n\nThis software is provided 'as-is', without any express or implied warranty.\nIn no event will the authors be held liable for any damages arising from\nthe use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented;\n\tyou must not claim that you wrote the original software.\n\tIf you use this software in a product, an acknowledgment\n\tin the product documentation would be appreciated but is\n\tnot required.\n\n2. Altered source versions must be plainly marked as such,\n\tand must not be misrepresented as being the original software.\n\n3. This notice may not be removed or altered from any source distribution.\n\n***********************************************************************/\n\n/********************************************************************\n\tcreated:\t2006-01-28\n\tfilename: \ttokenizer.cpp\n\tauthor:\t\tJrg Wiedenmann\n\n\tpurpose:\tA tokenizer function which provides a very\n\t\t\t\tcustomizable way of breaking up strings.\n*********************************************************************/\n\n#include <vector>\n#include <string>\nusing namespace std;\n\n// Function to break up a string into tokens\n//\n// Parameters:\n//-----------\n// str = the input string that will be tokenized\n// result = the tokens for str\n// delimiters = the delimiter characters\n// delimiters preserve = same as above, but the delimiter characters\n//\t\twill be put into the result as a token\n// quote = characters to protect the enclosed characters\n// esc = characters to protect a single character\n//\n\nvoid tokenize ( const string& str, vector<string>& result,\n\t\t\tconst string& delimiters, const string& delimiters_preserve = \"\",\n\t\t\tconst string& quote = \"\\\"\", const string& esc = \"\\\\\" );\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/simulator/.npmignore",
    "content": "/public\n/src\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/Logger.cpp",
    "content": "/*\n * Copyright (c) 2013 BlackBerry Limited\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"Logger.hpp\"\n#include \"barcodescanner_js.hpp\"\n#include <slog2.h>\n\nnamespace webworks {\n\nLogger::Logger(const char* name, BarcodeScannerJS *parent): m_pParent(parent) {\n\tbuffer_config.buffer_set_name = name;\n\tbuffer_config.num_buffers = 2;\n\tbuffer_config.verbosity_level = SLOG2_DEBUG1;\n\n\t/* Configure the first buffer, using 7 x 4KB pages.  This larger buffer will be used for\n\t   very chatty logging.  Our goal is to have 30-60 seconds of history at any given time,\n\t   so we will want to log at a rate of around one log line with a string of 16 bytes\n\t   long every 150 milliseconds.\n\t*/\n\n\tbuffer_config.buffer_config[0].buffer_name = \"low_priority\";\n\tbuffer_config.buffer_config[0].num_pages = 7;\n\n\t/* Configure the second buffer, which we will use for high level info logging that is very\n\t   infrequent, but we want a longer history (hours or maybe even over a day or two).  This\n\t   buffer uses 1 x 4KB.\n\t*/\n\n\tbuffer_config.buffer_config[1].buffer_name = \"high_priority\";\n\tbuffer_config.buffer_config[1].num_pages = 1;\n\n\t/* Register the buffer set. */\n\n\tif( -1 == slog2_register( &buffer_config, buffer_handle, 0 ) ) {\n\t\tfprintf( stderr, \"Error registering slogger2 buffer!\\n\" );\n\t} else {\n\t\tinfo(\"Created slogger2 buffers\");\n\t}\n\n}\n\nLogger::~Logger() {\n\tcritical(\"slogger2 buffers reset\");\n\tslog2_reset();\n}\n\nint Logger::log(slog2_buffer_t buffer, _Uint8t severity, const char* message) {\n\treturn slog2c(buffer, 0, severity, message);\n}\n\nint Logger::debug(const char* message) {\n\treturn log(lowPriorityBuffer(), SLOG2_DEBUG1, message);\n}\n\nint Logger::info(const char* message) {\n\treturn log(lowPriorityBuffer(), SLOG2_INFO, message);\n}\n\nint Logger::notice(const char* message) {\n\treturn log(lowPriorityBuffer(), SLOG2_NOTICE, message);\n}\n\nint Logger::warn(const char* message) {\n\treturn log(lowPriorityBuffer(), SLOG2_WARNING, message);\n}\n\nint Logger::error(const char* message) {\n\treturn log(hiPriorityBuffer(), SLOG2_ERROR, message);\n}\n\nint Logger::critical(const char* message) {\n\treturn log(hiPriorityBuffer(), SLOG2_CRITICAL, message);\n}\n\nint Logger::setVerbosity(_Uint8t verbosity) {\n\treturn slog2_set_verbosity(buffer_handle[0], verbosity);\n}\n\n_Uint8t Logger::getVerbosity() {\n\treturn slog2_get_verbosity(buffer_handle[0]);\n}\n\nslog2_buffer_t Logger::hiPriorityBuffer() {\n\treturn buffer_handle[1];\n}\n\nslog2_buffer_t Logger::lowPriorityBuffer() {\n\treturn buffer_handle[0];\n}\n\n} /* namespace webworks */\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/Logger.hpp",
    "content": "/*\n * Copyright (c) 2013 BlackBerry Limited\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef LOGGER_HPP_\n#define LOGGER_HPP_\n\n#include <string>\n#include <slog2.h>\n\nclass BarcodeScannerJS;\n\nnamespace webworks {\n\nclass Logger {\npublic:\n\texplicit Logger(const char* name, BarcodeScannerJS *parent = NULL);\n\tvirtual ~Logger();\n\tint debug(const char* message);\n\tint info(const char* message);\n\tint notice(const char* message);\n\tint warn(const char* message);\n\tint error(const char* message);\n\tint critical(const char* message);\n\tint setVerbosity(_Uint8t verbosity);\n\t_Uint8t getVerbosity();\n\tslog2_buffer_t hiPriorityBuffer();\n\tslog2_buffer_t lowPriorityBuffer();\nprivate:\n\tBarcodeScannerJS *m_pParent;\n\tslog2_buffer_set_config_t buffer_config;\n\tslog2_buffer_t buffer_handle[2];\n\tint log(slog2_buffer_t buffer, _Uint8t severity, const char* message);\n};\n\n} /* namespace webworks */\n#endif /* LOGGER_HPP_ */\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_js.cpp",
    "content": "/*\n * Copyright 2013-2014 BlackBerry Limited.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"../public/tokenizer.h\"\n#include \"barcodescanner_js.hpp\"\n#include \"barcodescanner_ndk.hpp\"\n\nusing namespace std;\n\n/**\n * Default constructor.\n */\nBarcodeScannerJS::BarcodeScannerJS(const std::string& id) :\n        m_id(id) {\n\tm_pLogger = new webworks::Logger(\"BarcodeScannerJS\", this);\n    m_pBarcodeScannerController = new webworks::BarcodeScannerNDK(this);\n}\n\n/**\n * BarcodeScannerJS destructor.\n */\nBarcodeScannerJS::~BarcodeScannerJS() {\n    if (m_pBarcodeScannerController)\n    \t\tdelete m_pBarcodeScannerController;\n\tif (m_pLogger)\n\t\tdelete m_pLogger;\n}\n\nwebworks::Logger* BarcodeScannerJS::getLog() {\n\treturn m_pLogger;\n}\n\n/**\n * This method returns the list of objects implemented by this native\n * extension.\n */\nchar* onGetObjList() {\n    static char name[] = \"BarcodeScannerJS\";\n    return name;\n}\n\n/**\n * This method is used by JNext to instantiate the BarcodeScannerJS object when\n * an object is created on the JavaScript server side.\n */\nJSExt* onCreateObject(const string& className, const string& id) {\n    if (className == \"BarcodeScannerJS\") {\n        return new BarcodeScannerJS(id);\n    }\n\n    return NULL;\n}\n\n/**\n * Method used by JNext to determine if the object can be deleted.\n */\nbool BarcodeScannerJS::CanDelete() {\n    return true;\n}\n\n/**\n * It will be called from JNext JavaScript side with passed string.\n * This method implements the interface for the JavaScript to native binding\n * for invoking native code. This method is triggered when JNext.invoke is\n * called on the JavaScript side with this native objects id.\n */\nstring BarcodeScannerJS::InvokeMethod(const std::string& command) {\n    // command appears with parameters following after a space\n\tsize_t commandIndex = command.find_first_of(\" \");\n\tstd::string strCommand = command.substr(0, commandIndex);\n\tsize_t callbackIndex = command.find_first_of(\" \", commandIndex + 1);\n\tstd::string callbackId = command.substr(commandIndex + 1, callbackIndex - commandIndex - 1);\n\tstd::string arg = command.substr(callbackIndex + 1, command.length());\n\n    if (strCommand == \"startRead\") {\n        m_pBarcodeScannerController->startRead(callbackId, arg);\n    }\n    else if (strCommand == \"stopRead\") {\n        m_pBarcodeScannerController->stopRead(callbackId);\n    }\n\n    strCommand.append(\";\");\n    strCommand.append(command);\n    return strCommand;\n}\n\n// Notifies JavaScript of an event\nvoid BarcodeScannerJS::NotifyEvent(const std::string& event) {\n    std::string eventString = m_id + \" \";\n    eventString.append(event);\n    SendPluginEvent(eventString.c_str(), m_pContext);\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_js.hpp",
    "content": "/*\n* Copyright 2013-2014 BlackBerry Limited.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n\n#ifndef BARCODESCANNERJS_HPP_\n#define BARCODESCANNERJS_HPP_\n\n#include \"../public/plugin.h\"\n#include \"barcodescanner_ndk.hpp\"\n#include \"Logger.hpp\"\n#include <string>\n\nclass BarcodeScannerJS: public JSExt {\n\npublic:\n    explicit BarcodeScannerJS(const std::string& id);\n    virtual ~BarcodeScannerJS();\n    virtual bool CanDelete();\n    virtual std::string InvokeMethod(const std::string& command);\n    void NotifyEvent(const std::string& event);\n    webworks::Logger* getLog();\n    webworks::BarcodeScannerNDK *m_pBarcodeScannerController;\nprivate:\n    std::string m_id;\n    // Definition of a pointer to the actual native extension code\n    webworks::Logger *m_pLogger;\n};\n\n#endif /* BarcodeScannerJS_HPP_ */\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_ndk.cpp",
    "content": "/*\n * Copyright 2013-2015 BlackBerry Limited.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <json/reader.h>\n#include <json/writer.h>\n\n#include <zxing/common/GreyscaleLuminanceSource.h>\n#include <zxing/common/HybridBinarizer.h>\n#include <zxing/MultiFormatReader.h>\n#include <img/img.h>\n#include <stdio.h>\n#include <bps/bps.h>\n#include <bps/event.h>\n#include <bps/navigator.h>\n#include <bps/screen.h>\n#include <screen/screen.h>\n#include <pthread.h>\n\n#include \"barcodescanner_ndk.hpp\"\n#include \"barcodescanner_js.hpp\"\n\n#include <string>\n#include <sstream>\n\nusing namespace zxing;\n\nnamespace webworks {\n\nBarcodeScannerJS* eventDispatcher = NULL;\n// Variables for native viewfinder screen\nstatic screen_window_t vf_win = NULL;\nstatic uint32_t vfRotation = 0;\nstatic bool touch = false;\n\n\n#define MUTEX_LOCK() pthread_mutex_trylock(&m_lock)\n#define MUTEX_UNLOCK() pthread_mutex_unlock(&m_lock)\n\nstatic pthread_mutex_t m_lock;\nstatic pthread_t m_thread = 0;\n\n    /*\n     * getCameraErrorDesc\n     *\n     * Returns a descriptive error message for a given camera error code\n     */\n    const char* getCameraErrorDesc(camera_error_t err) {\n        switch (err) {\n        case CAMERA_EOK:\n            return \"The function call to the camera completed successfully.\";\n        case CAMERA_EAGAIN:\n            return \"The specified camera was not available. Try again.\";\n        case CAMERA_EINVAL:\n            return \"The camera call failed because of an invalid parameter.\";\n        case CAMERA_ENODEV:\n            return \"No such camera was found.\";\n        case CAMERA_EMFILE:\n            return \"The camera called failed because of a file table overflow.\";\n        case CAMERA_EBADF:\n            return \"Indicates that an invalid handle to a @c camera_handle_t value was used.\";\n        case CAMERA_EACCESS:\n            return \"Indicates that the necessary permissions to access the camera are not available.\";\n        case CAMERA_EBADR:\n            return \"Indicates that an invalid file descriptor was used.\";\n        case CAMERA_ENOENT:\n            return \"Indicates that the access a file or directory that does not exist.\";\n        case CAMERA_ENOMEM:\n            return \"Indicates that memory allocation failed.\";\n        case CAMERA_EOPNOTSUPP:\n            return \"Indicates that the requested operation is not supported.\";\n        case CAMERA_ETIMEDOUT:\n            return \"The function call failed due to communication problem or time-out with the camera.\";\n        case CAMERA_EALREADY:\n            return \"Indicates an operation on the camera is already in progress. In addition, this error can indicate that an error could not be completed because it was already completed. For example, if you called the @c camera_stop_video() function but the camera had already stopped recording video, this error code would be returned.\";\n        case CAMERA_EUNINIT:\n            return \"Indicates that the Camera Library is not initialized.\";\n        case CAMERA_EREGFAULT:\n            return \"Indicates that registration of a callback failed.\";\n        case CAMERA_EMICINUSE:\n            return \"Indicates that it failed to open because microphone is already in use.\";\n        }\n        return NULL;\n    }\n\n\n    /*\n     * viewfinder_callback\n     *\n     * This callback is invoked when an image frame from the camera viewfinder becomes available.\n     * The frame is analyzed to determine if a barcode can be matched.\n     * Frames come in NV12 format which makes code analysis very fast.\n     */\n    void viewfinder_callback(camera_handle_t handle,camera_buffer_t* buf,void* arg) {\n        camera_frame_nv12_t* data = (camera_frame_nv12_t*)(&(buf->framedesc));\n        uint8_t* buff = buf->framebuf;\n        int stride = data->stride;\n        int width = data->width;\n        int height = data->height;\n        if ( eventDispatcher != NULL ){\n//            eventDispatcher->getLog()->debug(\"Frame received\");\n        }\n\n        try {\n            Ref<LuminanceSource> source(new GreyscaleLuminanceSource((unsigned char *)buff, stride, height, 0,0,width,height));\n\n            Ref<Binarizer> binarizer(new HybridBinarizer(source));\n            Ref<BinaryBitmap> bitmap(new BinaryBitmap(binarizer));\n            Ref<Result> result;\n\n            // setup the code reader\n            MultiFormatReader *reader = new MultiFormatReader();\n            DecodeHints *hints = new DecodeHints();\n\n            hints->addFormat(BarcodeFormat_QR_CODE);\n            hints->addFormat(BarcodeFormat_EAN_8);\n            hints->addFormat(BarcodeFormat_EAN_13);\n            hints->addFormat(BarcodeFormat_UPC_A);\n            hints->addFormat(BarcodeFormat_UPC_E);\n            hints->addFormat(BarcodeFormat_DATA_MATRIX);\n            hints->addFormat(BarcodeFormat_CODE_128);\n            hints->addFormat(BarcodeFormat_CODE_39);\n            hints->addFormat(BarcodeFormat_ITF);\n            hints->addFormat(BarcodeFormat_AZTEC);\n\n\t\t\t// attempt to decode and retrieve a valid QR code from the image bitmap\n\t\t\tresult = reader->decode(bitmap, *hints);\n\n            std::string newBarcodeData = result->getText()->getText().data();\n\n            Json::FastWriter writer;\n            Json::Value root;\n            root[\"text\"] = newBarcodeData;\n            root[\"format\"] = barcodeFormatNames[result->getBarcodeFormat()];\n            root[\"cancelled\"] = false;\n\n            // notify caller that a valid QR code has been decoded\n            if ( eventDispatcher != NULL){\n            \tstd::string event = \"community.barcodescanner.codefound.native\";\n            \tevent.insert(0, \" \");\n            \tevent.insert(0, (char *) arg);\n            \teventDispatcher->NotifyEvent(event + \" \" + writer.write(root));\n            \teventDispatcher->getLog()->debug(\"This is the detected Barcode\");\n            \teventDispatcher->getLog()->debug(newBarcodeData.c_str());\n            }\n\n        }\n        catch (const std::exception& ex)\n        {\n            // Uncomment this if you need to verify scanning\n            if ( eventDispatcher != NULL ){\n//               eventDispatcher->getLog()->warn(\"Scan error\");\n//               eventDispatcher->getLog()->warn(ex.what());\n            }\n        }\n    }\n\n    std::string convertIntToString(int i) {\n\t\tstringstream ss;\n\t\tss << i;\n\t\treturn ss.str();\n\t}\n\n\n    /*\n     * Constructor for Barcode Scanner NDK class\n     */\n    BarcodeScannerNDK::BarcodeScannerNDK(BarcodeScannerJS *parent): threadHalt(false) {\n    \tcbId = new char[1000];\n        m_pParent     = parent;\n        eventDispatcher = parent;\n        mCameraHandle = CAMERA_HANDLE_INVALID;\n    }\n\n    BarcodeScannerNDK::~BarcodeScannerNDK() {\n    \tdelete[] cbId;\n    }\n\n    webworks::Logger* BarcodeScannerNDK::getLog() {\n        return m_pParent->getLog();\n    }\n\n    void interrogateWindowCV(screen_window_t window, Logger* log, string description, int property) {\n        char* value = new char[256];\n        int ok = screen_get_window_property_cv(window, property, 256, value);\n        if (ok == 0) {\n            log->info(description.c_str());\n            log->info(value);\n        } else {\n            log->warn(\"Unable to interpret value for\");\n            log->warn(description.c_str());\n        }\n    }\n\n    void interrogateWindowIV(screen_window_t window, Logger* log, string description, int property) {\n        int value = -1;\n        int ok = screen_get_window_property_iv(window, property, &value);\n        if (ok == 0) {\n            log->info(description.c_str());\n            log->info(convertIntToString(value).c_str());\n        } else {\n            log->warn(\"Unable to interpret value for\");\n            log->warn(description.c_str());\n        }\n    }\n\n    void interrogateWindow(screen_window_t window, Logger* log) {\n        log->info(\"Window Details--->\");\n        interrogateWindowCV(window, log, \"Window ID\", SCREEN_PROPERTY_ID_STRING);\n        interrogateWindowIV(window, log, \"Window Type\", SCREEN_PROPERTY_TYPE);\n        interrogateWindowIV(window, log, \"Window Owner PID\", SCREEN_PROPERTY_OWNER_PID);\n        interrogateWindowCV(window, log, \"Window Group\", SCREEN_PROPERTY_GROUP);\n        interrogateWindowIV(window, log, \"Window Z Order\", SCREEN_PROPERTY_ZORDER);\n        interrogateWindowIV(window, log, \"Window Visible\", SCREEN_PROPERTY_VISIBLE);\n        log->info(\"Window Interrogation complete\");\n    }\n\n    void *HandleEvents(void *args) {\n        BarcodeScannerNDK *parent = static_cast<BarcodeScannerNDK *>(args);\n        parent->getLog()->debug(\"BarcodeScannerNDK EventHandler\");\n\n        /**\n         * Creating a native viewfinder screen\n         */\n        const int usage = SCREEN_USAGE_NATIVE;\n        screen_window_t screen_win;\n        screen_buffer_t screen_buf = NULL;\n        int rect[4] = { 0, 0, 0, 0 };\n\n        if(screen_create_window_type(&screen_win, parent->windowContext, SCREEN_CHILD_WINDOW) == -1) {\n            parent->getLog()->error(\"screen_create_window() failed\");;\n        }\n        screen_join_window_group(screen_win, parent->windowGroup);\n        char * groupCheck = new char[256];\n        screen_get_window_property_cv(screen_win, SCREEN_PROPERTY_GROUP, 256, groupCheck);\n        parent->getLog()->info(\"Window Group Check\");\n        parent->getLog()->info(groupCheck);\n        screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_USAGE, &usage);\n        int r = 0;\n        screen_display_t display = NULL;\n        screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_DISPLAY, (void**)&display);\n        if (display != NULL) {\n            screen_get_display_property_iv(display, SCREEN_PROPERTY_ROTATION, &r);\n            parent->getLog()->debug(\"Current Display Rotation\");\n            parent->getLog()->debug(convertIntToString(r).c_str());\n        }\n        screen_create_window_buffers(screen_win, 1);\n        screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&screen_buf);\n        screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, rect+2);\n        // The screen (and backing buffer) don't take into account the rotation, so we need to swap the size.\n        if (r == 90 || r == 270) {\n            int swap = rect[2];\n            rect[2] = rect[3];\n            rect[3] = swap;\n        }\n        // Set the window size and the buffer follows along\n        screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_SIZE, rect+2);\n        screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, rect+2);\n\n        parent->getLog()->debug(\"Screen Buffer Size:\");\n        parent->getLog()->debug(convertIntToString(rect[0]).c_str());\n        parent->getLog()->debug(convertIntToString(rect[1]).c_str());\n        parent->getLog()->debug(convertIntToString(rect[2]).c_str());\n        parent->getLog()->debug(convertIntToString(rect[3]).c_str());\n\n        int type = -1;\n        screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_TYPE, &type);\n        parent->getLog()->debug(\"Window Type\");\n        parent->getLog()->debug(convertIntToString(type).c_str());\n\n        // fill the window with a flat colour\n        int attribs[] = { SCREEN_BLIT_COLOR, 0x00333333, SCREEN_BLIT_END };\n        screen_fill(parent->windowContext, screen_buf, attribs);\n        screen_post_window(screen_win, screen_buf, 1, rect, 0);\n        // position the window at an arbitrary z-order\n        int i = 1;\n        screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &i);\n        screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &i);\n        parent->getLog()->debug(\"Current Zorder\");\n        parent->getLog()->debug(convertIntToString(i).c_str());\n        int visible = 1;\n        screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_VISIBLE, &visible);\n        screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_VISIBLE, &visible);\n        parent->getLog()->debug(\"Visible?\");\n        parent->getLog()->debug(convertIntToString(visible).c_str());\n        screen_flush_context(parent->windowContext, 0);\n\n        parent->getLog()->debug(\"Created Background window\");\n\n        if (parent->windowContext) {\n            if (BPS_SUCCESS == screen_request_events(parent->windowContext)) {\n                parent->getLog()->debug(\"Requested Events\");\n            } else {\n                parent->getLog()->error(\"Unable to request events\");\n                return NULL;\n            }\n        }\n\n        screen_group_t group;\n        screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_GROUP, (void **)&group);\n        char* groupName = new char[256];\n        screen_get_group_property_cv(group, SCREEN_PROPERTY_NAME, 256, groupName);\n        parent->getLog()->debug(\"Group Found\");\n        parent->getLog()->debug(groupName);\n\n        // reset Touch value before starting up listening for touch events\n        touch = false;\n\n        while(!parent->isThreadHalt()) {\n            MUTEX_LOCK();\n\n            int domain;\n            // Get the first event in the queue.\n            bps_event_t *event = NULL;\n            if (BPS_SUCCESS != bps_get_event(&event, 0)) {\n                parent->getLog()->warn(\"bps_get_event() failed\");\n            }\n\n            // Handle all events in the queue.\n            while (event) {\n                if (touch) {\n                    // HandleScreenEvent got a tap on the screen\n                    // Shutdown the scanning\n                    parent->cancelScan();\n                    break;\n                }\n                if (event) {\n                    domain = bps_event_get_domain(event);\n                    parent->getLog()->debug(\"BPS Event\");\n                    if (domain == screen_get_domain()) {\n                        parent->getLog()->debug(\"BPS Screen Event\");\n                        parent->handleScreenEvent(event, parent->getLog(), parent->windowGroup);\n                    }\n                }\n                if (BPS_SUCCESS != bps_get_event(&event, 0)) {\n                    parent->getLog()->error(\"bps_get_event() failed\");\n//                                return;\n                }\n            }\n\n            MUTEX_UNLOCK();\n\n            // Poll at 10hz\n            usleep(100000);\n        }\n        // stop screen events on this thread\n        if(screen_stop_events(parent->windowContext) == -1) {\n            parent->getLog()->error(\"screen_stop_events failed\");\n        }\n        screen_destroy_window(screen_win);\n        return NULL;\n    }\n\n    void BarcodeScannerNDK::handleScreenEvent(bps_event_t *event, Logger* log, const char* windowGroup) {\n        int eventType, objectType, eventProperty;\n\n        screen_event_t screen_event = screen_event_get_event(event);\n        screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &eventType);\n\n        switch (eventType) {\n        case SCREEN_EVENT_MTOUCH_RELEASE:\n        case SCREEN_EVENT_MTOUCH_TOUCH:\n        case SCREEN_EVENT_MTOUCH_MOVE:\n            log->info(\"Touch Event\");\n            touch = true;\n            break;\n        case SCREEN_EVENT_CREATE:\n            log->info(\"Screen Create Event\");\n            if (screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_WINDOW, (void **)&vf_win) == -1) {\n                log->error(\"screen_get_event_property_pv(SCREEN_PROPERTY_WINDOW)\");\n            } else {\n                log->info(\"viewfinder window found!\");\n            }\n            break;\n        case SCREEN_EVENT_IDLE:\n            log->debug(\"Screen Idle\");\n            break;\n        case SCREEN_EVENT_POST:\n            log->debug(\"Screen posted first frame\");\n            if (screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_WINDOW, (void **)&vf_win) == -1) {\n                log->error(\"screen_get_event_property_pv(SCREEN_PROPERTY_WINDOW)\");\n            } else {\n                interrogateWindow(vf_win, log);\n                int i = 100;\n                screen_set_window_property_iv(vf_win, SCREEN_PROPERTY_ZORDER, &i);\n                screen_get_window_property_iv(vf_win, SCREEN_PROPERTY_ZORDER, &i);\n                log->debug(\"Current Zorder\");\n                log->debug(convertIntToString(i).c_str());\n                // make viewfinder window visible\n                i = 1;\n                screen_set_window_property_iv(vf_win, SCREEN_PROPERTY_VISIBLE, &i);\n                screen_get_window_property_iv(vf_win, SCREEN_PROPERTY_VISIBLE, &i);\n                log->debug(\"Visible?\");\n                log->debug(convertIntToString(i).c_str());\n                // Rotate the window as needed\n                screen_get_window_property_iv(vf_win, SCREEN_PROPERTY_ROTATION, &i);\n                log->debug(\"Current Rotation\");\n                log->debug(convertIntToString(i).c_str());\n                i = 360 - vfRotation;\n                screen_set_window_property_iv(vf_win, SCREEN_PROPERTY_ROTATION, &i);\n                screen_get_window_property_iv(vf_win, SCREEN_PROPERTY_ROTATION, &i);\n                log->debug(\"Rotation\");\n                log->debug(convertIntToString(i).c_str());\n                // Make full screen\n                screen_display_t display = NULL;\n                screen_get_window_property_pv(vf_win, SCREEN_PROPERTY_DISPLAY, (void **)&display);\n                if (display != NULL) {\n                    log->debug(\"Found a Display\");\n                    int size[2] = { 0, 0 };\n                    screen_get_display_property_iv(display, SCREEN_PROPERTY_SIZE, size);\n                    log->debug(\"Display Size\");\n                    log->debug(convertIntToString(size[0]).c_str());\n                    log->debug(convertIntToString(size[1]).c_str());\n                    int r = 0;\n                    screen_get_display_property_iv(display, SCREEN_PROPERTY_ROTATION, &r);\n                    log->debug(\"Current Display Rotation\");\n                    log->debug(convertIntToString(r).c_str());\n                    if (r == 90 || r == 270) {\n                        int swap = size[0];\n                        size[0] = size[1];\n                        size[1] = swap;\n                    }\n                    screen_set_window_property_iv(vf_win, SCREEN_PROPERTY_SIZE, size);\n                    screen_get_window_property_iv(vf_win, SCREEN_PROPERTY_SIZE, size);\n                    log->debug(\"Window Size\");\n                    log->debug(convertIntToString(size[0]).c_str());\n                    log->debug(convertIntToString(size[1]).c_str());\n                }\n\n            }\n            break;\n        case SCREEN_EVENT_CLOSE:\n            log->debug(\"Screen closed\");\n            break;\n        case SCREEN_EVENT_INPUT:\n            log->debug(\"Screen input event\");\n            break;\n        case SCREEN_EVENT_PROPERTY:\n            log->debug(\"Screen property event\");\n            screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_OBJECT_TYPE, &objectType);\n            log->debug(\"Object Type\");\n            log->debug(convertIntToString(objectType).c_str());\n            screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_NAME, &eventProperty);\n            log->debug(\"Property Name\");\n            log->debug(convertIntToString(eventProperty).c_str());\n            break;\n        default:\n            log->warn(\"Unhandled Screen Event Type\");\n            log->warn(convertIntToString(eventType).c_str());\n            break;\n        }\n    }\n\n    bool BarcodeScannerNDK::StartEvents() {\n        if (!m_thread) {\n            threadHalt = false;\n            pthread_attr_t thread_attr;\n            pthread_attr_init(&thread_attr);\n            pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);\n            int error = pthread_create(&m_thread, &thread_attr, HandleEvents, static_cast<void *>(this));\n            pthread_attr_destroy(&thread_attr);\n            if (error) {\n                m_pParent->getLog()->error(\"Thread Failed to start\");\n                m_thread = 0;\n                return false;\n            } else {\n                m_pParent->getLog()->info(\"Thread Started\");\n                MUTEX_LOCK();\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    void BarcodeScannerNDK::StopEvents() {\n        if (m_thread) {\n            MUTEX_LOCK();\n            threadHalt = true;\n            MUTEX_UNLOCK();\n            m_pParent->getLog()->debug(\"BarcodeScannerNDK joining event thread\");\n            pthread_join(m_thread, NULL);\n            m_thread = 0;\n            m_pParent->getLog()->debug(\"BarcodeScannerNDK event thread stopped\");\n        }\n    }\n\n\n    // getter for the stop value\n    bool BarcodeScannerNDK::isThreadHalt() {\n        bool isThreadHalt;\n        MUTEX_LOCK();\n        isThreadHalt = threadHalt;\n        MUTEX_UNLOCK();\n        return isThreadHalt;\n    }\n\n    void BarcodeScannerNDK::cancelScan() {\n        m_pParent->getLog()->warn(\"Cancel Scan\");\n        std::string event = \"community.barcodescanner.codefound.native\";\n        std::string callbackId = cbId;\n        Json::FastWriter writer;\n        Json::Value root;\n\n        // Scan cancelled by user\n        root[\"text\"] = \"\";\n        root[\"format\"] = \"\";\n        root[\"cancelled\"] = true;\n\n        m_pParent->NotifyEvent(callbackId + \" \"  + event + \" \" + writer.write(root));\n    }\n\n    /*\n     * BarcodeScannerNDK::startRead\n     *\n     * This method is called to start a QR code read. A connection is opened to the device camera\n     * and the photo viewfinder is started.\n     */\n    int BarcodeScannerNDK::startRead(const string &callbackId, const string &arg) {\n    \tstd::string errorEvent = \"community.barcodescanner.errorfound.native\";\n        Json::FastWriter writer;\n        Json::Value root;\n\n        // Important for maintaining proper event queue support on 10.2.1\n        bps_initialize();\n\n        std::string handle;\n        std::string group;\n        Json::Reader reader;\n        Json::Value input;\n        bool parse = reader.parse(arg, input);\n\n        if (!parse) {\n            m_pParent->getLog()->error(\"Parse Error\");\n            Json::Value error;\n            root[\"state\"] = \"Parsing JSON object\";\n            root[\"error\"] = \"Cannot parse JSON object\";\n            root[\"description\"] = \"\";\n            m_pParent->NotifyEvent(callbackId + \" \" + errorEvent + \" \" + writer.write(error));\n            return EIO;\n        } else {\n            handle = input[\"handle\"].asString();\n            group = input[\"group\"].asString();\n        }\n\n        std::copy(callbackId.begin(), callbackId.end(), this->cbId);\n        this->cbId[callbackId.size()] = '\\0';\n\n        this->windowHandle = handle;\n        m_pParent->getLog()->info(\"Window Handle\");\n        m_pParent->getLog()->info(handle.c_str());\n        // the jsScreenWindowHandle of the UIWebView that we passed in\n        int windowPointer = (int) strtol(handle.c_str(), NULL, 10);\n        // As an integer is the actual window handle\n        screen_window_t window = (screen_window_t) windowPointer;\n        interrogateWindow(window, m_pParent->getLog());\n        // Create a group for the main window\n        windowGroup = new char[group.length()+1];\n        std::strcpy (windowGroup, group.c_str());\n        m_pParent->getLog()->debug(\"Window Group using:\");\n        m_pParent->getLog()->debug(windowGroup);\n\n        int getContext = screen_get_window_property_pv(window, SCREEN_PROPERTY_CONTEXT, (void **)&windowContext);\n        if (getContext == -1) {\n            m_pParent->getLog()->critical(\"Unable to get Context\");\n            root[\"state\"] = \"Get App Window Context\";\n            root[\"error\"] = getContext;\n            root[\"description\"] = \"Unable to get application context\";\n            m_pParent->NotifyEvent(callbackId + \" \" + errorEvent + \" \" + writer.write(root));\n            return EIO;\n        }\n\n        StartEvents();\n\n        camera_error_t err;\n        // Open the camera first before running any operations on it\n        err = camera_open(CAMERA_UNIT_REAR,CAMERA_MODE_RW | CAMERA_MODE_ROLL,&mCameraHandle);\n\n        if ( err != CAMERA_EOK){\n            m_pParent->getLog()->error(\"Ran into an issue when initializing the camera\");\n            m_pParent->getLog()->error(getCameraErrorDesc( err ));\n            root[\"state\"] = \"Open Camera\";\n            root[\"error\"] = err;\n            root[\"description\"] = getCameraErrorDesc( err );\n            m_pParent->NotifyEvent(callbackId + \" \" + errorEvent + \" \" + writer.write(root));\n            return EIO;\n        }\n\n        // We want maximum framerate from the viewfinder which will scan for codes\n        int numRates = 0;\n\t\terr = camera_get_photo_vf_framerates(mCameraHandle, true, 0, &numRates, NULL, NULL);\n\t\tdouble* camFramerates = new double[numRates];\n\t\tbool maxmin = false;\n\t\terr = camera_get_photo_vf_framerates(mCameraHandle, true, numRates, &numRates, camFramerates, &maxmin);\n\n\t\t// do we need to rotate the viewfinder?\n\n\t\terr = camera_get_photovf_property(mCameraHandle, CAMERA_IMGPROP_ROTATION, &vfRotation);\n\t\tm_pParent->getLog()->debug(\"Viewfinder Rotation\");\n\t\tm_pParent->getLog()->debug(convertIntToString(vfRotation).c_str());\n\n\t\tm_pParent->getLog()->debug(\"Camera Window Group\");\n\t\tm_pParent->getLog()->debug(windowGroup);\n\t\t// We're going to have the viewfinder window join our app's window group, and start an embedded window\n\t\terr = camera_set_photovf_property(mCameraHandle,\n\t\t    CAMERA_IMGPROP_WIN_GROUPID, windowGroup,\n\t\t    CAMERA_IMGPROP_WIN_ID, \"my_viewfinder\");\n\t\tif ( err != CAMERA_EOK){\n\t\t    m_pParent->getLog()->error(\"Ran into an issue when configuring the camera viewfinder\");\n\t\t    m_pParent->getLog()->error(getCameraErrorDesc( err ));\n\t\t\troot[\"state\"] = \"Set VF Props\";\n\t\t\troot[\"error\"] = err;\n\t\t\troot[\"description\"] = getCameraErrorDesc( err );\n\t\t\tm_pParent->NotifyEvent(callbackId + \" \" + errorEvent + \" \" + writer.write(root));\n\t\t\treturn EIO;\n\t\t}\n\n\t\t// Starting viewfinder up which will call the viewfinder callback - this gets the NV12 images for scanning\n        err = camera_start_photo_viewfinder( mCameraHandle, &viewfinder_callback, NULL, this->cbId);\n        if ( err != CAMERA_EOK) {\n            m_pParent->getLog()->error(\"Ran into a strange issue when starting up the camera viewfinder\");\n            m_pParent->getLog()->error(getCameraErrorDesc( err ));\n            root[\"state\"] = \"ViewFinder Start\";\n            root[\"error\"] = err;\n            root[\"description\"] = getCameraErrorDesc( err );\n            m_pParent->NotifyEvent(callbackId + \" \" + errorEvent + \" \" + writer.write(root));\n            return EIO;\n        }\n\n        // Focus mode can't be set until the viewfinder is started. We need Continuous Macro for barcodes\n        err = camera_set_focus_mode(mCameraHandle, CAMERA_FOCUSMODE_CONTINUOUS_MACRO);\n\t\tif ( err != CAMERA_EOK){\n\t\t    m_pParent->getLog()->error(\"Ran into an issue when setting focus mode\");\n\t\t    m_pParent->getLog()->error(getCameraErrorDesc( err ));\n\t\t\troot[\"state\"] = \"Set Focus Mode\";\n\t\t\troot[\"error\"] = err;\n\t\t\troot[\"description\"] =  getCameraErrorDesc( err );\n\t\t\tm_pParent->NotifyEvent(callbackId + \" \" + errorEvent + \" \" + writer.write(root));\n\t\t\treturn EIO;\n\t\t}\n\n        std::string successEvent = \"community.barcodescanner.started.native\";\n        root[\"successful\"] = true;\n        m_pParent->NotifyEvent(callbackId + \" \" + successEvent + \" \" + writer.write(root));\n        return EOK;\n    }\n\n\n    /*\n     * BarcodeScannerNDK::stopRead\n     *\n     * This method is called to clean up following successful detection of a barcode.\n     * Calling this method will stop the viewfinder and close an open connection to the device camera.\n     */\n    int BarcodeScannerNDK::stopRead(const string &callbackId) {\n    \tstd::string errorEvent = \"community.barcodescanner.errorfound.native\";\n\t\tJson::FastWriter writer;\n\t\tJson::Value root;\n        camera_error_t err;\n\n        // Stop events first so that you don't get better response from the screen\n        StopEvents();\n\n        err = camera_stop_photo_viewfinder(mCameraHandle);\n        if ( err != CAMERA_EOK)\n        {\n            m_pParent->getLog()->error(\"Error with turning off the photo viewfinder\");\n            m_pParent->getLog()->error(getCameraErrorDesc( err ));\n            root[\"error\"] = err;\n\t\t    root[\"description\"] = getCameraErrorDesc( err );\n\t\t    m_pParent->NotifyEvent(callbackId + \" \" + errorEvent + \" \" + writer.write(root));\n            return EIO;\n        }\n\n        //check to see if the camera is open, if it is open, then close it\n        err = camera_close(mCameraHandle);\n        if ( err != CAMERA_EOK){\n            m_pParent->getLog()->error(\"Error with closing the camera\");\n            m_pParent->getLog()->error(getCameraErrorDesc( err ));\n            root[\"error\"] = err;\n            root[\"description\"] = getCameraErrorDesc( err );\n            m_pParent->NotifyEvent(callbackId + \" \" + errorEvent + \" \" + writer.write(root));\n            return EIO;\n        }\n\n        std::string successEvent = \"community.barcodescanner.ended.native\";\n        root[\"successful\"] = true;\n        mCameraHandle = CAMERA_HANDLE_INVALID;\n        m_pParent->NotifyEvent(callbackId + \" \" + successEvent + \" \" + writer.write(root));\n\n        // Important for maintaining proper event queue support on 10.2.1\n        bps_shutdown();\n\n        return EOK;\n    }\n\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/native/src/barcodescanner_ndk.hpp",
    "content": "/*\n* Copyright 2013-2015 BlackBerry Limited.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n* http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n\n#ifndef BARCODESCANNERNDK_HPP_\n#define BARCODESCANNERNDK_HPP_\n\n#include <camera/camera_api.h>\n#include \"Logger.hpp\"\n#include <bps/event.h>\n#include <string>\n\nclass BarcodeScannerJS;\n\nnamespace webworks {\n\nclass BarcodeScannerNDK {\npublic:\n    explicit BarcodeScannerNDK(BarcodeScannerJS *parent = NULL);\n    virtual ~BarcodeScannerNDK();\n\n    int startRead(const std::string& callbackId, const std::string& handle);\n    int stopRead(const std::string& callbackId);\n    bool isThreadHalt();\n    void StopEvents();\n    bool StartEvents();\n    Logger* getLog();\n    void handleScreenEvent(bps_event_t *event, Logger* log, const char* windowGroup);\n    void cancelScan();\n    char* windowGroup;\n    screen_context_t windowContext;\n    char* cbId;\n\nprivate:\n    BarcodeScannerJS *m_pParent;\n    camera_handle_t mCameraHandle;\n    bool threadHalt;\n    std::string windowHandle;\n};\n\n} // namespace webworks\n\n#endif /* BARCODESCANNERNDK_H_ */\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/blackberry10/qrcode.js",
    "content": "/**\n * @fileoverview\n * - Using the 'QRCode for Javascript library'\n * - Fixed dataset of 'QRCode for Javascript library' for support full-spec.\n * - this library has no dependencies.\n * \n * @author davidshimjs\n * @see <a href=\"http://www.d-project.com/\" target=\"_blank\">http://www.d-project.com/</a>\n * @see <a href=\"http://jeromeetienne.github.com/jquery-qrcode/\" target=\"_blank\">http://jeromeetienne.github.com/jquery-qrcode/</a>\n */\nvar QRCode;\n//var _utils = require(\"../../lib/utils\");\n\n(function () {\n\t//---------------------------------------------------------------------\n\t// QRCode for JavaScript\n\t//\n\t// Copyright (c) 2009 Kazuhiko Arase\n\t//\n\t// URL: http://www.d-project.com/\n\t//\n\t// Licensed under the MIT license:\n\t//   http://www.opensource.org/licenses/mit-license.php\n\t//\n\t// The word \"QR Code\" is registered trademark of \n\t// DENSO WAVE INCORPORATED\n\t//   http://www.denso-wave.com/qrcode/faqpatent-e.html\n\t//\n\t//---------------------------------------------------------------------\n\tfunction QR8bitByte(data) {\n\t\tthis.mode = QRMode.MODE_8BIT_BYTE;\n\t\tthis.data = data;\n\t\tthis.parsedData = [];\n\n\t\t// Added to support UTF-8 Characters\n\t\tfor (var i = 0, l = this.data.length; i < l; i++) {\n\t\t\tvar byteArray = [];\n\t\t\tvar code = this.data.charCodeAt(i);\n\n\t\t\tif (code > 0x10000) {\n\t\t\t\tbyteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18);\n\t\t\t\tbyteArray[1] = 0x80 | ((code & 0x3F000) >>> 12);\n\t\t\t\tbyteArray[2] = 0x80 | ((code & 0xFC0) >>> 6);\n\t\t\t\tbyteArray[3] = 0x80 | (code & 0x3F);\n\t\t\t} else if (code > 0x800) {\n\t\t\t\tbyteArray[0] = 0xE0 | ((code & 0xF000) >>> 12);\n\t\t\t\tbyteArray[1] = 0x80 | ((code & 0xFC0) >>> 6);\n\t\t\t\tbyteArray[2] = 0x80 | (code & 0x3F);\n\t\t\t} else if (code > 0x80) {\n\t\t\t\tbyteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6);\n\t\t\t\tbyteArray[1] = 0x80 | (code & 0x3F);\n\t\t\t} else {\n\t\t\t\tbyteArray[0] = code;\n\t\t\t}\n\n\t\t\tthis.parsedData.push(byteArray);\n\t\t}\n\n\t\tthis.parsedData = Array.prototype.concat.apply([], this.parsedData);\n\n\t\tif (this.parsedData.length != this.data.length) {\n\t\t\tthis.parsedData.unshift(191);\n\t\t\tthis.parsedData.unshift(187);\n\t\t\tthis.parsedData.unshift(239);\n\t\t}\n\t}\n\n\tQR8bitByte.prototype = {\n\t\tgetLength: function (buffer) {\n\t\t\treturn this.parsedData.length;\n\t\t},\n\t\twrite: function (buffer) {\n\t\t\tfor (var i = 0, l = this.parsedData.length; i < l; i++) {\n\t\t\t\tbuffer.put(this.parsedData[i], 8);\n\t\t\t}\n\t\t}\n\t};\n\n\tfunction QRCodeModel(typeNumber, errorCorrectLevel) {\n\t\tthis.typeNumber = typeNumber;\n\t\tthis.errorCorrectLevel = errorCorrectLevel;\n\t\tthis.modules = null;\n\t\tthis.moduleCount = 0;\n\t\tthis.dataCache = null;\n\t\tthis.dataList = [];\n\t}\n\n\tQRCodeModel.prototype={addData:function(data){var newData=new QR8bitByte(data);this.dataList.push(newData);this.dataCache=null;},isDark:function(row,col){if(row<0||this.moduleCount<=row||col<0||this.moduleCount<=col){throw new Error(row+\",\"+col);}\n\treturn this.modules[row][col];},getModuleCount:function(){return this.moduleCount;},make:function(){this.makeImpl(false,this.getBestMaskPattern());},makeImpl:function(test,maskPattern){this.moduleCount=this.typeNumber*4+17;this.modules=new Array(this.moduleCount);for(var row=0;row<this.moduleCount;row++){this.modules[row]=new Array(this.moduleCount);for(var col=0;col<this.moduleCount;col++){this.modules[row][col]=null;}}\n\tthis.setupPositionProbePattern(0,0);this.setupPositionProbePattern(this.moduleCount-7,0);this.setupPositionProbePattern(0,this.moduleCount-7);this.setupPositionAdjustPattern();this.setupTimingPattern();this.setupTypeInfo(test,maskPattern);if(this.typeNumber>=7){this.setupTypeNumber(test);}\n\tif(this.dataCache==null){this.dataCache=QRCodeModel.createData(this.typeNumber,this.errorCorrectLevel,this.dataList);}\n\tthis.mapData(this.dataCache,maskPattern);},setupPositionProbePattern:function(row,col){for(var r=-1;r<=7;r++){if(row+r<=-1||this.moduleCount<=row+r)continue;for(var c=-1;c<=7;c++){if(col+c<=-1||this.moduleCount<=col+c)continue;if((0<=r&&r<=6&&(c==0||c==6))||(0<=c&&c<=6&&(r==0||r==6))||(2<=r&&r<=4&&2<=c&&c<=4)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}},getBestMaskPattern:function(){var minLostPoint=0;var pattern=0;for(var i=0;i<8;i++){this.makeImpl(true,i);var lostPoint=QRUtil.getLostPoint(this);if(i==0||minLostPoint>lostPoint){minLostPoint=lostPoint;pattern=i;}}\n\treturn pattern;},createMovieClip:function(target_mc,instance_name,depth){var qr_mc=target_mc.createEmptyMovieClip(instance_name,depth);var cs=1;this.make();for(var row=0;row<this.modules.length;row++){var y=row*cs;for(var col=0;col<this.modules[row].length;col++){var x=col*cs;var dark=this.modules[row][col];if(dark){qr_mc.beginFill(0,100);qr_mc.moveTo(x,y);qr_mc.lineTo(x+cs,y);qr_mc.lineTo(x+cs,y+cs);qr_mc.lineTo(x,y+cs);qr_mc.endFill();}}}\n\treturn qr_mc;},setupTimingPattern:function(){for(var r=8;r<this.moduleCount-8;r++){if(this.modules[r][6]!=null){continue;}\n\tthis.modules[r][6]=(r%2==0);}\n\tfor(var c=8;c<this.moduleCount-8;c++){if(this.modules[6][c]!=null){continue;}\n\tthis.modules[6][c]=(c%2==0);}},setupPositionAdjustPattern:function(){var pos=QRUtil.getPatternPosition(this.typeNumber);for(var i=0;i<pos.length;i++){for(var j=0;j<pos.length;j++){var row=pos[i];var col=pos[j];if(this.modules[row][col]!=null){continue;}\n\tfor(var r=-2;r<=2;r++){for(var c=-2;c<=2;c++){if(r==-2||r==2||c==-2||c==2||(r==0&&c==0)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}}}},setupTypeNumber:function(test){var bits=QRUtil.getBCHTypeNumber(this.typeNumber);for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[Math.floor(i/3)][i%3+this.moduleCount-8-3]=mod;}\n\tfor(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[i%3+this.moduleCount-8-3][Math.floor(i/3)]=mod;}},setupTypeInfo:function(test,maskPattern){var data=(this.errorCorrectLevel<<3)|maskPattern;var bits=QRUtil.getBCHTypeInfo(data);for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<6){this.modules[i][8]=mod;}else if(i<8){this.modules[i+1][8]=mod;}else{this.modules[this.moduleCount-15+i][8]=mod;}}\n\tfor(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<8){this.modules[8][this.moduleCount-i-1]=mod;}else if(i<9){this.modules[8][15-i-1+1]=mod;}else{this.modules[8][15-i-1]=mod;}}\n\tthis.modules[this.moduleCount-8][8]=(!test);},mapData:function(data,maskPattern){var inc=-1;var row=this.moduleCount-1;var bitIndex=7;var byteIndex=0;for(var col=this.moduleCount-1;col>0;col-=2){if(col==6)col--;while(true){for(var c=0;c<2;c++){if(this.modules[row][col-c]==null){var dark=false;if(byteIndex<data.length){dark=(((data[byteIndex]>>>bitIndex)&1)==1);}\n\tvar mask=QRUtil.getMask(maskPattern,row,col-c);if(mask){dark=!dark;}\n\tthis.modules[row][col-c]=dark;bitIndex--;if(bitIndex==-1){byteIndex++;bitIndex=7;}}}\n\trow+=inc;if(row<0||this.moduleCount<=row){row-=inc;inc=-inc;break;}}}}};QRCodeModel.PAD0=0xEC;QRCodeModel.PAD1=0x11;QRCodeModel.createData=function(typeNumber,errorCorrectLevel,dataList){var rsBlocks=QRRSBlock.getRSBlocks(typeNumber,errorCorrectLevel);var buffer=new QRBitBuffer();for(var i=0;i<dataList.length;i++){var data=dataList[i];buffer.put(data.mode,4);buffer.put(data.getLength(),QRUtil.getLengthInBits(data.mode,typeNumber));data.write(buffer);}\n\tvar totalDataCount=0;for(var i=0;i<rsBlocks.length;i++){totalDataCount+=rsBlocks[i].dataCount;}\n\tif(buffer.getLengthInBits()>totalDataCount*8){throw new Error(\"code length overflow. (\"\n\t+buffer.getLengthInBits()\n\t+\">\"\n\t+totalDataCount*8\n\t+\")\");}\n\tif(buffer.getLengthInBits()+4<=totalDataCount*8){buffer.put(0,4);}\n\twhile(buffer.getLengthInBits()%8!=0){buffer.putBit(false);}\n\twhile(true){if(buffer.getLengthInBits()>=totalDataCount*8){break;}\n\tbuffer.put(QRCodeModel.PAD0,8);if(buffer.getLengthInBits()>=totalDataCount*8){break;}\n\tbuffer.put(QRCodeModel.PAD1,8);}\n\treturn QRCodeModel.createBytes(buffer,rsBlocks);};QRCodeModel.createBytes=function(buffer,rsBlocks){var offset=0;var maxDcCount=0;var maxEcCount=0;var dcdata=new Array(rsBlocks.length);var ecdata=new Array(rsBlocks.length);for(var r=0;r<rsBlocks.length;r++){var dcCount=rsBlocks[r].dataCount;var ecCount=rsBlocks[r].totalCount-dcCount;maxDcCount=Math.max(maxDcCount,dcCount);maxEcCount=Math.max(maxEcCount,ecCount);dcdata[r]=new Array(dcCount);for(var i=0;i<dcdata[r].length;i++){dcdata[r][i]=0xff&buffer.buffer[i+offset];}\n\toffset+=dcCount;var rsPoly=QRUtil.getErrorCorrectPolynomial(ecCount);var rawPoly=new QRPolynomial(dcdata[r],rsPoly.getLength()-1);var modPoly=rawPoly.mod(rsPoly);ecdata[r]=new Array(rsPoly.getLength()-1);for(var i=0;i<ecdata[r].length;i++){var modIndex=i+modPoly.getLength()-ecdata[r].length;ecdata[r][i]=(modIndex>=0)?modPoly.get(modIndex):0;}}\n\tvar totalCodeCount=0;for(var i=0;i<rsBlocks.length;i++){totalCodeCount+=rsBlocks[i].totalCount;}\n\tvar data=new Array(totalCodeCount);var index=0;for(var i=0;i<maxDcCount;i++){for(var r=0;r<rsBlocks.length;r++){if(i<dcdata[r].length){data[index++]=dcdata[r][i];}}}\n\tfor(var i=0;i<maxEcCount;i++){for(var r=0;r<rsBlocks.length;r++){if(i<ecdata[r].length){data[index++]=ecdata[r][i];}}}\n\treturn data;};var QRMode={MODE_NUMBER:1<<0,MODE_ALPHA_NUM:1<<1,MODE_8BIT_BYTE:1<<2,MODE_KANJI:1<<3};var QRErrorCorrectLevel={L:1,M:0,Q:3,H:2};var QRMaskPattern={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};var QRUtil={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:(1<<10)|(1<<8)|(1<<5)|(1<<4)|(1<<2)|(1<<1)|(1<<0),G18:(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)|(1<<5)|(1<<2)|(1<<0),G15_MASK:(1<<14)|(1<<12)|(1<<10)|(1<<4)|(1<<1),getBCHTypeInfo:function(data){var d=data<<10;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)>=0){d^=(QRUtil.G15<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)));}\n\treturn((data<<10)|d)^QRUtil.G15_MASK;},getBCHTypeNumber:function(data){var d=data<<12;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)>=0){d^=(QRUtil.G18<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)));}\n\treturn(data<<12)|d;},getBCHDigit:function(data){var digit=0;while(data!=0){digit++;data>>>=1;}\n\treturn digit;},getPatternPosition:function(typeNumber){return QRUtil.PATTERN_POSITION_TABLE[typeNumber-1];},getMask:function(maskPattern,i,j){switch(maskPattern){case QRMaskPattern.PATTERN000:return(i+j)%2==0;case QRMaskPattern.PATTERN001:return i%2==0;case QRMaskPattern.PATTERN010:return j%3==0;case QRMaskPattern.PATTERN011:return(i+j)%3==0;case QRMaskPattern.PATTERN100:return(Math.floor(i/2)+Math.floor(j/3))%2==0;case QRMaskPattern.PATTERN101:return(i*j)%2+(i*j)%3==0;case QRMaskPattern.PATTERN110:return((i*j)%2+(i*j)%3)%2==0;case QRMaskPattern.PATTERN111:return((i*j)%3+(i+j)%2)%2==0;default:throw new Error(\"bad maskPattern:\"+maskPattern);}},getErrorCorrectPolynomial:function(errorCorrectLength){var a=new QRPolynomial([1],0);for(var i=0;i<errorCorrectLength;i++){a=a.multiply(new QRPolynomial([1,QRMath.gexp(i)],0));}\n\treturn a;},getLengthInBits:function(mode,type){if(1<=type&&type<10){switch(mode){case QRMode.MODE_NUMBER:return 10;case QRMode.MODE_ALPHA_NUM:return 9;case QRMode.MODE_8BIT_BYTE:return 8;case QRMode.MODE_KANJI:return 8;default:throw new Error(\"mode:\"+mode);}}else if(type<27){switch(mode){case QRMode.MODE_NUMBER:return 12;case QRMode.MODE_ALPHA_NUM:return 11;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 10;default:throw new Error(\"mode:\"+mode);}}else if(type<41){switch(mode){case QRMode.MODE_NUMBER:return 14;case QRMode.MODE_ALPHA_NUM:return 13;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 12;default:throw new Error(\"mode:\"+mode);}}else{throw new Error(\"type:\"+type);}},getLostPoint:function(qrCode){var moduleCount=qrCode.getModuleCount();var lostPoint=0;for(var row=0;row<moduleCount;row++){for(var col=0;col<moduleCount;col++){var sameCount=0;var dark=qrCode.isDark(row,col);for(var r=-1;r<=1;r++){if(row+r<0||moduleCount<=row+r){continue;}\n\tfor(var c=-1;c<=1;c++){if(col+c<0||moduleCount<=col+c){continue;}\n\tif(r==0&&c==0){continue;}\n\tif(dark==qrCode.isDark(row+r,col+c)){sameCount++;}}}\n\tif(sameCount>5){lostPoint+=(3+sameCount-5);}}}\n\tfor(var row=0;row<moduleCount-1;row++){for(var col=0;col<moduleCount-1;col++){var count=0;if(qrCode.isDark(row,col))count++;if(qrCode.isDark(row+1,col))count++;if(qrCode.isDark(row,col+1))count++;if(qrCode.isDark(row+1,col+1))count++;if(count==0||count==4){lostPoint+=3;}}}\n\tfor(var row=0;row<moduleCount;row++){for(var col=0;col<moduleCount-6;col++){if(qrCode.isDark(row,col)&&!qrCode.isDark(row,col+1)&&qrCode.isDark(row,col+2)&&qrCode.isDark(row,col+3)&&qrCode.isDark(row,col+4)&&!qrCode.isDark(row,col+5)&&qrCode.isDark(row,col+6)){lostPoint+=40;}}}\n\tfor(var col=0;col<moduleCount;col++){for(var row=0;row<moduleCount-6;row++){if(qrCode.isDark(row,col)&&!qrCode.isDark(row+1,col)&&qrCode.isDark(row+2,col)&&qrCode.isDark(row+3,col)&&qrCode.isDark(row+4,col)&&!qrCode.isDark(row+5,col)&&qrCode.isDark(row+6,col)){lostPoint+=40;}}}\n\tvar darkCount=0;for(var col=0;col<moduleCount;col++){for(var row=0;row<moduleCount;row++){if(qrCode.isDark(row,col)){darkCount++;}}}\n\tvar ratio=Math.abs(100*darkCount/moduleCount/moduleCount-50)/5;lostPoint+=ratio*10;return lostPoint;}};var QRMath={glog:function(n){if(n<1){throw new Error(\"glog(\"+n+\")\");}\n\treturn QRMath.LOG_TABLE[n];},gexp:function(n){while(n<0){n+=255;}\n\twhile(n>=256){n-=255;}\n\treturn QRMath.EXP_TABLE[n];},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)};for(var i=0;i<8;i++){QRMath.EXP_TABLE[i]=1<<i;}\n\tfor(var i=8;i<256;i++){QRMath.EXP_TABLE[i]=QRMath.EXP_TABLE[i-4]^QRMath.EXP_TABLE[i-5]^QRMath.EXP_TABLE[i-6]^QRMath.EXP_TABLE[i-8];}\n\tfor(var i=0;i<255;i++){QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]]=i;}\n\tfunction QRPolynomial(num,shift){if(num.length==undefined){throw new Error(num.length+\"/\"+shift);}\n\tvar offset=0;while(offset<num.length&&num[offset]==0){offset++;}\n\tthis.num=new Array(num.length-offset+shift);for(var i=0;i<num.length-offset;i++){this.num[i]=num[i+offset];}}\n\tQRPolynomial.prototype={get:function(index){return this.num[index];},getLength:function(){return this.num.length;},multiply:function(e){var num=new Array(this.getLength()+e.getLength()-1);for(var i=0;i<this.getLength();i++){for(var j=0;j<e.getLength();j++){num[i+j]^=QRMath.gexp(QRMath.glog(this.get(i))+QRMath.glog(e.get(j)));}}\n\treturn new QRPolynomial(num,0);},mod:function(e){if(this.getLength()-e.getLength()<0){return this;}\n\tvar ratio=QRMath.glog(this.get(0))-QRMath.glog(e.get(0));var num=new Array(this.getLength());for(var i=0;i<this.getLength();i++){num[i]=this.get(i);}\n\tfor(var i=0;i<e.getLength();i++){num[i]^=QRMath.gexp(QRMath.glog(e.get(i))+ratio);}\n\treturn new QRPolynomial(num,0).mod(e);}};function QRRSBlock(totalCount,dataCount){this.totalCount=totalCount;this.dataCount=dataCount;}\n\tQRRSBlock.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];QRRSBlock.getRSBlocks=function(typeNumber,errorCorrectLevel){var rsBlock=QRRSBlock.getRsBlockTable(typeNumber,errorCorrectLevel);if(rsBlock==undefined){throw new Error(\"bad rs block @ typeNumber:\"+typeNumber+\"/errorCorrectLevel:\"+errorCorrectLevel);}\n\tvar length=rsBlock.length/3;var list=[];for(var i=0;i<length;i++){var count=rsBlock[i*3+0];var totalCount=rsBlock[i*3+1];var dataCount=rsBlock[i*3+2];for(var j=0;j<count;j++){list.push(new QRRSBlock(totalCount,dataCount));}}\n\treturn list;};QRRSBlock.getRsBlockTable=function(typeNumber,errorCorrectLevel){switch(errorCorrectLevel){case QRErrorCorrectLevel.L:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+0];case QRErrorCorrectLevel.M:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+1];case QRErrorCorrectLevel.Q:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+2];case QRErrorCorrectLevel.H:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+3];default:return undefined;}};function QRBitBuffer(){this.buffer=[];this.length=0;}\n\tQRBitBuffer.prototype={get:function(index){var bufIndex=Math.floor(index/8);return((this.buffer[bufIndex]>>>(7-index%8))&1)==1;},put:function(num,length){for(var i=0;i<length;i++){this.putBit(((num>>>(length-i-1))&1)==1);}},getLengthInBits:function(){return this.length;},putBit:function(bit){var bufIndex=Math.floor(this.length/8);if(this.buffer.length<=bufIndex){this.buffer.push(0);}\n\tif(bit){this.buffer[bufIndex]|=(0x80>>>(this.length%8));}\n\tthis.length++;}};var QRCodeLimitLength=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]];\n\t\n\tfunction _isSupportCanvas() {\n\t\treturn typeof CanvasRenderingContext2D != \"undefined\";\n\t}\n\t\n\t// android 2.x doesn't support Data-URI spec\n\tfunction _getAndroid() {\n\t\tvar android = false;\n\t\tvar sAgent = navigator.userAgent;\n\t\t\n\t\tif (/android/i.test(sAgent)) { // android\n\t\t\tandroid = true;\n\t\t\tvar aMat = sAgent.toString().match(/android ([0-9]\\.[0-9])/i);\n\t\t\t\n\t\t\tif (aMat && aMat[1]) {\n\t\t\t\tandroid = parseFloat(aMat[1]);\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn android;\n\t}\n\t\n\tvar svgDrawer = (function() {\n\n\t\tvar Drawing = function (el, htOption) {\n\t\t\tthis._el = el;\n\t\t\tthis._htOption = htOption;\n\t\t};\n\n\t\tDrawing.prototype.draw = function (oQRCode) {\n\t\t\tvar _htOption = this._htOption;\n\t\t\tvar _el = this._el;\n\t\t\tvar nCount = oQRCode.getModuleCount();\n\t\t\tvar nWidth = Math.floor(_htOption.width / nCount);\n\t\t\tvar nHeight = Math.floor(_htOption.height / nCount);\n\n\t\t\tthis.clear();\n\n\t\t\tfunction makeSVG(tag, attrs) {\n\t\t\t\tvar el = document.createElementNS('http://www.w3.org/2000/svg', tag);\n\t\t\t\tfor (var k in attrs)\n\t\t\t\t\tif (attrs.hasOwnProperty(k)) el.setAttribute(k, attrs[k]);\n\t\t\t\treturn el;\n\t\t\t}\n\n\t\t\tvar svg = makeSVG(\"svg\" , {'viewBox': '0 0 ' + String(nCount) + \" \" + String(nCount), 'width': '100%', 'height': '100%', 'fill': _htOption.colorLight});\n\t\t\tsvg.setAttributeNS(\"http://www.w3.org/2000/xmlns/\", \"xmlns:xlink\", \"http://www.w3.org/1999/xlink\");\n\t\t\t_el.appendChild(svg);\n\n\t\t\tsvg.appendChild(makeSVG(\"rect\", {\"fill\": _htOption.colorLight, \"width\": \"100%\", \"height\": \"100%\"}));\n\t\t\tsvg.appendChild(makeSVG(\"rect\", {\"fill\": _htOption.colorDark, \"width\": \"1\", \"height\": \"1\", \"id\": \"template\"}));\n\n\t\t\tfor (var row = 0; row < nCount; row++) {\n\t\t\t\tfor (var col = 0; col < nCount; col++) {\n\t\t\t\t\tif (oQRCode.isDark(row, col)) {\n\t\t\t\t\t\tvar child = makeSVG(\"use\", {\"x\": String(col), \"y\": String(row)});\n\t\t\t\t\t\tchild.setAttributeNS(\"http://www.w3.org/1999/xlink\", \"href\", \"#template\");\n\t\t\t\t\t\tsvg.appendChild(child);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tDrawing.prototype.clear = function () {\n\t\t\twhile (this._el.hasChildNodes())\n\t\t\t\tthis._el.removeChild(this._el.lastChild);\n\t\t};\n\t\treturn Drawing;\n\t})();\n\n\tvar useSVG = document.documentElement.tagName.toLowerCase() === \"svg\";\n\n\t// Drawing in DOM by using Table tag\n\tvar Drawing = useSVG ? svgDrawer : !_isSupportCanvas() ? (function () {\n\t\tvar Drawing = function (el, htOption) {\n\t\t\tthis._el = el;\n\t\t\tthis._htOption = htOption;\n\t\t};\n\t\t\t\n\t\t/**\n\t\t * Draw the QRCode\n\t\t * \n\t\t * @param {QRCode} oQRCode\n\t\t */\n\t\tDrawing.prototype.draw = function (oQRCode) {\n            var _htOption = this._htOption;\n            var _el = this._el;\n\t\t\tvar nCount = oQRCode.getModuleCount();\n\t\t\tvar nWidth = Math.floor(_htOption.width / nCount);\n\t\t\tvar nHeight = Math.floor(_htOption.height / nCount);\n\t\t\tvar aHTML = ['<table style=\"border:0;border-collapse:collapse;\">'];\n\t\t\t\n\t\t\tfor (var row = 0; row < nCount; row++) {\n\t\t\t\taHTML.push('<tr>');\n\t\t\t\t\n\t\t\t\tfor (var col = 0; col < nCount; col++) {\n\t\t\t\t\taHTML.push('<td style=\"border:0;border-collapse:collapse;padding:0;margin:0;width:' + nWidth + 'px;height:' + nHeight + 'px;background-color:' + (oQRCode.isDark(row, col) ? _htOption.colorDark : _htOption.colorLight) + ';\"></td>');\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\taHTML.push('</tr>');\n\t\t\t}\n\t\t\t\n\t\t\taHTML.push('</table>');\n\t\t\t_el.innerHTML = aHTML.join('');\n\t\t\t\n\t\t\t// Fix the margin values as real size.\n\t\t\tvar elTable = _el.childNodes[0];\n\t\t\tvar nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2;\n\t\t\tvar nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2;\n\t\t\t\n\t\t\tif (nLeftMarginTable > 0 && nTopMarginTable > 0) {\n\t\t\t\telTable.style.margin = nTopMarginTable + \"px \" + nLeftMarginTable + \"px\";\t\n\t\t\t}\n\t\t};\n\t\t\n\t\t/**\n\t\t * Clear the QRCode\n\t\t */\n\t\tDrawing.prototype.clear = function () {\n\t\t\tthis._el.innerHTML = '';\n\t\t};\n\t\t\n\t\treturn Drawing;\n\t})() : (function () { // Drawing in Canvas\n\t\tfunction _onMakeImage() {\n\t\t\tthis._elImage.src = this._elCanvas.toDataURL(\"image/png\");\n\t\t\tthis._elImage.style.display = \"block\";\n\t\t\tthis._elCanvas.style.display = \"none\";\t\t\t\n\t\t}\n\t\t\n\t\t// Android 2.1 bug workaround\n\t\t// http://code.google.com/p/android/issues/detail?id=5141\n\t\tif (this._android && this._android <= 2.1) {\n\t    \tvar factor = 1 / window.devicePixelRatio;\n\t        var drawImage = CanvasRenderingContext2D.prototype.drawImage; \n\t    \tCanvasRenderingContext2D.prototype.drawImage = function (image, sx, sy, sw, sh, dx, dy, dw, dh) {\n\t    \t\tif ((\"nodeName\" in image) && /img/i.test(image.nodeName)) {\n\t\t        \tfor (var i = arguments.length - 1; i >= 1; i--) {\n\t\t            \targuments[i] = arguments[i] * factor;\n\t\t        \t}\n\t    \t\t} else if (typeof dw == \"undefined\") {\n\t    \t\t\targuments[1] *= factor;\n\t    \t\t\targuments[2] *= factor;\n\t    \t\t\targuments[3] *= factor;\n\t    \t\t\targuments[4] *= factor;\n\t    \t\t}\n\t    \t\t\n\t        \tdrawImage.apply(this, arguments); \n\t    \t};\n\t\t}\n\t\t\n\t\t/**\n\t\t * Check whether the user's browser supports Data URI or not\n\t\t * \n\t\t * @private\n\t\t * @param {Function} fSuccess Occurs if it supports Data URI\n\t\t * @param {Function} fFail Occurs if it doesn't support Data URI\n\t\t */\n\t\tfunction _safeSetDataURI(fSuccess, fFail) {\n            var self = this;\n            self._fFail = fFail;\n            self._fSuccess = fSuccess;\n\n            // Check it just once\n            if (self._bSupportDataURI === null) {\n                var el = document.createElement(\"img\");\n                var fOnError = function() {\n                    self._bSupportDataURI = false;\n\n                    if (self._fFail) {\n                        self._fFail.call(self);\n                    }\n                };\n                var fOnSuccess = function() {\n                    self._bSupportDataURI = true;\n\n                    if (self._fSuccess) {\n                        self._fSuccess.call(self);\n                    }\n                };\n\n                el.onabort = fOnError;\n                el.onerror = fOnError;\n                el.onload = fOnSuccess;\n                el.src = \"data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==\"; // the Image contains 1px data.\n                return;\n            } else if (self._bSupportDataURI === true && self._fSuccess) {\n                self._fSuccess.call(self);\n            } else if (self._bSupportDataURI === false && self._fFail) {\n                self._fFail.call(self);\n            }\n\t\t};\n\t\t\n\t\t/**\n\t\t * Drawing QRCode by using canvas\n\t\t * \n\t\t * @constructor\n\t\t * @param {HTMLElement} el\n\t\t * @param {Object} htOption QRCode Options \n\t\t */\n\t\tvar Drawing = function (el, htOption) {\n    \t\tthis._bIsPainted = false;\n    \t\tthis._android = _getAndroid();\n\t\t\n\t\t\tthis._htOption = htOption;\n\t\t\tthis._elCanvas = document.createElement(\"canvas\");\n\t\t\tthis._elCanvas.width = htOption.width;\n\t\t\tthis._elCanvas.height = htOption.height;\n\t\t\tel.appendChild(this._elCanvas);\n\t\t\tthis._el = el;\n\t\t\tthis._oContext = this._elCanvas.getContext(\"2d\");\n\t\t\tthis._bIsPainted = false;\n\t\t\tthis._elImage = document.createElement(\"img\");\n\t\t\tthis._elImage.alt = \"Scan me!\";\n\t\t\tthis._elImage.style.display = \"none\";\n\t\t\tthis._el.appendChild(this._elImage);\n\t\t\tthis._bSupportDataURI = null;\n\t\t};\n\t\t\t\n\t\t/**\n\t\t * Draw the QRCode\n\t\t * \n\t\t * @param {QRCode} oQRCode \n\t\t */\n\t\tDrawing.prototype.draw = function (oQRCode) {\n            var _elImage = this._elImage;\n            var _oContext = this._oContext;\n            var _htOption = this._htOption;\n            \n\t\t\tvar nCount = oQRCode.getModuleCount();\n\t\t\tvar nWidth = _htOption.width / nCount;\n\t\t\tvar nHeight = _htOption.height / nCount;\n\t\t\tvar nRoundedWidth = Math.round(nWidth);\n\t\t\tvar nRoundedHeight = Math.round(nHeight);\n\n\t\t\t_elImage.style.display = \"none\";\n\t\t\tthis.clear();\n\t\t\t\n\t\t\tfor (var row = 0; row < nCount; row++) {\n\t\t\t\tfor (var col = 0; col < nCount; col++) {\n\t\t\t\t\tvar bIsDark = oQRCode.isDark(row, col);\n\t\t\t\t\tvar nLeft = col * nWidth;\n\t\t\t\t\tvar nTop = row * nHeight;\n\t\t\t\t\t_oContext.strokeStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight;\n\t\t\t\t\t_oContext.lineWidth = 1;\n\t\t\t\t\t_oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight;\t\t\t\t\t\n\t\t\t\t\t_oContext.fillRect(nLeft, nTop, nWidth, nHeight);\n\t\t\t\t\t\n\t\t\t\t\t// 안티 앨리어싱 방지 처리\n\t\t\t\t\t_oContext.strokeRect(\n\t\t\t\t\t\tMath.floor(nLeft) + 0.5,\n\t\t\t\t\t\tMath.floor(nTop) + 0.5,\n\t\t\t\t\t\tnRoundedWidth,\n\t\t\t\t\t\tnRoundedHeight\n\t\t\t\t\t);\n\t\t\t\t\t\n\t\t\t\t\t_oContext.strokeRect(\n\t\t\t\t\t\tMath.ceil(nLeft) - 0.5,\n\t\t\t\t\t\tMath.ceil(nTop) - 0.5,\n\t\t\t\t\t\tnRoundedWidth,\n\t\t\t\t\t\tnRoundedHeight\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tthis._bIsPainted = true;\n\t\t};\n\t\t\t\n\t\t/**\n\t\t * Make the image from Canvas if the browser supports Data URI.\n\t\t */\n\t\tDrawing.prototype.makeImage = function () {\n\t\t\tif (this._bIsPainted) {\n\t\t\t\t_safeSetDataURI.call(this, _onMakeImage);\n\t\t\t}\n\t\t};\n\t\t\t\n\t\t/**\n\t\t * Return whether the QRCode is painted or not\n\t\t * \n\t\t * @return {Boolean}\n\t\t */\n\t\tDrawing.prototype.isPainted = function () {\n\t\t\treturn this._bIsPainted;\n\t\t};\n\t\t\n\t\t/**\n\t\t * Clear the QRCode\n\t\t */\n\t\tDrawing.prototype.clear = function () {\n\t\t\tthis._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height);\n\t\t\tthis._bIsPainted = false;\n\t\t};\n\t\t\n\t\t/**\n\t\t * @private\n\t\t * @param {Number} nNumber\n\t\t */\n\t\tDrawing.prototype.round = function (nNumber) {\n\t\t\tif (!nNumber) {\n\t\t\t\treturn nNumber;\n\t\t\t}\n\t\t\t\n\t\t\treturn Math.floor(nNumber * 1000) / 1000;\n\t\t};\n\t\t\n\t\treturn Drawing;\n\t})();\n\t\n\t/**\n\t * Get the type by string length\n\t * \n\t * @private\n\t * @param {String} sText\n\t * @param {Number} nCorrectLevel\n\t * @return {Number} type\n\t */\n\tfunction _getTypeNumber(sText, nCorrectLevel) {\t\t\t\n\t\tvar nType = 1;\n\t\tvar length = _getUTF8Length(sText);\n\t\t\n\t\tfor (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) {\n\t\t\tvar nLimit = 0;\n\t\t\t\n\t\t\tswitch (nCorrectLevel) {\n\t\t\t\tcase QRErrorCorrectLevel.L :\n\t\t\t\t\tnLimit = QRCodeLimitLength[i][0];\n\t\t\t\t\tbreak;\n\t\t\t\tcase QRErrorCorrectLevel.M :\n\t\t\t\t\tnLimit = QRCodeLimitLength[i][1];\n\t\t\t\t\tbreak;\n\t\t\t\tcase QRErrorCorrectLevel.Q :\n\t\t\t\t\tnLimit = QRCodeLimitLength[i][2];\n\t\t\t\t\tbreak;\n\t\t\t\tcase QRErrorCorrectLevel.H :\n\t\t\t\t\tnLimit = QRCodeLimitLength[i][3];\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (length <= nLimit) {\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tnType++;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (nType > QRCodeLimitLength.length) {\n\t\t\tthrow new Error(\"Too long data\");\n\t\t}\n\t\t\n\t\treturn nType;\n\t}\n\n\tfunction _getUTF8Length(sText) {\n\t\tvar replacedText = encodeURI(sText).toString().replace(/\\%[0-9a-fA-F]{2}/g, 'a');\n\t\treturn replacedText.length + (replacedText.length != sText ? 3 : 0);\n\t}\n\t\n\t/**\n\t * @class QRCode\n\t * @constructor\n\t * @example \n\t * new QRCode(document.getElementById(\"test\"), \"http://jindo.dev.naver.com/collie\");\n\t *\n\t * @example\n\t * var oQRCode = new QRCode(\"test\", {\n\t *    text : \"http://naver.com\",\n\t *    width : 128,\n\t *    height : 128\n\t * });\n\t * \n\t * oQRCode.clear(); // Clear the QRCode.\n\t * oQRCode.makeCode(\"http://map.naver.com\"); // Re-create the QRCode.\n\t *\n\t * @param {HTMLElement|String} el target element or 'id' attribute of element.\n\t * @param {Object|String} vOption\n\t * @param {String} vOption.text QRCode link data\n\t * @param {Number} [vOption.width=256]\n\t * @param {Number} [vOption.height=256]\n\t * @param {String} [vOption.colorDark=\"#000000\"]\n\t * @param {String} [vOption.colorLight=\"#ffffff\"]\n\t * @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H] \n\t */\n\tQRCode = function (el, vOption) {\n\t\tthis._htOption = {\n\t\t\twidth : 256, \n\t\t\theight : 256,\n\t\t\ttypeNumber : 4,\n\t\t\tcolorDark : \"#000000\",\n\t\t\tcolorLight : \"#ffffff\",\n\t\t\tcorrectLevel : QRErrorCorrectLevel.H\n\t\t};\n\t\t\n\t\tif (typeof vOption === 'string') {\n\t\t\tvOption\t= {\n\t\t\t\ttext : vOption\n\t\t\t};\n\t\t}\n\t\t\n\t\t// Overwrites options\n\t\tif (vOption) {\n\t\t\tfor (var i in vOption) {\n\t\t\t\tthis._htOption[i] = vOption[i];\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (typeof el == \"string\") {\n\t\t\tel = document.getElementById(el);\n\t\t}\n\n\t\tif (this._htOption.useSVG) {\n\t\t\tDrawing = svgDrawer;\n\t\t}\n\t\t\n\t\tthis._android = _getAndroid();\n\t\tthis._el = el;\n\t\tthis._oQRCode = null;\n\t\tthis._oDrawing = new Drawing(this._el, this._htOption);\n\t\t\n\t\tif (this._htOption.text) {\n\t\t\tthis.makeCode(this._htOption.text);\t\n\t\t}\n\t};\n\t\n\t/**\n\t * Make the QRCode\n\t * \n\t * @param {String} sText link data\n\t */\n\tQRCode.prototype.makeCode = function (sText) {\n\t\tthis._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel);\n\t\tthis._oQRCode.addData(sText);\n\t\tthis._oQRCode.make();\n\t\tthis._el.title = sText;\n\t\tthis._oDrawing.draw(this._oQRCode);\t\t\t\n\t\tthis.makeImage();\n\t};\n\t\n\t/**\n\t * Make the Image from Canvas element\n\t * - It occurs automatically\n\t * - Android below 3 doesn't support Data-URI spec.\n\t * \n\t * @private\n\t */\n\tQRCode.prototype.makeImage = function () {\n\t\tif (typeof this._oDrawing.makeImage == \"function\" && (!this._android || this._android >= 3)) {\n\t\t\tthis._oDrawing.makeImage();\n\t\t}\n\t};\n\t\n\t/**\n\t * Clear the QRCode\n\t */\n\tQRCode.prototype.clear = function () {\n\t\tthis._oDrawing.clear();\n\t};\n\t\n\t/**\n\t * @name QRCode.CorrectLevel\n\t */\n\tQRCode.CorrectLevel = QRErrorCorrectLevel;\n\n\tmodule.exports = {\n\t\tmakeQRcode : function(el, vOption){\n\t\t\tvar qrcode = new QRCode(el, vOption);\n\t\t\treturn qrcode._oDrawing._elCanvas.toDataURL();\n\t\t}\n\t}\n})();\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/browser/BarcodeScannerProxy.js",
    "content": "function scan(success, error) {\n    var code = window.prompt(\"Enter barcode value (empty value will fire the error handler):\");\n    if(code) {\n        var result = {\n            text:code,\n            format:\"Fake\",\n            cancelled:false\n        };\n        success(result);\n    } else {\n        error(\"No barcode\");\n    }\n}\n\nfunction encode(type, data, success, errorCallback) {\n    success();\n}\n\nmodule.exports = {\n    scan: scan,\n    encode: encode\n};\n\nrequire(\"cordova/exec/proxy\").add(\"BarcodeScanner\",module.exports);"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/ios/CDVBarcodeScanner.mm",
    "content": "/*\n * PhoneGap is available under *either* the terms of the modified BSD license *or* the\n * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.\n *\n * Copyright 2011 Matt Kane. All rights reserved.\n * Copyright (c) 2011, IBM Corporation\n */\n\n#import <AVFoundation/AVFoundation.h>\n#import <AssetsLibrary/AssetsLibrary.h>\n\n//------------------------------------------------------------------------------\n// use the all-in-one version of zxing that we built\n//------------------------------------------------------------------------------\n#import \"zxing-all-in-one.h\"\n#import <Cordova/CDVPlugin.h>\n\n\n//------------------------------------------------------------------------------\n// Delegate to handle orientation functions\n//------------------------------------------------------------------------------\n@protocol CDVBarcodeScannerOrientationDelegate <NSObject>\n\n- (NSUInteger)supportedInterfaceOrientations;\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;\n- (BOOL)shouldAutorotate;\n\n@end\n\n//------------------------------------------------------------------------------\n// Adds a shutter button to the UI, and changes the scan from continuous to\n// only performing a scan when you click the shutter button.  For testing.\n//------------------------------------------------------------------------------\n#define USE_SHUTTER 0\n\n//------------------------------------------------------------------------------\n@class CDVbcsProcessor;\n@class CDVbcsViewController;\n\n//------------------------------------------------------------------------------\n// plugin class\n//------------------------------------------------------------------------------\n@interface CDVBarcodeScanner : CDVPlugin {}\n- (NSString*)isScanNotPossible;\n- (void)scan:(CDVInvokedUrlCommand*)command;\n- (void)encode:(CDVInvokedUrlCommand*)command;\n- (void)returnImage:(NSString*)filePath format:(NSString*)format callback:(NSString*)callback;\n- (void)returnSuccess:(NSString*)scannedText format:(NSString*)format cancelled:(BOOL)cancelled flipped:(BOOL)flipped callback:(NSString*)callback;\n- (void)returnError:(NSString*)message callback:(NSString*)callback;\n@end\n\n//------------------------------------------------------------------------------\n// class that does the grunt work\n//------------------------------------------------------------------------------\n@interface CDVbcsProcessor : NSObject <AVCaptureMetadataOutputObjectsDelegate> {}\n@property (nonatomic, retain) CDVBarcodeScanner*           plugin;\n@property (nonatomic, retain) NSString*                   callback;\n@property (nonatomic, retain) UIViewController*           parentViewController;\n@property (nonatomic, retain) CDVbcsViewController*        viewController;\n@property (nonatomic, retain) AVCaptureSession*           captureSession;\n@property (nonatomic, retain) AVCaptureVideoPreviewLayer* previewLayer;\n@property (nonatomic, retain) NSString*                   alternateXib;\n@property (nonatomic, retain) NSMutableArray*             results;\n@property (nonatomic, retain) NSString*                   formats;\n@property (nonatomic)         BOOL                        is1D;\n@property (nonatomic)         BOOL                        is2D;\n@property (nonatomic)         BOOL                        capturing;\n@property (nonatomic)         BOOL                        isFrontCamera;\n@property (nonatomic)         BOOL                        isShowFlipCameraButton;\n@property (nonatomic)         BOOL                        isShowTorchButton;\n@property (nonatomic)         BOOL                        isFlipped;\n@property (nonatomic)         BOOL                        isTransitionAnimated;\n@property (nonatomic)         BOOL                        isSuccessBeepEnabled;\n\n\n- (id)initWithPlugin:(CDVBarcodeScanner*)plugin callback:(NSString*)callback parentViewController:(UIViewController*)parentViewController alterateOverlayXib:(NSString *)alternateXib;\n- (void)scanBarcode;\n- (void)barcodeScanSucceeded:(NSString*)text format:(NSString*)format;\n- (void)barcodeScanFailed:(NSString*)message;\n- (void)barcodeScanCancelled;\n- (void)openDialog;\n- (NSString*)setUpCaptureSession;\n- (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection;\n- (NSString*)formatStringFrom:(zxing::BarcodeFormat)format;\n- (UIImage*)getImageFromSample:(CMSampleBufferRef)sampleBuffer;\n- (zxing::Ref<zxing::LuminanceSource>) getLuminanceSourceFromSample:(CMSampleBufferRef)sampleBuffer imageBytes:(uint8_t**)ptr;\n- (UIImage*) getImageFromLuminanceSource:(zxing::LuminanceSource*)luminanceSource;\n- (void)dumpImage:(UIImage*)image;\n@end\n\n//------------------------------------------------------------------------------\n// Qr encoder processor\n//------------------------------------------------------------------------------\n@interface CDVqrProcessor: NSObject\n@property (nonatomic, retain) CDVBarcodeScanner*          plugin;\n@property (nonatomic, retain) NSString*                   callback;\n@property (nonatomic, retain) NSString*                   stringToEncode;\n@property                     NSInteger                   size;\n\n- (id)initWithPlugin:(CDVBarcodeScanner*)plugin callback:(NSString*)callback stringToEncode:(NSString*)stringToEncode;\n- (void)generateImage;\n@end\n\n//------------------------------------------------------------------------------\n// view controller for the ui\n//------------------------------------------------------------------------------\n@interface CDVbcsViewController : UIViewController <CDVBarcodeScannerOrientationDelegate> {}\n@property (nonatomic, retain) CDVbcsProcessor*  processor;\n@property (nonatomic, retain) NSString*        alternateXib;\n@property (nonatomic)         BOOL             shutterPressed;\n@property (nonatomic, retain) IBOutlet UIView* overlayView;\n// unsafe_unretained is equivalent to assign - used to prevent retain cycles in the property below\n@property (nonatomic, unsafe_unretained) id orientationDelegate;\n\n- (id)initWithProcessor:(CDVbcsProcessor*)processor alternateOverlay:(NSString *)alternateXib;\n- (void)startCapturing;\n- (UIView*)buildOverlayView;\n- (UIImage*)buildReticleImage;\n- (void)shutterButtonPressed;\n- (IBAction)cancelButtonPressed:(id)sender;\n\n@end\n\n//------------------------------------------------------------------------------\n// plugin class\n//------------------------------------------------------------------------------\n@implementation CDVBarcodeScanner\n\n//--------------------------------------------------------------------------\n- (NSString*)isScanNotPossible {\n    NSString* result = nil;\n\n    Class aClass = NSClassFromString(@\"AVCaptureSession\");\n    if (aClass == nil) {\n        return @\"AVFoundation Framework not available\";\n    }\n\n    return result;\n}\n\n-(BOOL)notHasPermission\n{\n    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];\n    return (authStatus == AVAuthorizationStatusDenied ||\n            authStatus == AVAuthorizationStatusRestricted);\n}\n\n\n\n//--------------------------------------------------------------------------\n- (void)scan:(CDVInvokedUrlCommand*)command {\n    CDVbcsProcessor* processor;\n    NSString*       callback;\n    NSString*       capabilityError;\n\n    callback = command.callbackId;\n\n    NSDictionary* options;\n    if (command.arguments.count == 0) {\n      options = [NSDictionary dictionary];\n    } else {\n      options = command.arguments[0];\n    }\n\n    BOOL preferFrontCamera = [options[@\"preferFrontCamera\"] boolValue];\n    BOOL showFlipCameraButton = [options[@\"showFlipCameraButton\"] boolValue];\n    BOOL showTorchButton = [options[@\"showTorchButton\"] boolValue];\n    BOOL disableAnimations = [options[@\"disableAnimations\"] boolValue];\n    BOOL disableSuccessBeep = [options[@\"disableSuccessBeep\"] boolValue];\n\n    // We allow the user to define an alternate xib file for loading the overlay.\n    NSString *overlayXib = options[@\"overlayXib\"];\n\n    capabilityError = [self isScanNotPossible];\n    if (capabilityError) {\n        [self returnError:capabilityError callback:callback];\n        return;\n    } else if ([self notHasPermission]) {\n        NSString * error = NSLocalizedString(@\"Access to the camera has been prohibited; please enable it in the Settings app to continue.\",nil);\n        [self returnError:error callback:callback];\n        return;\n    }\n\n    processor = [[[CDVbcsProcessor alloc]\n                initWithPlugin:self\n                      callback:callback\n          parentViewController:self.viewController\n            alterateOverlayXib:overlayXib\n            ] autorelease];\n    // queue [processor scanBarcode] to run on the event loop\n\n    if (preferFrontCamera) {\n      processor.isFrontCamera = true;\n    }\n\n    if (showFlipCameraButton) {\n      processor.isShowFlipCameraButton = true;\n    }\n\n    if (showTorchButton) {\n      processor.isShowTorchButton = true;\n    }\n\n    processor.isSuccessBeepEnabled = !disableSuccessBeep;\n\n    processor.isTransitionAnimated = !disableAnimations;\n\n    processor.formats = options[@\"formats\"];\n\n    [processor performSelector:@selector(scanBarcode) withObject:nil afterDelay:0];\n}\n\n//--------------------------------------------------------------------------\n- (void)encode:(CDVInvokedUrlCommand*)command {\n    if([command.arguments count] < 1)\n        [self returnError:@\"Too few arguments!\" callback:command.callbackId];\n\n    CDVqrProcessor* processor;\n    NSString*       callback;\n    callback = command.callbackId;\n\n    processor = [[CDVqrProcessor alloc]\n                 initWithPlugin:self\n                 callback:callback\n                 stringToEncode: command.arguments[0][@\"data\"]\n                 ];\n\n    [processor retain];\n    [processor retain];\n    [processor retain];\n    // queue [processor generateImage] to run on the event loop\n    [processor performSelector:@selector(generateImage) withObject:nil afterDelay:0];\n}\n\n- (void)returnImage:(NSString*)filePath format:(NSString*)format callback:(NSString*)callback{\n    NSMutableDictionary* resultDict = [[[NSMutableDictionary alloc] init] autorelease];\n    resultDict[@\"format\"] = format;\n    resultDict[@\"file\"] = filePath;\n\n    CDVPluginResult* result = [CDVPluginResult\n                               resultWithStatus: CDVCommandStatus_OK\n                               messageAsDictionary:resultDict\n                               ];\n\n    [[self commandDelegate] sendPluginResult:result callbackId:callback];\n}\n\n//--------------------------------------------------------------------------\n- (void)returnSuccess:(NSString*)scannedText format:(NSString*)format cancelled:(BOOL)cancelled flipped:(BOOL)flipped callback:(NSString*)callback{\n    NSNumber* cancelledNumber = @(cancelled ? 1 : 0);\n\n    NSMutableDictionary* resultDict = [[NSMutableDictionary new] autorelease];\n    resultDict[@\"text\"] = scannedText;\n    resultDict[@\"format\"] = format;\n    resultDict[@\"cancelled\"] = cancelledNumber;\n\n    CDVPluginResult* result = [CDVPluginResult\n                               resultWithStatus: CDVCommandStatus_OK\n                               messageAsDictionary: resultDict\n                               ];\n    [self.commandDelegate sendPluginResult:result callbackId:callback];\n}\n\n//--------------------------------------------------------------------------\n- (void)returnError:(NSString*)message callback:(NSString*)callback {\n    CDVPluginResult* result = [CDVPluginResult\n                               resultWithStatus: CDVCommandStatus_ERROR\n                               messageAsString: message\n                               ];\n\n    [self.commandDelegate sendPluginResult:result callbackId:callback];\n}\n\n@end\n\n//------------------------------------------------------------------------------\n// class that does the grunt work\n//------------------------------------------------------------------------------\n@implementation CDVbcsProcessor\n\n@synthesize plugin               = _plugin;\n@synthesize callback             = _callback;\n@synthesize parentViewController = _parentViewController;\n@synthesize viewController       = _viewController;\n@synthesize captureSession       = _captureSession;\n@synthesize previewLayer         = _previewLayer;\n@synthesize alternateXib         = _alternateXib;\n@synthesize is1D                 = _is1D;\n@synthesize is2D                 = _is2D;\n@synthesize capturing            = _capturing;\n@synthesize results              = _results;\n\nSystemSoundID _soundFileObject;\n\n//--------------------------------------------------------------------------\n- (id)initWithPlugin:(CDVBarcodeScanner*)plugin\n            callback:(NSString*)callback\nparentViewController:(UIViewController*)parentViewController\n  alterateOverlayXib:(NSString *)alternateXib {\n    self = [super init];\n    if (!self) return self;\n\n    self.plugin               = plugin;\n    self.callback             = callback;\n    self.parentViewController = parentViewController;\n    self.alternateXib         = alternateXib;\n\n    self.is1D      = YES;\n    self.is2D      = YES;\n    self.capturing = NO;\n    self.results = [[NSMutableArray new] autorelease];\n\n    CFURLRef soundFileURLRef  = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR(\"CDVBarcodeScanner.bundle/beep\"), CFSTR (\"caf\"), NULL);\n    AudioServicesCreateSystemSoundID(soundFileURLRef, &_soundFileObject);\n\n    return self;\n}\n\n//--------------------------------------------------------------------------\n- (void)dealloc {\n    self.plugin = nil;\n    self.callback = nil;\n    self.parentViewController = nil;\n    self.viewController = nil;\n    self.captureSession = nil;\n    self.previewLayer = nil;\n    self.alternateXib = nil;\n    self.results = nil;\n\n    self.capturing = NO;\n\n    AudioServicesRemoveSystemSoundCompletion(_soundFileObject);\n    AudioServicesDisposeSystemSoundID(_soundFileObject);\n\n    [super dealloc];\n}\n\n//--------------------------------------------------------------------------\n- (void)scanBarcode {\n\n//    self.captureSession = nil;\n//    self.previewLayer = nil;\n    NSString* errorMessage = [self setUpCaptureSession];\n    if (errorMessage) {\n        [self barcodeScanFailed:errorMessage];\n        return;\n    }\n\n    self.viewController = [[[CDVbcsViewController alloc] initWithProcessor: self alternateOverlay:self.alternateXib] autorelease];\n    // here we set the orientation delegate to the MainViewController of the app (orientation controlled in the Project Settings)\n    self.viewController.orientationDelegate = self.plugin.viewController;\n\n    // delayed [self openDialog];\n    [self performSelector:@selector(openDialog) withObject:nil afterDelay:1];\n}\n\n//--------------------------------------------------------------------------\n- (void)openDialog {\n    [self.parentViewController\n     presentViewController:self.viewController\n     animated:self.isTransitionAnimated completion:nil\n     ];\n}\n\n//--------------------------------------------------------------------------\n- (void)barcodeScanDone:(void (^)(void))callbackBlock {\n    self.capturing = NO;\n    [self.captureSession stopRunning];\n    [self.parentViewController dismissViewControllerAnimated:self.isTransitionAnimated completion:callbackBlock];\n\n    // viewcontroller holding onto a reference to us, release them so they\n    // will release us\n    self.viewController = nil;\n}\n\n//--------------------------------------------------------------------------\n- (BOOL)checkResult:(NSString *)result {\n    [self.results addObject:result];\n\n    NSInteger treshold = 7;\n\n    if (self.results.count > treshold) {\n        [self.results removeObjectAtIndex:0];\n    }\n\n    if (self.results.count < treshold)\n    {\n        return NO;\n    }\n\n    BOOL allEqual = YES;\n    NSString *compareString = self.results[0];\n\n    for (NSString *aResult in self.results)\n    {\n        if (![compareString isEqualToString:aResult])\n        {\n            allEqual = NO;\n            //NSLog(@\"Did not fit: %@\",self.results);\n            break;\n        }\n    }\n\n    return allEqual;\n}\n\n//--------------------------------------------------------------------------\n- (void)barcodeScanSucceeded:(NSString*)text format:(NSString*)format {\n    dispatch_sync(dispatch_get_main_queue(), ^{\n        [self barcodeScanDone:^{\n            [self.plugin returnSuccess:text format:format cancelled:FALSE flipped:FALSE callback:self.callback];\n        }];\n        if (self.isSuccessBeepEnabled) {\n          AudioServicesPlaySystemSound(_soundFileObject);\n        }\n    });\n}\n\n//--------------------------------------------------------------------------\n- (void)barcodeScanFailed:(NSString*)message {\n    [self barcodeScanDone:^{\n        [self.plugin returnError:message callback:self.callback];\n    }];\n}\n\n//--------------------------------------------------------------------------\n- (void)barcodeScanCancelled {\n    [self barcodeScanDone:^{\n        [self.plugin returnSuccess:@\"\" format:@\"\" cancelled:TRUE flipped:self.isFlipped callback:self.callback];\n    }];\n    if (self.isFlipped) {\n        self.isFlipped = NO;\n    }\n}\n\n- (void)flipCamera {\n    self.isFlipped = YES;\n    self.isFrontCamera = !self.isFrontCamera;\n    [self barcodeScanDone:^{\n        if (self.isFlipped) {\n            self.isFlipped = NO;\n        }\n    [self performSelector:@selector(scanBarcode) withObject:nil afterDelay:0.1];\n    }];\n}\n\n- (void)toggleTorch {\n  AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];\n  [device lockForConfiguration:nil];\n  if (device.flashActive) {\n    [device setTorchMode:AVCaptureTorchModeOff];\n    [device setFlashMode:AVCaptureFlashModeOff];\n  } else {\n    [device setTorchModeOnWithLevel:AVCaptureMaxAvailableTorchLevel error:nil];\n    [device setFlashMode:AVCaptureFlashModeOn];\n  }\n  [device unlockForConfiguration];\n}\n\n//--------------------------------------------------------------------------\n- (NSString*)setUpCaptureSession {\n    NSError* error = nil;\n\n    AVCaptureSession* captureSession = [[[AVCaptureSession alloc] init] autorelease];\n    self.captureSession = captureSession;\n\n       AVCaptureDevice* __block device = nil;\n    if (self.isFrontCamera) {\n\n        NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];\n        [devices enumerateObjectsUsingBlock:^(AVCaptureDevice *obj, NSUInteger idx, BOOL *stop) {\n            if (obj.position == AVCaptureDevicePositionFront) {\n                device = obj;\n            }\n        }];\n    } else {\n        device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];\n        if (!device) return @\"unable to obtain video capture device\";\n\n    }\n\n    // set focus params if available to improve focusing\n    [device lockForConfiguration:&error];\n    if (error == nil) {\n        if([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {\n            [device setFocusMode:AVCaptureFocusModeContinuousAutoFocus];\n        }\n        if([device isAutoFocusRangeRestrictionSupported]) {\n            [device setAutoFocusRangeRestriction:AVCaptureAutoFocusRangeRestrictionNear];\n        }\n    }\n    [device unlockForConfiguration];\n\n    AVCaptureDeviceInput* input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];\n    if (!input) return @\"unable to obtain video capture device input\";\n\n    AVCaptureMetadataOutput* output = [[[AVCaptureMetadataOutput alloc] init] autorelease];\n    if (!output) return @\"unable to obtain video capture output\";\n\n    [output setMetadataObjectsDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)];\n\n    if ([captureSession canSetSessionPreset:AVCaptureSessionPresetHigh]) {\n      captureSession.sessionPreset = AVCaptureSessionPresetHigh;\n    } else if ([captureSession canSetSessionPreset:AVCaptureSessionPresetMedium]) {\n      captureSession.sessionPreset = AVCaptureSessionPresetMedium;\n    } else {\n      return @\"unable to preset high nor medium quality video capture\";\n    }\n\n    if ([captureSession canAddInput:input]) {\n        [captureSession addInput:input];\n    }\n    else {\n        return @\"unable to add video capture device input to session\";\n    }\n\n    if ([captureSession canAddOutput:output]) {\n        [captureSession addOutput:output];\n    }\n    else {\n        return @\"unable to add video capture output to session\";\n    }\n\n    [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode,\n                                     AVMetadataObjectTypeAztecCode,\n                                     AVMetadataObjectTypeDataMatrixCode,\n                                     AVMetadataObjectTypeUPCECode,\n                                     AVMetadataObjectTypeEAN8Code,\n                                     AVMetadataObjectTypeEAN13Code,\n                                     AVMetadataObjectTypeCode128Code,\n                                     AVMetadataObjectTypeCode93Code,\n                                     AVMetadataObjectTypeCode39Code,\n                                     AVMetadataObjectTypeITF14Code,\n                                     AVMetadataObjectTypePDF417Code]];\n\n    // setup capture preview layer\n    self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession];\n    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;\n\n    // run on next event loop pass [captureSession startRunning]\n    [captureSession performSelector:@selector(startRunning) withObject:nil afterDelay:0];\n\n    return nil;\n}\n\n//--------------------------------------------------------------------------\n// this method gets sent the captured frames\n//--------------------------------------------------------------------------\n- (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection*)connection {\n\n    if (!self.capturing) return;\n\n#if USE_SHUTTER\n    if (!self.viewController.shutterPressed) return;\n    self.viewController.shutterPressed = NO;\n\n    UIView* flashView = [[UIView alloc] initWithFrame:self.viewController.view.frame];\n    [flashView setBackgroundColor:[UIColor whiteColor]];\n    [self.viewController.view.window addSubview:flashView];\n\n    [UIView\n     animateWithDuration:.4f\n     animations:^{\n         [flashView setAlpha:0.f];\n     }\n     completion:^(BOOL finished){\n         [flashView removeFromSuperview];\n     }\n     ];\n\n    //         [self dumpImage: [[self getImageFromSample:sampleBuffer] autorelease]];\n#endif\n\n\n    try {\n        // This will bring in multiple entities if there are multiple 2D codes in frame.\n        for (AVMetadataObject *metaData in metadataObjects) {\n            AVMetadataMachineReadableCodeObject* code = (AVMetadataMachineReadableCodeObject*)[self.previewLayer transformedMetadataObjectForMetadataObject:(AVMetadataMachineReadableCodeObject*)metaData];\n\n            if ([self checkResult:code.stringValue]) {\n                [self barcodeScanSucceeded:code.stringValue format:[self formatStringFromMetadata:code]];\n            }\n        }\n    }\n    catch (...) {\n        //            NSLog(@\"decoding: unknown exception\");\n        //            [self barcodeScanFailed:@\"unknown exception decoding barcode\"];\n    }\n\n    //        NSTimeInterval timeElapsed  = [NSDate timeIntervalSinceReferenceDate] - timeStart;\n    //        NSLog(@\"decoding completed in %dms\", (int) (timeElapsed * 1000));\n\n}\n\n//--------------------------------------------------------------------------\n// convert barcode format to string\n//--------------------------------------------------------------------------\n- (NSString*)formatStringFrom:(zxing::BarcodeFormat)format {\n    if (format == zxing::BarcodeFormat_QR_CODE)      return @\"QR_CODE\";\n    if (format == zxing::BarcodeFormat_DATA_MATRIX)  return @\"DATA_MATRIX\";\n    if (format == zxing::BarcodeFormat_UPC_E)        return @\"UPC_E\";\n    if (format == zxing::BarcodeFormat_UPC_A)        return @\"UPC_A\";\n    if (format == zxing::BarcodeFormat_EAN_8)        return @\"EAN_8\";\n    if (format == zxing::BarcodeFormat_EAN_13)       return @\"EAN_13\";\n    if (format == zxing::BarcodeFormat_CODE_128)     return @\"CODE_128\";\n    if (format == zxing::BarcodeFormat_CODE_39)      return @\"CODE_39\";\n    if (format == zxing::BarcodeFormat_ITF)          return @\"ITF\";\n    return @\"???\";\n}\n\n//--------------------------------------------------------------------------\n// convert metadata object information to barcode format string\n//--------------------------------------------------------------------------\n- (NSString*)formatStringFromMetadata:(AVMetadataMachineReadableCodeObject*)format {\n    if (format.type == AVMetadataObjectTypeQRCode)          return @\"QR_CODE\";\n    if (format.type == AVMetadataObjectTypeAztecCode)       return @\"AZTEC\";\n    if (format.type == AVMetadataObjectTypeDataMatrixCode)  return @\"DATA_MATRIX\";\n    if (format.type == AVMetadataObjectTypeUPCECode)        return @\"UPC_E\";\n    // According to Apple documentation, UPC_A is EAN13 with a leading 0.\n    if (format.type == AVMetadataObjectTypeEAN13Code && [format.stringValue characterAtIndex:0] == '0') return @\"UPC_A\";\n    if (format.type == AVMetadataObjectTypeEAN8Code)        return @\"EAN_8\";\n    if (format.type == AVMetadataObjectTypeEAN13Code)       return @\"EAN_13\";\n    if (format.type == AVMetadataObjectTypeCode128Code)     return @\"CODE_128\";\n    if (format.type == AVMetadataObjectTypeCode93Code)      return @\"CODE_93\";\n    if (format.type == AVMetadataObjectTypeCode39Code)      return @\"CODE_39\";\n    if (format.type == AVMetadataObjectTypeITF14Code)          return @\"ITF\";\n    if (format.type == AVMetadataObjectTypePDF417Code)      return @\"PDF_417\";\n    return @\"???\";\n}\n\n//--------------------------------------------------------------------------\n// convert capture's sample buffer (scanned picture) into the thing that\n// zxing needs.\n//--------------------------------------------------------------------------\n- (zxing::Ref<zxing::LuminanceSource>) getLuminanceSourceFromSample:(CMSampleBufferRef)sampleBuffer imageBytes:(uint8_t**)ptr {\n    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);\n    CVPixelBufferLockBaseAddress(imageBuffer, 0);\n\n    size_t   bytesPerRow =            CVPixelBufferGetBytesPerRow(imageBuffer);\n    size_t   width       =            CVPixelBufferGetWidth(imageBuffer);\n    size_t   height      =            CVPixelBufferGetHeight(imageBuffer);\n    uint8_t* baseAddress = (uint8_t*) CVPixelBufferGetBaseAddress(imageBuffer);\n\n    // only going to get 90% of the min(width,height) of the captured image\n    size_t    greyWidth  = 9 * MIN(width, height) / 10;\n    uint8_t*  greyData   = (uint8_t*) malloc(greyWidth * greyWidth);\n\n    // remember this pointer so we can free it later\n    *ptr = greyData;\n\n    if (!greyData) {\n        CVPixelBufferUnlockBaseAddress(imageBuffer,0);\n        throw new zxing::ReaderException(\"out of memory\");\n    }\n\n    size_t offsetX = (width  - greyWidth) / 2;\n    size_t offsetY = (height - greyWidth) / 2;\n\n    // pixel-by-pixel ...\n    for (size_t i=0; i<greyWidth; i++) {\n        for (size_t j=0; j<greyWidth; j++) {\n            // i,j are the coordinates from the sample buffer\n            // ni, nj are the coordinates in the LuminanceSource\n            // in this case, there's a rotation taking place\n            size_t ni = greyWidth-j;\n            size_t nj = i;\n\n            size_t baseOffset = (j+offsetY)*bytesPerRow + (i + offsetX)*4;\n\n            // convert from color to grayscale\n            // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale\n            size_t value = 0.11 * baseAddress[baseOffset] +\n            0.59 * baseAddress[baseOffset + 1] +\n            0.30 * baseAddress[baseOffset + 2];\n\n            greyData[nj*greyWidth + ni] = value;\n        }\n    }\n\n    CVPixelBufferUnlockBaseAddress(imageBuffer,0);\n\n    using namespace zxing;\n\n    Ref<LuminanceSource> luminanceSource (\n                                          new GreyscaleLuminanceSource(greyData, (int)greyWidth, (int)greyWidth, 0, 0, (int)greyWidth, (int)greyWidth)\n                                          );\n\n    return luminanceSource;\n}\n\n//--------------------------------------------------------------------------\n// for debugging\n//--------------------------------------------------------------------------\n- (UIImage*) getImageFromLuminanceSource:(zxing::LuminanceSource*)luminanceSource  {\n    unsigned char* bytes = luminanceSource->getMatrix();\n    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();\n    CGContextRef context = CGBitmapContextCreate(\n                                                 bytes,\n                                                 luminanceSource->getWidth(), luminanceSource->getHeight(), 8, luminanceSource->getWidth(),\n                                                 colorSpace,\n                                                 kCGImageAlphaNone\n                                                 );\n\n    CGImageRef cgImage = CGBitmapContextCreateImage(context);\n    UIImage*   image   = [[UIImage alloc] initWithCGImage:cgImage];\n\n    CGContextRelease(context);\n    CGColorSpaceRelease(colorSpace);\n    CGImageRelease(cgImage);\n    free(bytes);\n\n    return image;\n}\n\n//--------------------------------------------------------------------------\n// for debugging\n//--------------------------------------------------------------------------\n- (UIImage*)getImageFromSample:(CMSampleBufferRef)sampleBuffer {\n    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);\n    CVPixelBufferLockBaseAddress(imageBuffer, 0);\n\n    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);\n    size_t width       = CVPixelBufferGetWidth(imageBuffer);\n    size_t height      = CVPixelBufferGetHeight(imageBuffer);\n\n    uint8_t* baseAddress    = (uint8_t*) CVPixelBufferGetBaseAddress(imageBuffer);\n    int      length         = (int)(height * bytesPerRow);\n    uint8_t* newBaseAddress = (uint8_t*) malloc(length);\n    memcpy(newBaseAddress, baseAddress, length);\n    baseAddress = newBaseAddress;\n\n    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();\n    CGContextRef context = CGBitmapContextCreate(\n                                                 baseAddress,\n                                                 width, height, 8, bytesPerRow,\n                                                 colorSpace,\n                                                 kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst\n                                                 );\n\n    CGImageRef cgImage = CGBitmapContextCreateImage(context);\n    UIImage*   image   = [[UIImage alloc] initWithCGImage:cgImage];\n\n    CVPixelBufferUnlockBaseAddress(imageBuffer,0);\n    CGContextRelease(context);\n    CGColorSpaceRelease(colorSpace);\n    CGImageRelease(cgImage);\n\n    free(baseAddress);\n\n    return image;\n}\n\n//--------------------------------------------------------------------------\n// for debugging\n//--------------------------------------------------------------------------\n- (void)dumpImage:(UIImage*)image {\n    NSLog(@\"writing image to library: %dx%d\", (int)image.size.width, (int)image.size.height);\n    ALAssetsLibrary* assetsLibrary = [[[ALAssetsLibrary alloc] init] autorelease];\n    [assetsLibrary\n     writeImageToSavedPhotosAlbum:image.CGImage\n     orientation:ALAssetOrientationUp\n     completionBlock:^(NSURL* assetURL, NSError* error){\n         if (error) NSLog(@\"   error writing image to library\");\n         else       NSLog(@\"   wrote image to library %@\", assetURL);\n     }\n     ];\n}\n\n@end\n\n//------------------------------------------------------------------------------\n// qr encoder processor\n//------------------------------------------------------------------------------\n@implementation CDVqrProcessor\n@synthesize plugin               = _plugin;\n@synthesize callback             = _callback;\n@synthesize stringToEncode       = _stringToEncode;\n@synthesize size                 = _size;\n\n- (id)initWithPlugin:(CDVBarcodeScanner*)plugin callback:(NSString*)callback stringToEncode:(NSString*)stringToEncode{\n    self = [super init];\n    if (!self) return self;\n\n    self.plugin          = plugin;\n    self.callback        = callback;\n    self.stringToEncode  = stringToEncode;\n    self.size            = 300;\n\n    return self;\n}\n\n//--------------------------------------------------------------------------\n- (void)dealloc {\n    self.plugin = nil;\n    self.callback = nil;\n    self.stringToEncode = nil;\n\n    [super dealloc];\n}\n//--------------------------------------------------------------------------\n- (void)generateImage{\n    /* setup qr filter */\n    CIFilter *filter = [CIFilter filterWithName:@\"CIQRCodeGenerator\"];\n    [filter setDefaults];\n\n    /* set filter's input message\n     * the encoding string has to be convert to a UTF-8 encoded NSData object */\n    [filter setValue:[self.stringToEncode dataUsingEncoding:NSUTF8StringEncoding]\n              forKey:@\"inputMessage\"];\n\n    /* on ios >= 7.0  set low image error correction level */\n    if (floor(NSFoundationVersionNumber) >= NSFoundationVersionNumber_iOS_7_0)\n        [filter setValue:@\"L\" forKey:@\"inputCorrectionLevel\"];\n\n    /* prepare cgImage */\n    CIImage *outputImage = [filter outputImage];\n    CIContext *context = [CIContext contextWithOptions:nil];\n    CGImageRef cgImage = [context createCGImage:outputImage\n                                       fromRect:[outputImage extent]];\n\n    /* returned qr code image */\n    UIImage *qrImage = [UIImage imageWithCGImage:cgImage\n                                           scale:1.\n                                     orientation:UIImageOrientationUp];\n    /* resize generated image */\n    CGFloat width = _size;\n    CGFloat height = _size;\n\n    UIGraphicsBeginImageContext(CGSizeMake(width, height));\n\n    CGContextRef ctx = UIGraphicsGetCurrentContext();\n    CGContextSetInterpolationQuality(ctx, kCGInterpolationNone);\n    [qrImage drawInRect:CGRectMake(0, 0, width, height)];\n    qrImage = UIGraphicsGetImageFromCurrentImageContext();\n\n    /* clean up */\n    UIGraphicsEndImageContext();\n    CGImageRelease(cgImage);\n\n    /* save image to file */\n    NSString* fileName = [[[NSProcessInfo processInfo] globallyUniqueString] stringByAppendingString:@\".jpg\"];\n    NSString* filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];\n    [UIImageJPEGRepresentation(qrImage, 1.0) writeToFile:filePath atomically:YES];\n\n    /* return file path back to cordova */\n    [self.plugin returnImage:filePath format:@\"QR_CODE\" callback: self.callback];\n}\n@end\n\n//------------------------------------------------------------------------------\n// view controller for the ui\n//------------------------------------------------------------------------------\n@implementation CDVbcsViewController\n@synthesize processor      = _processor;\n@synthesize shutterPressed = _shutterPressed;\n@synthesize alternateXib   = _alternateXib;\n@synthesize overlayView    = _overlayView;\n\n//--------------------------------------------------------------------------\n- (id)initWithProcessor:(CDVbcsProcessor*)processor alternateOverlay:(NSString *)alternateXib {\n    self = [super init];\n    if (!self) return self;\n\n    self.processor = processor;\n    self.shutterPressed = NO;\n    self.alternateXib = alternateXib;\n    self.overlayView = nil;\n    return self;\n}\n\n//--------------------------------------------------------------------------\n- (void)dealloc {\n    self.view = nil;\n    self.processor = nil;\n    self.shutterPressed = NO;\n    self.alternateXib = nil;\n    self.overlayView = nil;\n    [super dealloc];\n}\n\n//--------------------------------------------------------------------------\n- (void)loadView {\n    self.view = [[UIView alloc] initWithFrame: self.processor.parentViewController.view.frame];\n\n    // setup capture preview layer\n    AVCaptureVideoPreviewLayer* previewLayer = self.processor.previewLayer;\n    previewLayer.frame = self.view.bounds;\n    previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;\n\n    if ([previewLayer.connection isVideoOrientationSupported]) {\n        [previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];\n    }\n\n    [self.view.layer insertSublayer:previewLayer below:[[self.view.layer sublayers] objectAtIndex:0]];\n\n    [self.view addSubview:[self buildOverlayView]];\n}\n\n//--------------------------------------------------------------------------\n- (void)viewWillAppear:(BOOL)animated {\n\n    // set video orientation to what the camera sees\n    self.processor.previewLayer.connection.videoOrientation = (AVCaptureVideoOrientation) [[UIApplication sharedApplication] statusBarOrientation];\n\n    // this fixes the bug when the statusbar is landscape, and the preview layer\n    // starts up in portrait (not filling the whole view)\n    self.processor.previewLayer.frame = self.view.bounds;\n}\n\n//--------------------------------------------------------------------------\n- (void)viewDidAppear:(BOOL)animated {\n    [self startCapturing];\n\n    [super viewDidAppear:animated];\n}\n\n//--------------------------------------------------------------------------\n- (void)startCapturing {\n    self.processor.capturing = YES;\n}\n\n//--------------------------------------------------------------------------\n- (void)shutterButtonPressed {\n    self.shutterPressed = YES;\n}\n\n//--------------------------------------------------------------------------\n- (IBAction)cancelButtonPressed:(id)sender {\n    [self.processor performSelector:@selector(barcodeScanCancelled) withObject:nil afterDelay:0];\n}\n\n- (void)flipCameraButtonPressed:(id)sender\n{\n    [self.processor performSelector:@selector(flipCamera) withObject:nil afterDelay:0];\n}\n\n- (void)torchButtonPressed:(id)sender\n{\n  [self.processor performSelector:@selector(toggleTorch) withObject:nil afterDelay:0];\n}\n\n//--------------------------------------------------------------------------\n- (UIView *)buildOverlayViewFromXib\n{\n    [[NSBundle mainBundle] loadNibNamed:self.alternateXib owner:self options:NULL];\n\n    if ( self.overlayView == nil )\n    {\n        NSLog(@\"%@\", @\"An error occurred loading the overlay xib.  It appears that the overlayView outlet is not set.\");\n        return nil;\n    }\n\n    return self.overlayView;\n}\n\n//--------------------------------------------------------------------------\n- (UIView*)buildOverlayView {\n\n    if ( nil != self.alternateXib )\n    {\n        return [self buildOverlayViewFromXib];\n    }\n    CGRect bounds = self.view.bounds;\n    bounds = CGRectMake(0, 0, bounds.size.width, bounds.size.height);\n\n    UIView* overlayView = [[UIView alloc] initWithFrame:bounds];\n    overlayView.autoresizesSubviews = YES;\n    overlayView.autoresizingMask    = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;\n    overlayView.opaque              = NO;\n\n    UIToolbar* toolbar = [[UIToolbar alloc] init];\n    toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;\n\n    id cancelButton = [[[UIBarButtonItem alloc]\n                       initWithBarButtonSystemItem:UIBarButtonSystemItemCancel\n                       target:(id)self\n                       action:@selector(cancelButtonPressed:)\n                       ] autorelease];\n\n\n    id flexSpace = [[[UIBarButtonItem alloc]\n                    initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace\n                    target:nil\n                    action:nil\n                    ] autorelease];\n\n    id flipCamera = [[[UIBarButtonItem alloc]\n                       initWithBarButtonSystemItem:UIBarButtonSystemItemCamera\n                       target:(id)self\n                       action:@selector(flipCameraButtonPressed:)\n                       ] autorelease];\n\n    NSMutableArray *items;\n\n#if USE_SHUTTER\n    id shutterButton = [[[UIBarButtonItem alloc]\n                        initWithBarButtonSystemItem:UIBarButtonSystemItemCamera\n                        target:(id)self\n                        action:@selector(shutterButtonPressed)\n                        ] autorelease];\n\n    if (_processor.isShowFlipCameraButton) {\n      items = [NSMutableArray arrayWithObjects:flexSpace, cancelButton, flexSpace, flipCamera, shutterButton, nil];\n    } else {\n      items = [NSMutableArray arrayWithObjects:flexSpace, cancelButton, flexSpace, shutterButton, nil];\n    }\n#else\n    if (_processor.isShowFlipCameraButton) {\n      items = [@[flexSpace, cancelButton, flexSpace, flipCamera] mutableCopy];\n    } else {\n      items = [@[flexSpace, cancelButton, flexSpace] mutableCopy];\n    }\n#endif\n\n    if (_processor.isShowTorchButton && !_processor.isFrontCamera) {\n      AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];\n      if ([device hasTorch] && [device hasFlash]) {\n        NSURL *bundleURL = [[NSBundle mainBundle] URLForResource:@\"CDVBarcodeScanner\" withExtension:@\"bundle\"];\n        NSBundle *bundle = [NSBundle bundleWithURL:bundleURL];\n        NSString *imagePath = [bundle pathForResource:@\"torch\" ofType:@\"png\"];\n        UIImage *image = [UIImage imageWithContentsOfFile:imagePath];\n\n        id torchButton = [[[UIBarButtonItem alloc]\n                           initWithImage:image\n                                   style:UIBarButtonItemStylePlain\n                                  target:(id)self\n                                  action:@selector(torchButtonPressed:)\n                           ] autorelease];\n\n      [items insertObject:torchButton atIndex:0];\n    }\n  }\n\n    toolbar.items = items;\n\n    bounds = overlayView.bounds;\n\n    [toolbar sizeToFit];\n    CGFloat toolbarHeight  = [toolbar frame].size.height;\n    CGFloat rootViewHeight = CGRectGetHeight(bounds);\n    CGFloat rootViewWidth  = CGRectGetWidth(bounds);\n    CGRect  rectArea       = CGRectMake(0, rootViewHeight - toolbarHeight, rootViewWidth, toolbarHeight);\n    [toolbar setFrame:rectArea];\n\n    [overlayView addSubview: toolbar];\n\n    UIImage* reticleImage = [self buildReticleImage];\n    UIView* reticleView = [[[UIImageView alloc] initWithImage:reticleImage] autorelease];\n    CGFloat minAxis = MIN(rootViewHeight, rootViewWidth);\n\n    rectArea = CGRectMake(\n        (CGFloat) (0.5 * (rootViewWidth  - minAxis)),\n        (CGFloat) (0.5 * (rootViewHeight - minAxis)),\n        minAxis,\n        minAxis\n    );\n\n    [reticleView setFrame:rectArea];\n\n    reticleView.opaque           = NO;\n    reticleView.contentMode      = UIViewContentModeScaleAspectFit;\n    reticleView.autoresizingMask = (UIViewAutoresizing) (0\n        | UIViewAutoresizingFlexibleLeftMargin\n        | UIViewAutoresizingFlexibleRightMargin\n        | UIViewAutoresizingFlexibleTopMargin\n        | UIViewAutoresizingFlexibleBottomMargin)\n    ;\n\n    [overlayView addSubview: reticleView];\n\n    return overlayView;\n}\n\n//--------------------------------------------------------------------------\n\n#define RETICLE_SIZE    500.0f\n#define RETICLE_WIDTH    10.0f\n#define RETICLE_OFFSET   60.0f\n#define RETICLE_ALPHA     0.4f\n\n//-------------------------------------------------------------------------\n// builds the green box and red line\n//-------------------------------------------------------------------------\n- (UIImage*)buildReticleImage {\n    UIImage* result;\n    UIGraphicsBeginImageContext(CGSizeMake(RETICLE_SIZE, RETICLE_SIZE));\n    CGContextRef context = UIGraphicsGetCurrentContext();\n\n    if (self.processor.is1D) {\n        UIColor* color = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:RETICLE_ALPHA];\n        CGContextSetStrokeColorWithColor(context, color.CGColor);\n        CGContextSetLineWidth(context, RETICLE_WIDTH);\n        CGContextBeginPath(context);\n        CGFloat lineOffset = (CGFloat) (RETICLE_OFFSET+(0.5*RETICLE_WIDTH));\n        CGContextMoveToPoint(context, lineOffset, RETICLE_SIZE/2);\n        CGContextAddLineToPoint(context, RETICLE_SIZE-lineOffset, (CGFloat) (0.5*RETICLE_SIZE));\n        CGContextStrokePath(context);\n    }\n\n    if (self.processor.is2D) {\n        UIColor* color = [UIColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:RETICLE_ALPHA];\n        CGContextSetStrokeColorWithColor(context, color.CGColor);\n        CGContextSetLineWidth(context, RETICLE_WIDTH);\n        CGContextStrokeRect(context,\n                            CGRectMake(\n                                       RETICLE_OFFSET,\n                                       RETICLE_OFFSET,\n                                       RETICLE_SIZE-2*RETICLE_OFFSET,\n                                       RETICLE_SIZE-2*RETICLE_OFFSET\n                                       )\n                            );\n    }\n\n    result = UIGraphicsGetImageFromCurrentImageContext();\n    UIGraphicsEndImageContext();\n    return result;\n}\n\n#pragma mark CDVBarcodeScannerOrientationDelegate\n\n- (BOOL)shouldAutorotate\n{\n    return YES;\n}\n\n- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation\n{\n    return [[UIApplication sharedApplication] statusBarOrientation];\n}\n\n- (NSUInteger)supportedInterfaceOrientations\n{\n    return UIInterfaceOrientationMaskAll;\n}\n\n- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation\n{\n    if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) {\n        return [self.orientationDelegate shouldAutorotateToInterfaceOrientation:interfaceOrientation];\n    }\n\n    return YES;\n}\n\n- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration\n{\n    [UIView setAnimationsEnabled:NO];\n    AVCaptureVideoPreviewLayer* previewLayer = self.processor.previewLayer;\n    previewLayer.frame = self.view.bounds;\n\n    if (orientation == UIInterfaceOrientationLandscapeLeft) {\n        [previewLayer setOrientation:AVCaptureVideoOrientationLandscapeLeft];\n    } else if (orientation == UIInterfaceOrientationLandscapeRight) {\n        [previewLayer setOrientation:AVCaptureVideoOrientationLandscapeRight];\n    } else if (orientation == UIInterfaceOrientationPortrait) {\n        [previewLayer setOrientation:AVCaptureVideoOrientationPortrait];\n    } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {\n        [previewLayer setOrientation:AVCaptureVideoOrientationPortraitUpsideDown];\n    }\n\n    previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;\n    [UIView setAnimationsEnabled:YES];\n}\n\n@end\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/ios/scannerOverlay.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<archive type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"8.00\">\n\t<data>\n\t\t<int key=\"IBDocument.SystemTarget\">1280</int>\n\t\t<string key=\"IBDocument.SystemVersion\">11C74</string>\n\t\t<string key=\"IBDocument.InterfaceBuilderVersion\">1938</string>\n\t\t<string key=\"IBDocument.AppKitVersion\">1138.23</string>\n\t\t<string key=\"IBDocument.HIToolboxVersion\">567.00</string>\n\t\t<object class=\"NSMutableDictionary\" key=\"IBDocument.PluginVersions\">\n\t\t\t<string key=\"NS.key.0\">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>\n\t\t\t<string key=\"NS.object.0\">933</string>\n\t\t</object>\n\t\t<array key=\"IBDocument.IntegratedClassDependencies\">\n\t\t\t<string>IBUINavigationItem</string>\n\t\t\t<string>IBUIBarButtonItem</string>\n\t\t\t<string>IBUIView</string>\n\t\t\t<string>IBUINavigationBar</string>\n\t\t\t<string>IBProxyObject</string>\n\t\t</array>\n\t\t<array key=\"IBDocument.PluginDependencies\">\n\t\t\t<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>\n\t\t</array>\n\t\t<object class=\"NSMutableDictionary\" key=\"IBDocument.Metadata\">\n\t\t\t<string key=\"NS.key.0\">PluginDependencyRecalculationVersion</string>\n\t\t\t<integer value=\"1\" key=\"NS.object.0\"/>\n\t\t</object>\n\t\t<array class=\"NSMutableArray\" key=\"IBDocument.RootObjects\" id=\"1000\">\n\t\t\t<object class=\"IBProxyObject\" id=\"372490531\">\n\t\t\t\t<string key=\"IBProxiedObjectIdentifier\">IBFilesOwner</string>\n\t\t\t\t<string key=\"targetRuntimeIdentifier\">IBCocoaTouchFramework</string>\n\t\t\t</object>\n\t\t\t<object class=\"IBProxyObject\" id=\"975951072\">\n\t\t\t\t<string key=\"IBProxiedObjectIdentifier\">IBFirstResponder</string>\n\t\t\t\t<string key=\"targetRuntimeIdentifier\">IBCocoaTouchFramework</string>\n\t\t\t</object>\n\t\t\t<object class=\"IBUIView\" id=\"191373211\">\n\t\t\t\t<reference key=\"NSNextResponder\"/>\n\t\t\t\t<int key=\"NSvFlags\">274</int>\n\t\t\t\t<array class=\"NSMutableArray\" key=\"NSSubviews\">\n\t\t\t\t\t<object class=\"IBUINavigationBar\" id=\"1064216609\">\n\t\t\t\t\t\t<reference key=\"NSNextResponder\" ref=\"191373211\"/>\n\t\t\t\t\t\t<int key=\"NSvFlags\">290</int>\n\t\t\t\t\t\t<string key=\"NSFrameSize\">{320, 44}</string>\n\t\t\t\t\t\t<reference key=\"NSSuperview\" ref=\"191373211\"/>\n\t\t\t\t\t\t<reference key=\"NSWindow\"/>\n\t\t\t\t\t\t<reference key=\"NSNextKeyView\"/>\n\t\t\t\t\t\t<string key=\"NSReuseIdentifierKey\">_NS:260</string>\n\t\t\t\t\t\t<string key=\"targetRuntimeIdentifier\">IBCocoaTouchFramework</string>\n\t\t\t\t\t\t<int key=\"IBUIBarStyle\">1</int>\n\t\t\t\t\t\t<array class=\"NSMutableArray\" key=\"IBUIItems\">\n\t\t\t\t\t\t\t<object class=\"IBUINavigationItem\" id=\"240626599\">\n\t\t\t\t\t\t\t\t<reference key=\"IBUINavigationBar\" ref=\"1064216609\"/>\n\t\t\t\t\t\t\t\t<string key=\"IBUITitle\">Barcode Scanner</string>\n\t\t\t\t\t\t\t\t<object class=\"IBUIBarButtonItem\" key=\"IBUILeftBarButtonItem\" id=\"1053701234\">\n\t\t\t\t\t\t\t\t\t<string key=\"IBUITitle\">Cancel</string>\n\t\t\t\t\t\t\t\t\t<string key=\"targetRuntimeIdentifier\">IBCocoaTouchFramework</string>\n\t\t\t\t\t\t\t\t\t<int key=\"IBUIStyle\">1</int>\n\t\t\t\t\t\t\t\t\t<reference key=\"IBUINavigationItem\" ref=\"240626599\"/>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<string key=\"targetRuntimeIdentifier\">IBCocoaTouchFramework</string>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</array>\n\t\t\t\t\t</object>\n\t\t\t\t</array>\n\t\t\t\t<string key=\"NSFrameSize\">{320, 460}</string>\n\t\t\t\t<reference key=\"NSSuperview\"/>\n\t\t\t\t<reference key=\"NSWindow\"/>\n\t\t\t\t<reference key=\"NSNextKeyView\" ref=\"1064216609\"/>\n\t\t\t\t<object class=\"NSColor\" key=\"IBUIBackgroundColor\">\n\t\t\t\t\t<int key=\"NSColorSpace\">3</int>\n\t\t\t\t\t<bytes key=\"NSWhite\">MSAwAA</bytes>\n\t\t\t\t\t<object class=\"NSColorSpace\" key=\"NSCustomColorSpace\">\n\t\t\t\t\t\t<int key=\"NSID\">2</int>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t<string key=\"targetRuntimeIdentifier\">IBCocoaTouchFramework</string>\n\t\t\t</object>\n\t\t</array>\n\t\t<object class=\"IBObjectContainer\" key=\"IBDocument.Objects\">\n\t\t\t<array class=\"NSMutableArray\" key=\"connectionRecords\">\n\t\t\t\t<object class=\"IBConnectionRecord\">\n\t\t\t\t\t<object class=\"IBCocoaTouchOutletConnection\" key=\"connection\">\n\t\t\t\t\t\t<string key=\"label\">overlayView</string>\n\t\t\t\t\t\t<reference key=\"source\" ref=\"372490531\"/>\n\t\t\t\t\t\t<reference key=\"destination\" ref=\"191373211\"/>\n\t\t\t\t\t</object>\n\t\t\t\t\t<int key=\"connectionID\">9</int>\n\t\t\t\t</object>\n\t\t\t</array>\n\t\t\t<object class=\"IBMutableOrderedSet\" key=\"objectRecords\">\n\t\t\t\t<array key=\"orderedObjects\">\n\t\t\t\t\t<object class=\"IBObjectRecord\">\n\t\t\t\t\t\t<int key=\"objectID\">0</int>\n\t\t\t\t\t\t<array key=\"object\" id=\"0\"/>\n\t\t\t\t\t\t<reference key=\"children\" ref=\"1000\"/>\n\t\t\t\t\t\t<nil key=\"parent\"/>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"IBObjectRecord\">\n\t\t\t\t\t\t<int key=\"objectID\">1</int>\n\t\t\t\t\t\t<reference key=\"object\" ref=\"191373211\"/>\n\t\t\t\t\t\t<array class=\"NSMutableArray\" key=\"children\">\n\t\t\t\t\t\t\t<reference ref=\"1064216609\"/>\n\t\t\t\t\t\t</array>\n\t\t\t\t\t\t<reference key=\"parent\" ref=\"0\"/>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"IBObjectRecord\">\n\t\t\t\t\t\t<int key=\"objectID\">-1</int>\n\t\t\t\t\t\t<reference key=\"object\" ref=\"372490531\"/>\n\t\t\t\t\t\t<reference key=\"parent\" ref=\"0\"/>\n\t\t\t\t\t\t<string key=\"objectName\">File's Owner</string>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"IBObjectRecord\">\n\t\t\t\t\t\t<int key=\"objectID\">-2</int>\n\t\t\t\t\t\t<reference key=\"object\" ref=\"975951072\"/>\n\t\t\t\t\t\t<reference key=\"parent\" ref=\"0\"/>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"IBObjectRecord\">\n\t\t\t\t\t\t<int key=\"objectID\">3</int>\n\t\t\t\t\t\t<reference key=\"object\" ref=\"1064216609\"/>\n\t\t\t\t\t\t<array class=\"NSMutableArray\" key=\"children\">\n\t\t\t\t\t\t\t<reference ref=\"240626599\"/>\n\t\t\t\t\t\t</array>\n\t\t\t\t\t\t<reference key=\"parent\" ref=\"191373211\"/>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"IBObjectRecord\">\n\t\t\t\t\t\t<int key=\"objectID\">4</int>\n\t\t\t\t\t\t<reference key=\"object\" ref=\"240626599\"/>\n\t\t\t\t\t\t<array class=\"NSMutableArray\" key=\"children\">\n\t\t\t\t\t\t\t<reference ref=\"1053701234\"/>\n\t\t\t\t\t\t</array>\n\t\t\t\t\t\t<reference key=\"parent\" ref=\"1064216609\"/>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"IBObjectRecord\">\n\t\t\t\t\t\t<int key=\"objectID\">10</int>\n\t\t\t\t\t\t<reference key=\"object\" ref=\"1053701234\"/>\n\t\t\t\t\t\t<reference key=\"parent\" ref=\"240626599\"/>\n\t\t\t\t\t</object>\n\t\t\t\t</array>\n\t\t\t</object>\n\t\t\t<dictionary class=\"NSMutableDictionary\" key=\"flattenedProperties\">\n\t\t\t\t<string key=\"-1.CustomClassName\">PGbcsViewController</string>\n\t\t\t\t<string key=\"-1.IBPluginDependency\">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>\n\t\t\t\t<string key=\"-2.CustomClassName\">UIResponder</string>\n\t\t\t\t<string key=\"-2.IBPluginDependency\">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>\n\t\t\t\t<string key=\"1.IBPluginDependency\">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>\n\t\t\t\t<string key=\"10.IBPluginDependency\">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>\n\t\t\t\t<string key=\"3.IBPluginDependency\">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>\n\t\t\t\t<string key=\"4.IBPluginDependency\">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>\n\t\t\t</dictionary>\n\t\t\t<dictionary class=\"NSMutableDictionary\" key=\"unlocalizedProperties\"/>\n\t\t\t<nil key=\"activeLocalization\"/>\n\t\t\t<dictionary class=\"NSMutableDictionary\" key=\"localizations\"/>\n\t\t\t<nil key=\"sourceID\"/>\n\t\t\t<int key=\"maxID\">11</int>\n\t\t</object>\n\t\t<object class=\"IBClassDescriber\" key=\"IBDocument.Classes\">\n\t\t\t<array class=\"NSMutableArray\" key=\"referencedPartialClassDescriptions\">\n\t\t\t\t<object class=\"IBPartialClassDescription\">\n\t\t\t\t\t<string key=\"className\">PGbcsViewController</string>\n\t\t\t\t\t<string key=\"superclassName\">UIViewController</string>\n\t\t\t\t\t<object class=\"NSMutableDictionary\" key=\"outlets\">\n\t\t\t\t\t\t<string key=\"NS.key.0\">overlayView</string>\n\t\t\t\t\t\t<string key=\"NS.object.0\">UIView</string>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"NSMutableDictionary\" key=\"toOneOutletInfosByName\">\n\t\t\t\t\t\t<string key=\"NS.key.0\">overlayView</string>\n\t\t\t\t\t\t<object class=\"IBToOneOutletInfo\" key=\"NS.object.0\">\n\t\t\t\t\t\t\t<string key=\"name\">overlayView</string>\n\t\t\t\t\t\t\t<string key=\"candidateClassName\">UIView</string>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"IBClassDescriptionSource\" key=\"sourceIdentifier\">\n\t\t\t\t\t\t<string key=\"majorKey\">IBProjectSource</string>\n\t\t\t\t\t\t<string key=\"minorKey\">./Classes/PGbcsViewController.h</string>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</array>\n\t\t</object>\n\t\t<int key=\"IBDocument.localizationMode\">0</int>\n\t\t<string key=\"IBDocument.TargetRuntimeIdentifier\">IBCocoaTouchFramework</string>\n\t\t<bool key=\"IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion\">YES</bool>\n\t\t<int key=\"IBDocument.defaultPropertyAccessControl\">3</int>\n\t\t<string key=\"IBCocoaTouchPluginVersion\">933</string>\n\t</data>\n</archive>\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/ios/zxing-all-in-one.cpp",
    "content": "\n#include \"zxing-all-in-one.h\"\n\n// file: zxing/BarcodeFormat.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Created by Christian Brunschen on 13/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/BarcodeFormat.h>\n\nnamespace zxing {\n\nconst char *barcodeFormatNames[] = {\n    \"None\",\n    \"QR_CODE\",\n    \"DATA_MATRIX\",\n    \"UPC_E\",\n    \"UPC_A\",\n    \"EAN_8\",\n    \"EAN_13\",\n    \"CODE_128\",\n    \"CODE_39\",\n    \"ITF\"\n};\n\n}\n\n// file: zxing/Binarizer.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Binarizer.cpp\n *  zxing\n *\n *  Created by Ralf Kistner on 16/10/2009.\n *  Copyright 2008 ZXing authors All rights reserved.\n *  Modified by Lukasz Warchol on 02/02/2010.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/Binarizer.h>\n\nnamespace zxing {\n\n\tBinarizer::Binarizer(Ref<LuminanceSource> source) : source_(source) {\n  }\n\n\tBinarizer::~Binarizer() {\n\t}\n\n\tRef<LuminanceSource> Binarizer::getLuminanceSource() const {\n\t\treturn source_;\n\t}\n\n}\n\n// file: zxing/BinaryBitmap.cpp\n\n/*\n *  BinaryBitmap.cpp\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/BinaryBitmap.h>\n\nnamespace zxing {\n\n\tBinaryBitmap::BinaryBitmap(Ref<Binarizer> binarizer) : binarizer_(binarizer) {\n\n\t}\n\n\tBinaryBitmap::~BinaryBitmap() {\n\t}\n\n\tRef<BitArray> BinaryBitmap::getBlackRow(int y, Ref<BitArray> row) {\n\t\treturn binarizer_->getBlackRow(y, row);\n\t}\n\n\tRef<BitMatrix> BinaryBitmap::getBlackMatrix() {\n\t\treturn binarizer_->getBlackMatrix();\n\t}\n\n\tint BinaryBitmap::getWidth() const {\n\t\treturn getLuminanceSource()->getWidth();\n\t}\n\n\tint BinaryBitmap::getHeight() const {\n\t\treturn getLuminanceSource()->getHeight();\n\t}\n\n\tRef<LuminanceSource> BinaryBitmap::getLuminanceSource() const {\n\t\treturn binarizer_->getLuminanceSource();\n\t}\n\n\n\tbool BinaryBitmap::isCropSupported() const {\n\t  return getLuminanceSource()->isCropSupported();\n\t}\n\n\tRef<BinaryBitmap> BinaryBitmap::crop(int left, int top, int width, int height) {\n\t  return Ref<BinaryBitmap> (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->crop(left, top, width, height))));\n\t}\n\n\tbool BinaryBitmap::isRotateSupported() const {\n\t  return getLuminanceSource()->isRotateSupported();\n\t}\n\n\tRef<BinaryBitmap> BinaryBitmap::rotateCounterClockwise() {\n\t  return Ref<BinaryBitmap> (new BinaryBitmap(binarizer_->createBinarizer(getLuminanceSource()->rotateCounterClockwise())));\n\t}\n}\n\n// file: zxing/DecodeHints.cpp\n\n/*\n *  DecodeHintType.cpp\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/DecodeHints.h>\n// #include <zxing/common/IllegalArgumentException.h>\nnamespace zxing {\n\nconst DecodeHintType DecodeHints::CHARACTER_SET;\n\nconst DecodeHints DecodeHints::PRODUCT_HINT(\n    BARCODEFORMAT_UPC_E_HINT |\n    BARCODEFORMAT_UPC_A_HINT |\n    BARCODEFORMAT_EAN_8_HINT |\n    BARCODEFORMAT_EAN_13_HINT);\n\nconst DecodeHints DecodeHints::ONED_HINT(\n    BARCODEFORMAT_UPC_E_HINT |\n    BARCODEFORMAT_UPC_A_HINT |\n    BARCODEFORMAT_EAN_8_HINT |\n    BARCODEFORMAT_EAN_13_HINT |\n    BARCODEFORMAT_CODE_128_HINT |\n    BARCODEFORMAT_CODE_39_HINT |\n    BARCODEFORMAT_ITF_HINT);\n\nconst DecodeHints DecodeHints::DEFAULT_HINT(\n    BARCODEFORMAT_UPC_E_HINT |\n    BARCODEFORMAT_UPC_A_HINT |\n    BARCODEFORMAT_EAN_8_HINT |\n    BARCODEFORMAT_EAN_13_HINT |\n    BARCODEFORMAT_CODE_128_HINT |\n    BARCODEFORMAT_CODE_39_HINT |\n    BARCODEFORMAT_ITF_HINT |\n    BARCODEFORMAT_DATA_MATRIX_HINT |\n    BARCODEFORMAT_QR_CODE_HINT);\n\nDecodeHints::DecodeHints() {\n  hints = 0;\n}\n\nDecodeHints::DecodeHints(DecodeHintType init) {\n  hints = init;\n}\n\nvoid DecodeHints::addFormat(BarcodeFormat toadd) {\n  switch (toadd) {\n    case BarcodeFormat_QR_CODE: hints |= BARCODEFORMAT_QR_CODE_HINT; break;\n    case BarcodeFormat_DATA_MATRIX: hints |= BARCODEFORMAT_DATA_MATRIX_HINT; break;\n    case BarcodeFormat_UPC_E: hints |= BARCODEFORMAT_UPC_E_HINT; break;\n    case BarcodeFormat_UPC_A: hints |= BARCODEFORMAT_UPC_A_HINT; break;\n    case BarcodeFormat_EAN_8: hints |= BARCODEFORMAT_EAN_8_HINT; break;\n    case BarcodeFormat_EAN_13: hints |= BARCODEFORMAT_EAN_13_HINT; break;\n    case BarcodeFormat_CODE_128: hints |= BARCODEFORMAT_CODE_128_HINT; break;\n    case BarcodeFormat_CODE_39: hints |= BARCODEFORMAT_CODE_39_HINT; break;\n    case BarcodeFormat_ITF: hints |= BARCODEFORMAT_ITF_HINT; break;\n    default: throw IllegalArgumentException(\"Unrecognizd barcode format\");\n  }\n}\n\nbool DecodeHints::containsFormat(BarcodeFormat tocheck) const {\n  DecodeHintType checkAgainst;\n  switch (tocheck) {\n    case BarcodeFormat_QR_CODE: checkAgainst = BARCODEFORMAT_QR_CODE_HINT; break;\n    case BarcodeFormat_DATA_MATRIX: checkAgainst = BARCODEFORMAT_DATA_MATRIX_HINT; break;\n    case BarcodeFormat_UPC_E: checkAgainst = BARCODEFORMAT_UPC_E_HINT; break;\n    case BarcodeFormat_UPC_A: checkAgainst = BARCODEFORMAT_UPC_A_HINT; break;\n    case BarcodeFormat_EAN_8: checkAgainst = BARCODEFORMAT_EAN_8_HINT; break;\n    case BarcodeFormat_EAN_13: checkAgainst = BARCODEFORMAT_EAN_13_HINT; break;\n    case BarcodeFormat_CODE_128: checkAgainst = BARCODEFORMAT_CODE_128_HINT; break;\n    case BarcodeFormat_CODE_39: checkAgainst = BARCODEFORMAT_CODE_39_HINT; break;\n    case BarcodeFormat_ITF: checkAgainst = BARCODEFORMAT_ITF_HINT; break;\n    default: throw IllegalArgumentException(\"Unrecognizd barcode format\");\n  }\n  return (hints & checkAgainst);\n}\n\nvoid DecodeHints::setTryHarder(bool toset) {\n  if (toset) {\n    hints |= TRYHARDER_HINT;\n  } else {\n    hints &= ~TRYHARDER_HINT;\n  }\n}\n\nbool DecodeHints::getTryHarder() const {\n  return (hints & TRYHARDER_HINT);\n}\n\nvoid DecodeHints::setResultPointCallback(Ref<ResultPointCallback> const& _callback) {\n    callback = _callback;\n}\n\nRef<ResultPointCallback> DecodeHints::getResultPointCallback() const {\n    return callback;\n}\n\n} /* namespace */\n\n// file: zxing/Exception.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Exception.cpp\n *  ZXing\n *\n *  Created by Christian Brunschen on 03/06/2008.\n *  Copyright 2008-2011 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n\n */\n\n// #include <zxing/Exception.h>\n\nnamespace zxing {\n\nException::Exception() {}\n\nException::Exception(const char *msg) :\n    message(msg) {\n}\n\nconst char* Exception::what() const throw() {\n  return message.c_str();\n}\n\nException::~Exception() throw() {\n}\n\n}\n\n// file: zxing/FormatException.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  FormatException.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 13/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/FormatException.h>\n\nnamespace zxing {\n\nFormatException::FormatException() {}\n\nFormatException::FormatException(const char *msg) :\n    ReaderException(msg) {\n}\n\nFormatException::~FormatException() throw() {\n}\n\n}\n\n// file: zxing/LuminanceSource.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  LuminanceSource.cpp\n *  zxing\n *\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <sstream>\n// #include <zxing/LuminanceSource.h>\n// #include <zxing/common/IllegalArgumentException.h>\n\nnamespace zxing {\n\nLuminanceSource::LuminanceSource() {\n}\n\nLuminanceSource::~LuminanceSource() {\n}\n\nbool LuminanceSource::isCropSupported() const {\n  return false;\n}\n\nRef<LuminanceSource> LuminanceSource::crop(int left, int top, int width, int height) {\n  (void)left;\n  (void)top;\n  (void)width;\n  (void)height;\n  throw IllegalArgumentException(\"This luminance source does not support cropping.\");\n}\n\nbool LuminanceSource::isRotateSupported() const {\n  return false;\n}\n\nRef<LuminanceSource> LuminanceSource::rotateCounterClockwise() {\n  throw IllegalArgumentException(\"This luminance source does not support rotation.\");\n}\n\nLuminanceSource::operator std::string() {\n  unsigned char* row = 0;\n  std::ostringstream oss;\n  for (int y = 0; y < getHeight(); y++) {\n    row = getRow(y, row);\n    for (int x = 0; x < getWidth(); x++) {\n      int luminance = row[x] & 0xFF;\n      char c;\n      if (luminance < 0x40) {\n        c = '#';\n      } else if (luminance < 0x80) {\n        c = '+';\n      } else if (luminance < 0xC0) {\n        c = '.';\n      } else {\n        c = ' ';\n      }\n      oss << c;\n    }\n    oss << '\\n';\n  }\n  delete [] row;\n  return oss.str();\n}\n\n\n\n}\n\n// file: zxing/MultiFormatReader.cpp\n\n/*\n *  MultiFormatBarcodeReader.cpp\n *  ZXing\n *\n *  Created by Lukasz Warchol on 10-01-26.\n *  Modified by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/MultiFormatReader.h>\n// #include <zxing/qrcode/QRCodeReader.h>\n// #include <zxing/datamatrix/DataMatrixReader.h>\n// #include <zxing/oned/MultiFormatUPCEANReader.h>\n// #include <zxing/oned/MultiFormatOneDReader.h>\n// #include <zxing/ReaderException.h>\n\nnamespace zxing {\n  MultiFormatReader::MultiFormatReader() {\n\n  }\n\n  Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image) {\n    setHints(DecodeHints::DEFAULT_HINT);\n    return decodeInternal(image);\n  }\n\n  Ref<Result> MultiFormatReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {\n    setHints(hints);\n    return decodeInternal(image);\n  }\n\n  Ref<Result> MultiFormatReader::decodeWithState(Ref<BinaryBitmap> image) {\n    // Make sure to set up the default state so we don't crash\n    if (readers_.size() == 0) {\n      setHints(DecodeHints::DEFAULT_HINT);\n    }\n    return decodeInternal(image);\n  }\n\n  void MultiFormatReader::setHints(DecodeHints hints) {\n    hints_ = hints;\n    readers_.clear();\n    bool tryHarder = hints.getTryHarder();\n\n    bool addOneDReader = hints.containsFormat(BarcodeFormat_UPC_E) ||\n                         hints.containsFormat(BarcodeFormat_UPC_A) ||\n                         hints.containsFormat(BarcodeFormat_EAN_8) ||\n                         hints.containsFormat(BarcodeFormat_EAN_13) ||\n                         hints.containsFormat(BarcodeFormat_CODE_128) ||\n                         hints.containsFormat(BarcodeFormat_CODE_39) ||\n                         hints.containsFormat(BarcodeFormat_ITF);\n    if (addOneDReader && !tryHarder) {\n      readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));\n    }\n    if (hints.containsFormat(BarcodeFormat_QR_CODE)) {\n      readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader()));\n    }\n    if (hints.containsFormat(BarcodeFormat_DATA_MATRIX)) {\n      readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader()));\n    }\n    //TODO: add PDF417 here once PDF417 reader is implemented\n    if (addOneDReader && tryHarder) {\n      readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));\n    }\n    if (readers_.size() == 0) {\n      if (!tryHarder) {\n        readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));\n      }\n      readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader()));\n      if (tryHarder) {\n        readers_.push_back(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(hints)));\n      }\n    }\n  }\n\n  Ref<Result> MultiFormatReader::decodeInternal(Ref<BinaryBitmap> image) {\n    for (unsigned int i = 0; i < readers_.size(); i++) {\n      try {\n        return readers_[i]->decode(image, hints_);\n      } catch (ReaderException const& re) {\n        // continue\n      }\n    }\n    throw ReaderException(\"No code detected\");\n  }\n\n  MultiFormatReader::~MultiFormatReader() {\n\n  }\n}\n\n// file: zxing/NotFoundException.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n * Copyright 20011 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/NotFoundException.h>\n\nnamespace zxing {\n\n  NotFoundException::NotFoundException(const char *msg)\n    : ReaderException(msg) {}\n\n  NotFoundException::~NotFoundException() throw() {\n  }\n\n}\n\n// file: zxing/Reader.cpp\n\n/*\n *  Reader.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 13/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/Reader.h>\n\nnamespace zxing {\n\nReader::~Reader() { }\n\nRef<Result> Reader::decode(Ref<BinaryBitmap> image) {\n  return decode(image, DecodeHints::DEFAULT_HINT);\n}\n\n}\n\n// file: zxing/ReaderException.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  ReaderException.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 13/05/2008.\n *  Copyright 2008-2011 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ReaderException.h>\n\nnamespace zxing {\n\nReaderException::ReaderException() {}\n\nReaderException::ReaderException(const char *msg) :\n    Exception(msg) {\n}\n\nReaderException::~ReaderException() throw() {\n}\n\n}\n\n// file: zxing/Result.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Result.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 13/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/Result.h>\n\nnamespace zxing {\nusing namespace std;\n\nResult::Result(Ref<String> text, ArrayRef<unsigned char> rawBytes, std::vector<Ref<ResultPoint> > resultPoints,\n               BarcodeFormat format) :\n  text_(text), rawBytes_(rawBytes), resultPoints_(resultPoints), format_(format) {\n}\n\nResult::~Result() {\n}\n\nRef<String> Result::getText() {\n  return text_;\n}\n\nArrayRef<unsigned char> Result::getRawBytes() {\n  return rawBytes_;\n}\n\nconst std::vector<Ref<ResultPoint> >& Result::getResultPoints() const {\n  return resultPoints_;\n}\n\nstd::vector<Ref<ResultPoint> >& Result::getResultPoints() {\n  return resultPoints_;\n}\n\nBarcodeFormat Result::getBarcodeFormat() const {\n  return format_;\n}\n\nostream& operator<<(ostream &out, Result& result) {\n  if (result.text_ != 0) {\n    out << result.text_->getText();\n  } else {\n    out << \"[\" << result.rawBytes_->size() << \" bytes]\";\n  }\n  return out;\n}\n\n}\n\n// file: zxing/ResultPoint.cpp\n\n/*\n *  ResultPoint.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 13/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ResultPoint.h>\n// #include <math.h>\n\nnamespace zxing {\n\nResultPoint::ResultPoint() : posX_(0), posY_(0) {}\n\nResultPoint::ResultPoint(float x, float y) : posX_(x), posY_(y) {}\n\nResultPoint::~ResultPoint() {}\n\nfloat ResultPoint::getX() const {\n  return posX_;\n}\n\nfloat ResultPoint::getY() const {\n  return posY_;\n}\n\nbool ResultPoint::equals(Ref<ResultPoint> other) {\n  return posX_ == other->getX() && posY_ == other->getY();\n}\n\n/**\n * <p>Orders an array of three ResultPoints in an order [A,B,C] such that AB < AC and\n * BC < AC and the angle between BC and BA is less than 180 degrees.\n */\nvoid ResultPoint::orderBestPatterns(std::vector<Ref<ResultPoint> > &patterns) {\n    // Find distances between pattern centers\n    float zeroOneDistance = distance(patterns[0]->getX(), patterns[1]->getX(),patterns[0]->getY(), patterns[1]->getY());\n    float oneTwoDistance = distance(patterns[1]->getX(), patterns[2]->getX(),patterns[1]->getY(), patterns[2]->getY());\n    float zeroTwoDistance = distance(patterns[0]->getX(), patterns[2]->getX(),patterns[0]->getY(), patterns[2]->getY());\n\n    Ref<ResultPoint> pointA, pointB, pointC;\n    // Assume one closest to other two is B; A and C will just be guesses at first\n    if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) {\n      pointB = patterns[0];\n      pointA = patterns[1];\n      pointC = patterns[2];\n    } else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) {\n      pointB = patterns[1];\n      pointA = patterns[0];\n      pointC = patterns[2];\n    } else {\n      pointB = patterns[2];\n      pointA = patterns[0];\n      pointC = patterns[1];\n    }\n\n    // Use cross product to figure out whether A and C are correct or flipped.\n    // This asks whether BC x BA has a positive z component, which is the arrangement\n    // we want for A, B, C. If it's negative, then we've got it flipped around and\n    // should swap A and C.\n    if (crossProductZ(pointA, pointB, pointC) < 0.0f) {\n      Ref<ResultPoint> temp = pointA;\n      pointA = pointC;\n      pointC = temp;\n    }\n\n    patterns[0] = pointA;\n    patterns[1] = pointB;\n    patterns[2] = pointC;\n}\n\nfloat ResultPoint::distance(Ref<ResultPoint> point1, Ref<ResultPoint> point2) {\n  return distance(point1->getX(), point1->getY(), point2->getX(), point2->getY());\n}\n\nfloat ResultPoint::distance(float x1, float x2, float y1, float y2) {\n  float xDiff = x1 - x2;\n  float yDiff = y1 - y2;\n  return (float) sqrt((double) (xDiff * xDiff + yDiff * yDiff));\n}\n\nfloat ResultPoint::crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC) {\n  float bX = pointB->getX();\n  float bY = pointB->getY();\n  return ((pointC->getX() - bX) * (pointA->getY() - bY)) - ((pointC->getY() - bY) * (pointA->getX() - bX));\n}\n}\n\n// file: zxing/ResultPointCallback.cpp\n\n/*\n *  ResultPointCallback.cpp\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ResultPointCallback.h>\n\nnamespace zxing {\n\nResultPointCallback::~ResultPointCallback() {}\n\n}\n\n// file: zxing/common/Array.cpp\n\n/*\n *  Array.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 07/05/2008.\n *  Copyright 2008 Google UK. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Array.h>\n\n\n// file: zxing/common/BitArray.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Copyright 2010 ZXing authors. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/BitArray.h>\n\nusing namespace std;\n\nnamespace zxing {\n\n\nsize_t BitArray::wordsForBits(size_t bits) {\n  int arraySize = (bits + bitsPerWord_ - 1) >> logBits_;\n  return arraySize;\n}\n\nBitArray::BitArray(size_t size) :\n    size_(size), bits_(wordsForBits(size), (const unsigned int)0) {\n}\n\nBitArray::~BitArray() {\n}\n\nsize_t BitArray::getSize() {\n  return size_;\n}\n\nvoid BitArray::setBulk(size_t i, unsigned int newBits) {\n  bits_[i >> logBits_] = newBits;\n}\n\nvoid BitArray::setRange(int start, int end) {\n  if (end < start) {\n    throw IllegalArgumentException(\"invalid call to BitArray::setRange\");\n  }\n  if (end == start) {\n    return;\n  }\n  end--; // will be easier to treat this as the last actually set bit -- inclusive\n  int firstInt = start >> 5;\n  int lastInt = end >> 5;\n  for (int i = firstInt; i <= lastInt; i++) {\n    int firstBit = i > firstInt ? 0 : start & 0x1F;\n    int lastBit = i < lastInt ? 31 : end & 0x1F;\n    int mask;\n    if (firstBit == 0 && lastBit == 31) {\n      mask = -1;\n    } else {\n      mask = 0;\n      for (int j = firstBit; j <= lastBit; j++) {\n        mask |= 1 << j;\n      }\n    }\n    bits_[i] |= mask;\n  }\n}\n\nvoid BitArray::clear() {\n  size_t max = bits_.size();\n  for (size_t i = 0; i < max; i++) {\n    bits_[i] = 0;\n  }\n}\n\nbool BitArray::isRange(size_t start, size_t end, bool value) {\n  if (end < start) {\n    throw IllegalArgumentException(\"end must be after start\");\n  }\n  if (end == start) {\n    return true;\n  }\n  // treat the 'end' as inclusive, rather than exclusive\n  end--;\n  size_t firstWord = start >> logBits_;\n  size_t lastWord = end >> logBits_;\n  for (size_t i = firstWord; i <= lastWord; i++) {\n    size_t firstBit = i > firstWord ? 0 : start & bitsMask_;\n    size_t lastBit = i < lastWord ? bitsPerWord_ - 1: end & bitsMask_;\n    unsigned int mask;\n    if (firstBit == 0 && lastBit == bitsPerWord_ - 1) {\n      mask = numeric_limits<unsigned int>::max();\n    } else {\n      mask = 0;\n      for (size_t j = firstBit; j <= lastBit; j++) {\n        mask |= 1 << j;\n      }\n    }\n    if (value) {\n      if ((bits_[i] & mask) != mask) {\n        return false;\n      }\n    } else {\n      if ((bits_[i] & mask) != 0) {\n        return false;\n      }\n    }\n  }\n  return true;\n}\n\nvector<unsigned int>& BitArray::getBitArray() {\n  return bits_;\n}\n\nvoid BitArray::reverse() {\n  std::vector<unsigned int> newBits(bits_.size(),(const unsigned int) 0);\n  for (size_t i = 0; i < size_; i++) {\n    if (get(size_ - i - 1)) {\n      newBits[i >> logBits_] |= 1<< (i & bitsMask_);\n    }\n  }\n  bits_ = newBits;\n}\n}\n\n// file: zxing/common/BitMatrix.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Copyright 2010 ZXing authors. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/common/IllegalArgumentException.h>\n\n// #include <iostream>\n// #include <sstream>\n// #include <string>\n\nusing std::ostream;\nusing std::ostringstream;\n\nusing zxing::BitMatrix;\nusing zxing::BitArray;\nusing zxing::Ref;\n\nnamespace {\n  size_t wordsForSize(size_t width,\n                      size_t height,\n                      unsigned int bitsPerWord,\n                      unsigned int logBits) {\n    size_t bits = width * height;\n    int arraySize = (bits + bitsPerWord - 1) >> logBits;\n    return arraySize;\n  }\n}\n\nBitMatrix::BitMatrix(size_t dimension) :\n  width_(dimension), height_(dimension), words_(0), bits_(NULL) {\n  words_ = wordsForSize(width_, height_, bitsPerWord, logBits);\n  bits_ = new unsigned int[words_];\n  clear();\n}\n\nBitMatrix::BitMatrix(size_t width, size_t height) :\n  width_(width), height_(height), words_(0), bits_(NULL) {\n  words_ = wordsForSize(width_, height_, bitsPerWord, logBits);\n  bits_ = new unsigned int[words_];\n  clear();\n}\n\nBitMatrix::~BitMatrix() {\n  delete[] bits_;\n}\n\n\nvoid BitMatrix::flip(size_t x, size_t y) {\n  size_t offset = x + width_ * y;\n  bits_[offset >> logBits] ^= 1 << (offset & bitsMask);\n}\n\nvoid BitMatrix::clear() {\n  std::fill(bits_, bits_+words_, 0);\n}\n\nvoid BitMatrix::setRegion(size_t left, size_t top, size_t width, size_t height) {\n  if ((long)top < 0 || (long)left < 0) {\n    throw IllegalArgumentException(\"topI and leftJ must be nonnegative\");\n  }\n  if (height < 1 || width < 1) {\n    throw IllegalArgumentException(\"height and width must be at least 1\");\n  }\n  size_t right = left + width;\n  size_t bottom = top + height;\n  if (right > width_ || bottom > height_) {\n    throw IllegalArgumentException(\"top + height and left + width must be <= matrix dimension\");\n  }\n  for (size_t y = top; y < bottom; y++) {\n    int yOffset = width_ * y;\n    for (size_t x = left; x < right; x++) {\n      size_t offset = x + yOffset;\n      bits_[offset >> logBits] |= 1 << (offset & bitsMask);\n    }\n  }\n}\n\nRef<BitArray> BitMatrix::getRow(int y, Ref<BitArray> row) {\n  if (row.empty() || row->getSize() < width_) {\n    row = new BitArray(width_);\n  } else {\n    row->clear();\n  }\n  size_t start = y * width_;\n  size_t end = start + width_ - 1; // end is inclusive\n  size_t firstWord = start >> logBits;\n  size_t lastWord = end >> logBits;\n  size_t bitOffset = start & bitsMask;\n  for (size_t i = firstWord; i <= lastWord; i++) {\n    size_t firstBit = i > firstWord ? 0 : start & bitsMask;\n    size_t lastBit = i < lastWord ? bitsPerWord - 1 : end & bitsMask;\n    unsigned int mask;\n    if (firstBit == 0 && lastBit == logBits) {\n      mask = std::numeric_limits<unsigned int>::max();\n    } else {\n      mask = 0;\n      for (size_t j = firstBit; j <= lastBit; j++) {\n        mask |= 1 << j;\n      }\n    }\n    row->setBulk((i - firstWord) << logBits, (bits_[i] & mask) >> bitOffset);\n    if (firstBit == 0 && bitOffset != 0) {\n      unsigned int prevBulk = row->getBitArray()[i - firstWord - 1];\n      prevBulk |= (bits_[i] & mask) << (bitsPerWord - bitOffset);\n      row->setBulk((i - firstWord - 1) << logBits, prevBulk);\n    }\n  }\n  return row;\n}\n\nsize_t BitMatrix::getWidth() const {\n  return width_;\n}\n\nsize_t BitMatrix::getHeight() const {\n  return height_;\n}\n\nsize_t BitMatrix::getDimension() const {\n  return width_;\n}\n\nunsigned int* BitMatrix::getBits() const {\n  return bits_;\n}\n\nnamespace zxing {\n  ostream& operator<<(ostream &out, const BitMatrix &bm) {\n    for (size_t y = 0; y < bm.height_; y++) {\n      for (size_t x = 0; x < bm.width_; x++) {\n        out << (bm.get(x, y) ? \"X \" : \"  \");\n      }\n      out << \"\\n\";\n    }\n    return out;\n  }\n}\n\nconst char* BitMatrix::description() {\n  ostringstream out;\n  out << *this;\n  return out.str().c_str();\n}\n\n// file: zxing/common/BitSource.cpp\n\n/*\n *  BitSource.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 09/05/2008.\n *  Copyright 2008 Google UK. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/BitSource.h>\n// #include <zxing/common/IllegalArgumentException.h>\n\nnamespace zxing {\n\nint BitSource::readBits(int numBits) {\n  if (numBits < 0 || numBits > 32) {\n    throw IllegalArgumentException(\"cannot read <1 or >32 bits\");\n  } else if (numBits > available()) {\n    throw IllegalArgumentException(\"reading more bits than are available\");\n  }\n\n  int result = 0;\n\n  // First, read remainder from current byte\n  if (bitOffset_ > 0) {\n    int bitsLeft = 8 - bitOffset_;\n    int toRead = numBits < bitsLeft ? numBits : bitsLeft;\n    int bitsToNotRead = bitsLeft - toRead;\n    int mask = (0xFF >> (8 - toRead)) << bitsToNotRead;\n    result = (bytes_[byteOffset_] & mask) >> bitsToNotRead;\n    numBits -= toRead;\n    bitOffset_ += toRead;\n    if (bitOffset_ == 8) {\n      bitOffset_ = 0;\n      byteOffset_++;\n    }\n  }\n\n  // Next read whole bytes\n  if (numBits > 0) {\n    while (numBits >= 8) {\n      result = (result << 8) | (bytes_[byteOffset_] & 0xFF);\n      byteOffset_++;\n      numBits -= 8;\n    }\n\n\n    // Finally read a partial byte\n    if (numBits > 0) {\n      int bitsToNotRead = 8 - numBits;\n      int mask = (0xFF >> bitsToNotRead) << bitsToNotRead;\n      result = (result << numBits) | ((bytes_[byteOffset_] & mask) >> bitsToNotRead);\n      bitOffset_ += numBits;\n    }\n  }\n\n  return result;\n}\n\nint BitSource::available() {\n  return 8 * (bytes_.size() - byteOffset_) - bitOffset_;\n}\n}\n\n// file: zxing/common/CharacterSetECI.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n * Copyright 2008-2011 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/CharacterSetECI.h>\n// #include <sstream>\n// #include <zxing/common/IllegalArgumentException.h>\n\nusing std::string;\n\nusing zxing::common::CharacterSetECI;\nusing zxing::IllegalArgumentException;\n\nstd::map<int, CharacterSetECI*> CharacterSetECI::VALUE_TO_ECI;\nstd::map<std::string, CharacterSetECI*> CharacterSetECI::NAME_TO_ECI;\n\nconst bool CharacterSetECI::inited = CharacterSetECI::init_tables();\n\nbool CharacterSetECI::init_tables() {\n  addCharacterSet(0, \"Cp437\");\n  { char const* s[] = {\"ISO8859_1\", \"ISO-8859-1\", 0};\n    addCharacterSet(1, s); }\n  addCharacterSet(2, \"Cp437\");\n  { char const* s[] = {\"ISO8859_1\", \"ISO-8859-1\", 0};\n    addCharacterSet(3, s); }\n  addCharacterSet(4, \"ISO8859_2\");\n  addCharacterSet(5, \"ISO8859_3\");\n  addCharacterSet(6, \"ISO8859_4\");\n  addCharacterSet(7, \"ISO8859_5\");\n  addCharacterSet(8, \"ISO8859_6\");\n  addCharacterSet(9, \"ISO8859_7\");\n  addCharacterSet(10, \"ISO8859_8\");\n  addCharacterSet(11, \"ISO8859_9\");\n  addCharacterSet(12, \"ISO8859_10\");\n  addCharacterSet(13, \"ISO8859_11\");\n  addCharacterSet(15, \"ISO8859_13\");\n  addCharacterSet(16, \"ISO8859_14\");\n  addCharacterSet(17, \"ISO8859_15\");\n  addCharacterSet(18, \"ISO8859_16\");\n  { char const* s[] = {\"SJIS\", \"Shift_JIS\", 0};\n    addCharacterSet(20, s ); }\n  return true;\n}\n\nCharacterSetECI::CharacterSetECI(int value, char const* encodingName_)\n  : ECI(value), encodingName(encodingName_) {}\n\nchar const* CharacterSetECI::getEncodingName() {\n  return encodingName;\n}\n\nvoid CharacterSetECI::addCharacterSet(int value, char const* encodingName) {\n  CharacterSetECI* eci = new CharacterSetECI(value, encodingName);\n  VALUE_TO_ECI[value] = eci; // can't use valueOf\n  NAME_TO_ECI[string(encodingName)] = eci;\n}\n\nvoid CharacterSetECI::addCharacterSet(int value, char const* const* encodingNames) {\n  CharacterSetECI* eci = new CharacterSetECI(value, encodingNames[0]);\n  VALUE_TO_ECI[value] = eci;\n  for (int i = 0; encodingNames[i]; i++) {\n    NAME_TO_ECI[string(encodingNames[i])] = eci;\n  }\n}\n\nCharacterSetECI* CharacterSetECI::getCharacterSetECIByValue(int value) {\n  if (value < 0 || value >= 900) {\n    std::ostringstream oss;\n    oss << \"Bad ECI value: \" << value;\n    throw IllegalArgumentException(oss.str().c_str());\n  }\n  return VALUE_TO_ECI[value];\n}\n\nCharacterSetECI* CharacterSetECI::getCharacterSetECIByName(string const& name) {\n  return NAME_TO_ECI[name];\n}\n\n// file: zxing/common/Counted.cpp\n\n/*\n *  Counted.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 07/05/2008.\n *  Copyright 2008 Google UK. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n\nnamespace zxing {\n\nusing namespace std;\n\ntemplate<class T>\nostream& operator<<(ostream &out, Ref<T>& ref) {\n  out << \"Ref(\" << (ref.object_ ? (*ref.object_) : \"NULL\") << \")\";\n  return out;\n}\n}\n\n// file: zxing/common/DecoderResult.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  DecoderResult.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 20/05/2008.\n *  Copyright 2008-2011 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/DecoderResult.h>\n\nusing namespace std;\nusing namespace zxing;\n\nDecoderResult::DecoderResult(ArrayRef<unsigned char> rawBytes,\n                             Ref<String> text,\n                             ArrayRef< ArrayRef<unsigned char> >& byteSegments,\n                             string const& ecLevel) :\n  rawBytes_(rawBytes),\n  text_(text),\n  byteSegments_(byteSegments),\n  ecLevel_(ecLevel) {}\n\nDecoderResult::DecoderResult(ArrayRef<unsigned char> rawBytes,\n                             Ref<String> text)\n  : rawBytes_(rawBytes), text_(text) {}\n\nArrayRef<unsigned char> DecoderResult::getRawBytes() {\n  return rawBytes_;\n}\n\nRef<String> DecoderResult::getText() {\n  return text_;\n}\n\n// file: zxing/common/DetectorResult.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  DetectorResult.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 14/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/DetectorResult.h>\n\nnamespace zxing {\n\nDetectorResult::DetectorResult(Ref<BitMatrix> bits, std::vector<Ref<ResultPoint> > points, Ref<PerspectiveTransform> transform) :\n  bits_(bits), points_(points), transform_(transform) {\n}\n\nRef<BitMatrix> DetectorResult::getBits() {\n  return bits_;\n}\n\nstd::vector<Ref<ResultPoint> > DetectorResult::getPoints() {\n  return points_;\n}\n\nRef<PerspectiveTransform> DetectorResult::getTransform() {\n  return transform_;\n}\n\n}\n\n// file: zxing/common/ECI.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n * Copyright 2008-2011 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/ECI.h>\n// #include <sstream>\n// #include <zxing/common/CharacterSetECI.h>\n// #include <zxing/common/IllegalArgumentException.h>\n\nusing zxing::common::ECI;\nusing zxing::IllegalArgumentException;\n\nECI::ECI(int value_) : value(value_) {}\n\nint ECI::getValue() const {\n  return value;\n}\n\nECI* ECI::getECIByValue(int value) {\n  if (value < 0 || value > 999999) {\n    std::ostringstream oss;\n    oss << \"Bad ECI value: \" << value;\n    throw IllegalArgumentException(oss.str().c_str());\n  }\n  if (value < 900) { // Character set ECIs use 000000 - 000899\n    return CharacterSetECI::getCharacterSetECIByValue(value);\n  }\n  return 0;\n}\n\n// file: zxing/common/EdgeDetector.cpp\n\n/*\n *  EdgeDetector.cpp\n *  zxing\n *\n *  Created by Ralf Kistner on 7/12/2009.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/EdgeDetector.h>\n// #include <algorithm>\n// #include <cmath>\n\nusing namespace std;\n\nnamespace zxing {\nnamespace EdgeDetector {\n\nvoid findEdgePoints(std::vector<Point>& points, const BitMatrix& image, Point start, Point end, bool invert, int skip, float deviation) {\n  float xdist = end.x - start.x;\n  float ydist = end.y - start.y;\n  float length = sqrt(xdist * xdist + ydist * ydist);\n\n\n  int var;\n\n  if (abs(xdist) > abs(ydist)) {\n    // Horizontal\n    if (xdist < 0)\n      skip = -skip;\n\n    var = int(abs(deviation * length / xdist));\n\n    float dy = ydist / xdist * skip;\n    bool left = (skip < 0) ^ invert;\n    int x = int(start.x);\n\n    int steps = int(xdist / skip);\n    for (int i = 0; i < steps; i++) {\n      x += skip;\n      if (x < 0 || x >= (int)image.getWidth())\n        continue; // In case we start off the edge\n      int my = int(start.y + dy * i);\n      int ey = min(my + var + 1, (int)image.getHeight() - 1);\n      int sy = max(my - var, 0);\n      for (int y = sy + 1; y < ey; y++) {\n        if (left) {\n          if (image.get(x, y) && !image.get(x, y + 1)) {\n            points.push_back(Point(x, y + 0.5f));\n          }\n        } else {\n          if (!image.get(x, y) && image.get(x, y + 1)) {\n            points.push_back(Point(x, y + 0.5f));\n          }\n        }\n      }\n    }\n  } else {\n    // Vertical\n    if (ydist < 0)\n      skip = -skip;\n\n    var = int(abs(deviation * length / ydist));\n\n    float dx = xdist / ydist * skip;\n    bool down = (skip > 0) ^ invert;\n    int y = int(start.y);\n\n    int steps = int(ydist / skip);\n    for (int i = 0; i < steps; i++) {\n      y += skip;\n      if (y < 0 || y >= (int)image.getHeight())\n        continue; // In case we start off the edge\n      int mx = int(start.x + dx * i);\n      int ex = min(mx + var + 1, (int)image.getWidth() - 1);\n      int sx = max(mx - var, 0);\n      for (int x = sx + 1; x < ex; x++) {\n        if (down) {\n          if (image.get(x, y) && !image.get(x + 1, y)) {\n            points.push_back(Point(x + 0.5f, y));\n          }\n\n        } else {\n          if (!image.get(x, y) && image.get(x + 1, y)) {\n            points.push_back(Point(x + 0.5f, y));\n          }\n        }\n\n      }\n    }\n\n  }\n}\n\nLine findLine(const BitMatrix& image, Line estimate, bool invert, int deviation, float threshold, int skip) {\n  float t = threshold * threshold;\n\n  Point start = estimate.start;\n  Point end = estimate.end;\n\n  vector<Point> edges;\n  edges.clear();\n  findEdgePoints(edges, image, start, end, invert, skip, deviation);\n\n  int n = edges.size();\n\n  float xdist = end.x - start.x;\n  float ydist = end.y - start.y;\n\n  bool horizontal = abs(xdist) > abs(ydist);\n\n  float max = 0;\n  Line bestLine(start, end);  // prepopulate with the given line, in case we can't find any line for some reason\n\n  for (int i = -deviation; i < deviation; i++) {\n    float x1, y1;\n    if (horizontal) {\n      y1 = start.y + i;\n      x1 = start.x - i * ydist / xdist;\n    } else {\n      y1 = start.y - i * xdist / ydist;\n      x1 = start.x + i;\n    }\n\n    for (int j = -deviation; j < deviation; j++) {\n      float x2, y2;\n      if (horizontal) {\n        y2 = end.y + j;\n        x2 = end.x - j * ydist / xdist;\n      } else {\n        y2 = end.y - j * xdist / ydist;\n        x2 = end.x + j;\n      }\n\n      float dx = x1 - x2;\n      float dy = y1 - y2;\n      float length = sqrt(dx * dx + dy * dy);\n\n      float score = 0;\n\n      for(int k = 0; k < n; k++) {\n        const Point& edge = edges[k];\n        float dist = ((x1 - edge.x) * dy - (y1 - edge.y) * dx) / length;\n        // Similar to least squares method\n        float s = t - dist * dist;\n        if (s > 0)\n          score += s;\n      }\n\n      if (score > max) {\n        max = score;\n        bestLine.start = Point(x1, y1);\n        bestLine.end = Point(x2, y2);\n      }\n    }\n  }\n\n  return bestLine;\n}\n\nPoint intersection(Line a, Line b) {\n  float dxa = a.start.x - a.end.x;\n  float dxb = b.start.x - b.end.x;\n  float dya = a.start.y - a.end.y;\n  float dyb = b.start.y - b.end.y;\n\n  float p = a.start.x * a.end.y - a.start.y * a.end.x;\n  float q = b.start.x * b.end.y - b.start.y * b.end.x;\n  float denom = dxa * dyb - dya * dxb;\n  if(denom == 0)  // Lines don't intersect\n    return Point(INFINITY, INFINITY);\n\n  float x = (p * dxb - dxa * q) / denom;\n  float y = (p * dyb - dya * q) / denom;\n\n  return Point(x, y);\n}\n\n} // namespace EdgeDetector\n} // namespace zxing\n\n// file: zxing/common/GlobalHistogramBinarizer.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  GlobalHistogramBinarizer.cpp\n *  zxing\n *\n *  Copyright 2010 ZXing authors. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/GlobalHistogramBinarizer.h>\n// #include <zxing/common/IllegalArgumentException.h>\n// #include <zxing/common/Array.h>\n\nnamespace zxing {\nusing namespace std;\n\nconst int LUMINANCE_BITS_25 = 5;\nconst int LUMINANCE_SHIFT_25 = 8 - LUMINANCE_BITS_25;\nconst int LUMINANCE_BUCKETS_25 = 1 << LUMINANCE_BITS_25;\n\nGlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref<LuminanceSource> source) :\n  Binarizer(source), cached_matrix_(NULL), cached_row_(NULL), cached_row_num_(-1) {\n\n}\n\nGlobalHistogramBinarizer::~GlobalHistogramBinarizer() {\n}\n\n\nRef<BitArray> GlobalHistogramBinarizer::getBlackRow(int y, Ref<BitArray> row) {\n  if (y == cached_row_num_) {\n    if (cached_row_ != NULL) {\n      return cached_row_;\n    } else {\n      throw IllegalArgumentException(\"Too little dynamic range in luminance\");\n    }\n  }\n\n  vector<int> histogram(LUMINANCE_BUCKETS_25, 0);\n  LuminanceSource& source = *getLuminanceSource();\n  int width = source.getWidth();\n  if (row == NULL || static_cast<int>(row->getSize()) < width) {\n    row = new BitArray(width);\n  } else {\n    row->clear();\n  }\n\n  //TODO(flyashi): cache this instead of allocating and deleting per row\n  unsigned char* row_pixels = NULL;\n  try {\n    row_pixels = new unsigned char[width];\n    row_pixels = source.getRow(y, row_pixels);\n    for (int x = 0; x < width; x++) {\n      histogram[row_pixels[x] >> LUMINANCE_SHIFT_25]++;\n    }\n    int blackPoint = estimate(histogram);\n\n    BitArray& array = *row;\n    int left = row_pixels[0];\n    int center = row_pixels[1];\n    for (int x = 1; x < width - 1; x++) {\n      int right = row_pixels[x + 1];\n      // A simple -1 4 -1 box filter with a weight of 2.\n      int luminance = ((center << 2) - left - right) >> 1;\n      if (luminance < blackPoint) {\n        array.set(x);\n      }\n      left = center;\n      center = right;\n    }\n\n    cached_row_ = row;\n    cached_row_num_ = y;\n    delete [] row_pixels;\n    return row;\n  } catch (IllegalArgumentException const& iae) {\n    // Cache the fact that this row failed.\n    cached_row_ = NULL;\n    cached_row_num_ = y;\n    delete [] row_pixels;\n    throw iae;\n  }\n}\n\nRef<BitMatrix> GlobalHistogramBinarizer::getBlackMatrix() {\n  if (cached_matrix_ != NULL) {\n    return cached_matrix_;\n  }\n\n  // Faster than working with the reference\n  LuminanceSource& source = *getLuminanceSource();\n  int width = source.getWidth();\n  int height = source.getHeight();\n  vector<int> histogram(LUMINANCE_BUCKETS_25, 0);\n\n  // Quickly calculates the histogram by sampling four rows from the image.\n  // This proved to be more robust on the blackbox tests than sampling a\n  // diagonal as we used to do.\n  ArrayRef<unsigned char> ref (width);\n  unsigned char* row = &ref[0];\n  for (int y = 1; y < 5; y++) {\n    int rownum = height * y / 5;\n    int right = (width << 2) / 5;\n    row = source.getRow(rownum, row);\n    for (int x = width / 5; x < right; x++) {\n      histogram[row[x] >> LUMINANCE_SHIFT_25]++;\n    }\n  }\n\n  int blackPoint = estimate(histogram);\n\n  Ref<BitMatrix> matrix_ref(new BitMatrix(width, height));\n  BitMatrix& matrix = *matrix_ref;\n  for (int y = 0; y < height; y++) {\n    row = source.getRow(y, row);\n    for (int x = 0; x < width; x++) {\n      if (row[x] < blackPoint)\n        matrix.set(x, y);\n    }\n  }\n\n  cached_matrix_ = matrix_ref;\n  // delete [] row;\n  return matrix_ref;\n}\n\nint GlobalHistogramBinarizer::estimate(vector<int> &histogram) {\n  int numBuckets = histogram.size();\n  int maxBucketCount = 0;\n\n  // Find tallest peak in histogram\n  int firstPeak = 0;\n  int firstPeakSize = 0;\n  for (int i = 0; i < numBuckets; i++) {\n    if (histogram[i] > firstPeakSize) {\n      firstPeak = i;\n      firstPeakSize = histogram[i];\n    }\n    if (histogram[i] > maxBucketCount) {\n      maxBucketCount = histogram[i];\n    }\n  }\n\n  // Find second-tallest peak -- well, another peak that is tall and not\n  // so close to the first one\n  int secondPeak = 0;\n  int secondPeakScore = 0;\n  for (int i = 0; i < numBuckets; i++) {\n    int distanceToBiggest = i - firstPeak;\n    // Encourage more distant second peaks by multiplying by square of distance\n    int score = histogram[i] * distanceToBiggest * distanceToBiggest;\n    if (score > secondPeakScore) {\n      secondPeak = i;\n      secondPeakScore = score;\n    }\n  }\n\n  // Put firstPeak first\n  if (firstPeak > secondPeak) {\n    int temp = firstPeak;\n    firstPeak = secondPeak;\n    secondPeak = temp;\n  }\n\n  // Kind of arbitrary; if the two peaks are very close, then we figure there is\n  // so little dynamic range in the image, that discriminating black and white\n  // is too error-prone.\n  // Decoding the image/line is either pointless, or may in some cases lead to\n  // a false positive for 1D formats, which are relatively lenient.\n  // We arbitrarily say \"close\" is\n  // \"<= 1/16 of the total histogram buckets apart\"\n  if (secondPeak - firstPeak <= numBuckets >> 4) {\n    throw IllegalArgumentException(\"Too little dynamic range in luminance\");\n  }\n\n  // Find a valley between them that is low and closer to the white peak\n  int bestValley = secondPeak - 1;\n  int bestValleyScore = -1;\n  for (int i = secondPeak - 1; i > firstPeak; i--) {\n    int fromFirst = i - firstPeak;\n    // Favor a \"valley\" that is not too close to either peak -- especially not\n    // the black peak -- and that has a low value of course\n    int score = fromFirst * fromFirst * (secondPeak - i) *\n      (maxBucketCount - histogram[i]);\n    if (score > bestValleyScore) {\n      bestValley = i;\n      bestValleyScore = score;\n    }\n  }\n\n  return bestValley << LUMINANCE_SHIFT_25;\n}\n\nRef<Binarizer> GlobalHistogramBinarizer::createBinarizer(Ref<LuminanceSource> source) {\n  return Ref<Binarizer> (new GlobalHistogramBinarizer(source));\n}\n\n} // namespace zxing\n\n// file: zxing/common/GreyscaleLuminanceSource.cpp\n\n/*\n *  GreyscaleLuminanceSource.cpp\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/GreyscaleLuminanceSource.h>\n// #include <zxing/common/GreyscaleRotatedLuminanceSource.h>\n// #include <zxing/common/IllegalArgumentException.h>\n\nnamespace zxing {\n\nGreyscaleLuminanceSource::GreyscaleLuminanceSource(unsigned char* greyData, int dataWidth,\n    int dataHeight, int left, int top, int width, int height) : greyData_(greyData),\n    dataWidth_(dataWidth), dataHeight_(dataHeight), left_(left), top_(top), width_(width),\n    height_(height) {\n\n  if (left + width > dataWidth || top + height > dataHeight || top < 0 || left < 0) {\n    throw IllegalArgumentException(\"Crop rectangle does not fit within image data.\");\n  }\n}\n\nunsigned char* GreyscaleLuminanceSource::getRow(int y, unsigned char* row) {\n  if (y < 0 || y >= this->getHeight()) {\n    throw IllegalArgumentException(\"Requested row is outside the image.\");\n  }\n  int width = getWidth();\n  // TODO(flyashi): determine if row has enough size.\n  if (row == NULL) {\n    row = new unsigned char[width_];\n  }\n  int offset = (y + top_) * dataWidth_ + left_;\n  memcpy(row, &greyData_[offset], width);\n  return row;\n}\n\nunsigned char* GreyscaleLuminanceSource::getMatrix() {\n  int size = width_ * height_;\n  unsigned char* result = new unsigned char[size];\n  if (left_ == 0 && top_ == 0 && dataWidth_ == width_ && dataHeight_ == height_) {\n    memcpy(result, greyData_, size);\n  } else {\n    for (int row = 0; row < height_; row++) {\n      memcpy(result + row * width_, greyData_ + (top_ + row) * dataWidth_ + left_, width_);\n    }\n  }\n  return result;\n}\n\nRef<LuminanceSource> GreyscaleLuminanceSource::rotateCounterClockwise() {\n  // Intentionally flip the left, top, width, and height arguments as needed. dataWidth and\n  // dataHeight are always kept unrotated.\n  return Ref<LuminanceSource> (new GreyscaleRotatedLuminanceSource(greyData_, dataWidth_,\n      dataHeight_, top_, left_, height_, width_));\n}\n\n} /* namespace */\n\n// file: zxing/common/GreyscaleRotatedLuminanceSource.cpp\n\n/*\n *  GreyscaleRotatedLuminanceSource.cpp\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n// #include <zxing/common/GreyscaleRotatedLuminanceSource.h>\n// #include <zxing/common/IllegalArgumentException.h>\n\nnamespace zxing {\n\n// Note that dataWidth and dataHeight are not reversed, as we need to be able to traverse the\n// greyData correctly, which does not get rotated.\nGreyscaleRotatedLuminanceSource::GreyscaleRotatedLuminanceSource(unsigned char* greyData,\n    int dataWidth, int dataHeight, int left, int top, int width, int height) : greyData_(greyData),\n    dataWidth_(dataWidth), dataHeight_(dataHeight), left_(left), top_(top), width_(width),\n    height_(height) {\n\n  // Intentionally comparing to the opposite dimension since we're rotated.\n  if (left + width > dataHeight || top + height > dataWidth) {\n    throw IllegalArgumentException(\"Crop rectangle does not fit within image data.\");\n  }\n}\n\n// The API asks for rows, but we're rotated, so we return columns.\nunsigned char* GreyscaleRotatedLuminanceSource::getRow(int y, unsigned char* row) {\n  if (y < 0 || y >= getHeight()) {\n    throw IllegalArgumentException(\"Requested row is outside the image\");\n  }\n  int width = getWidth();\n  if (row == NULL) {\n    row = new unsigned char[width];\n  }\n  int offset = (left_ * dataWidth_) + (dataWidth_ - (y + top_));\n  for (int x = 0; x < width; x++) {\n    row[x] = greyData_[offset];\n    offset += dataWidth_;\n  }\n  return row;\n}\n\nunsigned char* GreyscaleRotatedLuminanceSource::getMatrix() {\n  unsigned char* result = new unsigned char[width_ * height_];\n  // This depends on getRow() honoring its second parameter.\n  for (int y = 0; y < height_; y++) {\n    getRow(y, &result[y * width_]);\n  }\n  return result;\n}\n\n} // namespace\n\n// file: zxing/common/GridSampler.cpp\n\n/*\n *  GridSampler.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 18/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/GridSampler.h>\n// #include <zxing/common/PerspectiveTransform.h>\n// #include <zxing/ReaderException.h>\n// #include <iostream>\n// #include <sstream>\n\nnamespace zxing {\nusing namespace std;\n\nGridSampler GridSampler::gridSampler;\n\nGridSampler::GridSampler() {\n}\n\nRef<BitMatrix> GridSampler::sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform) {\n  Ref<BitMatrix> bits(new BitMatrix(dimension));\n  vector<float> points(dimension << 1, (const float)0.0f);\n  for (int y = 0; y < dimension; y++) {\n    int max = points.size();\n    float yValue = (float)y + 0.5f;\n    for (int x = 0; x < max; x += 2) {\n      points[x] = (float)(x >> 1) + 0.5f;\n      points[x + 1] = yValue;\n    }\n    transform->transformPoints(points);\n    checkAndNudgePoints(image, points);\n    for (int x = 0; x < max; x += 2) {\n      if (image->get((int)points[x], (int)points[x + 1])) {\n        bits->set(x >> 1, y);\n      }\n    }\n  }\n  return bits;\n}\n\nRef<BitMatrix> GridSampler::sampleGrid(Ref<BitMatrix> image, int dimensionX, int dimensionY, Ref<PerspectiveTransform> transform) {\n  Ref<BitMatrix> bits(new BitMatrix(dimensionX, dimensionY));\n  vector<float> points(dimensionX << 1, (const float)0.0f);\n  for (int y = 0; y < dimensionY; y++) {\n    int max = points.size();\n    float yValue = (float)y + 0.5f;\n    for (int x = 0; x < max; x += 2) {\n      points[x] = (float)(x >> 1) + 0.5f;\n      points[x + 1] = yValue;\n    }\n    transform->transformPoints(points);\n    checkAndNudgePoints(image, points);\n    for (int x = 0; x < max; x += 2) {\n      if (image->get((int)points[x], (int)points[x + 1])) {\n        bits->set(x >> 1, y);\n      }\n    }\n  }\n  return bits;\n}\n\nRef<BitMatrix> GridSampler::sampleGrid(Ref<BitMatrix> image, int dimension, float p1ToX, float p1ToY, float p2ToX,\n                                       float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX,\n                                       float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY) {\n  Ref<PerspectiveTransform> transform(PerspectiveTransform::quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY,\n                                      p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY));\n\n  return sampleGrid(image, dimension, transform);\n\n}\n\nvoid GridSampler::checkAndNudgePoints(Ref<BitMatrix> image, vector<float> &points) {\n  int width = image->getWidth();\n  int height = image->getHeight();\n\n\n  // The Java code assumes that if the start and end points are in bounds, the rest will also be.\n  // However, in some unusual cases points in the middle may also be out of bounds.\n  // Since we can't rely on an ArrayIndexOutOfBoundsException like Java, we check every point.\n\n  for (size_t offset = 0; offset < points.size(); offset += 2) {\n    int x = (int)points[offset];\n    int y = (int)points[offset + 1];\n    if (x < -1 || x > width || y < -1 || y > height) {\n      ostringstream s;\n      s << \"Transformed point out of bounds at \" << x << \",\" << y;\n      throw ReaderException(s.str().c_str());\n    }\n\n    if (x == -1) {\n      points[offset] = 0.0f;\n    } else if (x == width) {\n      points[offset] = width - 1;\n    }\n    if (y == -1) {\n      points[offset + 1] = 0.0f;\n    } else if (y == height) {\n      points[offset + 1] = height - 1;\n    }\n  }\n\n}\n\nGridSampler &GridSampler::getInstance() {\n  return gridSampler;\n}\n}\n\n// file: zxing/common/HybridBinarizer.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  HybridBinarizer.cpp\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/HybridBinarizer.h>\n\n// #include <zxing/common/IllegalArgumentException.h>\n\nusing namespace std;\nusing namespace zxing;\n\nnamespace {\n  const int BLOCK_SIZE_POWER = 3;\n  const int BLOCK_SIZE = 1 << BLOCK_SIZE_POWER;\n  const int BLOCK_SIZE_MASK = BLOCK_SIZE - 1;\n  const int MINIMUM_DIMENSION = BLOCK_SIZE * 5;\n}\n\nHybridBinarizer::HybridBinarizer(Ref<LuminanceSource> source) :\n  GlobalHistogramBinarizer(source), matrix_(NULL), cached_row_(NULL), cached_row_num_(-1) {\n}\n\nHybridBinarizer::~HybridBinarizer() {\n}\n\n\nRef<Binarizer>\nHybridBinarizer::createBinarizer(Ref<LuminanceSource> source) {\n  return Ref<Binarizer> (new HybridBinarizer(source));\n}\n\nRef<BitMatrix> HybridBinarizer::getBlackMatrix() {\n  // Calculates the final BitMatrix once for all requests. This could\n  // be called once from the constructor instead, but there are some\n  // advantages to doing it lazily, such as making profiling easier,\n  // and not doing heavy lifting when callers don't expect it.\n  if (matrix_) {\n    return matrix_;\n  }\n  LuminanceSource& source = *getLuminanceSource();\n  if (source.getWidth() >= MINIMUM_DIMENSION &&\n      source.getHeight() >= MINIMUM_DIMENSION) {\n    unsigned char* luminances = source.getMatrix();\n    int width = source.getWidth();\n    int height = source.getHeight();\n    int subWidth = width >> BLOCK_SIZE_POWER;\n    if ((width & BLOCK_SIZE_MASK) != 0) {\n      subWidth++;\n    }\n    int subHeight = height >> BLOCK_SIZE_POWER;\n    if ((height & BLOCK_SIZE_MASK) != 0) {\n      subHeight++;\n    }\n    int* blackPoints =\n      calculateBlackPoints(luminances, subWidth, subHeight, width, height);\n\n    Ref<BitMatrix> newMatrix (new BitMatrix(width, height));\n    calculateThresholdForBlock(luminances,\n                               subWidth,\n                               subHeight,\n                               width,\n                               height,\n                               blackPoints,\n                               newMatrix);\n    matrix_ = newMatrix;\n\n    // N.B.: these deletes are inadequate if anything between the new\n    // and this point can throw.  As of this writing, it doesn't look\n    // like they do.\n\n    delete [] blackPoints;\n    delete [] luminances;\n  } else {\n    // If the image is too small, fall back to the global histogram approach.\n    matrix_ = GlobalHistogramBinarizer::getBlackMatrix();\n  }\n  return matrix_;\n}\n\nvoid\nHybridBinarizer::calculateThresholdForBlock(unsigned char* luminances,\n                                            int subWidth,\n                                            int subHeight,\n                                            int width,\n                                            int height,\n                                            int blackPoints[],\n                                            Ref<BitMatrix> const& matrix) {\n  for (int y = 0; y < subHeight; y++) {\n    int yoffset = y << BLOCK_SIZE_POWER;\n    if (yoffset + BLOCK_SIZE >= height) {\n      yoffset = height - BLOCK_SIZE;\n    }\n    for (int x = 0; x < subWidth; x++) {\n      int xoffset = x << BLOCK_SIZE_POWER;\n      if (xoffset + BLOCK_SIZE >= width) {\n        xoffset = width - BLOCK_SIZE;\n      }\n      int left = (x > 1) ? x : 2;\n      left = (left < subWidth - 2) ? left : subWidth - 3;\n      int top = (y > 1) ? y : 2;\n      top = (top < subHeight - 2) ? top : subHeight - 3;\n      int sum = 0;\n      for (int z = -2; z <= 2; z++) {\n        int *blackRow = &blackPoints[(top + z) * subWidth];\n        sum += blackRow[left - 2];\n        sum += blackRow[left - 1];\n        sum += blackRow[left];\n        sum += blackRow[left + 1];\n        sum += blackRow[left + 2];\n      }\n      int average = sum / 25;\n      threshold8x8Block(luminances, xoffset, yoffset, average, width, matrix);\n    }\n  }\n}\n\nvoid HybridBinarizer::threshold8x8Block(unsigned char* luminances,\n                                        int xoffset,\n                                        int yoffset,\n                                        int threshold,\n                                        int stride,\n                                        Ref<BitMatrix> const& matrix) {\n  for (int y = 0, offset = yoffset * stride + xoffset;\n       y < BLOCK_SIZE;\n       y++,  offset += stride) {\n    for (int x = 0; x < BLOCK_SIZE; x++) {\n      int pixel = luminances[offset + x] & 0xff;\n      if (pixel <= threshold) {\n        matrix->set(xoffset + x, yoffset + y);\n      }\n    }\n  }\n}\n\nnamespace {\n  inline int getBlackPointFromNeighbors(int* blackPoints, int subWidth, int x, int y) {\n    return (blackPoints[(y-1)*subWidth+x] +\n            2*blackPoints[y*subWidth+x-1] +\n            blackPoints[(y-1)*subWidth+x-1]) >> 2;\n  }\n}\n\nint* HybridBinarizer::calculateBlackPoints(unsigned char* luminances, int subWidth, int subHeight,\n    int width, int height) {\n  int *blackPoints = new int[subHeight * subWidth];\n  for (int y = 0; y < subHeight; y++) {\n    int yoffset = y << BLOCK_SIZE_POWER;\n    if (yoffset + BLOCK_SIZE >= height) {\n      yoffset = height - BLOCK_SIZE;\n    }\n    for (int x = 0; x < subWidth; x++) {\n      int xoffset = x << BLOCK_SIZE_POWER;\n      if (xoffset + BLOCK_SIZE >= width) {\n        xoffset = width - BLOCK_SIZE;\n      }\n      int sum = 0;\n      int min = 0xFF;\n      int max = 0;\n      for (int yy = 0, offset = yoffset * width + xoffset;\n           yy < BLOCK_SIZE;\n           yy++, offset += width) {\n        for (int xx = 0; xx < BLOCK_SIZE; xx++) {\n          int pixel = luminances[offset + xx] & 0xFF;\n          sum += pixel;\n          if (pixel < min) {\n            min = pixel;\n          }\n          if (pixel > max) {\n            max = pixel;\n          }\n        }\n      }\n\n      // See\n      // http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0\n      int average = sum >> 6;\n      if (max - min <= 24) {\n        average = min >> 1;\n        if (y > 0 && x > 0) {\n          int bp = getBlackPointFromNeighbors(blackPoints, subWidth, x, y);\n          if (min < bp) {\n            average = bp;\n          }\n        }\n      }\n      blackPoints[y * subWidth + x] = average;\n    }\n  }\n  return blackPoints;\n}\n\n\n// file: zxing/common/IllegalArgumentException.cpp\n\n/*\n *  IllegalArgumentException.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 06/05/2008.\n *  Copyright 2008 Google UK. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/IllegalArgumentException.h>\n\nnamespace zxing {\n\nIllegalArgumentException::IllegalArgumentException(const char *msg) :\n    Exception(msg) {\n}\nIllegalArgumentException::~IllegalArgumentException() throw() {\n\n}\n}\n\n// file: zxing/common/PerspectiveTransform.cpp\n\n/*\n *  PerspectiveTransform.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 12/05/2008.\n *  Copyright 2008 Google UK. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/PerspectiveTransform.h>\n\nnamespace zxing {\nusing namespace std;\n\nPerspectiveTransform::PerspectiveTransform(float inA11, float inA21,\n                                           float inA31, float inA12,\n                                           float inA22, float inA32,\n                                           float inA13, float inA23,\n                                           float inA33) :\n  a11(inA11), a12(inA12), a13(inA13), a21(inA21), a22(inA22), a23(inA23),\n  a31(inA31), a32(inA32), a33(inA33) {}\n\nRef<PerspectiveTransform> PerspectiveTransform::quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1,\n    float x2, float y2, float x3, float y3, float x0p, float y0p, float x1p, float y1p, float x2p, float y2p,\n    float x3p, float y3p) {\n  Ref<PerspectiveTransform> qToS = PerspectiveTransform::quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);\n  Ref<PerspectiveTransform> sToQ =\n    PerspectiveTransform::squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);\n  return sToQ->times(qToS);\n}\n\nRef<PerspectiveTransform> PerspectiveTransform::squareToQuadrilateral(float x0, float y0, float x1, float y1, float x2,\n    float y2, float x3, float y3) {\n  float dy2 = y3 - y2;\n  float dy3 = y0 - y1 + y2 - y3;\n  if (dy2 == 0.0f && dy3 == 0.0f) {\n    Ref<PerspectiveTransform> result(new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0f,\n                                     0.0f, 1.0f));\n    return result;\n  } else {\n    float dx1 = x1 - x2;\n    float dx2 = x3 - x2;\n    float dx3 = x0 - x1 + x2 - x3;\n    float dy1 = y1 - y2;\n    float denominator = dx1 * dy2 - dx2 * dy1;\n    float a13 = (dx3 * dy2 - dx2 * dy3) / denominator;\n    float a23 = (dx1 * dy3 - dx3 * dy1) / denominator;\n    Ref<PerspectiveTransform> result(new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0\n                                     + a13 * y1, y3 - y0 + a23 * y3, y0, a13, a23, 1.0f));\n    return result;\n  }\n}\n\nRef<PerspectiveTransform> PerspectiveTransform::quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2,\n    float y2, float x3, float y3) {\n  // Here, the adjoint serves as the inverse:\n  return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3)->buildAdjoint();\n}\n\nRef<PerspectiveTransform> PerspectiveTransform::buildAdjoint() {\n  // Adjoint is the transpose of the cofactor matrix:\n  Ref<PerspectiveTransform> result(new PerspectiveTransform(a22 * a33 - a23 * a32, a23 * a31 - a21 * a33, a21 * a32\n                                   - a22 * a31, a13 * a32 - a12 * a33, a11 * a33 - a13 * a31, a12 * a31 - a11 * a32, a12 * a23 - a13 * a22,\n                                   a13 * a21 - a11 * a23, a11 * a22 - a12 * a21));\n  return result;\n}\n\nRef<PerspectiveTransform> PerspectiveTransform::times(Ref<PerspectiveTransform> other) {\n  Ref<PerspectiveTransform> result(new PerspectiveTransform(a11 * other->a11 + a21 * other->a12 + a31 * other->a13,\n                                   a11 * other->a21 + a21 * other->a22 + a31 * other->a23, a11 * other->a31 + a21 * other->a32 + a31\n                                   * other->a33, a12 * other->a11 + a22 * other->a12 + a32 * other->a13, a12 * other->a21 + a22\n                                   * other->a22 + a32 * other->a23, a12 * other->a31 + a22 * other->a32 + a32 * other->a33, a13\n                                   * other->a11 + a23 * other->a12 + a33 * other->a13, a13 * other->a21 + a23 * other->a22 + a33\n                                   * other->a23, a13 * other->a31 + a23 * other->a32 + a33 * other->a33));\n  return result;\n}\n\nvoid PerspectiveTransform::transformPoints(vector<float> &points) {\n  int max = points.size();\n  for (int i = 0; i < max; i += 2) {\n    float x = points[i];\n    float y = points[i + 1];\n    float denominator = a13 * x + a23 * y + a33;\n    points[i] = (a11 * x + a21 * y + a31) / denominator;\n    points[i + 1] = (a12 * x + a22 * y + a32) / denominator;\n  }\n}\n\nostream& operator<<(ostream& out, const PerspectiveTransform &pt) {\n  out << pt.a11 << \", \" << pt.a12 << \", \" << pt.a13 << \", \\n\";\n  out << pt.a21 << \", \" << pt.a22 << \", \" << pt.a23 << \", \\n\";\n  out << pt.a31 << \", \" << pt.a32 << \", \" << pt.a33 << \"\\n\";\n  return out;\n}\n\n}\n\n// file: zxing/common/Str.cpp\n\n/*\n *  String.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 20/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Str.h>\n\nnamespace zxing {\nusing namespace std;\n\nString::String(const std::string &text) :\n    text_(text) {\n}\nconst std::string& String::getText() const {\n  return text_;\n}\n\nostream &operator<<(ostream &out, const String &s) {\n  out << s.text_;\n  return out;\n}\n\n}\n\n// file: zxing/common/StringUtils.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n\n/*\n * Copyright (C) 2010-2011 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/StringUtils.h>\n// #include <zxing/DecodeHints.h>\n\nusing namespace std;\nusing namespace zxing;\nusing namespace zxing::common;\n\n// N.B.: these are the iconv strings for at least some versions of iconv\n\nchar const* const StringUtils::PLATFORM_DEFAULT_ENCODING = \"UTF-8\";\nchar const* const StringUtils::ASCII = \"ASCII\";\nchar const* const StringUtils::SHIFT_JIS = \"SHIFT_JIS\";\nchar const* const StringUtils::GB2312 = \"GBK\";\nchar const* const StringUtils::EUC_JP = \"EUC-JP\";\nchar const* const StringUtils::UTF8 = \"UTF-8\";\nchar const* const StringUtils::ISO88591 = \"ISO8859-1\";\nconst bool StringUtils::ASSUME_SHIFT_JIS = false;\n\nstring\nStringUtils::guessEncoding(unsigned char* bytes, int length, Hashtable const& hints) {\n  Hashtable::const_iterator i = hints.find(DecodeHints::CHARACTER_SET);\n  if (i != hints.end()) {\n    return i->second;\n  }\n  // Does it start with the UTF-8 byte order mark? then guess it's UTF-8\n  if (length > 3 &&\n      bytes[0] == (unsigned char) 0xEF &&\n      bytes[1] == (unsigned char) 0xBB &&\n      bytes[2] == (unsigned char) 0xBF) {\n    return UTF8;\n  }\n  // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS,\n  // which should be by far the most common encodings. ISO-8859-1\n  // should not have bytes in the 0x80 - 0x9F range, while Shift_JIS\n  // uses this as a first byte of a two-byte character. If we see this\n  // followed by a valid second byte in Shift_JIS, assume it is Shift_JIS.\n  // If we see something else in that second byte, we'll make the risky guess\n  // that it's UTF-8.\n  bool canBeISO88591 = true;\n  bool canBeShiftJIS = true;\n  bool canBeUTF8 = true;\n  int utf8BytesLeft = 0;\n  int maybeDoubleByteCount = 0;\n  int maybeSingleByteKatakanaCount = 0;\n  bool sawLatin1Supplement = false;\n  bool sawUTF8Start = false;\n  bool lastWasPossibleDoubleByteStart = false;\n\n  for (int i = 0;\n       i < length && (canBeISO88591 || canBeShiftJIS || canBeUTF8);\n       i++) {\n\n    int value = bytes[i] & 0xFF;\n\n    // UTF-8 stuff\n    if (value >= 0x80 && value <= 0xBF) {\n      if (utf8BytesLeft > 0) {\n        utf8BytesLeft--;\n      }\n    } else {\n      if (utf8BytesLeft > 0) {\n        canBeUTF8 = false;\n      }\n      if (value >= 0xC0 && value <= 0xFD) {\n        sawUTF8Start = true;\n        int valueCopy = value;\n        while ((valueCopy & 0x40) != 0) {\n          utf8BytesLeft++;\n          valueCopy <<= 1;\n        }\n      }\n    }\n\n    // ISO-8859-1 stuff\n\n    if ((value == 0xC2 || value == 0xC3) && i < length - 1) {\n      // This is really a poor hack. The slightly more exotic characters people might want to put in\n      // a QR Code, by which I mean the Latin-1 supplement characters (e.g. u-umlaut) have encodings\n      // that start with 0xC2 followed by [0xA0,0xBF], or start with 0xC3 followed by [0x80,0xBF].\n      int nextValue = bytes[i + 1] & 0xFF;\n      if (nextValue <= 0xBF &&\n          ((value == 0xC2 && nextValue >= 0xA0) || (value == 0xC3 && nextValue >= 0x80))) {\n        sawLatin1Supplement = true;\n      }\n    }\n    if (value >= 0x7F && value <= 0x9F) {\n      canBeISO88591 = false;\n    }\n\n    // Shift_JIS stuff\n\n    if (value >= 0xA1 && value <= 0xDF) {\n      // count the number of characters that might be a Shift_JIS single-byte Katakana character\n      if (!lastWasPossibleDoubleByteStart) {\n        maybeSingleByteKatakanaCount++;\n      }\n    }\n    if (!lastWasPossibleDoubleByteStart &&\n        ((value >= 0xF0 && value <= 0xFF) || value == 0x80 || value == 0xA0)) {\n      canBeShiftJIS = false;\n    }\n    if ((value >= 0x81 && value <= 0x9F) || (value >= 0xE0 && value <= 0xEF)) {\n      // These start double-byte characters in Shift_JIS. Let's see if it's followed by a valid\n      // second byte.\n      if (lastWasPossibleDoubleByteStart) {\n        // If we just checked this and the last byte for being a valid double-byte\n        // char, don't check starting on this byte. If this and the last byte\n        // formed a valid pair, then this shouldn't be checked to see if it starts\n        // a double byte pair of course.\n        lastWasPossibleDoubleByteStart = false;\n      } else {\n        // ... otherwise do check to see if this plus the next byte form a valid\n        // double byte pair encoding a character.\n        lastWasPossibleDoubleByteStart = true;\n        if (i >= length - 1) {\n          canBeShiftJIS = false;\n        } else {\n          int nextValue = bytes[i + 1] & 0xFF;\n          if (nextValue < 0x40 || nextValue > 0xFC) {\n            canBeShiftJIS = false;\n          } else {\n            maybeDoubleByteCount++;\n          }\n          // There is some conflicting information out there about which bytes can follow which in\n          // double-byte Shift_JIS characters. The rule above seems to be the one that matches practice.\n        }\n      }\n    } else {\n      lastWasPossibleDoubleByteStart = false;\n    }\n  }\n  if (utf8BytesLeft > 0) {\n    canBeUTF8 = false;\n  }\n\n  // Easy -- if assuming Shift_JIS and no evidence it can't be, done\n  if (canBeShiftJIS && ASSUME_SHIFT_JIS) {\n    return SHIFT_JIS;\n  }\n  if (canBeUTF8 && sawUTF8Start) {\n    return UTF8;\n  }\n  // Distinguishing Shift_JIS and ISO-8859-1 can be a little tough. The crude heuristic is:\n  // - If we saw\n  //   - at least 3 bytes that starts a double-byte value (bytes that are rare in ISO-8859-1), or\n  //   - over 5% of bytes could be single-byte Katakana (also rare in ISO-8859-1),\n  // - and, saw no sequences that are invalid in Shift_JIS, then we conclude Shift_JIS\n  if (canBeShiftJIS && (maybeDoubleByteCount >= 3 || 20 * maybeSingleByteKatakanaCount > length)) {\n    return SHIFT_JIS;\n  }\n  // Otherwise, we default to ISO-8859-1 unless we know it can't be\n  if (!sawLatin1Supplement && canBeISO88591) {\n    return ISO88591;\n  }\n  // Otherwise, we take a wild guess with platform encoding\n  return PLATFORM_DEFAULT_ENCODING;\n}\n\n// file: zxing/common/detector/MonochromeRectangleDetector.cpp\n\n/*\n *  MonochromeRectangleDetector.cpp\n *  y_wmk\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 y_wmk authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/NotFoundException.h>\n// #include <zxing/common/detector/MonochromeRectangleDetector.h>\n// #include <sstream>\n\nnamespace zxing {\nusing namespace std;\n\nstd::vector<Ref<ResultPoint> > MonochromeRectangleDetector::detect() {\n    int height = image_->getHeight();\n    int width = image_->getWidth();\n    int halfHeight = height >> 1;\n    int halfWidth = width >> 1;\n    int deltaY = max(1, height / (MAX_MODULES << 3));\n    int deltaX = max(1, width / (MAX_MODULES << 3));\n\n    int top = 0;\n    int bottom = height;\n    int left = 0;\n    int right = width;\n    Ref<ResultPoint> pointA(findCornerFromCenter(halfWidth, 0, left, right,\n        halfHeight, -deltaY, top, bottom, halfWidth >> 1));\n    top = (int) pointA->getY() - 1;;\n    Ref<ResultPoint> pointB(findCornerFromCenter(halfWidth, -deltaX, left, right,\n        halfHeight, 0, top, bottom, halfHeight >> 1));\n    left = (int) pointB->getX() - 1;\n    Ref<ResultPoint> pointC(findCornerFromCenter(halfWidth, deltaX, left, right,\n        halfHeight, 0, top, bottom, halfHeight >> 1));\n    right = (int) pointC->getX() + 1;\n    Ref<ResultPoint> pointD(findCornerFromCenter(halfWidth, 0, left, right,\n        halfHeight, deltaY, top, bottom, halfWidth >> 1));\n    bottom = (int) pointD->getY() + 1;\n\n    // Go try to find point A again with better information -- might have been off at first.\n    pointA.reset(findCornerFromCenter(halfWidth, 0, left, right,\n        halfHeight, -deltaY, top, bottom, halfWidth >> 2));\n\n\t  std::vector<Ref<ResultPoint> > corners(4);\n  \tcorners[0].reset(pointA);\n  \tcorners[1].reset(pointB);\n  \tcorners[2].reset(pointC);\n  \tcorners[3].reset(pointD);\n    return corners;\n  }\n\nRef<ResultPoint> MonochromeRectangleDetector::findCornerFromCenter(int centerX, int deltaX, int left, int right,\n      int centerY, int deltaY, int top, int bottom, int maxWhiteRun) {\n\t  Ref<TwoInts> lastRange(NULL);\n    for (int y = centerY, x = centerX;\n         y < bottom && y >= top && x < right && x >= left;\n         y += deltaY, x += deltaX) {\n      Ref<TwoInts> range(NULL);\n      if (deltaX == 0) {\n        // horizontal slices, up and down\n        range = blackWhiteRange(y, maxWhiteRun, left, right, true);\n      } else {\n        // vertical slices, left and right\n        range = blackWhiteRange(x, maxWhiteRun, top, bottom, false);\n      }\n      if (range == NULL) {\n        if (lastRange == NULL) {\n\t\t\t    throw NotFoundException(\"Couldn't find corners (lastRange = NULL) \");\n        } else {\n        // lastRange was found\n        if (deltaX == 0) {\n          int lastY = y - deltaY;\n          if (lastRange->start < centerX) {\n            if (lastRange->end > centerX) {\n              // straddle, choose one or the other based on direction\n\t\t\t        Ref<ResultPoint> result(new ResultPoint(deltaY > 0 ? lastRange->start : lastRange->end, lastY));\n\t\t\t        return result;\n            }\n\t\t\t      Ref<ResultPoint> result(new ResultPoint(lastRange->start, lastY));\n\t\t\t      return result;\n          } else {\n\t\t\t      Ref<ResultPoint> result(new ResultPoint(lastRange->end, lastY));\n\t\t\t      return result;\n            }\n        } else {\n          int lastX = x - deltaX;\n          if (lastRange->start < centerY) {\n            if (lastRange->end > centerY) {\n\t\t\t        Ref<ResultPoint> result(new ResultPoint(lastX, deltaX < 0 ? lastRange->start : lastRange->end));\n\t\t\t        return result;\n            }\n\t\t\t      Ref<ResultPoint> result(new ResultPoint(lastX, lastRange->start));\n\t\t\t      return result;\n          } else {\n\t\t\t      Ref<ResultPoint> result(new ResultPoint(lastX, lastRange->end));\n\t\t\t      return result;\n            }\n          }\n        }\n      }\n      lastRange = range;\n    }\n    throw NotFoundException(\"Couldn't find corners\");\n  }\n\nRef<TwoInts> MonochromeRectangleDetector::blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim,\n      bool horizontal) {\n\n\t  int center = (minDim + maxDim) >> 1;\n\n    // Scan left/up first\n    int start = center;\n    while (start >= minDim) {\n      if (horizontal ? image_->get(start, fixedDimension) : image_->get(fixedDimension, start)) {\n        start--;\n      } else {\n        int whiteRunStart = start;\n        do {\n          start--;\n        } while (start >= minDim && !(horizontal ? image_->get(start, fixedDimension) :\n            image_->get(fixedDimension, start)));\n        int whiteRunSize = whiteRunStart - start;\n        if (start < minDim || whiteRunSize > maxWhiteRun) {\n          start = whiteRunStart;\n          break;\n        }\n      }\n    }\n    start++;\n\n    // Then try right/down\n    int end = center;\n    while (end < maxDim) {\n      if (horizontal ? image_->get(end, fixedDimension) : image_->get(fixedDimension, end)) {\n        end++;\n      } else {\n        int whiteRunStart = end;\n        do {\n          end++;\n        } while (end < maxDim && !(horizontal ? image_->get(end, fixedDimension) :\n            image_->get(fixedDimension, end)));\n        int whiteRunSize = end - whiteRunStart;\n        if (end >= maxDim || whiteRunSize > maxWhiteRun) {\n          end = whiteRunStart;\n          break;\n        }\n      }\n    }\n    end--;\n    Ref<TwoInts> result(NULL);\n    if (end > start) {\n\t\t  result = new TwoInts;\n      result->start = start;\n      result->end = end;\n    }\n    return result;\n  }\n}\n\n// file: zxing/common/detector/WhiteRectangleDetector.cpp\n\n/*\n *  WhiteRectangleDetector.cpp\n *  y_wmk\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 y_wmk authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/NotFoundException.h>\n// #include <zxing/common/detector/WhiteRectangleDetector.h>\n// #include <math.h>\n// #include <sstream>\n\nnamespace zxing {\nusing namespace std;\n\nint WhiteRectangleDetector::INIT_SIZE = 30;\nint WhiteRectangleDetector::CORR = 1;\n\n\nWhiteRectangleDetector::WhiteRectangleDetector(Ref<BitMatrix> image) : image_(image) {\n  width_ = image->getWidth();\n  height_ = image->getHeight();\n}\n\n/**\n * <p>\n * Detects a candidate barcode-like rectangular region within an image. It\n * starts around the center of the image, increases the size of the candidate\n * region until it finds a white rectangular region.\n * </p>\n *\n * @return {@link vector<Ref<ResultPoint> >} describing the corners of the rectangular\n *         region. The first and last points are opposed on the diagonal, as\n *         are the second and third. The first point will be the topmost\n *         point and the last, the bottommost. The second point will be\n *         leftmost and the third, the rightmost\n * @throws NotFoundException if no Data Matrix Code can be found\n*/\nstd::vector<Ref<ResultPoint> > WhiteRectangleDetector::detect() {\n  int left = (width_ - INIT_SIZE) >> 1;\n  int right = (width_ + INIT_SIZE) >> 1;\n  int up = (height_ - INIT_SIZE) >> 1;\n  int down = (height_ + INIT_SIZE) >> 1;\n  if (up < 0 || left < 0 || down >= height_ || right >= width_) {\n    throw NotFoundException(\"Invalid dimensions WhiteRectangleDetector\");\n  }\n\n  bool sizeExceeded = false;\n  bool aBlackPointFoundOnBorder = true;\n  bool atLeastOneBlackPointFoundOnBorder = false;\n\n  while (aBlackPointFoundOnBorder) {\n    aBlackPointFoundOnBorder = false;\n\n    // .....\n    // .   |\n    // .....\n    bool rightBorderNotWhite = true;\n    while (rightBorderNotWhite && right < width_) {\n      rightBorderNotWhite = containsBlackPoint(up, down, right, false);\n      if (rightBorderNotWhite) {\n        right++;\n        aBlackPointFoundOnBorder = true;\n      }\n    }\n\n    if (right >= width_) {\n      sizeExceeded = true;\n      break;\n    }\n\n    // .....\n    // .   .\n    // .___.\n    bool bottomBorderNotWhite = true;\n    while (bottomBorderNotWhite && down < height_) {\n      bottomBorderNotWhite = containsBlackPoint(left, right, down, true);\n      if (bottomBorderNotWhite) {\n        down++;\n        aBlackPointFoundOnBorder = true;\n      }\n    }\n\n    if (down >= height_) {\n      sizeExceeded = true;\n      break;\n    }\n\n    // .....\n    // |   .\n    // .....\n    bool leftBorderNotWhite = true;\n    while (leftBorderNotWhite && left >= 0) {\n      leftBorderNotWhite = containsBlackPoint(up, down, left, false);\n      if (leftBorderNotWhite) {\n        left--;\n        aBlackPointFoundOnBorder = true;\n      }\n    }\n\n    if (left < 0) {\n      sizeExceeded = true;\n      break;\n    }\n\n    // .___.\n    // .   .\n    // .....\n    bool topBorderNotWhite = true;\n    while (topBorderNotWhite && up >= 0) {\n      topBorderNotWhite = containsBlackPoint(left, right, up, true);\n      if (topBorderNotWhite) {\n        up--;\n        aBlackPointFoundOnBorder = true;\n      }\n    }\n\n    if (up < 0) {\n      sizeExceeded = true;\n      break;\n    }\n\n    if (aBlackPointFoundOnBorder) {\n      atLeastOneBlackPointFoundOnBorder = true;\n    }\n\n  }\n  if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) {\n\n    int maxSize = right - left;\n\n    Ref<ResultPoint> z(NULL);\n    //go up right\n    for (int i = 1; i < maxSize; i++) {\n      z = getBlackPointOnSegment(left, down - i, left + i, down);\n      if (z != NULL) {\n        break;\n      }\n    }\n\n    if (z == NULL) {\n      throw NotFoundException(\"z == NULL\");\n    }\n\n    Ref<ResultPoint> t(NULL);\n    //go down right\n    for (int i = 1; i < maxSize; i++) {\n      t = getBlackPointOnSegment(left, up + i, left + i, up);\n      if (t != NULL) {\n        break;\n      }\n    }\n\n    if (t == NULL) {\n      throw NotFoundException(\"t == NULL\");\n    }\n\n    Ref<ResultPoint> x(NULL);\n    //go down left\n    for (int i = 1; i < maxSize; i++) {\n      x = getBlackPointOnSegment(right, up + i, right - i, up);\n      if (x != NULL) {\n        break;\n      }\n    }\n\n    if (x == NULL) {\n      throw NotFoundException(\"x == NULL\");\n    }\n\n    Ref<ResultPoint> y(NULL);\n    //go up left\n    for (int i = 1; i < maxSize; i++) {\n      y = getBlackPointOnSegment(right, down - i, right - i, down);\n      if (y != NULL) {\n        break;\n      }\n    }\n\n    if (y == NULL) {\n      throw NotFoundException(\"y == NULL\");\n    }\n\n    return centerEdges(y, z, x, t);\n\n  } else {\n    throw NotFoundException(\"No black point found on border\");\n  }\n}\n\n/**\n * Ends up being a bit faster than Math.round(). This merely rounds its\n * argument to the nearest int, where x.5 rounds up.\n */\nint WhiteRectangleDetector::round(float d) {\n  return (int) (d + 0.5f);\n}\n\nRef<ResultPoint> WhiteRectangleDetector::getBlackPointOnSegment(float aX, float aY, float bX, float bY) {\n  int dist = distanceL2(aX, aY, bX, bY);\n  float xStep = (bX - aX) / dist;\n  float yStep = (bY - aY) / dist;\n  for (int i = 0; i < dist; i++) {\n    int x = round(aX + i * xStep);\n    int y = round(aY + i * yStep);\n    if (image_->get(x, y)) {\n      Ref<ResultPoint> point(new ResultPoint(x, y));\n      return point;\n    }\n  }\n  Ref<ResultPoint> point(NULL);\n  return point;\n}\n\nint WhiteRectangleDetector::distanceL2(float aX, float aY, float bX, float bY) {\n  float xDiff = aX - bX;\n  float yDiff = aY - bY;\n  return round((float)sqrt(xDiff * xDiff + yDiff * yDiff));\n}\n\n/**\n * recenters the points of a constant distance towards the center\n *\n * @param y bottom most point\n * @param z left most point\n * @param x right most point\n * @param t top most point\n * @return {@link vector<Ref<ResultPoint> >} describing the corners of the rectangular\n *         region. The first and last points are opposed on the diagonal, as\n *         are the second and third. The first point will be the topmost\n *         point and the last, the bottommost. The second point will be\n *         leftmost and the third, the rightmost\n */\nvector<Ref<ResultPoint> > WhiteRectangleDetector::centerEdges(Ref<ResultPoint> y, Ref<ResultPoint> z,\n                                  Ref<ResultPoint> x, Ref<ResultPoint> t) {\n\n  //\n  //       t            t\n  //  z                      x\n  //        x    OR    z\n  //   y                    y\n  //\n\n  float yi = y->getX();\n  float yj = y->getY();\n  float zi = z->getX();\n  float zj = z->getY();\n  float xi = x->getX();\n  float xj = x->getY();\n  float ti = t->getX();\n  float tj = t->getY();\n\n  std::vector<Ref<ResultPoint> > corners(4);\n  if (yi < (float)width_/2) {\n    Ref<ResultPoint> pointA(new ResultPoint(ti - CORR, tj + CORR));\n    Ref<ResultPoint> pointB(new ResultPoint(zi + CORR, zj + CORR));\n    Ref<ResultPoint> pointC(new ResultPoint(xi - CORR, xj - CORR));\n    Ref<ResultPoint> pointD(new ResultPoint(yi + CORR, yj - CORR));\n\t  corners[0].reset(pointA);\n\t  corners[1].reset(pointB);\n\t  corners[2].reset(pointC);\n\t  corners[3].reset(pointD);\n  } else {\n    Ref<ResultPoint> pointA(new ResultPoint(ti + CORR, tj + CORR));\n    Ref<ResultPoint> pointB(new ResultPoint(zi + CORR, zj - CORR));\n    Ref<ResultPoint> pointC(new ResultPoint(xi - CORR, xj + CORR));\n    Ref<ResultPoint> pointD(new ResultPoint(yi - CORR, yj - CORR));\n\t  corners[0].reset(pointA);\n\t  corners[1].reset(pointB);\n\t  corners[2].reset(pointC);\n\t  corners[3].reset(pointD);\n  }\n  return corners;\n}\n\n/**\n * Determines whether a segment contains a black point\n *\n * @param a          min value of the scanned coordinate\n * @param b          max value of the scanned coordinate\n * @param fixed      value of fixed coordinate\n * @param horizontal set to true if scan must be horizontal, false if vertical\n * @return true if a black point has been found, else false.\n */\nbool WhiteRectangleDetector::containsBlackPoint(int a, int b, int fixed, bool horizontal) {\n  if (horizontal) {\n    for (int x = a; x <= b; x++) {\n      if (image_->get(x, fixed)) {\n        return true;\n      }\n    }\n  } else {\n    for (int y = a; y <= b; y++) {\n      if (image_->get(fixed, y)) {\n        return true;\n      }\n    }\n  }\n\n  return false;\n}\n}\n\n// file: zxing/common/reedsolomon/GF256.cpp\n\n/*\n *  GF256.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 05/05/2008.\n *  Copyright 2008 Google UK. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <vector>\n// #include <iostream>\n// #include <zxing/common/reedsolomon/GF256.h>\n// #include <zxing/common/reedsolomon/GF256Poly.h>\n// #include <zxing/common/IllegalArgumentException.h>\n// #include <zxing/common/Array.h>\n// #include <zxing/common/Counted.h>\n\nnamespace zxing {\nusing namespace std;\n\nstatic inline ArrayRef<int> makeArray(int value) {\n  ArrayRef<int> valuesRef(new Array<int> (value, 1));\n  return valuesRef;\n}\n\nstatic inline Ref<GF256Poly> refPoly(GF256 &field, int value) {\n  ArrayRef<int> values(makeArray(value));\n  Ref<GF256Poly> result(new GF256Poly(field, values));\n  return result;\n}\n\nGF256::GF256(int primitive) :\n    exp_(256, (const int)0), log_(256, (const int)0), zero_(refPoly(*this, 0)), one_(refPoly(*this, 1)) {\n  int x = 1;\n  for (int i = 0; i < 256; i++) {\n    exp_[i] = x;\n    x <<= 1;\n    if (x >= 0x100) {\n      x ^= primitive;\n    }\n  }\n\n  // log(0) == 0, but should never be used\n  log_[0] = 0;\n  for (int i = 0; i < 255; i++) {\n    log_[exp_[i]] = i;\n  }\n}\n\nRef<GF256Poly> GF256::getZero() {\n  return zero_;\n}\n\nRef<GF256Poly> GF256::getOne() {\n  return one_;\n}\n\nRef<GF256Poly> GF256::buildMonomial(int degree, int coefficient) {\n#ifdef DEBUG\n  cout << __FUNCTION__ << \"\\n\";\n#endif\n  if (degree < 0) {\n    throw IllegalArgumentException(\"Degree must be non-negative\");\n  }\n  if (coefficient == 0) {\n    return zero_;\n  }\n  int nCoefficients = degree + 1;\n  ArrayRef<int> coefficients(new Array<int> (nCoefficients));\n  coefficients[0] = coefficient;\n  Ref<GF256Poly> result(new GF256Poly(*this, coefficients));\n  return result;\n}\n\nint GF256::addOrSubtract(int a, int b) {\n  return a ^ b;\n}\n\nint GF256::exp(int a) {\n  return exp_[a];\n}\n\nint GF256::log(int a) {\n  if (a == 0) {\n    throw IllegalArgumentException(\"Cannot take the logarithm of 0\");\n  }\n  return log_[a];\n}\n\nint GF256::inverse(int a) {\n  if (a == 0) {\n    throw IllegalArgumentException(\"Cannot calculate the inverse of 0\");\n  }\n  return exp_[255 - log_[a]];\n}\n\nint GF256::multiply(int a, int b) {\n  if (a == 0 || b == 0) {\n    return 0;\n  }\n  int logSum = log_[a] + log_[b];\n  // index is a sped-up alternative to logSum % 255 since sum\n  // is in [0,510]. Thanks to jmsachs for the idea\n  return exp_[(logSum & 0xFF) + (logSum >> 8)];\n}\n\nGF256 GF256::QR_CODE_FIELD(0x011D); // x^8 + x^4 + x^3 + x^2 + 1\nGF256 GF256::DATA_MATRIX_FIELD(0x012D); // x^8 + x^5 + x^3 + x^2 + 1\n\nostream& operator<<(ostream& out, const GF256& field) {\n  out << \"Field[\\nexp=(\";\n  out << field.exp_[0];\n  for (int i = 1; i < 256; i++) {\n    out << \",\" << field.exp_[i];\n  }\n  out << \"),\\nlog=(\";\n  out << field.log_[0];\n  for (int i = 1; i < 256; i++) {\n    out << \",\" << field.log_[i];\n  }\n  out << \")\\n]\";\n  return out;\n}\n\n}\n\n// file: zxing/common/reedsolomon/GF256Poly.cpp\n\n/*\n *  GF256Poly.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 05/05/2008.\n *  Copyright 2008 Google UK. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <iostream>\n// #include <sstream>\n// #include <zxing/common/reedsolomon/GF256Poly.h>\n// #include <zxing/common/reedsolomon/GF256.h>\n// #include <zxing/common/IllegalArgumentException.h>\n\nnamespace zxing {\nusing namespace std;\n\nvoid GF256Poly::fixCoefficients() {\n  int coefficientsLength = coefficients.size();\n  if (coefficientsLength > 1 && coefficients[0] == 0) {\n    // Leading term must be non-zero for anything except\n    // the constant polynomial \"0\"\n    int firstNonZero = 1;\n    while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) {\n      firstNonZero++;\n    }\n    if (firstNonZero == coefficientsLength) {\n      coefficientsLength = field.getZero()->coefficients.size();\n      coefficients.reset(new Array<int> (coefficientsLength));\n      *coefficients = *(field.getZero()->coefficients);\n    } else {\n      ArrayRef<int> c(coefficients);\n      coefficientsLength -= firstNonZero;\n      coefficients.reset(new Array<int> (coefficientsLength));\n      for (int i = 0; i < coefficientsLength; i++) {\n        coefficients[i] = c[i + firstNonZero];\n      }\n    }\n  }\n}\n\nGF256Poly::GF256Poly(GF256 &f, ArrayRef<int> c) :\n    Counted(), field(f), coefficients(c) {\n  fixCoefficients();\n}\n\nGF256Poly::~GF256Poly() {\n\n}\n\nint GF256Poly::getDegree() {\n  return coefficients.size() - 1;\n}\n\nbool GF256Poly::isZero() {\n  return coefficients[0] == 0;\n}\n\nint GF256Poly::getCoefficient(int degree) {\n  return coefficients[coefficients.size() - 1 - degree];\n}\n\nint GF256Poly::evaluateAt(int a) {\n  if (a == 0) {\n    return getCoefficient(0);\n  }\n  int size = coefficients.size();\n  if (a == 1) {\n    // Just the sum of the coefficients\n    int result = 0;\n    for (int i = 0; i < size; i++) {\n      result = GF256::addOrSubtract(result, coefficients[i]);\n    }\n    return result;\n  }\n  int result = coefficients[0];\n  for (int i = 1; i < size; i++) {\n    result = GF256::addOrSubtract(field.multiply(a, result), coefficients[i]);\n  }\n  return result;\n}\n\nRef<GF256Poly> GF256Poly::addOrSubtract(Ref<GF256Poly> b) {\n  if (&field != &b->field) {\n    throw IllegalArgumentException(\"Fields must be the same\");\n  }\n  if (isZero()) {\n    return b;\n  }\n  if (b->isZero()) {\n    return Ref<GF256Poly>(this);\n  }\n\n  ArrayRef<int> largerCoefficients = coefficients;\n  ArrayRef<int> smallerCoefficients = b->coefficients;\n  if (smallerCoefficients.size() > largerCoefficients.size()) {\n    ArrayRef<int> tmp(smallerCoefficients);\n    smallerCoefficients = largerCoefficients;\n    largerCoefficients = tmp;\n  }\n\n  ArrayRef<int> sumDiff(new Array<int> (largerCoefficients.size()));\n\n  unsigned lengthDiff = largerCoefficients.size() - smallerCoefficients.size();\n  for (unsigned i = 0; i < lengthDiff; i++) {\n    sumDiff[i] = largerCoefficients[i];\n  }\n  for (unsigned i = lengthDiff; i < largerCoefficients.size(); i++) {\n    sumDiff[i] = GF256::addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);\n  }\n  return Ref<GF256Poly>(new GF256Poly(field, sumDiff));\n}\n\nRef<GF256Poly> GF256Poly::multiply(Ref<GF256Poly> b) {\n  if (&field != &b->field) {\n    throw IllegalArgumentException(\"Fields must be the same\");\n  }\n  if (isZero() || b->isZero()) {\n    return field.getZero();\n  }\n  ArrayRef<int> aCoefficients = coefficients;\n  int aLength = aCoefficients.size();\n  ArrayRef<int> bCoefficients = b->coefficients;\n  int bLength = bCoefficients.size();\n  int productLength = aLength + bLength - 1;\n  ArrayRef<int> product(new Array<int> (productLength));\n  for (int i = 0; i < aLength; i++) {\n    int aCoeff = aCoefficients[i];\n    for (int j = 0; j < bLength; j++) {\n      product[i + j] = GF256::addOrSubtract(product[i + j], field.multiply(aCoeff, bCoefficients[j]));\n    }\n  }\n\n  return Ref<GF256Poly>(new GF256Poly(field, product));\n}\n\nRef<GF256Poly> GF256Poly::multiply(int scalar) {\n  if (scalar == 0) {\n    return field.getZero();\n  }\n  if (scalar == 1) {\n    return Ref<GF256Poly>(this);\n  }\n  int size = coefficients.size();\n  ArrayRef<int> product(new Array<int> (size));\n  for (int i = 0; i < size; i++) {\n    product[i] = field.multiply(coefficients[i], scalar);\n  }\n  return Ref<GF256Poly>(new GF256Poly(field, product));\n}\n\nRef<GF256Poly> GF256Poly::multiplyByMonomial(int degree, int coefficient) {\n  if (degree < 0) {\n    throw IllegalArgumentException(\"Degree must be non-negative\");\n  }\n  if (coefficient == 0) {\n    return field.getZero();\n  }\n  int size = coefficients.size();\n  ArrayRef<int> product(new Array<int> (size + degree));\n  for (int i = 0; i < size; i++) {\n    product[i] = field.multiply(coefficients[i], coefficient);\n  }\n  return Ref<GF256Poly>(new GF256Poly(field, product));\n}\n\nconst char *GF256Poly::description() const {\n  ostringstream result;\n  result << *this;\n  return result.str().c_str();\n}\n\nostream& operator<<(ostream& out, const GF256Poly& p) {\n  GF256Poly &poly = const_cast<GF256Poly&>(p);\n  out << \"Poly[\" << poly.coefficients.size() << \"]\";\n  if (poly.coefficients.size() > 0) {\n    out << \"(\" << poly.coefficients[0];\n    for (unsigned i = 1; i < poly.coefficients.size(); i++) {\n      out << \",\" << poly.coefficients[i];\n    }\n    out << \")\";\n  }\n  return out;\n}\n\n}\n\n// file: zxing/common/reedsolomon/ReedSolomonDecoder.cpp\n\n/*\n *  ReedSolomonDecoder.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 05/05/2008.\n *  Copyright 2008 Google UK. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <iostream>\n\n// #include <memory>\n// #include <zxing/common/reedsolomon/ReedSolomonDecoder.h>\n// #include <zxing/common/reedsolomon/GF256.h>\n// #include <zxing/common/reedsolomon/GF256Poly.h>\n// #include <zxing/common/reedsolomon/ReedSolomonException.h>\n// #include <zxing/common/IllegalArgumentException.h>\n\nusing namespace std;\n\nnamespace zxing {\n\nReedSolomonDecoder::ReedSolomonDecoder(GF256 &fld) :\n    field(fld) {\n}\n\nReedSolomonDecoder::~ReedSolomonDecoder() {\n}\n\nvoid ReedSolomonDecoder::decode(ArrayRef<int> received, int twoS) {\n\n  Ref<GF256Poly> poly(new GF256Poly(field, received));\n\n\n#ifdef DEBUG\n  cout << \"decoding with poly \" << *poly << \"\\n\";\n#endif\n\n  ArrayRef<int> syndromeCoefficients(new Array<int> (twoS));\n\n\n#ifdef DEBUG\n  cout << \"syndromeCoefficients array = \" <<\n       syndromeCoefficients.array_ << \"\\n\";\n#endif\n\n  bool dataMatrix = (&field == &GF256::DATA_MATRIX_FIELD);\n  bool noError = true;\n  for (int i = 0; i < twoS; i++) {\n    int eval = poly->evaluateAt(field.exp(dataMatrix ? i + 1 : i));\n    syndromeCoefficients[syndromeCoefficients->size() - 1 - i] = eval;\n    if (eval != 0) {\n      noError = false;\n    }\n  }\n  if (noError) {\n    return;\n  }\n\n  Ref<GF256Poly> syndrome(new GF256Poly(field, syndromeCoefficients));\n  Ref<GF256Poly> monomial(field.buildMonomial(twoS, 1));\n  vector<Ref<GF256Poly> > sigmaOmega(runEuclideanAlgorithm(monomial, syndrome, twoS));\n  ArrayRef<int> errorLocations = findErrorLocations(sigmaOmega[0]);\n  ArrayRef<int> errorMagitudes = findErrorMagnitudes(sigmaOmega[1], errorLocations, dataMatrix);\n  for (unsigned i = 0; i < errorLocations->size(); i++) {\n    int position = received->size() - 1 - field.log(errorLocations[i]);\n    //TODO: check why the position would be invalid\n    if (position < 0 || (size_t)position >= received.size())\n      throw IllegalArgumentException(\"Invalid position (ReedSolomonDecoder)\");\n    received[position] = GF256::addOrSubtract(received[position], errorMagitudes[i]);\n  }\n}\n\nvector<Ref<GF256Poly> > ReedSolomonDecoder::runEuclideanAlgorithm(Ref<GF256Poly> a, Ref<GF256Poly> b, int R) {\n  // Assume a's degree is >= b's\n  if (a->getDegree() < b->getDegree()) {\n    Ref<GF256Poly> tmp = a;\n    a = b;\n    b = tmp;\n  }\n\n  Ref<GF256Poly> rLast(a);\n  Ref<GF256Poly> r(b);\n  Ref<GF256Poly> sLast(field.getOne());\n  Ref<GF256Poly> s(field.getZero());\n  Ref<GF256Poly> tLast(field.getZero());\n  Ref<GF256Poly> t(field.getOne());\n\n\n  // Run Euclidean algorithm until r's degree is less than R/2\n  while (r->getDegree() >= R / 2) {\n    Ref<GF256Poly> rLastLast(rLast);\n    Ref<GF256Poly> sLastLast(sLast);\n    Ref<GF256Poly> tLastLast(tLast);\n    rLast = r;\n    sLast = s;\n    tLast = t;\n\n\n    // Divide rLastLast by rLast, with quotient q and remainder r\n    if (rLast->isZero()) {\n      // Oops, Euclidean algorithm already terminated?\n      throw ReedSolomonException(\"r_{i-1} was zero\");\n    }\n    r = rLastLast;\n    Ref<GF256Poly> q(field.getZero());\n    int denominatorLeadingTerm = rLast->getCoefficient(rLast->getDegree());\n    int dltInverse = field.inverse(denominatorLeadingTerm);\n    while (r->getDegree() >= rLast->getDegree() && !r->isZero()) {\n      int degreeDiff = r->getDegree() - rLast->getDegree();\n      int scale = field.multiply(r->getCoefficient(r->getDegree()), dltInverse);\n      q = q->addOrSubtract(field.buildMonomial(degreeDiff, scale));\n      r = r->addOrSubtract(rLast->multiplyByMonomial(degreeDiff, scale));\n    }\n\n    s = q->multiply(sLast)->addOrSubtract(sLastLast);\n    t = q->multiply(tLast)->addOrSubtract(tLastLast);\n  }\n\n  int sigmaTildeAtZero = t->getCoefficient(0);\n  if (sigmaTildeAtZero == 0) {\n    throw ReedSolomonException(\"sigmaTilde(0) was zero\");\n  }\n\n  int inverse = field.inverse(sigmaTildeAtZero);\n  Ref<GF256Poly> sigma(t->multiply(inverse));\n  Ref<GF256Poly> omega(r->multiply(inverse));\n\n\n#ifdef DEBUG\n  cout << \"t = \" << *t << \"\\n\";\n  cout << \"r = \" << *r << \"\\n\";\n  cout << \"sigma = \" << *sigma << \"\\n\";\n  cout << \"omega = \" << *omega << \"\\n\";\n#endif\n\n  vector<Ref<GF256Poly> > result(2);\n  result[0] = sigma;\n  result[1] = omega;\n  return result;\n}\n\nArrayRef<int> ReedSolomonDecoder::findErrorLocations(Ref<GF256Poly> errorLocator) {\n  // This is a direct application of Chien's search\n  int numErrors = errorLocator->getDegree();\n  if (numErrors == 1) { // shortcut\n    ArrayRef<int> result(1);\n    result[0] = errorLocator->getCoefficient(1);\n    return result;\n  }\n  ArrayRef<int> result(numErrors);\n  int e = 0;\n  for (int i = 1; i < 256 && e < numErrors; i++) {\n    // cout << \"errorLocator(\" << i << \") == \" << errorLocator->evaluateAt(i) << \"\\n\";\n    if (errorLocator->evaluateAt(i) == 0) {\n      result[e] = field.inverse(i);\n      e++;\n    }\n  }\n  if (e != numErrors) {\n    throw ReedSolomonException(\"Error locator degree does not match number of roots\");\n  }\n  return result;\n}\n\nArrayRef<int> ReedSolomonDecoder::findErrorMagnitudes(Ref<GF256Poly> errorEvaluator, ArrayRef<int> errorLocations, bool dataMatrix) {\n  // This is directly applying Forney's Formula\n  int s = errorLocations.size();\n  ArrayRef<int> result(s);\n  for (int i = 0; i < s; i++) {\n    int xiInverse = field.inverse(errorLocations[i]);\n    int denominator = 1;\n    for (int j = 0; j < s; j++) {\n      if (i != j) {\n        denominator = field.multiply(denominator, GF256::addOrSubtract(1, field.multiply(errorLocations[j],\n                                     xiInverse)));\n      }\n    }\n    result[i] = field.multiply(errorEvaluator->evaluateAt(xiInverse), field.inverse(denominator));\n\n    if (dataMatrix) {\n      result[i] = field.multiply(result[i], xiInverse);\n\t}\n  }\n  return result;\n}\n}\n\n// file: zxing/common/reedsolomon/ReedSolomonException.cpp\n\n/*\n *  ReedSolomonException.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 06/05/2008.\n *  Copyright 2008 Google UK. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/reedsolomon/ReedSolomonException.h>\n\nnamespace zxing {\nReedSolomonException::ReedSolomonException(const char *msg) throw() :\n    Exception(msg) {\n}\nReedSolomonException::~ReedSolomonException() throw() {\n}\n\n}\n\n// file: zxing/datamatrix/DataMatrixReader.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  DataMatrixReader.cpp\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/datamatrix/DataMatrixReader.h>\n// #include <zxing/datamatrix/detector/Detector.h>\n// #include <iostream>\n\nnamespace zxing {\nnamespace datamatrix {\n\nusing namespace std;\n\nDataMatrixReader::DataMatrixReader() :\n    decoder_() {\n}\n\nRef<Result> DataMatrixReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {\n  (void)hints;\n#ifdef DEBUG\n  cout << \"decoding image \" << image.object_ << \":\\n\" << flush;\n#endif\n\n  Detector detector(image->getBlackMatrix());\n\n\n#ifdef DEBUG\n  cout << \"(1) created detector \" << &detector << \"\\n\" << flush;\n#endif\n\n  Ref<DetectorResult> detectorResult(detector.detect());\n#ifdef DEBUG\n  cout << \"(2) detected, have detectorResult \" << detectorResult.object_ << \"\\n\" << flush;\n#endif\n\n  std::vector<Ref<ResultPoint> > points(detectorResult->getPoints());\n\n\n#ifdef DEBUG\n  cout << \"(3) extracted points \" << &points << \"\\n\" << flush;\n  cout << \"found \" << points.size() << \" points:\\n\";\n  for (size_t i = 0; i < points.size(); i++) {\n    cout << \"   \" << points[i]->getX() << \",\" << points[i]->getY() << \"\\n\";\n  }\n  cout << \"bits:\\n\";\n  cout << *(detectorResult->getBits()) << \"\\n\";\n#endif\n\n  Ref<DecoderResult> decoderResult(decoder_.decode(detectorResult->getBits()));\n#ifdef DEBUG\n  cout << \"(4) decoded, have decoderResult \" << decoderResult.object_ << \"\\n\" << flush;\n#endif\n\n  Ref<Result> result(\n    new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_DATA_MATRIX));\n#ifdef DEBUG\n  cout << \"(5) created result \" << result.object_ << \", returning\\n\" << flush;\n#endif\n\n  return result;\n}\n\nDataMatrixReader::~DataMatrixReader() {\n}\n\n}\n}\n\n// file: zxing/datamatrix/Version.cpp\n\n/*\n *  Version.cpp\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/datamatrix/Version.h>\n// #include <limits>\n// #include <iostream>\n\nnamespace zxing {\nnamespace datamatrix {\nusing namespace std;\n\nECB::ECB(int count, int dataCodewords) :\n    count_(count), dataCodewords_(dataCodewords) {\n}\n\nint ECB::getCount() {\n  return count_;\n}\n\nint ECB::getDataCodewords() {\n  return dataCodewords_;\n}\n\nECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks) :\n    ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks) {\n}\n\nECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2) :\n    ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks1) {\n  ecBlocks_.push_back(ecBlocks2);\n}\n\nint ECBlocks::getECCodewords() {\n  return ecCodewords_;\n}\n\nstd::vector<ECB*>& ECBlocks::getECBlocks() {\n  return ecBlocks_;\n}\n\nECBlocks::~ECBlocks() {\n  for (size_t i = 0; i < ecBlocks_.size(); i++) {\n    delete ecBlocks_[i];\n  }\n}\n\nvector<Ref<Version> > Version::VERSIONS;\nstatic int N_VERSIONS = Version::buildVersions();\n\nVersion::Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows,\n\t\tint dataRegionSizeColumns, ECBlocks* ecBlocks) : versionNumber_(versionNumber),\n\t\tsymbolSizeRows_(symbolSizeRows), symbolSizeColumns_(symbolSizeColumns),\n\t\tdataRegionSizeRows_(dataRegionSizeRows), dataRegionSizeColumns_(dataRegionSizeColumns),\n\t\tecBlocks_(ecBlocks), totalCodewords_(0) {\n    // Calculate the total number of codewords\n    int total = 0;\n    int ecCodewords = ecBlocks_->getECCodewords();\n    vector<ECB*> &ecbArray = ecBlocks_->getECBlocks();\n    for (unsigned int i = 0; i < ecbArray.size(); i++) {\n      ECB *ecBlock = ecbArray[i];\n      total += ecBlock->getCount() * (ecBlock->getDataCodewords() + ecCodewords);\n    }\n    totalCodewords_ = total;\n}\n\nVersion::~Version() {\n    delete ecBlocks_;\n}\n\nint Version::getVersionNumber() {\n  return versionNumber_;\n}\n\nint Version::getSymbolSizeRows() {\n  return symbolSizeRows_;\n}\n\nint Version::getSymbolSizeColumns() {\n  return symbolSizeColumns_;\n}\n\nint Version::getDataRegionSizeRows() {\n  return dataRegionSizeRows_;\n}\n\nint Version::getDataRegionSizeColumns() {\n  return dataRegionSizeColumns_;\n}\n\nint Version::getTotalCodewords() {\n  return totalCodewords_;\n}\n\nECBlocks* Version::getECBlocks() {\n  return ecBlocks_;\n}\n\nRef<Version> Version::getVersionForDimensions(int numRows, int numColumns) {\n    if ((numRows & 0x01) != 0 || (numColumns & 0x01) != 0) {\n      throw ReaderException(\"Number of rows and columns must be even\");\n    }\n\n    // TODO(bbrown): This is doing a linear search through the array of versions.\n    // If we interleave the rectangular versions with the square versions we could\n    // do a binary search.\n    for (int i = 0; i < N_VERSIONS; ++i){\n      Ref<Version> version(VERSIONS[i]);\n      if (version->getSymbolSizeRows() == numRows && version->getSymbolSizeColumns() == numColumns) {\n        return version;\n      }\n    }\n    throw ReaderException(\"Error version not found\");\n  }\n\n/**\n * See ISO 16022:2006 5.5.1 Table 7\n */\nint Version::buildVersions() {\n  VERSIONS.push_back(Ref<Version>(new Version(1, 10, 10, 8, 8,\n            \t\t\t\t\t  new ECBlocks(5, new ECB(1, 3)))));\n  VERSIONS.push_back(Ref<Version>(new Version(2, 12, 12, 10, 10,\n            \t\t\t\t\t  new ECBlocks(7, new ECB(1, 5)))));\n  VERSIONS.push_back(Ref<Version>(new Version(3, 14, 14, 12, 12,\n            \t\t\t\t\t  new ECBlocks(10, new ECB(1, 8)))));\n  VERSIONS.push_back(Ref<Version>(new Version(4, 16, 16, 14, 14,\n            \t\t\t\t\t  new ECBlocks(12, new ECB(1, 12)))));\n  VERSIONS.push_back(Ref<Version>(new Version(5, 18, 18, 16, 16,\n            \t\t\t\t\t  new ECBlocks(14, new ECB(1, 18)))));\n  VERSIONS.push_back(Ref<Version>(new Version(6, 20, 20, 18, 18,\n            \t\t\t\t\t  new ECBlocks(18, new ECB(1, 22)))));\n  VERSIONS.push_back(Ref<Version>(new Version(7, 22, 22, 20, 20,\n            \t\t\t\t\t  new ECBlocks(20, new ECB(1, 30)))));\n  VERSIONS.push_back(Ref<Version>(new Version(8, 24, 24, 22, 22,\n            \t\t\t\t\t  new ECBlocks(24, new ECB(1, 36)))));\n  VERSIONS.push_back(Ref<Version>(new Version(9, 26, 26, 24, 24,\n            \t\t\t\t\t  new ECBlocks(28, new ECB(1, 44)))));\n  VERSIONS.push_back(Ref<Version>(new Version(10, 32, 32, 14, 14,\n            \t\t\t\t\t  new ECBlocks(36, new ECB(1, 62)))));\n  VERSIONS.push_back(Ref<Version>(new Version(11, 36, 36, 16, 16,\n            \t\t\t\t\t  new ECBlocks(42, new ECB(1, 86)))));\n  VERSIONS.push_back(Ref<Version>(new Version(12, 40, 40, 18, 18,\n            \t\t\t\t\t  new ECBlocks(48, new ECB(1, 114)))));\n  VERSIONS.push_back(Ref<Version>(new Version(13, 44, 44, 20, 20,\n            \t\t\t\t\t  new ECBlocks(56, new ECB(1, 144)))));\n  VERSIONS.push_back(Ref<Version>(new Version(14, 48, 48, 22, 22,\n            \t\t\t\t\t  new ECBlocks(68, new ECB(1, 174)))));\n  VERSIONS.push_back(Ref<Version>(new Version(15, 52, 52, 24, 24,\n            \t\t\t\t\t  new ECBlocks(42, new ECB(2, 102)))));\n  VERSIONS.push_back(Ref<Version>(new Version(16, 64, 64, 14, 14,\n            \t\t\t\t\t  new ECBlocks(56, new ECB(2, 140)))));\n  VERSIONS.push_back(Ref<Version>(new Version(17, 72, 72, 16, 16,\n            \t\t\t\t\t  new ECBlocks(36, new ECB(4, 92)))));\n  VERSIONS.push_back(Ref<Version>(new  Version(18, 80, 80, 18, 18,\n            \t\t\t\t\t  new ECBlocks(48, new ECB(4, 114)))));\n  VERSIONS.push_back(Ref<Version>(new Version(19, 88, 88, 20, 20,\n            \t\t\t\t\t  new ECBlocks(56, new ECB(4, 144)))));\n  VERSIONS.push_back(Ref<Version>(new Version(20, 96, 96, 22, 22,\n            \t\t\t\t\t  new ECBlocks(68, new ECB(4, 174)))));\n  VERSIONS.push_back(Ref<Version>(new Version(21, 104, 104, 24, 24,\n            \t\t\t\t\t  new ECBlocks(56, new ECB(6, 136)))));\n  VERSIONS.push_back(Ref<Version>(new Version(22, 120, 120, 18, 18,\n            \t\t\t\t\t  new ECBlocks(68, new ECB(6, 175)))));\n  VERSIONS.push_back(Ref<Version>(new Version(23, 132, 132, 20, 20,\n            \t\t\t\t\t  new ECBlocks(62, new ECB(8, 163)))));\n  VERSIONS.push_back(Ref<Version>(new Version(24, 144, 144, 22, 22,\n            \t\t\t\t\t  new ECBlocks(62, new ECB(8, 156), new ECB(2, 155)))));\n  VERSIONS.push_back(Ref<Version>(new Version(25, 8, 18, 6, 16,\n            \t\t\t\t\t  new ECBlocks(7, new ECB(1, 5)))));\n  VERSIONS.push_back(Ref<Version>(new Version(26, 8, 32, 6, 14,\n            \t\t\t\t\t  new ECBlocks(11, new ECB(1, 10)))));\n  VERSIONS.push_back(Ref<Version>(new Version(27, 12, 26, 10, 24,\n\t\t\t\t\t              new ECBlocks(14, new ECB(1, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(28, 12, 36, 10, 16,\n\t\t\t\t\t              new ECBlocks(18, new ECB(1, 22)))));\n  VERSIONS.push_back(Ref<Version>(new Version(29, 16, 36, 14, 16,\n\t\t\t\t\t              new ECBlocks(24, new ECB(1, 32)))));\n  VERSIONS.push_back(Ref<Version>(new Version(30, 16, 48, 14, 22,\n\t\t\t\t\t              new ECBlocks(28, new ECB(1, 49)))));\n  return VERSIONS.size();\n}\n}\n}\n\n// file: zxing/datamatrix/decoder/BitMatrixParser.cpp\n\n/*\n *  BitMatrixParser.cpp\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/datamatrix/decoder/BitMatrixParser.h>\n// #include <zxing/common/IllegalArgumentException.h>\n\n// #include <iostream>\n\nnamespace zxing {\nnamespace datamatrix {\n\nint BitMatrixParser::copyBit(size_t x, size_t y, int versionBits) {\n  return bitMatrix_->get(x, y) ? (versionBits << 1) | 0x1 : versionBits << 1;\n}\n\nBitMatrixParser::BitMatrixParser(Ref<BitMatrix> bitMatrix) : bitMatrix_(NULL),\n                                                             parsedVersion_(NULL),\n                                                             readBitMatrix_(NULL) {\n  size_t dimension = bitMatrix->getDimension();\n  if (dimension < 8 || dimension > 144 || (dimension & 0x01) != 0)\n    throw ReaderException(\"Dimension must be even, > 8 < 144\");\n\n  parsedVersion_ = readVersion(bitMatrix);\n  bitMatrix_ = extractDataRegion(bitMatrix);\n  readBitMatrix_ = new BitMatrix(bitMatrix_->getWidth(), bitMatrix_->getHeight());\n}\n\nRef<Version> BitMatrixParser::readVersion(Ref<BitMatrix> bitMatrix) {\n  if (parsedVersion_ != 0) {\n    return parsedVersion_;\n  }\n\n  int numRows = bitMatrix->getHeight();//getDimension();\n  int numColumns = bitMatrix->getWidth();//numRows;\n\n  Ref<Version> version = parsedVersion_->getVersionForDimensions(numRows, numColumns);\n  if (version != 0) {\n    return version;\n  }\n  throw ReaderException(\"Couldn't decode version\");\n}\n\nArrayRef<unsigned char> BitMatrixParser::readCodewords() {\n  \tArrayRef<unsigned char> result(parsedVersion_->getTotalCodewords());\n  \tint resultOffset = 0;\n    int row = 4;\n    int column = 0;\n\n    int numRows = bitMatrix_->getHeight();\n    int numColumns = bitMatrix_->getWidth();\n\n    bool corner1Read = false;\n    bool corner2Read = false;\n    bool corner3Read = false;\n    bool corner4Read = false;\n\n    // Read all of the codewords\n    do {\n      // Check the four corner cases\n      if ((row == numRows) && (column == 0) && !corner1Read) {\n        result[resultOffset++] = (unsigned char) readCorner1(numRows, numColumns);\n        row -= 2;\n        column +=2;\n        corner1Read = true;\n      } else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) {\n        result[resultOffset++] = (unsigned char) readCorner2(numRows, numColumns);\n        row -= 2;\n        column +=2;\n        corner2Read = true;\n      } else if ((row == numRows+4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) {\n        result[resultOffset++] = (unsigned char) readCorner3(numRows, numColumns);\n        row -= 2;\n        column +=2;\n        corner3Read = true;\n      } else if ((row == numRows-2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) {\n        result[resultOffset++] = (unsigned char) readCorner4(numRows, numColumns);\n        row -= 2;\n        column +=2;\n        corner4Read = true;\n      } else {\n        // Sweep upward diagonally to the right\n        do {\n          if ((row < numRows) && (column >= 0) && !readBitMatrix_->get(column, row)) {\n            result[resultOffset++] = (unsigned char) readUtah(row, column, numRows, numColumns);\n          }\n          row -= 2;\n          column +=2;\n        } while ((row >= 0) && (column < numColumns));\n        row += 1;\n        column +=3;\n\n        // Sweep downward diagonally to the left\n        do {\n          if ((row >= 0) && (column < numColumns) && !readBitMatrix_->get(column, row)) {\n             result[resultOffset++] = (unsigned char) readUtah(row, column, numRows, numColumns);\n          }\n          row += 2;\n          column -=2;\n        } while ((row < numRows) && (column >= 0));\n        row += 3;\n        column +=1;\n      }\n    } while ((row < numRows) || (column < numColumns));\n\n    if (resultOffset != parsedVersion_->getTotalCodewords()) {\n      throw ReaderException(\"Did not read all codewords\");\n    }\n    return result;\n}\n\nbool BitMatrixParser::readModule(int row, int column, int numRows, int numColumns) {\n    // Adjust the row and column indices based on boundary wrapping\n    if (row < 0) {\n      row += numRows;\n      column += 4 - ((numRows + 4) & 0x07);\n    }\n    if (column < 0) {\n      column += numColumns;\n      row += 4 - ((numColumns + 4) & 0x07);\n    }\n    readBitMatrix_->set(column, row);\n    return bitMatrix_->get(column, row);\n  }\n\nint BitMatrixParser::readUtah(int row, int column, int numRows, int numColumns) {\n    int currentByte = 0;\n    if (readModule(row - 2, column - 2, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(row - 2, column - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(row - 1, column - 2, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(row - 1, column - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(row - 1, column, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(row, column - 2, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(row, column - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(row, column, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    return currentByte;\n  }\n\nint BitMatrixParser::readCorner1(int numRows, int numColumns) {\n    int currentByte = 0;\n    if (readModule(numRows - 1, 0, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(numRows - 1, 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(numRows - 1, 2, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(0, numColumns - 2, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(0, numColumns - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(1, numColumns - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(2, numColumns - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(3, numColumns - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    return currentByte;\n  }\n\nint BitMatrixParser::readCorner2(int numRows, int numColumns) {\n    int currentByte = 0;\n    if (readModule(numRows - 3, 0, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(numRows - 2, 0, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(numRows - 1, 0, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(0, numColumns - 4, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(0, numColumns - 3, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(0, numColumns - 2, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(0, numColumns - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(1, numColumns - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    return currentByte;\n  }\n\nint BitMatrixParser::readCorner3(int numRows, int numColumns) {\n    int currentByte = 0;\n    if (readModule(numRows - 1, 0, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(numRows - 1, numColumns - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(0, numColumns - 3, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(0, numColumns - 2, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(0, numColumns - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(1, numColumns - 3, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(1, numColumns - 2, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(1, numColumns - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    return currentByte;\n  }\n\nint BitMatrixParser::readCorner4(int numRows, int numColumns) {\n    int currentByte = 0;\n    if (readModule(numRows - 3, 0, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(numRows - 2, 0, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(numRows - 1, 0, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(0, numColumns - 2, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(0, numColumns - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(1, numColumns - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(2, numColumns - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    currentByte <<= 1;\n    if (readModule(3, numColumns - 1, numRows, numColumns)) {\n      currentByte |= 1;\n    }\n    return currentByte;\n  }\n\nRef<BitMatrix> BitMatrixParser::extractDataRegion(Ref<BitMatrix> bitMatrix) {\n    int symbolSizeRows = parsedVersion_->getSymbolSizeRows();\n    int symbolSizeColumns = parsedVersion_->getSymbolSizeColumns();\n\n    if ((int)bitMatrix->getHeight() != symbolSizeRows) {\n      throw IllegalArgumentException(\"Dimension of bitMatrix must match the version size\");\n    }\n\n    int dataRegionSizeRows = parsedVersion_->getDataRegionSizeRows();\n    int dataRegionSizeColumns = parsedVersion_->getDataRegionSizeColumns();\n\n    int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows;\n    int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns;\n\n    int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows;\n    int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;\n\n    Ref<BitMatrix> bitMatrixWithoutAlignment(new BitMatrix(sizeDataRegionColumn, sizeDataRegionRow));\n    for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) {\n      int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows;\n      for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) {\n        int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns;\n        for (int i = 0; i < dataRegionSizeRows; ++i) {\n          int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i;\n          int writeRowOffset = dataRegionRowOffset + i;\n          for (int j = 0; j < dataRegionSizeColumns; ++j) {\n            int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;\n            if (bitMatrix->get(readColumnOffset, readRowOffset)) {\n              int writeColumnOffset = dataRegionColumnOffset + j;\n              bitMatrixWithoutAlignment->set(writeColumnOffset, writeRowOffset);\n            }\n          }\n        }\n      }\n    }\n    return bitMatrixWithoutAlignment;\n}\n\n}\n}\n\n// file: zxing/datamatrix/decoder/DataBlock.cpp\n\n/*\n *  DataBlock.cpp\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/datamatrix/decoder/DataBlock.h>\n// #include <zxing/common/IllegalArgumentException.h>\n\nnamespace zxing {\nnamespace datamatrix {\n\nusing namespace std;\n\nDataBlock::DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords) :\n    numDataCodewords_(numDataCodewords), codewords_(codewords) {\n}\n\nint DataBlock::getNumDataCodewords() {\n  return numDataCodewords_;\n}\n\nArrayRef<unsigned char> DataBlock::getCodewords() {\n  return codewords_;\n}\n\nstd::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version) {\n  // Figure out the number and size of data blocks used by this version and\n  // error correction level\n  ECBlocks* ecBlocks = version->getECBlocks();\n\n  // First count the total number of data blocks\n  int totalBlocks = 0;\n  vector<ECB*> ecBlockArray = ecBlocks->getECBlocks();\n  for (size_t i = 0; i < ecBlockArray.size(); i++) {\n    totalBlocks += ecBlockArray[i]->getCount();\n  }\n\n  // Now establish DataBlocks of the appropriate size and number of data codewords\n  std::vector<Ref<DataBlock> > result(totalBlocks);\n  int numResultBlocks = 0;\n  for (size_t j = 0; j < ecBlockArray.size(); j++) {\n    ECB *ecBlock = ecBlockArray[j];\n    for (int i = 0; i < ecBlock->getCount(); i++) {\n      int numDataCodewords = ecBlock->getDataCodewords();\n      int numBlockCodewords = ecBlocks->getECCodewords() + numDataCodewords;\n      ArrayRef<unsigned char> buffer(numBlockCodewords);\n      Ref<DataBlock> blockRef(new DataBlock(numDataCodewords, buffer));\n      result[numResultBlocks++] = blockRef;\n    }\n  }\n\n  // All blocks have the same amount of data, except that the last n\n  // (where n may be 0) have 1 more byte. Figure out where these start.\n  int shorterBlocksTotalCodewords = result[0]->codewords_.size();\n  int longerBlocksStartAt = result.size() - 1;\n  while (longerBlocksStartAt >= 0) {\n    int numCodewords = result[longerBlocksStartAt]->codewords_.size();\n    if (numCodewords == shorterBlocksTotalCodewords) {\n      break;\n    }\n    if (numCodewords != shorterBlocksTotalCodewords + 1) {\n      throw IllegalArgumentException(\"Data block sizes differ by more than 1\");\n    }\n    longerBlocksStartAt--;\n  }\n  longerBlocksStartAt++;\n\n  int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks->getECCodewords();\n  // The last elements of result may be 1 element longer;\n  // first fill out as many elements as all of them have\n  int rawCodewordsOffset = 0;\n  for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {\n    for (int j = 0; j < numResultBlocks; j++) {\n      result[j]->codewords_[i] = rawCodewords[rawCodewordsOffset++];\n    }\n  }\n  // Fill out the last data block in the longer ones\n  for (int j = longerBlocksStartAt; j < numResultBlocks; j++) {\n    result[j]->codewords_[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];\n  }\n  // Now add in error correction blocks\n  int max = result[0]->codewords_.size();\n  for (int i = shorterBlocksNumDataCodewords; i < max; i++) {\n    for (int j = 0; j < numResultBlocks; j++) {\n      int iOffset = j < longerBlocksStartAt ? i : i + 1;\n      result[j]->codewords_[iOffset] = rawCodewords[rawCodewordsOffset++];\n    }\n  }\n\n  if ((size_t)rawCodewordsOffset != rawCodewords.size()) {\n    throw IllegalArgumentException(\"rawCodewordsOffset != rawCodewords.length\");\n  }\n\n  return result;\n}\n\n}\n}\n\n// file: zxing/datamatrix/decoder/DecodedBitStreamParser.cpp\n\n/*\n *  DecodedBitStreamParser.cpp\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/FormatException.h>\n// #include <zxing/datamatrix/decoder/DecodedBitStreamParser.h>\n// #include <iostream>\n// #include <zxing/common/DecoderResult.h>\n\nnamespace zxing {\nnamespace datamatrix {\n\nusing namespace std;\n\nconst char DecodedBitStreamParser::C40_BASIC_SET_CHARS[] = {\n    '*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',\n    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',\n    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'\n};\n\nconst char DecodedBitStreamParser::C40_SHIFT2_SET_CHARS[] = {\n    '!', '\"', '#', '$', '%', '&', '\\'', '(', ')', '*', '+', ',', '-', '.',\n    '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\\\', ']', '^', '_'\n};\n\nconst char DecodedBitStreamParser::TEXT_BASIC_SET_CHARS[] = {\n    '*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',\n    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',\n    'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'\n};\n\nconst char DecodedBitStreamParser::TEXT_SHIFT3_SET_CHARS[] = {\n    '\\'', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',\n    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (char) 127\n};\n\nRef<DecoderResult> DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes) {\n  Ref<BitSource> bits(new BitSource(bytes));\n  ostringstream result;\n  ostringstream resultTrailer;\n  vector<unsigned char> byteSegments;\n  int mode = ASCII_ENCODE;\n  do {\n    if (mode == ASCII_ENCODE) {\n      mode = decodeAsciiSegment(bits, result, resultTrailer);\n    } else {\n      switch (mode) {\n        case C40_ENCODE:\n          decodeC40Segment(bits, result);\n          break;\n        case TEXT_ENCODE:\n          decodeTextSegment(bits, result);\n          break;\n        case ANSIX12_ENCODE:\n          decodeAnsiX12Segment(bits, result);\n          break;\n        case EDIFACT_ENCODE:\n          decodeEdifactSegment(bits, result);\n          break;\n        case BASE256_ENCODE:\n          decodeBase256Segment(bits, result, byteSegments);\n          break;\n        default:\n          throw FormatException(\"Unsupported mode indicator\");\n      }\n      mode = ASCII_ENCODE;\n    }\n  } while (mode != PAD_ENCODE && bits->available() > 0);\n\n  if (resultTrailer.str().size() > 0) {\n    result << resultTrailer.str();\n  }\n  ArrayRef<unsigned char> rawBytes(bytes);\n  Ref<String> text(new String(result.str()));\n  return Ref<DecoderResult>(new DecoderResult(rawBytes, text));\n}\n\nint DecodedBitStreamParser::decodeAsciiSegment(Ref<BitSource> bits, ostringstream & result,\n  ostringstream & resultTrailer) {\n  bool upperShift = false;\n  do {\n    int oneByte = bits->readBits(8);\n    if (oneByte == 0) {\n      throw FormatException(\"Not enough bits to decode\");\n    } else if (oneByte <= 128) {  // ASCII data (ASCII value + 1)\n      oneByte = upperShift ? (oneByte + 128) : oneByte;\n      // upperShift = false;\n      result << (char) (oneByte - 1);\n      return ASCII_ENCODE;\n    } else if (oneByte == 129) {  // Pad\n      return PAD_ENCODE;\n    } else if (oneByte <= 229) {  // 2-digit data 00-99 (Numeric Value + 130)\n      int value = oneByte - 130;\n      if (value < 10) { // padd with '0' for single digit values\n        result << '0';\n      }\n      result << value;\n    } else if (oneByte == 230) {  // Latch to C40 encodation\n      return C40_ENCODE;\n    } else if (oneByte == 231) {  // Latch to Base 256 encodation\n      return BASE256_ENCODE;\n    } else if (oneByte == 232) {  // FNC1\n      result << ((char) 29); // translate as ASCII 29\n    } else if (oneByte == 233 || oneByte == 234) {\n      // Structured Append, Reader Programming\n      // Ignore these symbols for now\n      // throw FormatException.getInstance();\n    } else if (oneByte == 235) {  // Upper Shift (shift to Extended ASCII)\n      upperShift = true;\n    } else if (oneByte == 236) {  // 05 Macro\n        result << (\"[)>RS05GS\");\n        resultTrailer << (\"RSEOT\");\n    } else if (oneByte == 237) {  // 06 Macro\n      result << (\"[)>RS06GS\");\n      resultTrailer <<  (\"RSEOT\");\n    } else if (oneByte == 238) {  // Latch to ANSI X12 encodation\n      return ANSIX12_ENCODE;\n    } else if (oneByte == 239) {  // Latch to Text encodation\n      return TEXT_ENCODE;\n    } else if (oneByte == 240) {  // Latch to EDIFACT encodation\n      return EDIFACT_ENCODE;\n    } else if (oneByte == 241) {  // ECI Character\n      // TODO(bbrown): I think we need to support ECI\n      // throw FormatException.getInstance();\n      // Ignore this symbol for now\n    } else if (oneByte >= 242) { // Not to be used in ASCII encodation\n      // ... but work around encoders that end with 254, latch back to ASCII\n      if (oneByte == 254 && bits->available() == 0) {\n        // Ignore\n      } else {\n        throw FormatException(\"Not to be used in ASCII encodation\");\n      }\n    }\n  } while (bits->available() > 0);\n  return ASCII_ENCODE;\n}\n\nvoid DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream & result) {\n  // Three C40 values are encoded in a 16-bit value as\n  // (1600 * C1) + (40 * C2) + C3 + 1\n  // TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time\n  bool upperShift = false;\n\n  int* cValues = new int[3];\n  int shift = 0;\n  do {\n    // If there is only one byte left then it will be encoded as ASCII\n    if (bits->available() == 8) {\n      return;\n    }\n    int firstByte = bits->readBits(8);\n    if (firstByte == 254) {  // Unlatch codeword\n      return;\n    }\n\n    parseTwoBytes(firstByte, bits->readBits(8), cValues);\n\n    for (int i = 0; i < 3; i++) {\n      int cValue = cValues[i];\n      switch (shift) {\n        case 0:\n          if (cValue < 3) {\n            shift = cValue + 1;\n          } else {\n            if (upperShift) {\n              result << (char) (C40_BASIC_SET_CHARS[cValue] + 128);\n              upperShift = false;\n            } else {\n              result << C40_BASIC_SET_CHARS[cValue];\n            }\n          }\n          break;\n        case 1:\n          if (upperShift) {\n            result << (char) (cValue + 128);\n            upperShift = false;\n          } else {\n            result << (char) cValue;\n          }\n          shift = 0;\n          break;\n        case 2:\n          if (cValue < 27) {\n            if (upperShift) {\n              result << (char) (C40_SHIFT2_SET_CHARS[cValue] + 128);\n              upperShift = false;\n            } else {\n              result << C40_SHIFT2_SET_CHARS[cValue];\n            }\n          } else if (cValue == 27) {  // FNC1\n            result << ((char) 29); // translate as ASCII 29\n          } else if (cValue == 30) {  // Upper Shift\n            upperShift = true;\n          } else {\n            throw FormatException(\"decodeC40Segment: Upper Shift\");\n          }\n          shift = 0;\n          break;\n        case 3:\n          if (upperShift) {\n            result << (char) (cValue + 224);\n            upperShift = false;\n          } else {\n            result << (char) (cValue + 96);\n          }\n          shift = 0;\n          break;\n        default:\n          throw FormatException(\"decodeC40Segment: no case\");\n      }\n    }\n  } while (bits->available() > 0);\n}\n\nvoid DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstream & result) {\n  // Three Text values are encoded in a 16-bit value as\n  // (1600 * C1) + (40 * C2) + C3 + 1\n  // TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time\n  bool upperShift = false;\n\n  int* cValues = new int[3];\n  int shift = 0;\n  do {\n    // If there is only one byte left then it will be encoded as ASCII\n    if (bits->available() == 8) {\n      return;\n    }\n    int firstByte = bits->readBits(8);\n    if (firstByte == 254) {  // Unlatch codeword\n      return;\n    }\n\n    parseTwoBytes(firstByte, bits->readBits(8), cValues);\n\n    for (int i = 0; i < 3; i++) {\n      int cValue = cValues[i];\n      switch (shift) {\n        case 0:\n          if (cValue < 3) {\n            shift = cValue + 1;\n          } else {\n            if (upperShift) {\n              result << (char) (TEXT_BASIC_SET_CHARS[cValue] + 128);\n              upperShift = false;\n            } else {\n              result << (TEXT_BASIC_SET_CHARS[cValue]);\n            }\n          }\n          break;\n        case 1:\n          if (upperShift) {\n            result << (char) (cValue + 128);\n            upperShift = false;\n          } else {\n            result << (char) (cValue);\n          }\n          shift = 0;\n          break;\n        case 2:\n          // Shift 2 for Text is the same encoding as C40\n          if (cValue < 27) {\n            if (upperShift) {\n              result << (char) (C40_SHIFT2_SET_CHARS[cValue] + 128);\n              upperShift = false;\n            } else {\n              result << (C40_SHIFT2_SET_CHARS[cValue]);\n            }\n          } else if (cValue == 27) {  // FNC1\n            result << ((char) 29); // translate as ASCII 29\n          } else if (cValue == 30) {  // Upper Shift\n            upperShift = true;\n          } else {\n            throw FormatException(\"decodeTextSegment: Upper Shift\");\n          }\n          shift = 0;\n          break;\n        case 3:\n          if (upperShift) {\n            result << (char) (TEXT_SHIFT3_SET_CHARS[cValue] + 128);\n            upperShift = false;\n          } else {\n            result << (TEXT_SHIFT3_SET_CHARS[cValue]);\n          }\n          shift = 0;\n          break;\n        default:\n          throw FormatException(\"decodeTextSegment: no case\");\n      }\n    }\n  } while (bits->available() > 0);\n}\n\nvoid DecodedBitStreamParser::decodeAnsiX12Segment(Ref<BitSource> bits, ostringstream & result) {\n  // Three ANSI X12 values are encoded in a 16-bit value as\n  // (1600 * C1) + (40 * C2) + C3 + 1\n\n  int* cValues = new int[3];\n  do {\n    // If there is only one byte left then it will be encoded as ASCII\n    if (bits->available() == 8) {\n      return;\n    }\n    int firstByte = bits->readBits(8);\n    if (firstByte == 254) {  // Unlatch codeword\n      return;\n    }\n\n    parseTwoBytes(firstByte, bits->readBits(8), cValues);\n\n    for (int i = 0; i < 3; i++) {\n      int cValue = cValues[i];\n      if (cValue == 0) {  // X12 segment terminator <CR>\n        result << '\\r';\n      } else if (cValue == 1) {  // X12 segment separator *\n        result << '*';\n      } else if (cValue == 2) {  // X12 sub-element separator >\n        result << '>';\n      } else if (cValue == 3) {  // space\n        result << ' ';\n      } else if (cValue < 14) {  // 0 - 9\n        result << (char) (cValue + 44);\n      } else if (cValue < 40) {  // A - Z\n        result << (char) (cValue + 51);\n      } else {\n        throw FormatException(\"decodeAnsiX12Segment: no case\");\n      }\n    }\n  } while (bits->available() > 0);\n}\n\nvoid DecodedBitStreamParser::parseTwoBytes(int firstByte, int secondByte, int*& result) {\n  int fullBitValue = (firstByte << 8) + secondByte - 1;\n  int temp = fullBitValue / 1600;\n  result[0] = temp;\n  fullBitValue -= temp * 1600;\n  temp = fullBitValue / 40;\n  result[1] = temp;\n  result[2] = fullBitValue - temp * 40;\n}\n\nvoid DecodedBitStreamParser::decodeEdifactSegment(Ref<BitSource> bits, ostringstream & result) {\n  bool unlatch = false;\n  do {\n    // If there is only two or less bytes left then it will be encoded as ASCII\n    if (bits->available() <= 16) {\n      return;\n    }\n\n    for (int i = 0; i < 4; i++) {\n      int edifactValue = bits->readBits(6);\n\n      // Check for the unlatch character\n      if (edifactValue == 0x2B67) {  // 011111\n        unlatch = true;\n        // If we encounter the unlatch code then continue reading because the Codeword triple\n        // is padded with 0's\n      }\n\n      if (!unlatch) {\n        if ((edifactValue & 0x20) == 0) {  // no 1 in the leading (6th) bit\n          edifactValue |= 0x40;  // Add a leading 01 to the 6 bit binary value\n        }\n        result << (char)(edifactValue);\n      }\n    }\n  } while (!unlatch && bits->available() > 0);\n}\n\nvoid DecodedBitStreamParser::decodeBase256Segment(Ref<BitSource> bits, ostringstream& result, vector<unsigned char> byteSegments) {\n  // Figure out how long the Base 256 Segment is.\n  int codewordPosition = 1 + bits->getByteOffset(); // position is 1-indexed\n  int d1 = unrandomize255State(bits->readBits(8), codewordPosition++);\n  int count;\n  if (d1 == 0) {  // Read the remainder of the symbol\n    count = bits->available() / 8;\n  } else if (d1 < 250) {\n    count = d1;\n  } else {\n    count = 250 * (d1 - 249) + unrandomize255State(bits->readBits(8), codewordPosition++);\n  }\n\n  // We're seeing NegativeArraySizeException errors from users.\n  if (count < 0) {\n    throw FormatException(\"NegativeArraySizeException\");\n  }\n\n  unsigned char* bytes = new unsigned char[count];\n  for (int i = 0; i < count; i++) {\n    // Have seen this particular error in the wild, such as at\n    // http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2\n    if (bits->available() < 8) {\n      throw FormatException(\"byteSegments\");\n    }\n    bytes[i] = unrandomize255State(bits->readBits(8), codewordPosition++);\n    byteSegments.push_back(bytes[i]);\n    result << (char)bytes[i];\n  }\n}\n}\n}\n\n\n// file: zxing/datamatrix/decoder/Decoder.cpp\n\n/*\n *  Decoder.cpp\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/datamatrix/decoder/Decoder.h>\n// #include <zxing/datamatrix/decoder/BitMatrixParser.h>\n// #include <zxing/datamatrix/decoder/DataBlock.h>\n// #include <zxing/datamatrix/decoder/DecodedBitStreamParser.h>\n// #include <zxing/datamatrix/Version.h>\n// #include <zxing/ReaderException.h>\n// #include <zxing/common/reedsolomon/ReedSolomonException.h>\n\nnamespace zxing {\nnamespace datamatrix {\n\nusing namespace std;\n\nDecoder::Decoder() :\n    rsDecoder_(GF256::DATA_MATRIX_FIELD) {\n}\n\n\nvoid Decoder::correctErrors(ArrayRef<unsigned char> codewordBytes, int numDataCodewords) {\n  int numCodewords = codewordBytes->size();\n  ArrayRef<int> codewordInts(numCodewords);\n  for (int i = 0; i < numCodewords; i++) {\n    codewordInts[i] = codewordBytes[i] & 0xff;\n  }\n  int numECCodewords = numCodewords - numDataCodewords;\n  try {\n    rsDecoder_.decode(codewordInts, numECCodewords);\n  } catch (ReedSolomonException const& ex) {\n    ReaderException rex(ex.what());\n    throw rex;\n  }\n  // Copy back into array of bytes -- only need to worry about the bytes that were data\n  // We don't care about errors in the error-correction codewords\n  for (int i = 0; i < numDataCodewords; i++) {\n    codewordBytes[i] = (unsigned char)codewordInts[i];\n  }\n}\n\nRef<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {\n  // Construct a parser and read version, error-correction level\n  BitMatrixParser parser(bits);\n  Version *version = parser.readVersion(bits);\n\n  // Read codewords\n  ArrayRef<unsigned char> codewords(parser.readCodewords());\n  // Separate into data blocks\n  std::vector<Ref<DataBlock> > dataBlocks = DataBlock::getDataBlocks(codewords, version);\n\n  int dataBlocksCount = dataBlocks.size();\n\n  // Count total number of data bytes\n  int totalBytes = 0;\n  for (int i = 0; i < dataBlocksCount; i++) {\n    totalBytes += dataBlocks[i]->getNumDataCodewords();\n  }\n  ArrayRef<unsigned char> resultBytes(totalBytes);\n\n  // Error-correct and copy data blocks together into a stream of bytes\n  for (int j = 0; j < dataBlocksCount; j++) {\n    Ref<DataBlock> dataBlock(dataBlocks[j]);\n    ArrayRef<unsigned char> codewordBytes = dataBlock->getCodewords();\n    int numDataCodewords = dataBlock->getNumDataCodewords();\n    correctErrors(codewordBytes, numDataCodewords);\n    for (int i = 0; i < numDataCodewords; i++) {\n      // De-interlace data blocks.\n      resultBytes[i * dataBlocksCount + j] = codewordBytes[i];\n    }\n  }\n  // Decode the contents of that stream of bytes\n  DecodedBitStreamParser decodedBSParser;\n  return Ref<DecoderResult> (decodedBSParser.decode(resultBytes));\n}\n}\n}\n\n// file: zxing/datamatrix/detector/CornerPoint.cpp\n\n/*\n *  CornerPoint.cpp\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/datamatrix/detector/CornerPoint.h>\n\n\nnamespace zxing {\n\tnamespace datamatrix {\n\n\t\tusing namespace std;\n\n\t\tCornerPoint::CornerPoint(float posX, float posY) :\n\t\t  ResultPoint(posX,posY), counter_(0) {\n\t\t}\n\n\t\tint CornerPoint::getCount() const {\n\t\t\treturn counter_;\n\t\t}\n\n\t\tvoid CornerPoint::incrementCount() {\n\t\t\tcounter_++;\n\t\t}\n\n\t\tbool CornerPoint::equals(Ref<CornerPoint> other) const {\n\t\t\treturn posX_ == other->getX() && posY_ == other->getY();\n\t\t}\n\n\t}\n}\n\n// file: zxing/datamatrix/detector/Detector.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Detector.cpp\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ResultPoint.h>\n// #include <zxing/common/GridSampler.h>\n// #include <zxing/datamatrix/detector/Detector.h>\n// #include <cmath>\n// #include <sstream>\n// #include <cstdlib>\n\nnamespace zxing {\nnamespace datamatrix {\n\nusing namespace std;\n\nResultPointsAndTransitions::ResultPointsAndTransitions() {\n  Ref<ResultPoint> ref(new ResultPoint(0, 0));\n  from_ = ref;\n  to_ = ref;\n  transitions_ = 0;\n}\n\nResultPointsAndTransitions::ResultPointsAndTransitions(Ref<ResultPoint> from, Ref<ResultPoint> to,\n    int transitions)\n    : to_(to), from_(from), transitions_(transitions) {\n}\n\nRef<ResultPoint> ResultPointsAndTransitions::getFrom() {\n  return from_;\n}\n\nRef<ResultPoint> ResultPointsAndTransitions::getTo() {\n  return to_;\n}\n\nint ResultPointsAndTransitions::getTransitions() {\n  return transitions_;\n}\n\nDetector::Detector(Ref<BitMatrix> image)\n    : image_(image) {\n}\n\nRef<BitMatrix> Detector::getImage() {\n  return image_;\n}\n\nRef<DetectorResult> Detector::detect() {\n  Ref<WhiteRectangleDetector> rectangleDetector_(new WhiteRectangleDetector(image_));\n  std::vector<Ref<ResultPoint> > ResultPoints = rectangleDetector_->detect();\n  Ref<ResultPoint> pointA = ResultPoints[0];\n  Ref<ResultPoint> pointB = ResultPoints[1];\n  Ref<ResultPoint> pointC = ResultPoints[2];\n  Ref<ResultPoint> pointD = ResultPoints[3];\n\n  // Point A and D are across the diagonal from one another,\n  // as are B and C. Figure out which are the solid black lines\n  // by counting transitions\n  std::vector<Ref<ResultPointsAndTransitions> > transitions(4);\n  transitions[0].reset(transitionsBetween(pointA, pointB));\n  transitions[1].reset(transitionsBetween(pointA, pointC));\n  transitions[2].reset(transitionsBetween(pointB, pointD));\n  transitions[3].reset(transitionsBetween(pointC, pointD));\n  insertionSort(transitions);\n\n  // Sort by number of transitions. First two will be the two solid sides; last two\n  // will be the two alternating black/white sides\n  Ref<ResultPointsAndTransitions> lSideOne(transitions[0]);\n  Ref<ResultPointsAndTransitions> lSideTwo(transitions[1]);\n\n  // Figure out which point is their intersection by tallying up the number of times we see the\n  // endpoints in the four endpoints. One will show up twice.\n  Ref<ResultPoint> maybeTopLeft;\n  Ref<ResultPoint> bottomLeft;\n  Ref<ResultPoint> maybeBottomRight;\n  if (lSideOne->getFrom()->equals(lSideOne->getTo())) {\n    bottomLeft = lSideOne->getFrom();\n    maybeTopLeft = lSideTwo->getFrom();\n    maybeBottomRight = lSideTwo->getTo();\n  } else if (lSideOne->getFrom()->equals(lSideTwo->getFrom())) {\n    bottomLeft = lSideOne->getFrom();\n    maybeTopLeft = lSideOne->getTo();\n    maybeBottomRight = lSideTwo->getTo();\n  } else if (lSideOne->getFrom()->equals(lSideTwo->getTo())) {\n    bottomLeft = lSideOne->getFrom();\n    maybeTopLeft = lSideOne->getTo();\n    maybeBottomRight = lSideTwo->getFrom();\n  } else if (lSideOne->getTo()->equals(lSideTwo->getFrom())) {\n    bottomLeft = lSideOne->getTo();\n    maybeTopLeft = lSideOne->getFrom();\n    maybeBottomRight = lSideTwo->getTo();\n  } else if (lSideOne->getTo()->equals(lSideTwo->getTo())) {\n    bottomLeft = lSideOne->getTo();\n    maybeTopLeft = lSideOne->getFrom();\n    maybeBottomRight = lSideTwo->getFrom();\n  } else {\n    bottomLeft = lSideTwo->getFrom();\n    maybeTopLeft = lSideOne->getTo();\n    maybeBottomRight = lSideOne->getFrom();\n  }\n\n  // Bottom left is correct but top left and bottom right might be switched\n  std::vector<Ref<ResultPoint> > corners(3);\n  corners[0].reset(maybeTopLeft);\n  corners[1].reset(bottomLeft);\n  corners[2].reset(maybeBottomRight);\n\n  // Use the dot product trick to sort them out\n  ResultPoint::orderBestPatterns(corners);\n\n  // Now we know which is which:\n  Ref<ResultPoint> bottomRight(corners[0]);\n  bottomLeft = corners[1];\n  Ref<ResultPoint> topLeft(corners[2]);\n\n  // Which point didn't we find in relation to the \"L\" sides? that's the top right corner\n  Ref<ResultPoint> topRight;\n  if (!(pointA->equals(bottomRight) || pointA->equals(bottomLeft) || pointA->equals(topLeft))) {\n    topRight = pointA;\n  } else if (!(pointB->equals(bottomRight) || pointB->equals(bottomLeft)\n      || pointB->equals(topLeft))) {\n    topRight = pointB;\n  } else if (!(pointC->equals(bottomRight) || pointC->equals(bottomLeft)\n      || pointC->equals(topLeft))) {\n    topRight = pointC;\n  } else {\n    topRight = pointD;\n  }\n\n  // Next determine the dimension by tracing along the top or right side and counting black/white\n  // transitions. Since we start inside a black module, we should see a number of transitions\n  // equal to 1 less than the code dimension. Well, actually 2 less, because we are going to\n  // end on a black module:\n\n  // The top right point is actually the corner of a module, which is one of the two black modules\n  // adjacent to the white module at the top right. Tracing to that corner from either the top left\n  // or bottom right should work here.\n\n  int dimensionTop = transitionsBetween(topLeft, topRight)->getTransitions();\n  int dimensionRight = transitionsBetween(bottomRight, topRight)->getTransitions();\n\n  //dimensionTop++;\n  if ((dimensionTop & 0x01) == 1) {\n    // it can't be odd, so, round... up?\n    dimensionTop++;\n  }\n  dimensionTop += 2;\n\n  //dimensionRight++;\n  if ((dimensionRight & 0x01) == 1) {\n    // it can't be odd, so, round... up?\n    dimensionRight++;\n  }\n  dimensionRight += 2;\n\n  Ref<BitMatrix> bits;\n  Ref<PerspectiveTransform> transform;\n  Ref<ResultPoint> correctedTopRight;\n\n\n  // Rectanguar symbols are 6x16, 6x28, 10x24, 10x32, 14x32, or 14x44. If one dimension is more\n  // than twice the other, it's certainly rectangular, but to cut a bit more slack we accept it as\n  // rectangular if the bigger side is at least 7/4 times the other:\n  if (4 * dimensionTop >= 7 * dimensionRight || 4 * dimensionRight >= 7 * dimensionTop) {\n    // The matrix is rectangular\n    correctedTopRight = correctTopRightRectangular(bottomLeft, bottomRight, topLeft, topRight,\n        dimensionTop, dimensionRight);\n    if (correctedTopRight == NULL) {\n      correctedTopRight = topRight;\n    }\n\n    dimensionTop = transitionsBetween(topLeft, correctedTopRight)->getTransitions();\n    dimensionRight = transitionsBetween(bottomRight, correctedTopRight)->getTransitions();\n\n    if ((dimensionTop & 0x01) == 1) {\n      // it can't be odd, so, round... up?\n      dimensionTop++;\n    }\n\n    if ((dimensionRight & 0x01) == 1) {\n      // it can't be odd, so, round... up?\n      dimensionRight++;\n    }\n\n    transform = createTransform(topLeft, correctedTopRight, bottomLeft, bottomRight, dimensionTop,\n        dimensionRight);\n    bits = sampleGrid(image_, dimensionTop, dimensionRight, transform);\n\n  } else {\n    // The matrix is square\n    int dimension = min(dimensionRight, dimensionTop);\n\n    // correct top right point to match the white module\n    correctedTopRight = correctTopRight(bottomLeft, bottomRight, topLeft, topRight, dimension);\n    if (correctedTopRight == NULL) {\n      correctedTopRight = topRight;\n    }\n\n    // Redetermine the dimension using the corrected top right point\n    int dimensionCorrected = max(transitionsBetween(topLeft, correctedTopRight)->getTransitions(),\n        transitionsBetween(bottomRight, correctedTopRight)->getTransitions());\n    dimensionCorrected++;\n    if ((dimensionCorrected & 0x01) == 1) {\n      dimensionCorrected++;\n    }\n\n    transform = createTransform(topLeft, correctedTopRight, bottomLeft, bottomRight,\n        dimensionCorrected, dimensionCorrected);\n    bits = sampleGrid(image_, dimensionCorrected, dimensionCorrected, transform);\n  }\n\n  std::vector<Ref<ResultPoint> > points(4);\n  points[0].reset(topLeft);\n  points[1].reset(bottomLeft);\n  points[2].reset(correctedTopRight);\n  points[3].reset(bottomRight);\n  Ref<DetectorResult> detectorResult(new DetectorResult(bits, points, transform));\n  return detectorResult;\n}\n\n/**\n * Calculates the position of the white top right module using the output of the rectangle detector\n * for a rectangular matrix\n */\nRef<ResultPoint> Detector::correctTopRightRectangular(Ref<ResultPoint> bottomLeft,\n    Ref<ResultPoint> bottomRight, Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight,\n    int dimensionTop, int dimensionRight) {\n\n  float corr = distance(bottomLeft, bottomRight) / (float) dimensionTop;\n  int norm = distance(topLeft, topRight);\n  float cos = (topRight->getX() - topLeft->getX()) / norm;\n  float sin = (topRight->getY() - topLeft->getY()) / norm;\n\n  Ref<ResultPoint> c1(\n      new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin));\n\n  corr = distance(bottomLeft, topLeft) / (float) dimensionRight;\n  norm = distance(bottomRight, topRight);\n  cos = (topRight->getX() - bottomRight->getX()) / norm;\n  sin = (topRight->getY() - bottomRight->getY()) / norm;\n\n  Ref<ResultPoint> c2(\n      new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin));\n\n  if (!isValid(c1)) {\n    if (isValid(c2)) {\n      return c2;\n    }\n    return Ref<ResultPoint>(NULL);\n  }\n  if (!isValid(c2)) {\n    return c1;\n  }\n\n  int l1 = abs(dimensionTop - transitionsBetween(topLeft, c1)->getTransitions())\n      + abs(dimensionRight - transitionsBetween(bottomRight, c1)->getTransitions());\n  int l2 = abs(dimensionTop - transitionsBetween(topLeft, c2)->getTransitions())\n      + abs(dimensionRight - transitionsBetween(bottomRight, c2)->getTransitions());\n\n  return l1 <= l2 ? c1 : c2;\n}\n\n/**\n * Calculates the position of the white top right module using the output of the rectangle detector\n * for a square matrix\n */\nRef<ResultPoint> Detector::correctTopRight(Ref<ResultPoint> bottomLeft,\n    Ref<ResultPoint> bottomRight, Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight,\n    int dimension) {\n\n  float corr = distance(bottomLeft, bottomRight) / (float) dimension;\n  int norm = distance(topLeft, topRight);\n  float cos = (topRight->getX() - topLeft->getX()) / norm;\n  float sin = (topRight->getY() - topLeft->getY()) / norm;\n\n  Ref<ResultPoint> c1(\n      new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin));\n\n  corr = distance(bottomLeft, bottomRight) / (float) dimension;\n  norm = distance(bottomRight, topRight);\n  cos = (topRight->getX() - bottomRight->getX()) / norm;\n  sin = (topRight->getY() - bottomRight->getY()) / norm;\n\n  Ref<ResultPoint> c2(\n      new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin));\n\n  if (!isValid(c1)) {\n    if (isValid(c2)) {\n      return c2;\n    }\n    return Ref<ResultPoint>(NULL);\n  }\n  if (!isValid(c2)) {\n    return c1;\n  }\n\n  int l1 = abs(\n      transitionsBetween(topLeft, c1)->getTransitions()\n          - transitionsBetween(bottomRight, c1)->getTransitions());\n  int l2 = abs(\n      transitionsBetween(topLeft, c2)->getTransitions()\n          - transitionsBetween(bottomRight, c2)->getTransitions());\n\n  return l1 <= l2 ? c1 : c2;\n}\n\nbool Detector::isValid(Ref<ResultPoint> p) {\n  return p->getX() >= 0 && p->getX() < image_->getWidth() && p->getY() > 0\n      && p->getY() < image_->getHeight();\n}\n\n// L2 distance\nint Detector::distance(Ref<ResultPoint> a, Ref<ResultPoint> b) {\n  return round(\n      (float) sqrt(\n          (double) (a->getX() - b->getX()) * (a->getX() - b->getX())\n              + (a->getY() - b->getY()) * (a->getY() - b->getY())));\n}\n\nRef<ResultPointsAndTransitions> Detector::transitionsBetween(Ref<ResultPoint> from,\n    Ref<ResultPoint> to) {\n  // See QR Code Detector, sizeOfBlackWhiteBlackRun()\n  int fromX = (int) from->getX();\n  int fromY = (int) from->getY();\n  int toX = (int) to->getX();\n  int toY = (int) to->getY();\n  bool steep = abs(toY - fromY) > abs(toX - fromX);\n  if (steep) {\n    int temp = fromX;\n    fromX = fromY;\n    fromY = temp;\n    temp = toX;\n    toX = toY;\n    toY = temp;\n  }\n\n  int dx = abs(toX - fromX);\n  int dy = abs(toY - fromY);\n  int error = -dx >> 1;\n  int ystep = fromY < toY ? 1 : -1;\n  int xstep = fromX < toX ? 1 : -1;\n  int transitions = 0;\n  bool inBlack = image_->get(steep ? fromY : fromX, steep ? fromX : fromY);\n  for (int x = fromX, y = fromY; x != toX; x += xstep) {\n    bool isBlack = image_->get(steep ? y : x, steep ? x : y);\n    if (isBlack != inBlack) {\n      transitions++;\n      inBlack = isBlack;\n    }\n    error += dy;\n    if (error > 0) {\n      if (y == toY) {\n        break;\n      }\n      y += ystep;\n      error -= dx;\n    }\n  }\n  Ref<ResultPointsAndTransitions> result(new ResultPointsAndTransitions(from, to, transitions));\n  return result;\n}\n\nRef<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft,\n    Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft, Ref<ResultPoint> bottomRight,\n    int dimensionX, int dimensionY) {\n\n  Ref<PerspectiveTransform> transform(\n      PerspectiveTransform::quadrilateralToQuadrilateral(\n          0.5f,\n          0.5f,\n          dimensionX - 0.5f,\n          0.5f,\n          dimensionX - 0.5f,\n          dimensionY - 0.5f,\n          0.5f,\n          dimensionY - 0.5f,\n          topLeft->getX(),\n          topLeft->getY(),\n          topRight->getX(),\n          topRight->getY(),\n          bottomRight->getX(),\n          bottomRight->getY(),\n          bottomLeft->getX(),\n          bottomLeft->getY()));\n  return transform;\n}\n\nRef<BitMatrix> Detector::sampleGrid(Ref<BitMatrix> image, int dimensionX, int dimensionY,\n    Ref<PerspectiveTransform> transform) {\n  GridSampler &sampler = GridSampler::getInstance();\n  return sampler.sampleGrid(image, dimensionX, dimensionY, transform);\n}\n\nvoid Detector::insertionSort(std::vector<Ref<ResultPointsAndTransitions> > &vector) {\n  int max = vector.size();\n  bool swapped = true;\n  Ref<ResultPointsAndTransitions> value;\n  Ref<ResultPointsAndTransitions> valueB;\n  do {\n    swapped = false;\n    for (int i = 1; i < max; i++) {\n      value = vector[i - 1];\n      if (compare(value, (valueB = vector[i])) > 0){\n        swapped = true;\n        vector[i - 1].reset(valueB);\n        vector[i].reset(value);\n      }\n    }\n  } while (swapped);\n}\n\nint Detector::compare(Ref<ResultPointsAndTransitions> a, Ref<ResultPointsAndTransitions> b) {\n  return a->getTransitions() - b->getTransitions();\n}\n}\n}\n\n// file: zxing/datamatrix/detector/DetectorException.cpp\n\n/*\n * DetectorException.cpp\n *\n *  Created on: Aug 26, 2011\n *      Author: luiz\n */\n\n// #include \"DetectorException.h\"\n\nnamespace zxing {\nnamespace datamatrix {\n\nDetectorException::DetectorException(const char *msg) :\n    Exception(msg) {\n\n}\n\nDetectorException::~DetectorException() throw () {\n  // TODO Auto-generated destructor stub\n}\n\n}\n} /* namespace zxing */\n\n// file: zxing/datamatrix/detector/MonochromeRectangleDetector.cpp\n\n/*\n *  MonochromeRectangleDetector.cpp\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ReaderException.h>\n// #include <zxing/datamatrix/detector/MonochromeRectangleDetector.h>\n// #include <sstream>\n\nnamespace zxing {\nnamespace datamatrix {\n\nstd::vector<Ref<CornerPoint> > MonochromeRectangleDetector::detect() {\n    int height = image_->getHeight();\n    int width = image_->getWidth();\n    int halfHeight = height >> 1;\n    int halfWidth = width >> 1;\n    int deltaY = max(1, height / (MAX_MODULES << 3));\n    int deltaX = max(1, width / (MAX_MODULES << 3));\n\n    int top = 0;\n    int bottom = height;\n    int left = 0;\n    int right = width;\n    Ref<CornerPoint> pointA(findCornerFromCenter(halfWidth, 0, left, right,\n        halfHeight, -deltaY, top, bottom, halfWidth >> 1));\n    top = (int) pointA->getY() - 1;\n    Ref<CornerPoint> pointB(findCornerFromCenter(halfWidth, -deltaX, left, right,\n        halfHeight, 0, top, bottom, halfHeight >> 1));\n    left = (int) pointB->getX() - 1;\n    Ref<CornerPoint> pointC(findCornerFromCenter(halfWidth, deltaX, left, right,\n        halfHeight, 0, top, bottom, halfHeight >> 1));\n    right = (int) pointC->getX() + 1;\n    Ref<CornerPoint> pointD(findCornerFromCenter(halfWidth, 0, left, right,\n        halfHeight, deltaY, top, bottom, halfWidth >> 1));\n    bottom = (int) pointD->getY() + 1;\n\n    // Go try to find point A again with better information -- might have been off at first.\n    pointA.reset(findCornerFromCenter(halfWidth, 0, left, right,\n        halfHeight, -deltaY, top, bottom, halfWidth >> 2));\n\t  std::vector<Ref<CornerPoint> > corners(4);\n\n  \tcorners[0].reset(pointA);\n  \tcorners[1].reset(pointB);\n  \tcorners[2].reset(pointC);\n  \tcorners[3].reset(pointD);\n    return corners;\n  }\n\nRef<CornerPoint> MonochromeRectangleDetector::findCornerFromCenter(int centerX, int deltaX, int left, int right,\n      int centerY, int deltaY, int top, int bottom, int maxWhiteRun) {\n\tRef<TwoInts> lastRange(NULL);\n    for (int y = centerY, x = centerX;\n         y < bottom && y >= top && x < right && x >= left;\n         y += deltaY, x += deltaX) {\n    Ref<TwoInts> range(NULL);\n      if (deltaX == 0) {\n        // horizontal slices, up and down\n        range = blackWhiteRange(y, maxWhiteRun, left, right, true);\n      } else {\n        // vertical slices, left and right\n        range = blackWhiteRange(x, maxWhiteRun, top, bottom, false);\n      }\n      if (range == NULL) {\n        if (lastRange == NULL) {\n\t\t\t    throw ReaderException(\"Couldn't find corners (lastRange = NULL) \");\n        } else {\n        // lastRange was found\n        if (deltaX == 0) {\n          int lastY = y - deltaY;\n          if (lastRange->start < centerX) {\n            if (lastRange->end > centerX) {\n              // straddle, choose one or the other based on direction\n\t\t\t        Ref<CornerPoint> result(new CornerPoint(deltaY > 0 ? lastRange->start : lastRange->end, lastY));\n\t\t\t        return result;\n            }\n\t\t\t      Ref<CornerPoint> result(new CornerPoint(lastRange->start, lastY));\n\t\t\t      return result;\n          } else {\n\t\t\t      Ref<CornerPoint> result(new CornerPoint(lastRange->end, lastY));\n\t\t\t      return result;\n            }\n        } else {\n          int lastX = x - deltaX;\n          if (lastRange->start < centerY) {\n            if (lastRange->end > centerY) {\n\t\t\t        Ref<CornerPoint> result(new CornerPoint(lastX, deltaX < 0 ? lastRange->start : lastRange->end));\n\t\t\t        return result;\n            }\n\t\t\t      Ref<CornerPoint> result(new CornerPoint(lastX, lastRange->start));\n\t\t\t      return result;\n          } else {\n\t\t\t      Ref<CornerPoint> result(new CornerPoint(lastX, lastRange->end));\n\t\t\t      return result;\n            }\n          }\n        }\n      }\n      lastRange = range;\n    }\n    throw ReaderException(\"Couldn't find corners\");\n  }\n\nRef<TwoInts> MonochromeRectangleDetector::blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim,\n      bool horizontal) {\n\n\t  int center = (minDim + maxDim) >> 1;\n\n    // Scan left/up first\n    int start = center;\n    while (start >= minDim) {\n      if (horizontal ? image_->get(start, fixedDimension) : image_->get(fixedDimension, start)) {\n        start--;\n      } else {\n        int whiteRunStart = start;\n        do {\n          start--;\n        } while (start >= minDim && !(horizontal ? image_->get(start, fixedDimension) :\n            image_->get(fixedDimension, start)));\n        int whiteRunSize = whiteRunStart - start;\n        if (start < minDim || whiteRunSize > maxWhiteRun) {\n          start = whiteRunStart;\n          break;\n        }\n      }\n    }\n    start++;\n\n    // Then try right/down\n    int end = center;\n    while (end < maxDim) {\n      if (horizontal ? image_->get(end, fixedDimension) : image_->get(fixedDimension, end)) {\n        end++;\n      } else {\n        int whiteRunStart = end;\n        do {\n          end++;\n        } while (end < maxDim && !(horizontal ? image_->get(end, fixedDimension) :\n            image_->get(fixedDimension, end)));\n        int whiteRunSize = end - whiteRunStart;\n        if (end >= maxDim || whiteRunSize > maxWhiteRun) {\n          end = whiteRunStart;\n          break;\n        }\n      }\n    }\n    end--;\n    Ref<TwoInts> result(NULL);\n    if (end > start) {\n\t\tresult = new TwoInts;\n      result->start = start;\n      result->end = end;\n    }\n    return result;\n  }\n}\n}\n\n// file: zxing/multi/ByQuadrantReader.cpp\n\n/*\n *  Copyright 2011 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/multi/ByQuadrantReader.h>\n// #include <zxing/ReaderException.h>\n\nnamespace zxing {\nnamespace multi {\n\nByQuadrantReader::ByQuadrantReader(Reader& delegate) : delegate_(delegate) {}\n\nByQuadrantReader::~ByQuadrantReader(){}\n\nRef<Result> ByQuadrantReader::decode(Ref<BinaryBitmap> image){\n  return decode(image, DecodeHints::DEFAULT_HINT);\n}\n\nRef<Result> ByQuadrantReader::decode(Ref<BinaryBitmap> image, DecodeHints hints){\n  int width = image->getWidth();\n  int height = image->getHeight();\n  int halfWidth = width / 2;\n  int halfHeight = height / 2;\n  Ref<BinaryBitmap> topLeft = image->crop(0, 0, halfWidth, halfHeight);\n  try {\n    return delegate_.decode(topLeft, hints);\n  } catch (ReaderException re) {\n    // continue\n  }\n\n  Ref<BinaryBitmap> topRight = image->crop(halfWidth, 0, halfWidth, halfHeight);\n  try {\n    return delegate_.decode(topRight, hints);\n  } catch (ReaderException re) {\n    // continue\n  }\n\n  Ref<BinaryBitmap> bottomLeft = image->crop(0, halfHeight, halfWidth, halfHeight);\n  try {\n    return delegate_.decode(bottomLeft, hints);\n  } catch (ReaderException re) {\n    // continue\n  }\n\n  Ref<BinaryBitmap> bottomRight = image->crop(halfWidth, halfHeight, halfWidth, halfHeight);\n  try {\n    return delegate_.decode(bottomRight, hints);\n  } catch (ReaderException re) {\n    // continue\n  }\n\n  int quarterWidth = halfWidth / 2;\n  int quarterHeight = halfHeight / 2;\n  Ref<BinaryBitmap> center = image->crop(quarterWidth, quarterHeight, halfWidth, halfHeight);\n  return delegate_.decode(center, hints);\n}\n\n} // End zxing::multi namespace\n} // End zxing namespace\n\n// file: zxing/multi/GenericMultipleBarcodeReader.cpp\n\n/*\n *  Copyright 2011 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/multi/GenericMultipleBarcodeReader.h>\n// #include <zxing/ReaderException.h>\n// #include <zxing/ResultPoint.h>\n\nnamespace zxing {\nnamespace multi {\nGenericMultipleBarcodeReader::GenericMultipleBarcodeReader(Reader& delegate) :\n  delegate_(delegate)\n{\n}\n\nGenericMultipleBarcodeReader::~GenericMultipleBarcodeReader(){}\n\nstd::vector<Ref<Result> > GenericMultipleBarcodeReader::decodeMultiple(\n  Ref<BinaryBitmap> image, DecodeHints hints)\n{\n  std::vector<Ref<Result> > results;\n  doDecodeMultiple(image, hints, results, 0, 0);\n  if (results.empty()){\n    throw ReaderException(\"No code detected\");\n  }\n  return results;\n}\n\nvoid GenericMultipleBarcodeReader::doDecodeMultiple(Ref<BinaryBitmap> image,\n  DecodeHints hints, std::vector<Ref<Result> >& results, int xOffset, int yOffset)\n{\n  Ref<Result> result;\n  try {\n    result = delegate_.decode(image, hints);\n  } catch (ReaderException re) {\n    return;\n  }\n  bool alreadyFound = false;\n  for (unsigned int i = 0; i < results.size(); i++) {\n    Ref<Result> existingResult = results[i];\n    if (existingResult->getText()->getText() == result->getText()->getText()) {\n      alreadyFound = true;\n      break;\n    }\n  }\n  if (alreadyFound) {\n    return;\n  }\n\n  results.push_back(translateResultPoints(result, xOffset, yOffset));\n  const std::vector<Ref<ResultPoint> > resultPoints = result->getResultPoints();\n  if (resultPoints.empty()) {\n    return;\n  }\n\n  int width = image->getWidth();\n  int height = image->getHeight();\n  float minX = width;\n  float minY = height;\n  float maxX = 0.0f;\n  float maxY = 0.0f;\n  for (unsigned int i = 0; i < resultPoints.size(); i++) {\n    Ref<ResultPoint> point = resultPoints[i];\n    float x = point->getX();\n    float y = point->getY();\n    if (x < minX) {\n      minX = x;\n    }\n    if (y < minY) {\n      minY = y;\n    }\n    if (x > maxX) {\n      maxX = x;\n    }\n    if (y > maxY) {\n      maxY = y;\n    }\n  }\n\n  // Decode left of barcode\n  if (minX > MIN_DIMENSION_TO_RECUR) {\n    doDecodeMultiple(image->crop(0, 0, (int) minX, height),\n                     hints, results, xOffset, yOffset);\n  }\n  // Decode above barcode\n  if (minY > MIN_DIMENSION_TO_RECUR) {\n    doDecodeMultiple(image->crop(0, 0, width, (int) minY),\n                     hints, results, xOffset, yOffset);\n  }\n  // Decode right of barcode\n  if (maxX < width - MIN_DIMENSION_TO_RECUR) {\n    doDecodeMultiple(image->crop((int) maxX, 0, width - (int) maxX, height),\n                     hints, results, xOffset + (int) maxX, yOffset);\n  }\n  // Decode below barcode\n  if (maxY < height - MIN_DIMENSION_TO_RECUR) {\n    doDecodeMultiple(image->crop(0, (int) maxY, width, height - (int) maxY),\n                     hints, results, xOffset, yOffset + (int) maxY);\n  }\n}\n\nRef<Result> GenericMultipleBarcodeReader::translateResultPoints(Ref<Result> result, int xOffset, int yOffset){\n  const std::vector<Ref<ResultPoint> > oldResultPoints = result->getResultPoints();\n  if (oldResultPoints.empty()) {\n    return result;\n  }\n  std::vector<Ref<ResultPoint> > newResultPoints;\n  for (unsigned int i = 0; i < oldResultPoints.size(); i++) {\n    Ref<ResultPoint> oldPoint = oldResultPoints[i];\n    newResultPoints.push_back(Ref<ResultPoint>(new ResultPoint(oldPoint->getX() + xOffset, oldPoint->getY() + yOffset)));\n  }\n  return Ref<Result>(new Result(result->getText(), result->getRawBytes(), newResultPoints, result->getBarcodeFormat()));\n}\n\n} // End zxing::multi namespace\n} // End zxing namespace\n\n// file: zxing/multi/MultipleBarcodeReader.cpp\n\n/*\n *  Copyright 2011 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/multi/MultipleBarcodeReader.h>\n\nnamespace zxing {\nnamespace multi {\n\nMultipleBarcodeReader::~MultipleBarcodeReader() { }\n\nstd::vector<Ref<Result> > MultipleBarcodeReader::decodeMultiple(Ref<BinaryBitmap> image) {\n  return decodeMultiple(image, DecodeHints::DEFAULT_HINT);\n}\n\n} // End zxing::multi namespace\n} // End zxing namespace\n\n// file: zxing/multi/qrcode/QRCodeMultiReader.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Copyright 2011 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/multi/qrcode/QRCodeMultiReader.h>\n// #include <zxing/ReaderException.h>\n// #include <zxing/multi/qrcode/detector/MultiDetector.h>\n// #include <zxing/BarcodeFormat.h>\n\nnamespace zxing {\nnamespace multi {\nQRCodeMultiReader::QRCodeMultiReader(){}\n\nQRCodeMultiReader::~QRCodeMultiReader(){}\n\nstd::vector<Ref<Result> > QRCodeMultiReader::decodeMultiple(Ref<BinaryBitmap> image,\n  DecodeHints hints)\n{\n  std::vector<Ref<Result> > results;\n  MultiDetector detector(image->getBlackMatrix());\n\n  std::vector<Ref<DetectorResult> > detectorResult =  detector.detectMulti(hints);\n  for (unsigned int i = 0; i < detectorResult.size(); i++) {\n    try {\n      Ref<DecoderResult> decoderResult = getDecoder().decode(detectorResult[i]->getBits());\n      std::vector<Ref<ResultPoint> > points = detectorResult[i]->getPoints();\n      Ref<Result> result = Ref<Result>(new Result(decoderResult->getText(),\n      decoderResult->getRawBytes(),\n      points, BarcodeFormat_QR_CODE));\n      // result->putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult->getByteSegments());\n      // result->putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult->getECLevel().toString());\n      results.push_back(result);\n    } catch (ReaderException re) {\n    // ignore and continue\n    }\n  }\n  if (results.empty()){\n    throw ReaderException(\"No code detected\");\n  }\n  return results;\n}\n\n} // End zxing::multi namespace\n} // End zxing namespace\n\n// file: zxing/multi/qrcode/detector/MultiDetector.cpp\n\n/*\n *  Copyright 2011 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/multi/qrcode/detector/MultiDetector.h>\n// #include <zxing/multi/qrcode/detector/MultiFinderPatternFinder.h>\n// #include <zxing/ReaderException.h>\n\nnamespace zxing {\nnamespace multi {\nusing namespace zxing::qrcode;\n\nMultiDetector::MultiDetector(Ref<BitMatrix> image) : Detector(image) {}\n\nMultiDetector::~MultiDetector(){}\n\nstd::vector<Ref<DetectorResult> > MultiDetector::detectMulti(DecodeHints hints){\n  Ref<BitMatrix> image = getImage();\n  MultiFinderPatternFinder finder = MultiFinderPatternFinder(image, hints.getResultPointCallback());\n  std::vector<Ref<FinderPatternInfo> > info = finder.findMulti(hints);\n  std::vector<Ref<DetectorResult> > result;\n  for(unsigned int i = 0; i < info.size(); i++){\n    try{\n      result.push_back(processFinderPatternInfo(info[i]));\n    } catch (ReaderException e){\n      // ignore\n    }\n  }\n\n  return result;\n}\n\n} // End zxing::multi namespace\n} // End zxing namespace\n\n// file: zxing/multi/qrcode/detector/MultiFinderPatternFinder.cpp\n\n/*\n *  Copyright 2011 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <algorithm>\n// #include <math.h>\n// #include <stdlib.h>\n// #include <zxing/multi/qrcode/detector/MultiFinderPatternFinder.h>\n// #include <zxing/DecodeHints.h>\n// #include <zxing/ReaderException.h>\n\nnamespace zxing{\nnamespace multi {\nusing namespace zxing::qrcode;\n\nconst float MultiFinderPatternFinder::MAX_MODULE_COUNT_PER_EDGE = 180;\nconst float MultiFinderPatternFinder::MIN_MODULE_COUNT_PER_EDGE = 9;\nconst float MultiFinderPatternFinder::DIFF_MODSIZE_CUTOFF_PERCENT = 0.05f;\nconst float MultiFinderPatternFinder::DIFF_MODSIZE_CUTOFF = 0.5f;\n\nbool compareModuleSize(Ref<FinderPattern> a, Ref<FinderPattern> b){\n    float value = a->getEstimatedModuleSize() - b->getEstimatedModuleSize();\n    return value < 0.0;\n}\n\n\nMultiFinderPatternFinder::MultiFinderPatternFinder(Ref<BitMatrix> image,\n  Ref<ResultPointCallback> resultPointCallback) :\n    FinderPatternFinder(image, resultPointCallback)\n{\n}\n\nMultiFinderPatternFinder::~MultiFinderPatternFinder(){}\n\nstd::vector<Ref<FinderPatternInfo> > MultiFinderPatternFinder::findMulti(DecodeHints const& hints){\n  bool tryHarder = hints.getTryHarder();\n  Ref<BitMatrix> image = image_; // Protected member\n  int maxI = image->getHeight();\n  int maxJ = image->getWidth();\n  // We are looking for black/white/black/white/black modules in\n  // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far\n\n  // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the\n  // image, and then account for the center being 3 modules in size. This gives the smallest\n  // number of pixels the center could be, so skip this often. When trying harder, look for all\n  // QR versions regardless of how dense they are.\n  int iSkip = (int) (maxI / (MAX_MODULES * 4.0f) * 3);\n  if (iSkip < MIN_SKIP || tryHarder) {\n    iSkip = MIN_SKIP;\n  }\n\n  int stateCount[5];\n  for (int i = iSkip - 1; i < maxI; i += iSkip) {\n    // Get a row of black/white values\n    stateCount[0] = 0;\n    stateCount[1] = 0;\n    stateCount[2] = 0;\n    stateCount[3] = 0;\n    stateCount[4] = 0;\n    int currentState = 0;\n    for (int j = 0; j < maxJ; j++) {\n      if (image->get(j, i)) {\n        // Black pixel\n        if ((currentState & 1) == 1) { // Counting white pixels\n          currentState++;\n        }\n        stateCount[currentState]++;\n      } else { // White pixel\n        if ((currentState & 1) == 0) { // Counting black pixels\n          if (currentState == 4) { // A winner?\n            if (foundPatternCross(stateCount)) { // Yes\n              bool confirmed = handlePossibleCenter(stateCount, i, j);\n              if (!confirmed) {\n                do { // Advance to next black pixel\n                  j++;\n                } while (j < maxJ && !image->get(j, i));\n                  j--; // back up to that last white pixel\n              }\n              // Clear state to start looking again\n              currentState = 0;\n              stateCount[0] = 0;\n              stateCount[1] = 0;\n              stateCount[2] = 0;\n              stateCount[3] = 0;\n              stateCount[4] = 0;\n            } else { // No, shift counts back by two\n              stateCount[0] = stateCount[2];\n              stateCount[1] = stateCount[3];\n              stateCount[2] = stateCount[4];\n              stateCount[3] = 1;\n              stateCount[4] = 0;\n              currentState = 3;\n            }\n          } else {\n            stateCount[++currentState]++;\n          }\n        } else { // Counting white pixels\n            stateCount[currentState]++;\n        }\n      }\n    } // for j=...\n\n    if (foundPatternCross(stateCount)) {\n      handlePossibleCenter(stateCount, i, maxJ);\n    } // end if foundPatternCross\n  } // for i=iSkip-1 ...\n  std::vector<std::vector<Ref<FinderPattern> > > patternInfo = selectBestPatterns();\n  std::vector<Ref<FinderPatternInfo> > result;\n  for (unsigned int i = 0; i < patternInfo.size(); i++) {\n    std::vector<Ref<FinderPattern> > pattern = patternInfo[i];\n    FinderPatternFinder::orderBestPatterns(pattern);\n    result.push_back(Ref<FinderPatternInfo>(new FinderPatternInfo(pattern)));\n  }\n  return result;\n}\n\nstd::vector<std::vector<Ref<FinderPattern> > > MultiFinderPatternFinder::selectBestPatterns(){\n  std::vector<Ref<FinderPattern> > possibleCenters = possibleCenters_;\n\n  int size = possibleCenters.size();\n\n  if (size < 3) {\n    // Couldn't find enough finder patterns\n    throw ReaderException(\"No code detected\");\n  }\n\n  std::vector<std::vector<Ref<FinderPattern> > > results;\n\n  /*\n  * Begin HE modifications to safely detect multiple codes of equal size\n  */\n  if (size == 3) {\n    results.push_back(possibleCenters_);\n    return results;\n  }\n\n  // Sort by estimated module size to speed up the upcoming checks\n  //TODO do a sort based on module size\n  std::sort(possibleCenters.begin(), possibleCenters.end(), compareModuleSize);\n\n  /*\n  * Now lets start: build a list of tuples of three finder locations that\n  *  - feature similar module sizes\n  *  - are placed in a distance so the estimated module count is within the QR specification\n  *  - have similar distance between upper left/right and left top/bottom finder patterns\n  *  - form a triangle with 90° angle (checked by comparing top right/bottom left distance\n  *    with pythagoras)\n  *\n  * Note: we allow each point to be used for more than one code region: this might seem\n  * counterintuitive at first, but the performance penalty is not that big. At this point,\n  * we cannot make a good quality decision whether the three finders actually represent\n  * a QR code, or are just by chance layouted so it looks like there might be a QR code there.\n  * So, if the layout seems right, lets have the decoder try to decode.\n  */\n\n  for (int i1 = 0; i1 < (size - 2); i1++) {\n    Ref<FinderPattern> p1 = possibleCenters[i1];\n    for (int i2 = i1 + 1; i2 < (size - 1); i2++) {\n      Ref<FinderPattern> p2 = possibleCenters[i2];\n      // Compare the expected module sizes; if they are really off, skip\n      float vModSize12 = (p1->getEstimatedModuleSize() - p2->getEstimatedModuleSize()) / std::min(p1->getEstimatedModuleSize(), p2->getEstimatedModuleSize());\n      float vModSize12A = abs(p1->getEstimatedModuleSize() - p2->getEstimatedModuleSize());\n      if (vModSize12A > DIFF_MODSIZE_CUTOFF && vModSize12 >= DIFF_MODSIZE_CUTOFF_PERCENT) {\n        // break, since elements are ordered by the module size deviation there cannot be\n        // any more interesting elements for the given p1.\n        break;\n      }\n      for (int i3 = i2 + 1; i3 < size; i3++) {\n        Ref<FinderPattern> p3 = possibleCenters[i3];\n        // Compare the expected module sizes; if they are really off, skip\n        float vModSize23 = (p2->getEstimatedModuleSize() - p3->getEstimatedModuleSize()) / std::min(p2->getEstimatedModuleSize(), p3->getEstimatedModuleSize());\n        float vModSize23A = abs(p2->getEstimatedModuleSize() - p3->getEstimatedModuleSize());\n        if (vModSize23A > DIFF_MODSIZE_CUTOFF && vModSize23 >= DIFF_MODSIZE_CUTOFF_PERCENT) {\n          // break, since elements are ordered by the module size deviation there cannot be\n          // any more interesting elements for the given p1.\n          break;\n        }\n        std::vector<Ref<FinderPattern> > test;\n        test.push_back(p1);\n        test.push_back(p2);\n        test.push_back(p3);\n        FinderPatternFinder::orderBestPatterns(test);\n        // Calculate the distances: a = topleft-bottomleft, b=topleft-topright, c = diagonal\n        Ref<FinderPatternInfo> info = Ref<FinderPatternInfo>(new FinderPatternInfo(test));\n        float dA = FinderPatternFinder::distance(info->getTopLeft(), info->getBottomLeft());\n        float dC = FinderPatternFinder::distance(info->getTopRight(), info->getBottomLeft());\n        float dB = FinderPatternFinder::distance(info->getTopLeft(), info->getTopRight());\n        // Check the sizes\n        float estimatedModuleCount = (dA + dB) / (p1->getEstimatedModuleSize() * 2.0f);\n        if (estimatedModuleCount > MAX_MODULE_COUNT_PER_EDGE || estimatedModuleCount < MIN_MODULE_COUNT_PER_EDGE) {\n          continue;\n        }\n        // Calculate the difference of the edge lengths in percent\n        float vABBC = abs((dA - dB) / std::min(dA, dB));\n        if (vABBC >= 0.1f) {\n          continue;\n        }\n        // Calculate the diagonal length by assuming a 90° angle at topleft\n        float dCpy = (float) sqrt(dA * dA + dB * dB);\n        // Compare to the real distance in %\n        float vPyC = abs((dC - dCpy) / std::min(dC, dCpy));\n        if (vPyC >= 0.1f) {\n          continue;\n        }\n        // All tests passed!\n        results.push_back(test);\n      } // end iterate p3\n    } // end iterate p2\n  } // end iterate p1\n  if (results.empty()){\n    // Nothing found!\n    throw ReaderException(\"No code detected\");\n  }\n  return results;\n}\n\n} // End zxing::multi namespace\n} // End zxing namespace\n\n// file: zxing/oned/Code128Reader.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include \"Code128Reader.h\"\n// #include <zxing/oned/OneDResultPoint.h>\n// #include <zxing/common/Array.h>\n// #include <zxing/ReaderException.h>\n// #include <math.h>\n// #include <string.h>\n// #include <sstream>\n\nnamespace zxing {\n\tnamespace oned {\n\n\t\tconst int CODE_PATTERNS_LENGTH = 107;\n\t\tconst int countersLength = 6;\n\t\tstatic const int CODE_PATTERNS[CODE_PATTERNS_LENGTH][countersLength] = {\n\t\t\t{2, 1, 2, 2, 2, 2}, /* 0 */\n\t\t\t{2, 2, 2, 1, 2, 2},\n\t\t\t{2, 2, 2, 2, 2, 1},\n\t\t\t{1, 2, 1, 2, 2, 3},\n\t\t\t{1, 2, 1, 3, 2, 2},\n\t\t\t{1, 3, 1, 2, 2, 2}, /* 5 */\n\t\t\t{1, 2, 2, 2, 1, 3},\n\t\t\t{1, 2, 2, 3, 1, 2},\n\t\t\t{1, 3, 2, 2, 1, 2},\n\t\t\t{2, 2, 1, 2, 1, 3},\n\t\t\t{2, 2, 1, 3, 1, 2}, /* 10 */\n\t\t\t{2, 3, 1, 2, 1, 2},\n\t\t\t{1, 1, 2, 2, 3, 2},\n\t\t\t{1, 2, 2, 1, 3, 2},\n\t\t\t{1, 2, 2, 2, 3, 1},\n\t\t\t{1, 1, 3, 2, 2, 2}, /* 15 */\n\t\t\t{1, 2, 3, 1, 2, 2},\n\t\t\t{1, 2, 3, 2, 2, 1},\n\t\t\t{2, 2, 3, 2, 1, 1},\n\t\t\t{2, 2, 1, 1, 3, 2},\n\t\t\t{2, 2, 1, 2, 3, 1}, /* 20 */\n\t\t\t{2, 1, 3, 2, 1, 2},\n\t\t\t{2, 2, 3, 1, 1, 2},\n\t\t\t{3, 1, 2, 1, 3, 1},\n\t\t\t{3, 1, 1, 2, 2, 2},\n\t\t\t{3, 2, 1, 1, 2, 2}, /* 25 */\n\t\t\t{3, 2, 1, 2, 2, 1},\n\t\t\t{3, 1, 2, 2, 1, 2},\n\t\t\t{3, 2, 2, 1, 1, 2},\n\t\t\t{3, 2, 2, 2, 1, 1},\n\t\t\t{2, 1, 2, 1, 2, 3}, /* 30 */\n\t\t\t{2, 1, 2, 3, 2, 1},\n\t\t\t{2, 3, 2, 1, 2, 1},\n\t\t\t{1, 1, 1, 3, 2, 3},\n\t\t\t{1, 3, 1, 1, 2, 3},\n\t\t\t{1, 3, 1, 3, 2, 1}, /* 35 */\n\t\t\t{1, 1, 2, 3, 1, 3},\n\t\t\t{1, 3, 2, 1, 1, 3},\n\t\t\t{1, 3, 2, 3, 1, 1},\n\t\t\t{2, 1, 1, 3, 1, 3},\n\t\t\t{2, 3, 1, 1, 1, 3}, /* 40 */\n\t\t\t{2, 3, 1, 3, 1, 1},\n\t\t\t{1, 1, 2, 1, 3, 3},\n\t\t\t{1, 1, 2, 3, 3, 1},\n\t\t\t{1, 3, 2, 1, 3, 1},\n\t\t\t{1, 1, 3, 1, 2, 3}, /* 45 */\n\t\t\t{1, 1, 3, 3, 2, 1},\n\t\t\t{1, 3, 3, 1, 2, 1},\n\t\t\t{3, 1, 3, 1, 2, 1},\n\t\t\t{2, 1, 1, 3, 3, 1},\n\t\t\t{2, 3, 1, 1, 3, 1}, /* 50 */\n\t\t\t{2, 1, 3, 1, 1, 3},\n\t\t\t{2, 1, 3, 3, 1, 1},\n\t\t\t{2, 1, 3, 1, 3, 1},\n\t\t\t{3, 1, 1, 1, 2, 3},\n\t\t\t{3, 1, 1, 3, 2, 1}, /* 55 */\n\t\t\t{3, 3, 1, 1, 2, 1},\n\t\t\t{3, 1, 2, 1, 1, 3},\n\t\t\t{3, 1, 2, 3, 1, 1},\n\t\t\t{3, 3, 2, 1, 1, 1},\n\t\t\t{3, 1, 4, 1, 1, 1}, /* 60 */\n\t\t\t{2, 2, 1, 4, 1, 1},\n\t\t\t{4, 3, 1, 1, 1, 1},\n\t\t\t{1, 1, 1, 2, 2, 4},\n\t\t\t{1, 1, 1, 4, 2, 2},\n\t\t\t{1, 2, 1, 1, 2, 4}, /* 65 */\n\t\t\t{1, 2, 1, 4, 2, 1},\n\t\t\t{1, 4, 1, 1, 2, 2},\n\t\t\t{1, 4, 1, 2, 2, 1},\n\t\t\t{1, 1, 2, 2, 1, 4},\n\t\t\t{1, 1, 2, 4, 1, 2}, /* 70 */\n\t\t\t{1, 2, 2, 1, 1, 4},\n\t\t\t{1, 2, 2, 4, 1, 1},\n\t\t\t{1, 4, 2, 1, 1, 2},\n\t\t\t{1, 4, 2, 2, 1, 1},\n\t\t\t{2, 4, 1, 2, 1, 1}, /* 75 */\n\t\t\t{2, 2, 1, 1, 1, 4},\n\t\t\t{4, 1, 3, 1, 1, 1},\n\t\t\t{2, 4, 1, 1, 1, 2},\n\t\t\t{1, 3, 4, 1, 1, 1},\n\t\t\t{1, 1, 1, 2, 4, 2}, /* 80 */\n\t\t\t{1, 2, 1, 1, 4, 2},\n\t\t\t{1, 2, 1, 2, 4, 1},\n\t\t\t{1, 1, 4, 2, 1, 2},\n\t\t\t{1, 2, 4, 1, 1, 2},\n\t\t\t{1, 2, 4, 2, 1, 1}, /* 85 */\n\t\t\t{4, 1, 1, 2, 1, 2},\n\t\t\t{4, 2, 1, 1, 1, 2},\n\t\t\t{4, 2, 1, 2, 1, 1},\n\t\t\t{2, 1, 2, 1, 4, 1},\n\t\t\t{2, 1, 4, 1, 2, 1}, /* 90 */\n\t\t\t{4, 1, 2, 1, 2, 1},\n\t\t\t{1, 1, 1, 1, 4, 3},\n\t\t\t{1, 1, 1, 3, 4, 1},\n\t\t\t{1, 3, 1, 1, 4, 1},\n\t\t\t{1, 1, 4, 1, 1, 3}, /* 95 */\n\t\t\t{1, 1, 4, 3, 1, 1},\n\t\t\t{4, 1, 1, 1, 1, 3},\n\t\t\t{4, 1, 1, 3, 1, 1},\n\t\t\t{1, 1, 3, 1, 4, 1},\n\t\t\t{1, 1, 4, 1, 3, 1}, /* 100 */\n\t\t\t{3, 1, 1, 1, 4, 1},\n\t\t\t{4, 1, 1, 1, 3, 1},\n\t\t\t{2, 1, 1, 4, 1, 2},\n\t\t\t{2, 1, 1, 2, 1, 4},\n\t\t\t{2, 1, 1, 2, 3, 2}, /* 105 */\n\t\t\t{2, 3, 3, 1, 1, 1}\n\t\t};\n\n\n\t\tCode128Reader::Code128Reader(){\n\t\t}\n\n\t\tint* Code128Reader::findStartPattern(Ref<BitArray> row){\n\t\t\tint width = row->getSize();\n\t\t\tint rowOffset = 0;\n\t\t\twhile (rowOffset < width) {\n\t\t\t\tif (row->get(rowOffset)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\trowOffset++;\n\t\t\t}\n\n\t\t\tint counterPosition = 0;\n\t\t\tint counters[countersLength] = {0,0,0,0,0,0};\n\t\t\tint patternStart = rowOffset;\n\t\t\tbool isWhite = false;\n\t\t\tint patternLength =  sizeof(counters) / sizeof(int);\n\n\t\t\tfor (int i = rowOffset; i < width; i++) {\n\t\t\t\tbool pixel = row->get(i);\n\t\t\t\tif (pixel ^ isWhite) {\n\t\t\t\t\tcounters[counterPosition]++;\n\t\t\t\t} else {\n\t\t\t\t\tif (counterPosition == patternLength - 1) {\n\t\t\t\t\t\tunsigned int bestVariance = MAX_AVG_VARIANCE;\n\t\t\t\t\t\tint bestMatch = -1;\n\t\t\t\t\t\tfor (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) {\n\t\t\t\t\t\t\tunsigned int variance = patternMatchVariance(counters, sizeof(counters) / sizeof(int),\n\t\t\t\t\t\t\t    CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE);\n\t\t\t\t\t\t\tif (variance < bestVariance) {\n\t\t\t\t\t\t\t\tbestVariance = variance;\n\t\t\t\t\t\t\t\tbestMatch = startCode;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (bestMatch >= 0) {\n\t\t\t\t\t\t\t// Look for whitespace before start pattern, >= 50% of width of start pattern\n              if (row->isRange(std::max(0, patternStart - (i - patternStart) / 2), patternStart,\n\t\t\t\t\t\t\t    false)) {\n\t\t\t\t\t\t\t\tint* resultValue = new int[3];\n\t\t\t\t\t\t\t\tresultValue[0] = patternStart;\n\t\t\t\t\t\t\t\tresultValue[1] = i;\n\t\t\t\t\t\t\t\tresultValue[2] = bestMatch;\n\t\t\t\t\t\t\t\treturn resultValue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpatternStart += counters[0] + counters[1];\n\t\t\t\t\t\tfor (int y = 2; y < patternLength; y++) {\n\t\t\t\t\t\t\tcounters[y - 2] = counters[y];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcounters[patternLength - 2] = 0;\n\t\t\t\t\t\tcounters[patternLength - 1] = 0;\n\t\t\t\t\t\tcounterPosition--;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcounterPosition++;\n\t\t\t\t\t}\n\t\t\t\t\tcounters[counterPosition] = 1;\n\t\t\t\t\tisWhite = !isWhite;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow ReaderException(\"\");\n\t\t}\n\n\t\tint Code128Reader::decodeCode(Ref<BitArray> row, int counters[], int countersCount,\n\t\t    int rowOffset) {\n\t\t  if (!recordPattern(row, rowOffset, counters, countersCount)) {\n\t\t    throw ReaderException(\"\");\n\t\t  }\n\t\t\tunsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept\n\t\t\tint bestMatch = -1;\n\t\t\tfor (int d = 0; d < CODE_PATTERNS_LENGTH; d++) {\n\t\t\t\tint pattern[countersLength];\n\n\t\t\t\tfor(int ind = 0; ind< countersLength; ind++){\n\t\t\t\t\tpattern[ind] = CODE_PATTERNS[d][ind];\n\t\t\t\t}\n//\t\t\t\tmemcpy(pattern, CODE_PATTERNS[d], countersLength);\n\t\t\t\tunsigned int variance = patternMatchVariance(counters, countersCount, pattern,\n\t\t\t\t    MAX_INDIVIDUAL_VARIANCE);\n\t\t\t\tif (variance < bestVariance) {\n\t\t\t\t\tbestVariance = variance;\n\t\t\t\t\tbestMatch = d;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// TODO We're overlooking the fact that the STOP pattern has 7 values, not 6.\n\t\t\tif (bestMatch >= 0) {\n\t\t\t\treturn bestMatch;\n\t\t\t} else {\n\t\t\t\tthrow ReaderException(\"\");\n\t\t\t}\n\t\t}\n\n\t\tRef<Result> Code128Reader::decodeRow(int rowNumber, Ref<BitArray> row) {\n\t\t  int* startPatternInfo = NULL;\n\t\t  try {\n        startPatternInfo = findStartPattern(row);\n        int startCode = startPatternInfo[2];\n        int codeSet;\n        switch (startCode) {\n          case CODE_START_A:\n            codeSet = CODE_CODE_A;\n            break;\n          case CODE_START_B:\n            codeSet = CODE_CODE_B;\n            break;\n          case CODE_START_C:\n            codeSet = CODE_CODE_C;\n            break;\n          default:\n            throw ReaderException(\"\");\n        }\n\n        bool done = false;\n        bool isNextShifted = false;\n\n        std::string tmpResultString;\n        std::stringstream tmpResultSStr; // used if its Code 128C\n\n        int lastStart = startPatternInfo[0];\n        int nextStart = startPatternInfo[1];\n        int counters[countersLength] = {0,0,0,0,0,0};\n\n        int lastCode = 0;\n        int code = 0;\n        int checksumTotal = startCode;\n        int multiplier = 0;\n        bool lastCharacterWasPrintable = true;\n\n        while (!done) {\n          bool unshift = isNextShifted;\n          isNextShifted = false;\n\n          // Save off last code\n          lastCode = code;\n\n          // Decode another code from image\n          try {\n            code = decodeCode(row, counters, sizeof(counters)/sizeof(int), nextStart);\n          } catch (ReaderException const& re) {\n            throw re;\n          }\n\n          // Remember whether the last code was printable or not (excluding CODE_STOP)\n          if (code != CODE_STOP) {\n            lastCharacterWasPrintable = true;\n          }\n\n          // Add to checksum computation (if not CODE_STOP of course)\n          if (code != CODE_STOP) {\n            multiplier++;\n            checksumTotal += multiplier * code;\n          }\n\n          // Advance to where the next code will to start\n          lastStart = nextStart;\n          int _countersLength = sizeof(counters) / sizeof(int);\n          for (int i = 0; i < _countersLength; i++) {\n            nextStart += counters[i];\n          }\n\n          // Take care of illegal start codes\n          switch (code) {\n            case CODE_START_A:\n            case CODE_START_B:\n            case CODE_START_C:\n              throw ReaderException(\"\");\n          }\n\n          switch (codeSet) {\n\n            case CODE_CODE_A:\n              if (code < 64) {\n                tmpResultString.append(1, (char) (' ' + code));\n              } else if (code < 96) {\n                tmpResultString.append(1, (char) (code - 64));\n              } else {\n                // Don't let CODE_STOP, which always appears, affect whether whether we think the\n                // last code was printable or not.\n                if (code != CODE_STOP) {\n                  lastCharacterWasPrintable = false;\n                }\n                switch (code) {\n                  case CODE_FNC_1:\n                  case CODE_FNC_2:\n                  case CODE_FNC_3:\n                  case CODE_FNC_4_A:\n                    // do nothing?\n                    break;\n                  case CODE_SHIFT:\n                    isNextShifted = true;\n                    codeSet = CODE_CODE_B;\n                    break;\n                  case CODE_CODE_B:\n                    codeSet = CODE_CODE_B;\n                    break;\n                  case CODE_CODE_C:\n                    codeSet = CODE_CODE_C;\n                    break;\n                  case CODE_STOP:\n                    done = true;\n                    break;\n                }\n              }\n              break;\n            case CODE_CODE_B:\n              if (code < 96) {\n                tmpResultString.append(1, (char) (' ' + code));\n              } else {\n                if (code != CODE_STOP) {\n                  lastCharacterWasPrintable = false;\n                }\n                switch (code) {\n                  case CODE_FNC_1:\n                  case CODE_FNC_2:\n                  case CODE_FNC_3:\n                  case CODE_FNC_4_B:\n                    // do nothing?\n                    break;\n                  case CODE_SHIFT:\n                    isNextShifted = true;\n                    codeSet = CODE_CODE_C;\n                    break;\n                  case CODE_CODE_A:\n                    codeSet = CODE_CODE_A;\n                    break;\n                  case CODE_CODE_C:\n                    codeSet = CODE_CODE_C;\n                    break;\n                  case CODE_STOP:\n                    done = true;\n                    break;\n                }\n              }\n              break;\n            case CODE_CODE_C:\n              tmpResultSStr.str(std::string());\n              // the code read in this case is the number encoded directly\n              if (code < 100) {\n                if (code < 10) {\n \t\t\t\t\t        tmpResultSStr << '0';\n \t\t\t\t        }\n                tmpResultSStr << code;\n \t\t\t\t        tmpResultString.append(tmpResultSStr.str());\n              } else {\n                if (code != CODE_STOP) {\n                  lastCharacterWasPrintable = false;\n                }\n                switch (code) {\n                  case CODE_FNC_1:\n                    // do nothing?\n                    break;\n                  case CODE_CODE_A:\n                    codeSet = CODE_CODE_A;\n                    break;\n                  case CODE_CODE_B:\n                    codeSet = CODE_CODE_B;\n                    break;\n                  case CODE_STOP:\n                    done = true;\n                    break;\n                }\n              }\n              break;\n          }\n\n          // Unshift back to another code set if we were shifted\n          if (unshift) {\n            switch (codeSet) {\n              case CODE_CODE_A:\n                codeSet = CODE_CODE_C;\n                break;\n              case CODE_CODE_B:\n                codeSet = CODE_CODE_A;\n                break;\n              case CODE_CODE_C:\n                codeSet = CODE_CODE_B;\n                break;\n            }\n          }\n\n        }\n\n        // Check for ample whitespace following pattern, but, to do this we first need to remember that\n        // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left\n        // to read off. Would be slightly better to properly read. Here we just skip it:\n        int width = row->getSize();\n        while (nextStart < width && row->get(nextStart)) {\n          nextStart++;\n        }\n        if (!row->isRange(nextStart,\n                          std::min(width, nextStart + (nextStart - lastStart) / 2),\n                          false)) {\n          throw ReaderException(\"\");\n        }\n\n        // Pull out from sum the value of the penultimate check code\n        checksumTotal -= multiplier * lastCode;\n        // lastCode is the checksum then:\n        if (checksumTotal % 103 != lastCode) {\n          throw ReaderException(\"\");\n        }\n\n        // Need to pull out the check digits from string\n        int resultLength = tmpResultString.length();\n        // Only bother if the result had at least one character, and if the checksum digit happened to\n        // be a printable character. If it was just interpreted as a control code, nothing to remove.\n        if (resultLength > 0 && lastCharacterWasPrintable) {\n          if (codeSet == CODE_CODE_C) {\n            tmpResultString.erase(resultLength - 2, resultLength);\n          } else {\n            tmpResultString.erase(resultLength - 1, resultLength);\n          }\n        }\n\n        Ref<String> resultString(new String(tmpResultString));\n        if (tmpResultString.length() == 0) {\n          // Almost surely a false positive\n          throw ReaderException(\"\");\n        }\n\n        float left = (float) (startPatternInfo[1] + startPatternInfo[0]) / 2.0f;\n        float right = (float) (nextStart + lastStart) / 2.0f;\n\n        std::vector< Ref<ResultPoint> > resultPoints(2);\n        Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber));\n        Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(right, (float) rowNumber));\n        resultPoints[0] = resultPoint1;\n        resultPoints[1] = resultPoint2;\n\n        delete [] startPatternInfo;\n        ArrayRef<unsigned char> resultBytes(1);\n        return Ref<Result>(new Result(resultString, resultBytes, resultPoints,\n            BarcodeFormat_CODE_128));\n\t\t\t} catch (ReaderException const& re) {\n\t\t\t  delete [] startPatternInfo;\n\t\t\t  return Ref<Result>();\n\t\t\t}\n\t\t}\n\n\t\tvoid Code128Reader::append(char* s, char c){\n\t\t\tint len = strlen(s);\n\t\t\ts[len] = c;\n\t\t\ts[len + 1] = '\\0';\n\t\t}\n\n\t\tCode128Reader::~Code128Reader(){\n\t\t}\n\t}\n}\n\n// file: zxing/oned/Code39Reader.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include \"Code39Reader.h\"\n// #include <zxing/oned/OneDResultPoint.h>\n// #include <zxing/common/Array.h>\n// #include <zxing/ReaderException.h>\n// #include <math.h>\n// #include <limits.h>\n\nnamespace zxing {\nnamespace oned {\n\n  static const char* ALPHABET = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%\";\n\n\n  /**\n   * These represent the encodings of characters, as patterns of wide and narrow\n   * bars.\n   * The 9 least-significant bits of each int correspond to the pattern of wide\n   * and narrow, with 1s representing \"wide\" and 0s representing narrow.\n   */\n  const int CHARACTER_ENCODINGS_LEN = 44;\n  static int CHARACTER_ENCODINGS[CHARACTER_ENCODINGS_LEN] = {\n    0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9\n    0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J\n    0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T\n    0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, // U-*\n    0x0A8, 0x0A2, 0x08A, 0x02A // $-%\n  };\n\n  static int ASTERISK_ENCODING = 0x094;\n  static const char* ALPHABET_STRING =\n    \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%\";\n\n\n  /**\n   * Creates a reader that assumes all encoded data is data, and does not treat\n   * the final character as a check digit. It will not decoded \"extended\n   * Code 39\" sequences.\n   */\n  Code39Reader::Code39Reader() : alphabet_string(ALPHABET_STRING),\n                                 usingCheckDigit(false),\n                                 extendedMode(false) {\n  }\n\n  /**\n   * Creates a reader that can be configured to check the last character as a\n   * check digit. It will not decoded \"extended Code 39\" sequences.\n   *\n   * @param usingCheckDigit if true, treat the last data character as a check\n   * digit, not data, and verify that the checksum passes.\n   */\n  Code39Reader::Code39Reader(bool usingCheckDigit_) :\n    alphabet_string(ALPHABET_STRING),\n    usingCheckDigit(usingCheckDigit_),\n    extendedMode(false) {\n  }\n\n\n  Code39Reader::Code39Reader(bool usingCheckDigit_, bool extendedMode_) :\n    alphabet_string(ALPHABET_STRING),\n    usingCheckDigit(usingCheckDigit_),\n    extendedMode(extendedMode_) {\n  }\n\n  Ref<Result> Code39Reader::decodeRow(int rowNumber, Ref<BitArray> row) {\n    int* start = NULL;\n    try {\n      start = findAsteriskPattern(row);\n      int nextStart = start[1];\n      int end = row->getSize();\n\n      // Read off white space\n      while (nextStart < end && !row->get(nextStart)) {\n        nextStart++;\n      }\n\n      std::string tmpResultString;\n\n      const int countersLen = 9;\n      int counters[countersLen];\n      for (int i = 0; i < countersLen; i++) {\n        counters[i] = 0;\n      }\n      char decodedChar;\n      int lastStart;\n      do {\n        if (!recordPattern(row, nextStart, counters, countersLen)) {\n          throw ReaderException(\"\");\n        }\n        int pattern = toNarrowWidePattern(counters, countersLen);\n        if (pattern < 0) {\n          throw ReaderException(\"pattern < 0\");\n        }\n        decodedChar = patternToChar(pattern);\n        tmpResultString.append(1, decodedChar);\n        lastStart = nextStart;\n        for (int i = 0; i < countersLen; i++) {\n          nextStart += counters[i];\n        }\n        // Read off white space\n        while (nextStart < end && !row->get(nextStart)) {\n          nextStart++;\n        }\n      } while (decodedChar != '*');\n      tmpResultString.erase(tmpResultString.length()-1, 1);// remove asterisk\n\n      // Look for whitespace after pattern:\n      int lastPatternSize = 0;\n      for (int i = 0; i < countersLen; i++) {\n        lastPatternSize += counters[i];\n      }\n      int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize;\n      // If 50% of last pattern size, following last pattern, is not whitespace,\n      // fail (but if it's whitespace to the very end of the image, that's OK)\n      if (nextStart != end && whiteSpaceAfterEnd / 2 < lastPatternSize) {\n        throw ReaderException(\"too short end white space\");\n      }\n\n      if (usingCheckDigit) {\n        int max = tmpResultString.length() - 1;\n        unsigned int total = 0;\n        for (int i = 0; i < max; i++) {\n          total += alphabet_string.find_first_of(tmpResultString[i], 0);\n        }\n        if (total % 43 != alphabet_string.find_first_of(tmpResultString[max], 0)) {\n          throw ReaderException(\"\");\n        }\n        tmpResultString.erase(max, 1);\n      }\n\n      Ref<String> resultString(new String(tmpResultString));\n      if (extendedMode) {\n        resultString = decodeExtended(tmpResultString);\n      }\n\n      if (tmpResultString.length() == 0) {\n        // Almost surely a false positive\n        throw ReaderException(\"\");\n      }\n\n      float left = (float) (start[1] + start[0]) / 2.0f;\n      float right = (float) (nextStart + lastStart) / 2.0f;\n\n      std::vector< Ref<ResultPoint> > resultPoints(2);\n      Ref<OneDResultPoint> resultPoint1(\n        new OneDResultPoint(left, (float) rowNumber));\n      Ref<OneDResultPoint> resultPoint2(\n        new OneDResultPoint(right, (float) rowNumber));\n      resultPoints[0] = resultPoint1;\n      resultPoints[1] = resultPoint2;\n\n      ArrayRef<unsigned char> resultBytes(1);\n\n      Ref<Result> res(new Result(\n                        resultString, resultBytes, resultPoints, BarcodeFormat_CODE_39));\n\n      delete [] start;\n      return res;\n    } catch (ReaderException const& re) {\n      delete [] start;\n      return Ref<Result>();\n    }\n  }\n\n  int* Code39Reader::findAsteriskPattern(Ref<BitArray> row){\n    int width = row->getSize();\n    int rowOffset = 0;\n    while (rowOffset < width) {\n      if (row->get(rowOffset)) {\n        break;\n      }\n      rowOffset++;\n    }\n\n    int counterPosition = 0;\n    const int countersLen = 9;\n    int counters[countersLen];\n    for (int i = 0; i < countersLen; i++) {\n      counters[i] = 0;\n    }\n    int patternStart = rowOffset;\n    bool isWhite = false;\n    int patternLength = countersLen;\n\n    for (int i = rowOffset; i < width; i++) {\n      bool pixel = row->get(i);\n      if (pixel ^ isWhite) {\n        counters[counterPosition]++;\n      } else {\n        if (counterPosition == patternLength - 1) {\n          if (toNarrowWidePattern(counters, countersLen) == ASTERISK_ENCODING) {\n            // Look for whitespace before start pattern, >= 50% of width of\n            // start pattern.\n            if (row->isRange(std::max(0, patternStart - ((i - patternStart) >> 1)), patternStart, false)) {\n              int* resultValue = new int[2];\n              resultValue[0] = patternStart;\n              resultValue[1] = i;\n              return resultValue;\n            }\n          }\n          patternStart += counters[0] + counters[1];\n          for (int y = 2; y < patternLength; y++) {\n            counters[y - 2] = counters[y];\n          }\n          counters[patternLength - 2] = 0;\n          counters[patternLength - 1] = 0;\n          counterPosition--;\n        } else {\n          counterPosition++;\n        }\n        counters[counterPosition] = 1;\n        isWhite = !isWhite;\n      }\n    }\n    throw ReaderException(\"\");\n  }\n\n  // For efficiency, returns -1 on failure. Not throwing here saved as many as\n  // 700 exceptions per image when using some of our blackbox images.\n  int Code39Reader::toNarrowWidePattern(int counters[], int countersLen){\n    int numCounters = countersLen;\n    int maxNarrowCounter = 0;\n    int wideCounters;\n    do {\n      int minCounter = INT_MAX;\n      for (int i = 0; i < numCounters; i++) {\n        int counter = counters[i];\n        if (counter < minCounter && counter > maxNarrowCounter) {\n          minCounter = counter;\n        }\n      }\n      maxNarrowCounter = minCounter;\n      wideCounters = 0;\n      int totalWideCountersWidth = 0;\n      int pattern = 0;\n      for (int i = 0; i < numCounters; i++) {\n        int counter = counters[i];\n        if (counters[i] > maxNarrowCounter) {\n          pattern |= 1 << (numCounters - 1 - i);\n          wideCounters++;\n          totalWideCountersWidth += counter;\n        }\n      }\n      if (wideCounters == 3) {\n        // Found 3 wide counters, but are they close enough in width?\n        // We can perform a cheap, conservative check to see if any individual\n        // counter is more than 1.5 times the average:\n        for (int i = 0; i < numCounters && wideCounters > 0; i++) {\n          int counter = counters[i];\n          if (counters[i] > maxNarrowCounter) {\n            wideCounters--;\n            // totalWideCountersWidth = 3 * average, so this checks if\n            // counter >= 3/2 * average.\n            if ((counter << 1) >= totalWideCountersWidth) {\n              return -1;\n            }\n          }\n        }\n        return pattern;\n      }\n    } while (wideCounters > 3);\n    return -1;\n  }\n\n  char Code39Reader::patternToChar(int pattern){\n    for (int i = 0; i < CHARACTER_ENCODINGS_LEN; i++) {\n      if (CHARACTER_ENCODINGS[i] == pattern) {\n        return ALPHABET[i];\n      }\n    }\n    throw ReaderException(\"\");\n  }\n\n  Ref<String> Code39Reader::decodeExtended(std::string encoded){\n    int length = encoded.length();\n    std::string tmpDecoded;\n    for (int i = 0; i < length; i++) {\n      char c = encoded[i];\n      if (c == '+' || c == '$' || c == '%' || c == '/') {\n        char next = encoded[i + 1];\n        char decodedChar = '\\0';\n        switch (c) {\n          case '+':\n            // +A to +Z map to a to z\n            if (next >= 'A' && next <= 'Z') {\n              decodedChar = (char) (next + 32);\n            } else {\n              throw ReaderException(\"\");\n            }\n            break;\n          case '$':\n            // $A to $Z map to control codes SH to SB\n            if (next >= 'A' && next <= 'Z') {\n              decodedChar = (char) (next - 64);\n            } else {\n              throw ReaderException(\"\");\n            }\n            break;\n          case '%':\n            // %A to %E map to control codes ESC to US\n            if (next >= 'A' && next <= 'E') {\n              decodedChar = (char) (next - 38);\n            } else if (next >= 'F' && next <= 'W') {\n              decodedChar = (char) (next - 11);\n            } else {\n              throw ReaderException(\"\");\n            }\n            break;\n          case '/':\n            // /A to /O map to ! to , and /Z maps to :\n            if (next >= 'A' && next <= 'O') {\n              decodedChar = (char) (next - 32);\n            } else if (next == 'Z') {\n              decodedChar = ':';\n            } else {\n              throw ReaderException(\"\");\n            }\n            break;\n        }\n        tmpDecoded.append(1, decodedChar);\n        // bump up i again since we read two characters\n        i++;\n      } else {\n        tmpDecoded.append(1, c);\n      }\n    }\n    Ref<String> decoded(new String(tmpDecoded));\n    return decoded;\n  }\n} // namespace oned\n} // namespace zxing\n\n\n// file: zxing/oned/EAN13Reader.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include \"EAN13Reader.h\"\n// #include <zxing/ReaderException.h>\n\nnamespace zxing {\n  namespace oned {\n\n    static const int FIRST_DIGIT_ENCODINGS[10] = {\n      0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A\n    };\n\n    EAN13Reader::EAN13Reader() { }\n\n    int EAN13Reader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,\n        std::string& resultString) {\n      (void)startGuardBegin;\n      const int countersLen = 4;\n      int counters[countersLen] = { 0, 0, 0, 0 };\n\n      int end = row->getSize();\n      int rowOffset = startGuardEnd;\n      int lgPatternFound = 0;\n\n      for (int x = 0; x < 6 && rowOffset < end; x++) {\n        int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,\n            UPC_EAN_PATTERNS_L_AND_G_PATTERNS);\n        if (bestMatch < 0) {\n          return -1;\n        }\n        resultString.append(1, (char) ('0' + bestMatch % 10));\n        for (int i = 0; i < countersLen; i++) {\n          rowOffset += counters[i];\n        }\n        if (bestMatch >= 10) {\n          lgPatternFound |= 1 << (5 - x);\n        }\n      }\n\n      if (!determineFirstDigit(resultString, lgPatternFound)) {\n        return -1;\n      }\n\n      int middleRangeStart;\n      int middleRangeEnd;\n      if (findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(),\n            getMIDDLE_PATTERN_LEN(), &middleRangeStart, &middleRangeEnd)) {\n        rowOffset = middleRangeEnd;\n        for (int x = 0; x < 6 && rowOffset < end; x++) {\n          int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,\n              UPC_EAN_PATTERNS_L_PATTERNS);\n          if (bestMatch < 0) {\n            return -1;\n          }\n          resultString.append(1, (char) ('0' + bestMatch));\n          for (int i = 0; i < countersLen; i++) {\n            rowOffset += counters[i];\n          }\n        }\n        return rowOffset;\n      }\n      return -1;\n    }\n\n    bool EAN13Reader::determineFirstDigit(std::string& resultString, int lgPatternFound) {\n      for (int d = 0; d < 10; d++) {\n        if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) {\n          resultString.insert(0, 1, (char) ('0' + d));\n          return true;\n        }\n      }\n      return false;\n    }\n\n    BarcodeFormat EAN13Reader::getBarcodeFormat(){\n      return BarcodeFormat_EAN_13;\n    }\n  }\n}\n\n// file: zxing/oned/EAN8Reader.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include \"EAN8Reader.h\"\n// #include <zxing/ReaderException.h>\n\nnamespace zxing {\n  namespace oned {\n\n    EAN8Reader::EAN8Reader(){ }\n\n    int EAN8Reader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,\n        std::string& resultString){\n      (void)startGuardBegin;\n      const int countersLen = 4;\n      int counters[countersLen] = { 0, 0, 0, 0 };\n\n      int end = row->getSize();\n      int rowOffset = startGuardEnd;\n\n      for (int x = 0; x < 4 && rowOffset < end; x++) {\n        int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,\n            UPC_EAN_PATTERNS_L_PATTERNS);\n        if (bestMatch < 0) {\n          return -1;\n        }\n        resultString.append(1, (char) ('0' + bestMatch));\n        for (int i = 0; i < countersLen; i++) {\n          rowOffset += counters[i];\n        }\n      }\n\n      int middleRangeStart;\n      int middleRangeEnd;\n      if (findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(),\n            getMIDDLE_PATTERN_LEN(), &middleRangeStart, &middleRangeEnd)) {\n        rowOffset = middleRangeEnd;\n        for (int x = 0; x < 4 && rowOffset < end; x++) {\n          int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,\n              UPC_EAN_PATTERNS_L_PATTERNS);\n          if (bestMatch < 0) {\n            return -1;\n          }\n          resultString.append(1, (char) ('0' + bestMatch));\n          for (int i = 0; i < countersLen; i++) {\n            rowOffset += counters[i];\n          }\n        }\n        return rowOffset;\n      }\n      return -1;\n    }\n\n    BarcodeFormat EAN8Reader::getBarcodeFormat(){\n      return BarcodeFormat_EAN_8;\n    }\n  }\n}\n\n// file: zxing/oned/ITFReader.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include \"ITFReader.h\"\n// #include <zxing/oned/OneDResultPoint.h>\n// #include <zxing/common/Array.h>\n// #include <zxing/ReaderException.h>\n// #include <math.h>\n\nnamespace zxing {\n  namespace oned {\n\n    static const int W = 3; // Pixel width of a wide line\n    static const int N = 1; // Pixed width of a narrow line\n\n    const int DEFAULT_ALLOWED_LENGTHS_LEN = 10;\n    const int DEFAULT_ALLOWED_LENGTHS[DEFAULT_ALLOWED_LENGTHS_LEN] = { 44, 24, 20, 18, 16, 14, 12, 10, 8, 6 };\n\n    /**\n     * Start/end guard pattern.\n     *\n     * Note: The end pattern is reversed because the row is reversed before\n     * searching for the END_PATTERN\n     */\n    static const int START_PATTERN_LEN = 4;\n    static const int START_PATTERN[START_PATTERN_LEN] = {N, N, N, N};\n\n    static const int END_PATTERN_REVERSED_LEN = 3;\n    static const int END_PATTERN_REVERSED[END_PATTERN_REVERSED_LEN] = {N, N, W};\n\n    /**\n     * Patterns of Wide / Narrow lines to indicate each digit\n     */\n    static const int PATTERNS_LEN = 10;\n    static const int PATTERNS[PATTERNS_LEN][5] = {\n      {N, N, W, W, N}, // 0\n      {W, N, N, N, W}, // 1\n      {N, W, N, N, W}, // 2\n      {W, W, N, N, N}, // 3\n      {N, N, W, N, W}, // 4\n      {W, N, W, N, N}, // 5\n      {N, W, W, N, N}, // 6\n      {N, N, N, W, W}, // 7\n      {W, N, N, W, N}, // 8\n      {N, W, N, W, N}  // 9\n    };\n\n\n    ITFReader::ITFReader() : narrowLineWidth(-1) {\n    }\n\n\n    Ref<Result> ITFReader::decodeRow(int rowNumber, Ref<BitArray> row) {\n      int* startRange = 0;\n      int* endRange = 0;\n      try {\n        // Find out where the Middle section (payload) starts & ends\n        startRange = decodeStart(row);\n        endRange = decodeEnd(row);\n\n        std::string tmpResult;\n        decodeMiddle(row, startRange[1], endRange[0], tmpResult);\n\n        // To avoid false positives with 2D barcodes (and other patterns), make\n        // an assumption that the decoded string must be a known length\n        int length = tmpResult.length();\n        bool lengthOK = false;\n        for (int i = 0; i < DEFAULT_ALLOWED_LENGTHS_LEN; i++) {\n          if (length == DEFAULT_ALLOWED_LENGTHS[i]) {\n            lengthOK = true;\n            break;\n          }\n        }\n        if (!lengthOK) {\n          throw ReaderException(\"not enough characters count\");\n        }\n\n        Ref<String> resultString(new String(tmpResult));\n\n        std::vector< Ref<ResultPoint> > resultPoints(2);\n        Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber));\n        Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber));\n        resultPoints[0] = resultPoint1;\n        resultPoints[1] = resultPoint2;\n\n        delete [] startRange;\n        delete [] endRange;\n        ArrayRef<unsigned char> resultBytes(1);\n        return Ref<Result>(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF));\n      } catch (ReaderException const& re) {\n        delete [] startRange;\n        delete [] endRange;\n        return Ref<Result>();\n      }\n    }\n\n    /**\n     * @param row          row of black/white values to search\n     * @param payloadStart offset of start pattern\n     * @param resultString {@link StringBuffer} to append decoded chars to\n     * @throws ReaderException if decoding could not complete successfully\n     */\n    void ITFReader::decodeMiddle(Ref<BitArray> row, int payloadStart, int payloadEnd,\n        std::string& resultString) {\n      // Digits are interleaved in pairs - 5 black lines for one digit, and the\n      // 5\n      // interleaved white lines for the second digit.\n      // Therefore, need to scan 10 lines and then\n      // split these into two arrays\n      int counterDigitPairLen = 10;\n      int counterDigitPair[counterDigitPairLen];\n      for (int i=0; i<counterDigitPairLen; i++) {\n        counterDigitPair[i] = 0;\n      }\n\n      int counterBlack[5];\n      int counterWhite[5];\n      for (int i=0; i<5; i++) {\n        counterBlack[i] = 0;\n        counterWhite[i] = 0;\n      }\n\n      while (payloadStart < payloadEnd) {\n        // Get 10 runs of black/white.\n        if (!recordPattern(row, payloadStart, counterDigitPair, counterDigitPairLen)) {\n          throw ReaderException(\"\");\n        }\n        // Split them into each array\n        for (int k = 0; k < 5; k++) {\n          int twoK = k << 1;\n          counterBlack[k] = counterDigitPair[twoK];\n          counterWhite[k] = counterDigitPair[twoK + 1];\n        }\n\n        int bestMatch = decodeDigit(counterBlack, 5);\n        resultString.append(1, (char) ('0' + bestMatch));\n        bestMatch = decodeDigit(counterWhite, 5);\n        resultString.append(1, (char) ('0' + bestMatch));\n\n        for (int i = 0; i < counterDigitPairLen; i++) {\n          payloadStart += counterDigitPair[i];\n        }\n      }\n    }\n\n    /**\n     * Identify where the start of the middle / payload section starts.\n     *\n     * @param row row of black/white values to search\n     * @return Array, containing index of start of 'start block' and end of\n     *         'start block'\n     * @throws ReaderException\n     */\n    int* ITFReader::decodeStart(Ref<BitArray> row) {\n      int endStart = skipWhiteSpace(row);\n      int* startPattern = 0;\n      try {\n          startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN);\n\n          // Determine the width of a narrow line in pixels. We can do this by\n          // getting the width of the start pattern and dividing by 4 because its\n          // made up of 4 narrow lines.\n          narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2;\n          validateQuietZone(row, startPattern[0]);\n          return startPattern;\n      } catch (ReaderException const& re) {\n          delete [] startPattern;\n        throw re;\n      }\n    }\n\n    /**\n     * Identify where the end of the middle / payload section ends.\n     *\n     * @param row row of black/white values to search\n     * @return Array, containing index of start of 'end block' and end of 'end\n     *         block'\n     * @throws ReaderException\n     */\n\n    int* ITFReader::decodeEnd(Ref<BitArray> row) {\n      // For convenience, reverse the row and then\n      // search from 'the start' for the end block\n      row->reverse();\n                        int* endPattern = 0;\n      try {\n        int endStart = skipWhiteSpace(row);\n        endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED, END_PATTERN_REVERSED_LEN);\n\n        // The start & end patterns must be pre/post fixed by a quiet zone. This\n        // zone must be at least 10 times the width of a narrow line.\n        // ref: http://www.barcode-1.net/i25code.html\n        validateQuietZone(row, endPattern[0]);\n\n        // Now recalculate the indices of where the 'endblock' starts & stops to\n        // accommodate\n        // the reversed nature of the search\n        int temp = endPattern[0];\n        endPattern[0] = row->getSize() - endPattern[1];\n        endPattern[1] = row->getSize() - temp;\n\n        row->reverse();\n        return endPattern;\n      } catch (ReaderException const& re) {\n                                delete [] endPattern;\n        row->reverse();\n        throw re;\n      }\n    }\n\n    /**\n     * The start & end patterns must be pre/post fixed by a quiet zone. This\n     * zone must be at least 10 times the width of a narrow line.  Scan back until\n     * we either get to the start of the barcode or match the necessary number of\n     * quiet zone pixels.\n     *\n     * Note: Its assumed the row is reversed when using this method to find\n     * quiet zone after the end pattern.\n     *\n     * ref: http://www.barcode-1.net/i25code.html\n     *\n     * @param row bit array representing the scanned barcode.\n     * @param startPattern index into row of the start or end pattern.\n     * @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown.\n     */\n    void ITFReader::validateQuietZone(Ref<BitArray> row, int startPattern) {\n      (void)row;\n      (void)startPattern;\n//#pragma mark needs some corrections\n//      int quietCount = narrowLineWidth * 10;  // expect to find this many pixels of quiet zone\n//\n//      for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) {\n//        if (row->get(i)) {\n//          break;\n//        }\n//        quietCount--;\n//      }\n//      if (quietCount != 0) {\n//        // Unable to find the necessary number of quiet zone pixels.\n//        throw ReaderException(\"Unable to find the necessary number of quiet zone pixels\");\n//      }\n    }\n\n    /**\n     * Skip all whitespace until we get to the first black line.\n     *\n     * @param row row of black/white values to search\n     * @return index of the first black line.\n     * @throws ReaderException Throws exception if no black lines are found in the row\n     */\n    int ITFReader::skipWhiteSpace(Ref<BitArray> row) {\n      int width = row->getSize();\n      int endStart = 0;\n      while (endStart < width) {\n        if (row->get(endStart)) {\n          break;\n        }\n        endStart++;\n      }\n      if (endStart == width) {\n        throw ReaderException(\"\");\n      }\n      return endStart;\n    }\n\n    /**\n     * @param row       row of black/white values to search\n     * @param rowOffset position to start search\n     * @param pattern   pattern of counts of number of black and white pixels that are\n     *                  being searched for as a pattern\n     * @return start/end horizontal offset of guard pattern, as an array of two\n     *         ints\n     * @throws ReaderException if pattern is not found\n     */\n    int* ITFReader::findGuardPattern(Ref<BitArray> row, int rowOffset, const int pattern[],\n        int patternLen) {\n      // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be\n      // merged to a single method.\n      int patternLength = patternLen;\n      int counters[patternLength];\n      for (int i=0; i<patternLength; i++) {\n        counters[i] = 0;\n      }\n      int width = row->getSize();\n      bool isWhite = false;\n\n      int counterPosition = 0;\n      int patternStart = rowOffset;\n      for (int x = rowOffset; x < width; x++) {\n        bool pixel = row->get(x);\n        if (pixel ^ isWhite) {\n          counters[counterPosition]++;\n        } else {\n          if (counterPosition == patternLength - 1) {\n            if (patternMatchVariance(counters, patternLength, pattern,\n                MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {\n              int* resultValue = new int[2];\n              resultValue[0] = patternStart;\n              resultValue[1] = x;\n              return resultValue;\n            }\n            patternStart += counters[0] + counters[1];\n            for (int y = 2; y < patternLength; y++) {\n              counters[y - 2] = counters[y];\n            }\n            counters[patternLength - 2] = 0;\n            counters[patternLength - 1] = 0;\n            counterPosition--;\n          } else {\n            counterPosition++;\n          }\n          counters[counterPosition] = 1;\n          isWhite = !isWhite;\n        }\n      }\n      throw ReaderException(\"\");\n    }\n\n    /**\n     * Attempts to decode a sequence of ITF black/white lines into single\n     * digit.\n     *\n     * @param counters the counts of runs of observed black/white/black/... values\n     * @return The decoded digit\n     * @throws ReaderException if digit cannot be decoded\n     */\n    int ITFReader::decodeDigit(int counters[], int countersLen){\n      unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept\n      int bestMatch = -1;\n      int max = PATTERNS_LEN;\n      for (int i = 0; i < max; i++) {\n        int pattern[countersLen];\n        for(int ind = 0; ind<countersLen; ind++){\n          pattern[ind] = PATTERNS[i][ind];\n        }\n        unsigned int variance = patternMatchVariance(counters, countersLen, pattern,\n            MAX_INDIVIDUAL_VARIANCE);\n        if (variance < bestVariance) {\n          bestVariance = variance;\n          bestMatch = i;\n        }\n      }\n      if (bestMatch >= 0) {\n        return bestMatch;\n      } else {\n        throw ReaderException(\"digit didint found\");\n      }\n    }\n\n    ITFReader::~ITFReader(){\n    }\n  }\n}\n\n// file: zxing/oned/MultiFormatOneDReader.cpp\n\n/*\n *  MultiFormatOneDReader.cpp\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include \"MultiFormatOneDReader.h\"\n\n// #include <zxing/oned/MultiFormatUPCEANReader.h>\n// #include <zxing/oned/Code39Reader.h>\n// #include <zxing/oned/Code128Reader.h>\n// #include <zxing/oned/ITFReader.h>\n// #include <zxing/ReaderException.h>\n\nnamespace zxing {\n  namespace oned {\n    MultiFormatOneDReader::MultiFormatOneDReader(DecodeHints hints) : readers() {\n      if (hints.containsFormat(BarcodeFormat_EAN_13) ||\n          hints.containsFormat(BarcodeFormat_EAN_8) ||\n          hints.containsFormat(BarcodeFormat_UPC_A) ||\n          hints.containsFormat(BarcodeFormat_UPC_E)) {\n        readers.push_back(Ref<OneDReader>(new MultiFormatUPCEANReader(hints)));\n      }\n      if (hints.containsFormat(BarcodeFormat_CODE_39)) {\n        readers.push_back(Ref<OneDReader>(new Code39Reader()));\n      }\n      if (hints.containsFormat(BarcodeFormat_CODE_128)) {\n        readers.push_back(Ref<OneDReader>(new Code128Reader()));\n      }\n      if (hints.containsFormat(BarcodeFormat_ITF)) {\n        readers.push_back(Ref<OneDReader>(new ITFReader()));\n      }\n      if (readers.size() == 0) {\n        readers.push_back(Ref<OneDReader>(new MultiFormatUPCEANReader(hints)));\n        readers.push_back(Ref<OneDReader>(new Code39Reader()));\n        readers.push_back(Ref<OneDReader>(new Code128Reader()));\n        readers.push_back(Ref<OneDReader>(new ITFReader()));\n      }\n    }\n\n    Ref<Result> MultiFormatOneDReader::decodeRow(int rowNumber, Ref<BitArray> row) {\n      int size = readers.size();\n      for (int i = 0; i < size; i++) {\n        OneDReader* reader = readers[i];\n        Ref<Result> result = reader->decodeRow(rowNumber, row);\n        if (!result.empty()) {\n          return result;\n        }\n      }\n      return Ref<Result>();\n    }\n  }\n}\n\n// file: zxing/oned/MultiFormatUPCEANReader.cpp\n\n/*\n *  MultiFormatUPCEANReader.cpp\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n// #include \"MultiFormatUPCEANReader.h\"\n\n// #include <zxing/oned/EAN13Reader.h>\n// #include <zxing/oned/EAN8Reader.h>\n// #include <zxing/oned/UPCEReader.h>\n// #include <zxing/oned/UPCAReader.h>\n// #include <zxing/oned/OneDResultPoint.h>\n// #include <zxing/common/Array.h>\n// #include <zxing/ReaderException.h>\n// #include <math.h>\n\nnamespace zxing {\n  namespace oned {\n\n    MultiFormatUPCEANReader::MultiFormatUPCEANReader(DecodeHints hints) : readers() {\n      if (hints.containsFormat(BarcodeFormat_EAN_13)) {\n        readers.push_back(Ref<OneDReader>(new EAN13Reader()));\n      } else if (hints.containsFormat(BarcodeFormat_UPC_A)) {\n        readers.push_back(Ref<OneDReader>(new UPCAReader()));\n      }\n      if (hints.containsFormat(BarcodeFormat_EAN_8)) {\n        readers.push_back(Ref<OneDReader>(new EAN8Reader()));\n      }\n      if (hints.containsFormat(BarcodeFormat_UPC_E)) {\n        readers.push_back(Ref<OneDReader>(new UPCEReader()));\n      }\n      if (readers.size() == 0) {\n        readers.push_back(Ref<OneDReader>(new EAN13Reader()));\n        // UPC-A is covered by EAN-13\n        readers.push_back(Ref<OneDReader>(new EAN8Reader()));\n        readers.push_back(Ref<OneDReader>(new UPCEReader()));\n      }\n    }\n\n    Ref<Result> MultiFormatUPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) {\n      // Compute this location once and reuse it on multiple implementations\n      int size = readers.size();\n      for (int i = 0; i < size; i++) {\n        Ref<OneDReader> reader = readers[i];\n        Ref<Result> result = reader->decodeRow(rowNumber, row);\n        if (result.empty()) {\n          continue;\n        }\n\n        // Special case: a 12-digit code encoded in UPC-A is identical to a \"0\"\n        // followed by those 12 digits encoded as EAN-13. Each will recognize such a code,\n        // UPC-A as a 12-digit string and EAN-13 as a 13-digit string starting with \"0\".\n        // Individually these are correct and their readers will both read such a code\n        // and correctly call it EAN-13, or UPC-A, respectively.\n        //\n        // In this case, if we've been looking for both types, we'd like to call it\n        // a UPC-A code. But for efficiency we only run the EAN-13 decoder to also read\n        // UPC-A. So we special case it here, and convert an EAN-13 result to a UPC-A\n        // result if appropriate.\n        if (result->getBarcodeFormat() == BarcodeFormat_EAN_13) {\n          const std::string& text = (result->getText())->getText();\n          if (text[0] == '0') {\n            Ref<String> resultString(new String(text.substr(1)));\n            Ref<Result> res(new Result(resultString, result->getRawBytes(),\n                result->getResultPoints(), BarcodeFormat_UPC_A));\n            return res;\n          }\n        }\n        return result;\n      }\n      return Ref<Result>();\n    }\n  }\n}\n\n// file: zxing/oned/OneDReader.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  OneDReader.cpp\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include \"OneDReader.h\"\n// #include <zxing/ReaderException.h>\n// #include <zxing/oned/OneDResultPoint.h>\n// #include <math.h>\n// #include <limits.h>\n\nnamespace zxing {\n  namespace oned {\n    using namespace std;\n\n    OneDReader::OneDReader() {\n    }\n\n    Ref<Result> OneDReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {\n      Ref<Result> result = doDecode(image, hints);\n      if (result.empty()) { // && hints.getTryHarder() && image->isRotateSupported()) {\n        Ref<BinaryBitmap> rotatedImage(image->rotateCounterClockwise());\n        result = doDecode(rotatedImage, hints);\n        if (!result.empty()) {\n          /*\n          // Record that we found it rotated 90 degrees CCW / 270 degrees CW\n          Hashtable metadata = result.getResultMetadata();\n          int orientation = 270;\n          if (metadata != null && metadata.containsKey(ResultMetadataType.ORIENTATION)) {\n            // But if we found it reversed in doDecode(), add in that result here:\n            orientation = (orientation +\n                     ((Integer) metadata.get(ResultMetadataType.ORIENTATION)).intValue()) % 360;\n          }\n          result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(orientation));\n          */\n          // Update result points\n          std::vector<Ref<ResultPoint> >& points (result->getResultPoints());\n          int height = rotatedImage->getHeight();\n          for (size_t i = 0; i < points.size(); i++) {\n            points[i].reset(new OneDResultPoint(height - points[i]->getY() - 1, points[i]->getX()));\n          }\n        }\n      }\n      if (result.empty()) {\n        throw ReaderException(\"\");\n      }\n      return result;\n    }\n\n    Ref<Result> OneDReader::doDecode(Ref<BinaryBitmap> image, DecodeHints hints) {\n      int width = image->getWidth();\n      int height = image->getHeight();\n      Ref<BitArray> row(new BitArray(width));\n      int middle = height >> 1;\n      bool tryHarder = hints.getTryHarder();\n      int rowStep = (int)fmax(1, height >> (tryHarder ? 8 : 5));\n      int maxLines;\n      if (tryHarder) {\n        maxLines = height; // Look at the whole image, not just the center\n      } else {\n        maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image\n      }\n\n      for (int x = 0; x < maxLines; x++) {\n        // Scanning from the middle out. Determine which row we're looking at next:\n        int rowStepsAboveOrBelow = (x + 1) >> 1;\n        bool isAbove = (x & 0x01) == 0; // i.e. is x even?\n        int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);\n        if (rowNumber < 0 || rowNumber >= height) {\n          // Oops, if we run off the top or bottom, stop\n          break;\n        }\n\n        // Estimate black point for this row and load it:\n        try {\n          row = image->getBlackRow(rowNumber, row);\n        } catch (ReaderException const& re) {\n          continue;\n        } catch (IllegalArgumentException const& re) {\n          continue;\n        }\n\n        // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to\n        // handle decoding upside down barcodes.\n        for (int attempt = 0; attempt < 2; attempt++) {\n          if (attempt == 1) {\n            row->reverse(); // reverse the row and continue\n          }\n\n          // Look for a barcode\n          Ref<Result> result = decodeRow(rowNumber, row);\n          // We found our barcode\n          if (!result.empty()) {\n            if (attempt == 1) {\n              // But it was upside down, so note that\n              // result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180));\n              // And remember to flip the result points horizontally.\n              std::vector<Ref<ResultPoint> > points(result->getResultPoints());\n              // if there's exactly two points (which there should be), flip the x coordinate\n              // if there's not exactly 2, I don't know what do do with it\n              if (points.size() == 2) {\n                Ref<ResultPoint> pointZero(new OneDResultPoint(width - points[0]->getX() - 1,\n                    points[0]->getY()));\n                points[0] = pointZero;\n\n                Ref<ResultPoint> pointOne(new OneDResultPoint(width - points[1]->getX() - 1,\n                    points[1]->getY()));\n                points[1] = pointOne;\n\n                result.reset(new Result(result->getText(), result->getRawBytes(), points,\n                    result->getBarcodeFormat()));\n              }\n            }\n            return result;\n          }\n        }\n      }\n      return Ref<Result>();\n    }\n\n    unsigned int OneDReader::patternMatchVariance(int counters[], int countersSize,\n        const int pattern[], int maxIndividualVariance) {\n      int numCounters = countersSize;\n      unsigned int total = 0;\n      unsigned int patternLength = 0;\n      for (int i = 0; i < numCounters; i++) {\n        total += counters[i];\n        patternLength += pattern[i];\n      }\n      if (total < patternLength) {\n        // If we don't even have one pixel per unit of bar width, assume this is too small\n        // to reliably match, so fail:\n        return INT_MAX;\n      }\n      // We're going to fake floating-point math in integers. We just need to use more bits.\n      // Scale up patternLength so that intermediate values below like scaledCounter will have\n      // more \"significant digits\"\n      unsigned int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;\n      maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;\n\n      unsigned int totalVariance = 0;\n      for (int x = 0; x < numCounters; x++) {\n        int counter = counters[x] << INTEGER_MATH_SHIFT;\n        int scaledPattern = pattern[x] * unitBarWidth;\n        int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;\n        if (variance > maxIndividualVariance) {\n          return INT_MAX;\n        }\n        totalVariance += variance;\n      }\n      return totalVariance / total;\n    }\n\n    bool OneDReader::recordPattern(Ref<BitArray> row, int start, int counters[], int countersCount) {\n      int numCounters = countersCount;//sizeof(counters) / sizeof(int);\n      for (int i = 0; i < numCounters; i++) {\n        counters[i] = 0;\n      }\n      int end = row->getSize();\n      if (start >= end) {\n        return false;\n      }\n      bool isWhite = !row->get(start);\n      int counterPosition = 0;\n      int i = start;\n      while (i < end) {\n        bool pixel = row->get(i);\n        if (pixel ^ isWhite) { // that is, exactly one is true\n          counters[counterPosition]++;\n        } else {\n          counterPosition++;\n          if (counterPosition == numCounters) {\n            break;\n          } else {\n            counters[counterPosition] = 1;\n            isWhite ^= true; // isWhite = !isWhite;\n          }\n        }\n        i++;\n      }\n      // If we read fully the last section of pixels and filled up our counters -- or filled\n      // the last counter but ran off the side of the image, OK. Otherwise, a problem.\n      if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && i == end))) {\n        return false;\n      }\n      return true;\n    }\n\n    OneDReader::~OneDReader() {\n    }\n  }\n}\n\n// file: zxing/oned/OneDResultPoint.cpp\n\n/*\n *  OneDResultPoint.cpp\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include \"OneDResultPoint.h\"\n\nnamespace zxing {\n\tnamespace oned {\n\n\t\tOneDResultPoint::OneDResultPoint(float posX, float posY) : ResultPoint(posX,posY) {\n\t\t}\n\t}\n}\n\n// file: zxing/oned/UPCAReader.cpp\n\n/*\n *  UPCAReader.cpp\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include \"UPCAReader.h\"\n// #include <zxing/ReaderException.h>\n\nnamespace zxing {\n  namespace oned {\n    UPCAReader::UPCAReader() : ean13Reader() {\n    }\n\n    Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row) {\n      return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row));\n    }\n\n    Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardBegin,\n        int startGuardEnd) {\n      return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardBegin,\n          startGuardEnd));\n    }\n\n    Ref<Result> UPCAReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {\n      return maybeReturnResult(ean13Reader.decode(image, hints));\n    }\n\n    int UPCAReader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,\n        std::string& resultString) {\n      return ean13Reader.decodeMiddle(row, startGuardBegin, startGuardEnd, resultString);\n    }\n\n    Ref<Result> UPCAReader::maybeReturnResult(Ref<Result> result) {\n      if (result.empty()) {\n        return result;\n      }\n      const std::string& text = (result->getText())->getText();\n      if (text[0] == '0') {\n        Ref<String> resultString(new String(text.substr(1)));\n        Ref<Result> res(new Result(resultString, result->getRawBytes(), result->getResultPoints(),\n            BarcodeFormat_UPC_A));\n        return res;\n      }\n      return Ref<Result>();\n    }\n\n    BarcodeFormat UPCAReader::getBarcodeFormat(){\n      return BarcodeFormat_UPC_A;\n    }\n  }\n}\n\n// file: zxing/oned/UPCEANReader.cpp\n\n/*\n *  UPCEANReader.cpp\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include \"UPCEANReader.h\"\n// #include <zxing/oned/OneDResultPoint.h>\n// #include <zxing/ReaderException.h>\n\nnamespace zxing {\n  namespace oned {\n\n    /**\n     * Start/end guard pattern.\n     */\n    static const int START_END_PATTERN[3] = {1, 1, 1};\n\n    /**\n     * Pattern marking the middle of a UPC/EAN pattern, separating the two halves.\n     */\n    static const int MIDDLE_PATTERN_LEN = 5;\n    static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1};\n\n    /**\n     * \"Odd\", or \"L\" patterns used to encode UPC/EAN digits.\n     */\n    const int L_PATTERNS_LEN = 10;\n    const int L_PATTERNS_SUB_LEN = 4;\n    const int L_PATTERNS[L_PATTERNS_LEN][L_PATTERNS_SUB_LEN] = {\n      {3, 2, 1, 1}, // 0\n      {2, 2, 2, 1}, // 1\n      {2, 1, 2, 2}, // 2\n      {1, 4, 1, 1}, // 3\n      {1, 1, 3, 2}, // 4\n      {1, 2, 3, 1}, // 5\n      {1, 1, 1, 4}, // 6\n      {1, 3, 1, 2}, // 7\n      {1, 2, 1, 3}, // 8\n      {3, 1, 1, 2}  // 9\n    };\n\n    /**\n     * As above but also including the \"even\", or \"G\" patterns used to encode UPC/EAN digits.\n     */\n    const int L_AND_G_PATTERNS_LEN = 20;\n    const int L_AND_G_PATTERNS_SUB_LEN = 4;\n    const int L_AND_G_PATTERNS[L_AND_G_PATTERNS_LEN][L_AND_G_PATTERNS_SUB_LEN] = {\n      {3, 2, 1, 1}, // 0\n      {2, 2, 2, 1}, // 1\n      {2, 1, 2, 2}, // 2\n      {1, 4, 1, 1}, // 3\n      {1, 1, 3, 2}, // 4\n      {1, 2, 3, 1}, // 5\n      {1, 1, 1, 4}, // 6\n      {1, 3, 1, 2}, // 7\n      {1, 2, 1, 3}, // 8\n      {3, 1, 1, 2}, // 9\n      {1, 1, 2, 3}, // 10 reversed 0\n      {1, 2, 2, 2}, // 11 reversed 1\n      {2, 2, 1, 2}, // 12 reversed 2\n      {1, 1, 4, 1}, // 13 reversed 3\n      {2, 3, 1, 1}, // 14 reversed 4\n      {1, 3, 2, 1}, // 15 reversed 5\n      {4, 1, 1, 1}, // 16 reversed 6\n      {2, 1, 3, 1}, // 17 reversed 7\n      {3, 1, 2, 1}, // 18 reversed 8\n      {2, 1, 1, 3}  // 19 reversed 9\n    };\n\n\n    int UPCEANReader::getMIDDLE_PATTERN_LEN() {\n      return MIDDLE_PATTERN_LEN;\n    }\n\n    const int* UPCEANReader::getMIDDLE_PATTERN() {\n      return MIDDLE_PATTERN;\n    }\n\n    UPCEANReader::UPCEANReader() {\n    }\n\n\n    Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) {\n      int rangeStart;\n      int rangeEnd;\n\t\t\tif (findStartGuardPattern(row, &rangeStart, &rangeEnd)) {\n        try {\n          return decodeRow(rowNumber, row, rangeStart, rangeEnd);\n        } catch (ReaderException const& re) {\n        }\n\t\t\t}\n\t\t\treturn Ref<Result>();\n    }\n\n    Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardBegin,\n        int startGuardEnd) {\n      std::string tmpResultString;\n      std::string& tmpResultStringRef = tmpResultString;\n      int endStart = decodeMiddle(row, startGuardBegin, startGuardEnd, tmpResultStringRef);\n      if (endStart < 0) {\n        return Ref<Result>();\n      }\n\n      int endGuardBegin;\n      int endGuardEnd;\n      if (!decodeEnd(row, endStart, &endGuardBegin, &endGuardEnd)) {\n        return Ref<Result>();\n      }\n\n      // Make sure there is a quiet zone at least as big as the end pattern after the barcode.\n      // The spec might want more whitespace, but in practice this is the maximum we can count on.\n      size_t quietEnd = endGuardEnd + (endGuardEnd - endGuardBegin);\n      if (quietEnd >= row->getSize() || !row->isRange(endGuardEnd, quietEnd, false)) {\n        return Ref<Result>();\n      }\n\n      if (!checkChecksum(tmpResultString)) {\n        return Ref<Result>();\n      }\n\n      Ref<String> resultString(new String(tmpResultString));\n      float left = (float) (startGuardBegin + startGuardEnd) / 2.0f;\n      float right = (float) (endGuardBegin + endGuardEnd) / 2.0f;\n\n      std::vector< Ref<ResultPoint> > resultPoints(2);\n      Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber));\n      Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(right, (float) rowNumber));\n      resultPoints[0] = resultPoint1;\n      resultPoints[1] = resultPoint2;\n\n      ArrayRef<unsigned char> resultBytes(1);\n      return Ref<Result>(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat()));\n    }\n\n    bool UPCEANReader::findStartGuardPattern(Ref<BitArray> row, int* rangeStart, int* rangeEnd) {\n      int nextStart = 0;\n      while (findGuardPattern(row, nextStart, false, START_END_PATTERN,\n          sizeof(START_END_PATTERN) / sizeof(int), rangeStart, rangeEnd)) {\n        int start = *rangeStart;\n        nextStart = *rangeEnd;\n        // Make sure there is a quiet zone at least as big as the start pattern before the barcode.\n        // If this check would run off the left edge of the image, do not accept this barcode,\n        // as it is very likely to be a false positive.\n        int quietStart = start - (nextStart - start);\n        if (quietStart >= 0 && row->isRange(quietStart, start, false)) {\n          return true;\n        }\n      }\n      return false;\n    }\n\n    bool UPCEANReader::findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst,\n        const int pattern[], int patternLen, int* start, int* end) {\n      int patternLength = patternLen;\n      int counters[patternLength];\n      int countersCount = sizeof(counters) / sizeof(int);\n      for (int i = 0; i < countersCount; i++) {\n        counters[i] = 0;\n      }\n      int width = row->getSize();\n      bool isWhite = false;\n      while (rowOffset < width) {\n        isWhite = !row->get(rowOffset);\n        if (whiteFirst == isWhite) {\n          break;\n        }\n        rowOffset++;\n      }\n\n      int counterPosition = 0;\n      int patternStart = rowOffset;\n      for (int x = rowOffset; x < width; x++) {\n        bool pixel = row->get(x);\n        if (pixel ^ isWhite) {\n          counters[counterPosition]++;\n        } else {\n          if (counterPosition == patternLength - 1) {\n            if (patternMatchVariance(counters, countersCount, pattern,\n                MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {\n              *start = patternStart;\n              *end = x;\n              return true;\n            }\n            patternStart += counters[0] + counters[1];\n            for (int y = 2; y < patternLength; y++) {\n              counters[y - 2] = counters[y];\n            }\n            counters[patternLength - 2] = 0;\n            counters[patternLength - 1] = 0;\n            counterPosition--;\n          } else {\n            counterPosition++;\n          }\n          counters[counterPosition] = 1;\n          isWhite = !isWhite;\n        }\n      }\n      return false;\n    }\n\n    bool UPCEANReader::decodeEnd(Ref<BitArray> row, int endStart, int* endGuardBegin,\n        int* endGuardEnd) {\n      return findGuardPattern(row, endStart, false, START_END_PATTERN,\n          sizeof(START_END_PATTERN) / sizeof(int), endGuardBegin, endGuardEnd);\n    }\n\n    int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset,\n        UPC_EAN_PATTERNS patternType) {\n      if (!recordPattern(row, rowOffset, counters, countersLen)) {\n        return -1;\n      }\n      unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept\n      int bestMatch = -1;\n\n      int max = 0;\n      switch (patternType) {\n        case UPC_EAN_PATTERNS_L_PATTERNS:\n          max = L_PATTERNS_LEN;\n          for (int i = 0; i < max; i++) {\n            int pattern[countersLen];\n            for(int j = 0; j< countersLen; j++){\n              pattern[j] = L_PATTERNS[i][j];\n            }\n\n            unsigned int variance = patternMatchVariance(counters, countersLen, pattern,\n                MAX_INDIVIDUAL_VARIANCE);\n            if (variance < bestVariance) {\n              bestVariance = variance;\n              bestMatch = i;\n            }\n          }\n          break;\n        case UPC_EAN_PATTERNS_L_AND_G_PATTERNS:\n          max = L_AND_G_PATTERNS_LEN;\n          for (int i = 0; i < max; i++) {\n            int pattern[countersLen];\n            for(int j = 0; j< countersLen; j++){\n              pattern[j] = L_AND_G_PATTERNS[i][j];\n            }\n\n            unsigned int variance = patternMatchVariance(counters, countersLen, pattern,\n                MAX_INDIVIDUAL_VARIANCE);\n            if (variance < bestVariance) {\n              bestVariance = variance;\n              bestMatch = i;\n            }\n          }\n          break;\n        default:\n          break;\n      }\n      return bestMatch;\n    }\n\n    /**\n     * @return {@link #checkStandardUPCEANChecksum(String)}\n     */\n    bool UPCEANReader::checkChecksum(std::string s) {\n      return checkStandardUPCEANChecksum(s);\n    }\n\n    /**\n     * Computes the UPC/EAN checksum on a string of digits, and reports\n     * whether the checksum is correct or not.\n     *\n     * @param s string of digits to check\n     * @return true iff string of digits passes the UPC/EAN checksum algorithm\n     */\n    bool UPCEANReader::checkStandardUPCEANChecksum(std::string s) {\n      int length = s.length();\n      if (length == 0) {\n        return false;\n      }\n\n      int sum = 0;\n      for (int i = length - 2; i >= 0; i -= 2) {\n        int digit = (int) s[i] - (int) '0';\n        if (digit < 0 || digit > 9) {\n          return false;\n        }\n        sum += digit;\n      }\n      sum *= 3;\n      for (int i = length - 1; i >= 0; i -= 2) {\n        int digit = (int) s[i] - (int) '0';\n        if (digit < 0 || digit > 9) {\n          return false;\n        }\n        sum += digit;\n      }\n      return sum % 10 == 0;\n    }\n\n    UPCEANReader::~UPCEANReader() {\n    }\n  }\n}\n\n// file: zxing/oned/UPCEReader.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include \"UPCEReader.h\"\n// #include <zxing/ReaderException.h>\n\nnamespace zxing {\n  namespace oned {\n\n    /**\n     * The pattern that marks the middle, and end, of a UPC-E pattern.\n     * There is no \"second half\" to a UPC-E barcode.\n     */\n    static const int MIDDLE_END_PATTERN[6] = {1, 1, 1, 1, 1, 1};\n\n    /**\n     * See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of\n     * even-odd parity encodings of digits that imply both the number system (0 or 1)\n     * used, and the check digit.\n     */\n    static const int NUMSYS_AND_CHECK_DIGIT_PATTERNS[2][10] = {\n      {0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25},\n      {0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}\n    };\n\n    UPCEReader::UPCEReader() {\n    }\n\n    int UPCEReader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,\n        std::string& resultString) {\n      (void)startGuardBegin;\n      const int countersLen = 4;\n      int counters[countersLen] = { 0, 0, 0, 0 };\n\n      int end = row->getSize();\n      int rowOffset = startGuardEnd;\n      int lgPatternFound = 0;\n\n      for (int x = 0; x < 6 && rowOffset < end; x++) {\n        int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,\n            UPC_EAN_PATTERNS_L_AND_G_PATTERNS);\n        if (bestMatch < 0) {\n          return -1;\n        }\n        resultString.append(1, (char) ('0' + bestMatch % 10));\n        for (int i = 0; i < countersLen; i++) {\n          rowOffset += counters[i];\n        }\n        if (bestMatch >= 10) {\n          lgPatternFound |= 1 << (5 - x);\n        }\n      }\n\n      if (!determineNumSysAndCheckDigit(resultString, lgPatternFound)) {\n        return -1;\n      }\n      return rowOffset;\n    }\n\n    bool UPCEReader::decodeEnd(Ref<BitArray> row, int endStart, int* endGuardBegin,\n        int* endGuardEnd) {\n      return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN,\n          sizeof(MIDDLE_END_PATTERN) / sizeof(int), endGuardBegin, endGuardEnd);\n    }\n\n    bool UPCEReader::checkChecksum(std::string s){\n      return UPCEANReader::checkChecksum(convertUPCEtoUPCA(s));\n    }\n\n\n    bool UPCEReader::determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound) {\n      for (int numSys = 0; numSys <= 1; numSys++) {\n        for (int d = 0; d < 10; d++) {\n          if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) {\n            resultString.insert(0, 1, (char) ('0' + numSys));\n            resultString.append(1, (char) ('0' + d));\n            return true;\n          }\n        }\n      }\n      return false;\n    }\n\n    /**\n     * Expands a UPC-E value back into its full, equivalent UPC-A code value.\n     *\n     * @param upce UPC-E code as string of digits\n     * @return equivalent UPC-A code as string of digits\n     */\n    std::string UPCEReader::convertUPCEtoUPCA(std::string upce) {\n      std::string result;\n      result.append(1, upce[0]);\n      char lastChar = upce[6];\n      switch (lastChar) {\n        case '0':\n        case '1':\n        case '2':\n          result.append(upce.substr(1,2));\n          result.append(1, lastChar);\n          result.append(\"0000\");\n          result.append(upce.substr(3,3));\n          break;\n        case '3':\n          result.append(upce.substr(1,3));\n          result.append(\"00000\");\n          result.append(upce.substr(4,2));\n          break;\n        case '4':\n          result.append(upce.substr(1,4));\n          result.append(\"00000\");\n          result.append(1, upce[5]);\n          break;\n        default:\n          result.append(upce.substr(1,5));\n          result.append(\"0000\");\n          result.append(1, lastChar);\n          break;\n      }\n      result.append(1, upce[7]);\n      return result;\n    }\n\n\n    BarcodeFormat UPCEReader::getBarcodeFormat() {\n      return BarcodeFormat_UPC_E;\n    }\n  }\n}\n\n// file: zxing/qrcode/ErrorCorrectionLevel.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  ErrorCorrectionLevel.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 15/05/2008.\n *  Copyright 2008-2011 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/ErrorCorrectionLevel.h>\n\nusing std::string;\n\nnamespace zxing {\nnamespace qrcode {\n\nErrorCorrectionLevel::ErrorCorrectionLevel(int inOrdinal,\n                                           int bits,\n                                           char const* name) :\n  ordinal_(inOrdinal), bits_(bits), name_(name) {}\n\nint ErrorCorrectionLevel::ordinal() const {\n  return ordinal_;\n}\n\nint ErrorCorrectionLevel::bits() const {\n  return bits_;\n}\n\nstring const& ErrorCorrectionLevel::name() const {\n  return name_;\n}\n\nErrorCorrectionLevel::operator string const& () const {\n  return name_;\n}\n\nErrorCorrectionLevel& ErrorCorrectionLevel::forBits(int bits) {\n  if (bits < 0 || bits >= N_LEVELS) {\n    throw ReaderException(\"Ellegal error correction level bits\");\n  }\n  return *FOR_BITS[bits];\n}\n\n  ErrorCorrectionLevel ErrorCorrectionLevel::L(0, 0x01, \"L\");\n  ErrorCorrectionLevel ErrorCorrectionLevel::M(1, 0x00, \"M\");\n  ErrorCorrectionLevel ErrorCorrectionLevel::Q(2, 0x03, \"Q\");\n  ErrorCorrectionLevel ErrorCorrectionLevel::H(3, 0x02, \"H\");\nErrorCorrectionLevel *ErrorCorrectionLevel::FOR_BITS[] = { &M, &L, &H, &Q };\nint ErrorCorrectionLevel::N_LEVELS = 4;\n\n}\n}\n\n// file: zxing/qrcode/FormatInformation.cpp\n\n/*\n *  FormatInformation.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 18/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/FormatInformation.h>\n// #include <limits>\n\nnamespace zxing {\nnamespace qrcode {\n\nusing namespace std;\n\nint FormatInformation::FORMAT_INFO_MASK_QR = 0x5412;\nint FormatInformation::FORMAT_INFO_DECODE_LOOKUP[][2] = { { 0x5412, 0x00 }, { 0x5125, 0x01 }, { 0x5E7C, 0x02 }, {\n    0x5B4B, 0x03 }, { 0x45F9, 0x04 }, { 0x40CE, 0x05 }, { 0x4F97, 0x06 }, { 0x4AA0, 0x07 }, { 0x77C4, 0x08 }, {\n    0x72F3, 0x09 }, { 0x7DAA, 0x0A }, { 0x789D, 0x0B }, { 0x662F, 0x0C }, { 0x6318, 0x0D }, { 0x6C41, 0x0E }, {\n    0x6976, 0x0F }, { 0x1689, 0x10 }, { 0x13BE, 0x11 }, { 0x1CE7, 0x12 }, { 0x19D0, 0x13 }, { 0x0762, 0x14 }, {\n    0x0255, 0x15 }, { 0x0D0C, 0x16 }, { 0x083B, 0x17 }, { 0x355F, 0x18 }, { 0x3068, 0x19 }, { 0x3F31, 0x1A }, {\n    0x3A06, 0x1B }, { 0x24B4, 0x1C }, { 0x2183, 0x1D }, { 0x2EDA, 0x1E }, { 0x2BED, 0x1F },\n};\nint FormatInformation::N_FORMAT_INFO_DECODE_LOOKUPS = 32;\n\nint FormatInformation::BITS_SET_IN_HALF_BYTE[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };\n\nFormatInformation::FormatInformation(int formatInfo) :\n    errorCorrectionLevel_(ErrorCorrectionLevel::forBits((formatInfo >> 3) & 0x03)), dataMask_(\n      (unsigned char)(formatInfo & 0x07)) {\n}\n\nErrorCorrectionLevel& FormatInformation::getErrorCorrectionLevel() {\n  return errorCorrectionLevel_;\n}\n\nunsigned char FormatInformation::getDataMask() {\n  return dataMask_;\n}\n\nint FormatInformation::numBitsDiffering(unsigned int a, unsigned int b) {\n  a ^= b;\n  return BITS_SET_IN_HALF_BYTE[a & 0x0F] + BITS_SET_IN_HALF_BYTE[(a >> 4 & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 8\n         & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 12 & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 16 & 0x0F)]\n         + BITS_SET_IN_HALF_BYTE[(a >> 20 & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 24 & 0x0F)]\n         + BITS_SET_IN_HALF_BYTE[(a >> 28 & 0x0F)];\n}\n\nRef<FormatInformation> FormatInformation::decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) {\n  Ref<FormatInformation> result(doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2));\n  if (result != 0) {\n    return result;\n  }\n  // Should return null, but, some QR codes apparently\n  // do not mask this info. Try again by actually masking the pattern\n  // first\n  return doDecodeFormatInformation(maskedFormatInfo1 ^ FORMAT_INFO_MASK_QR,\n                                   maskedFormatInfo2  ^ FORMAT_INFO_MASK_QR);\n}\nRef<FormatInformation> FormatInformation::doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) {\n  // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing\n  int bestDifference = numeric_limits<int>::max();\n  int bestFormatInfo = 0;\n  for (int i = 0; i < N_FORMAT_INFO_DECODE_LOOKUPS; i++) {\n    int* decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i];\n    int targetInfo = decodeInfo[0];\n    if (targetInfo == maskedFormatInfo1 || targetInfo == maskedFormatInfo2) {\n      // Found an exact match\n      Ref<FormatInformation> result(new FormatInformation(decodeInfo[1]));\n      return result;\n    }\n    int bitsDifference = numBitsDiffering(maskedFormatInfo1, targetInfo);\n    if (bitsDifference < bestDifference) {\n      bestFormatInfo = decodeInfo[1];\n      bestDifference = bitsDifference;\n    }\n    if (maskedFormatInfo1 != maskedFormatInfo2) {\n        // also try the other option\n        bitsDifference = numBitsDiffering(maskedFormatInfo2, targetInfo);\n        if (bitsDifference < bestDifference) {\n            bestFormatInfo = decodeInfo[1];\n          bestDifference = bitsDifference;\n        }\n      }\n  }\n  if (bestDifference <= 3) {\n    Ref<FormatInformation> result(new FormatInformation(bestFormatInfo));\n    return result;\n  }\n  Ref<FormatInformation> result;\n  return result;\n}\n\nbool operator==(const FormatInformation &a, const FormatInformation &b) {\n  return &(a.errorCorrectionLevel_) == &(b.errorCorrectionLevel_) && a.dataMask_ == b.dataMask_;\n}\n\nostream& operator<<(ostream& out, const FormatInformation& fi) {\n  const FormatInformation *fip = &fi;\n  out << \"FormatInformation @ \" << fip;\n  return out;\n}\n\n}\n}\n\n// file: zxing/qrcode/QRCodeReader.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  QRCodeReader.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 20/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/QRCodeReader.h>\n// #include <zxing/qrcode/detector/Detector.h>\n\n// #include <iostream>\n\nnamespace zxing {\n\tnamespace qrcode {\n\n\t\tusing namespace std;\n\n\t\tQRCodeReader::QRCodeReader() :decoder_() {\n\t\t}\n\t\t//TODO: see if any of the other files in the qrcode tree need tryHarder\n\t\tRef<Result> QRCodeReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {\n#ifdef DEBUG\n\t\t\tcout << \"decoding image \" << image.object_ << \":\\n\" << flush;\n#endif\n\n\t\t\tDetector detector(image->getBlackMatrix());\n\n\n#ifdef DEBUG\n\t\t\tcout << \"(1) created detector \" << &detector << \"\\n\" << flush;\n#endif\n\n\t\t\tRef<DetectorResult> detectorResult(detector.detect(hints));\n#ifdef DEBUG\n\t\t\tcout << \"(2) detected, have detectorResult \" << detectorResult.object_ << \"\\n\" << flush;\n#endif\n\n\t\t\tstd::vector<Ref<ResultPoint> > points(detectorResult->getPoints());\n\n\n#ifdef DEBUG\n\t\t\tcout << \"(3) extracted points \" << &points << \"\\n\" << flush;\n\t\t\tcout << \"found \" << points.size() << \" points:\\n\";\n\t\t\tfor (size_t i = 0; i < points.size(); i++) {\n\t\t\t\tcout << \"   \" << points[i]->getX() << \",\" << points[i]->getY() << \"\\n\";\n\t\t\t}\n\t\t\tcout << \"bits:\\n\";\n\t\t\tcout << *(detectorResult->getBits()) << \"\\n\";\n#endif\n\n\t\t\tRef<DecoderResult> decoderResult(decoder_.decode(detectorResult->getBits()));\n#ifdef DEBUG\n\t\t\tcout << \"(4) decoded, have decoderResult \" << decoderResult.object_ << \"\\n\" << flush;\n#endif\n\n\t\t\tRef<Result> result(\n\t\t\t\t\t\t\t   new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_QR_CODE));\n#ifdef DEBUG\n\t\t\tcout << \"(5) created result \" << result.object_ << \", returning\\n\" << flush;\n#endif\n\n\t\t\treturn result;\n\t\t}\n\n\t\tQRCodeReader::~QRCodeReader() {\n\t\t}\n\n    Decoder& QRCodeReader::getDecoder() {\n        return decoder_;\n    }\n\t}\n}\n\n// file: zxing/qrcode/Version.cpp\n\n/*\n *  Version.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 14/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/Version.h>\n// #include <zxing/qrcode/FormatInformation.h>\n// #include <limits>\n// #include <iostream>\n// #include <cstdarg>\n\nnamespace zxing {\nnamespace qrcode {\nusing namespace std;\n\nECB::ECB(int count, int dataCodewords) :\n    count_(count), dataCodewords_(dataCodewords) {\n}\n\nint ECB::getCount() {\n  return count_;\n}\n\nint ECB::getDataCodewords() {\n  return dataCodewords_;\n}\n\nECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks) :\n    ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks) {\n}\n\nECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2) :\n    ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks1) {\n  ecBlocks_.push_back(ecBlocks2);\n}\n\nint ECBlocks::getECCodewords() {\n  return ecCodewords_;\n}\n\nstd::vector<ECB*>& ECBlocks::getECBlocks() {\n  return ecBlocks_;\n}\n\nECBlocks::~ECBlocks() {\n  for (size_t i = 0; i < ecBlocks_.size(); i++) {\n    delete ecBlocks_[i];\n  }\n}\n\nunsigned int Version::VERSION_DECODE_INFO[] = { 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847, 0x0E60D,\n    0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB,\n    0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64,\n    0x27541, 0x28C69\n                                              };\nint Version::N_VERSION_DECODE_INFOS = 34;\nvector<Ref<Version> > Version::VERSIONS;\nstatic int N_VERSIONS = Version::buildVersions();\n\nint Version::getVersionNumber() {\n  return versionNumber_;\n}\n\nvector<int> &Version::getAlignmentPatternCenters() {\n  return alignmentPatternCenters_;\n}\n\nint Version::getTotalCodewords() {\n  return totalCodewords_;\n}\n\nint Version::getDimensionForVersion() {\n  return 17 + 4 * versionNumber_;\n}\n\nECBlocks& Version::getECBlocksForLevel(ErrorCorrectionLevel &ecLevel) {\n  return *ecBlocks_[ecLevel.ordinal()];\n}\n\nVersion *Version::getProvisionalVersionForDimension(int dimension) {\n  if (dimension % 4 != 1) {\n    throw ReaderException(\"Dimension must be 1 mod 4\");\n  }\n  return Version::getVersionForNumber((dimension - 17) >> 2);\n}\n\nVersion *Version::getVersionForNumber(int versionNumber) {\n  if (versionNumber < 1 || versionNumber > N_VERSIONS) {\n    throw ReaderException(\"versionNumber must be between 1 and 40\");\n  }\n\n  return VERSIONS[versionNumber - 1];\n}\n\nVersion::Version(int versionNumber, vector<int> *alignmentPatternCenters, ECBlocks *ecBlocks1, ECBlocks *ecBlocks2,\n                 ECBlocks *ecBlocks3, ECBlocks *ecBlocks4) :\n    versionNumber_(versionNumber), alignmentPatternCenters_(*alignmentPatternCenters), ecBlocks_(4), totalCodewords_(0) {\n  ecBlocks_[0] = ecBlocks1;\n  ecBlocks_[1] = ecBlocks2;\n  ecBlocks_[2] = ecBlocks3;\n  ecBlocks_[3] = ecBlocks4;\n\n  int total = 0;\n  int ecCodewords = ecBlocks1->getECCodewords();\n  vector<ECB*> &ecbArray = ecBlocks1->getECBlocks();\n  for (size_t i = 0; i < ecbArray.size(); i++) {\n    ECB *ecBlock = ecbArray[i];\n    total += ecBlock->getCount() * (ecBlock->getDataCodewords() + ecCodewords);\n  }\n  totalCodewords_ = total;\n}\n\nVersion::~Version() {\n  delete &alignmentPatternCenters_;\n  for (size_t i = 0; i < ecBlocks_.size(); i++) {\n    delete ecBlocks_[i];\n  }\n}\n\nVersion *Version::decodeVersionInformation(unsigned int versionBits) {\n  int bestDifference = numeric_limits<int>::max();\n  size_t bestVersion = 0;\n  for (int i = 0; i < N_VERSION_DECODE_INFOS; i++) {\n    unsigned targetVersion = VERSION_DECODE_INFO[i];\n    // Do the version info bits match exactly? done.\n    if (targetVersion == versionBits) {\n      return getVersionForNumber(i + 7);\n    }\n    // Otherwise see if this is the closest to a real version info bit\n    // string we have seen so far\n    int bitsDifference = FormatInformation::numBitsDiffering(versionBits, targetVersion);\n    if (bitsDifference < bestDifference) {\n      bestVersion = i + 7;\n      bestDifference = bitsDifference;\n    }\n  }\n  // We can tolerate up to 3 bits of error since no two version info codewords will\n  // differ in less than 4 bits.\n  if (bestDifference <= 3) {\n    return getVersionForNumber(bestVersion);\n  }\n  // If we didn't find a close enough match, fail\n  return 0;\n}\n\nRef<BitMatrix> Version::buildFunctionPattern() {\n  int dimension = getDimensionForVersion();\n  Ref<BitMatrix> functionPattern(new BitMatrix(dimension));\n\n\n  // Top left finder pattern + separator + format\n  functionPattern->setRegion(0, 0, 9, 9);\n  // Top right finder pattern + separator + format\n  functionPattern->setRegion(dimension - 8, 0, 8, 9);\n  // Bottom left finder pattern + separator + format\n  functionPattern->setRegion(0, dimension - 8, 9, 8);\n\n\n  // Alignment patterns\n  size_t max = alignmentPatternCenters_.size();\n  for (size_t x = 0; x < max; x++) {\n    int i = alignmentPatternCenters_[x] - 2;\n    for (size_t y = 0; y < max; y++) {\n      if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) {\n        // No alignment patterns near the three finder patterns\n        continue;\n      }\n      functionPattern->setRegion(alignmentPatternCenters_[y] - 2, i, 5, 5);\n    }\n  }\n\n  // Vertical timing pattern\n  functionPattern->setRegion(6, 9, 1, dimension - 17);\n  // Horizontal timing pattern\n  functionPattern->setRegion(9, 6, dimension - 17, 1);\n\n  if (versionNumber_ > 6) {\n    // Version info, top right\n    functionPattern->setRegion(dimension - 11, 0, 3, 6);\n    // Version info, bottom left\n    functionPattern->setRegion(0, dimension - 11, 6, 3);\n  }\n\n\n  //#ifdef DEBUG\n  //\tcout << \"version \" << versionNumber_ << \" built function pattern:\\n\";\n  //\tcout << *functionPattern;\n  //#endif\n\n  return functionPattern;\n}\n\nstatic vector<int> *intArray(size_t n...) {\n  va_list ap;\n  va_start(ap, n);\n  vector<int> *result = new vector<int>(n);\n  for (size_t i = 0; i < n; i++) {\n    (*result)[i] = va_arg(ap, int);\n  }\n  va_end(ap);\n  return result;\n}\n\nint Version::buildVersions() {\n  VERSIONS.push_back(Ref<Version>(new Version(1, intArray(0),\n                                  new ECBlocks(7, new ECB(1, 19)),\n                                  new ECBlocks(10, new ECB(1, 16)),\n                                  new ECBlocks(13, new ECB(1, 13)),\n                                  new ECBlocks(17, new ECB(1, 9)))));\n  VERSIONS.push_back(Ref<Version>(new Version(2, intArray(2, 6, 18),\n                                  new ECBlocks(10, new ECB(1, 34)),\n                                  new ECBlocks(16, new ECB(1, 28)),\n                                  new ECBlocks(22, new ECB(1, 22)),\n                                  new ECBlocks(28, new ECB(1, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(3, intArray(2, 6, 22),\n                                  new ECBlocks(15, new ECB(1, 55)),\n                                  new ECBlocks(26, new ECB(1, 44)),\n                                  new ECBlocks(18, new ECB(2, 17)),\n                                  new ECBlocks(22, new ECB(2, 13)))));\n  VERSIONS.push_back(Ref<Version>(new Version(4, intArray(2, 6, 26),\n                                  new ECBlocks(20, new ECB(1, 80)),\n                                  new ECBlocks(18, new ECB(2, 32)),\n                                  new ECBlocks(26, new ECB(2, 24)),\n                                  new ECBlocks(16, new ECB(4, 9)))));\n  VERSIONS.push_back(Ref<Version>(new Version(5, intArray(2, 6, 30),\n                                  new ECBlocks(26, new ECB(1, 108)),\n                                  new ECBlocks(24, new ECB(2, 43)),\n                                  new ECBlocks(18, new ECB(2, 15),\n                                               new ECB(2, 16)),\n                                  new ECBlocks(22, new ECB(2, 11),\n                                               new ECB(2, 12)))));\n  VERSIONS.push_back(Ref<Version>(new Version(6, intArray(2, 6, 34),\n                                  new ECBlocks(18, new ECB(2, 68)),\n                                  new ECBlocks(16, new ECB(4, 27)),\n                                  new ECBlocks(24, new ECB(4, 19)),\n                                  new ECBlocks(28, new ECB(4, 15)))));\n  VERSIONS.push_back(Ref<Version>(new Version(7, intArray(3, 6, 22, 38),\n                                  new ECBlocks(20, new ECB(2, 78)),\n                                  new ECBlocks(18, new ECB(4, 31)),\n                                  new ECBlocks(18, new ECB(2, 14),\n                                               new ECB(4, 15)),\n                                  new ECBlocks(26, new ECB(4, 13),\n                                               new ECB(1, 14)))));\n  VERSIONS.push_back(Ref<Version>(new Version(8, intArray(3, 6, 24, 42),\n                                  new ECBlocks(24, new ECB(2, 97)),\n                                  new ECBlocks(22, new ECB(2, 38),\n                                               new ECB(2, 39)),\n                                  new ECBlocks(22, new ECB(4, 18),\n                                               new ECB(2, 19)),\n                                  new ECBlocks(26, new ECB(4, 14),\n                                               new ECB(2, 15)))));\n  VERSIONS.push_back(Ref<Version>(new Version(9, intArray(3, 6, 26, 46),\n                                  new ECBlocks(30, new ECB(2, 116)),\n                                  new ECBlocks(22, new ECB(3, 36),\n                                               new ECB(2, 37)),\n                                  new ECBlocks(20, new ECB(4, 16),\n                                               new ECB(4, 17)),\n                                  new ECBlocks(24, new ECB(4, 12),\n                                               new ECB(4, 13)))));\n  VERSIONS.push_back(Ref<Version>(new Version(10, intArray(3, 6, 28, 50),\n                                  new ECBlocks(18, new ECB(2, 68),\n                                               new ECB(2, 69)),\n                                  new ECBlocks(26, new ECB(4, 43),\n                                               new ECB(1, 44)),\n                                  new ECBlocks(24, new ECB(6, 19),\n                                               new ECB(2, 20)),\n                                  new ECBlocks(28, new ECB(6, 15),\n                                               new ECB(2, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(11, intArray(3, 6, 30, 54),\n                                  new ECBlocks(20, new ECB(4, 81)),\n                                  new ECBlocks(30, new ECB(1, 50),\n                                               new ECB(4, 51)),\n                                  new ECBlocks(28, new ECB(4, 22),\n                                               new ECB(4, 23)),\n                                  new ECBlocks(24, new ECB(3, 12),\n                                               new ECB(8, 13)))));\n  VERSIONS.push_back(Ref<Version>(new Version(12, intArray(3, 6, 32, 58),\n                                  new ECBlocks(24, new ECB(2, 92),\n                                               new ECB(2, 93)),\n                                  new ECBlocks(22, new ECB(6, 36),\n                                               new ECB(2, 37)),\n                                  new ECBlocks(26, new ECB(4, 20),\n                                               new ECB(6, 21)),\n                                  new ECBlocks(28, new ECB(7, 14),\n                                               new ECB(4, 15)))));\n  VERSIONS.push_back(Ref<Version>(new Version(13, intArray(3, 6, 34, 62),\n                                  new ECBlocks(26, new ECB(4, 107)),\n                                  new ECBlocks(22, new ECB(8, 37),\n                                               new ECB(1, 38)),\n                                  new ECBlocks(24, new ECB(8, 20),\n                                               new ECB(4, 21)),\n                                  new ECBlocks(22, new ECB(12, 11),\n                                               new ECB(4, 12)))));\n  VERSIONS.push_back(Ref<Version>(new Version(14, intArray(4, 6, 26, 46, 66),\n                                  new ECBlocks(30, new ECB(3, 115),\n                                               new ECB(1, 116)),\n                                  new ECBlocks(24, new ECB(4, 40),\n                                               new ECB(5, 41)),\n                                  new ECBlocks(20, new ECB(11, 16),\n                                               new ECB(5, 17)),\n                                  new ECBlocks(24, new ECB(11, 12),\n                                               new ECB(5, 13)))));\n  VERSIONS.push_back(Ref<Version>(new Version(15, intArray(4, 6, 26, 48, 70),\n                                  new ECBlocks(22, new ECB(5, 87),\n                                               new ECB(1, 88)),\n                                  new ECBlocks(24, new ECB(5, 41),\n                                               new ECB(5, 42)),\n                                  new ECBlocks(30, new ECB(5, 24),\n                                               new ECB(7, 25)),\n                                  new ECBlocks(24, new ECB(11, 12),\n                                               new ECB(7, 13)))));\n  VERSIONS.push_back(Ref<Version>(new Version(16, intArray(4, 6, 26, 50, 74),\n                                  new ECBlocks(24, new ECB(5, 98),\n                                               new ECB(1, 99)),\n                                  new ECBlocks(28, new ECB(7, 45),\n                                               new ECB(3, 46)),\n                                  new ECBlocks(24, new ECB(15, 19),\n                                               new ECB(2, 20)),\n                                  new ECBlocks(30, new ECB(3, 15),\n                                               new ECB(13, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(17, intArray(4, 6, 30, 54, 78),\n                                  new ECBlocks(28, new ECB(1, 107),\n                                               new ECB(5, 108)),\n                                  new ECBlocks(28, new ECB(10, 46),\n                                               new ECB(1, 47)),\n                                  new ECBlocks(28, new ECB(1, 22),\n                                               new ECB(15, 23)),\n                                  new ECBlocks(28, new ECB(2, 14),\n                                               new ECB(17, 15)))));\n  VERSIONS.push_back(Ref<Version>(new Version(18, intArray(4, 6, 30, 56, 82),\n                                  new ECBlocks(30, new ECB(5, 120),\n                                               new ECB(1, 121)),\n                                  new ECBlocks(26, new ECB(9, 43),\n                                               new ECB(4, 44)),\n                                  new ECBlocks(28, new ECB(17, 22),\n                                               new ECB(1, 23)),\n                                  new ECBlocks(28, new ECB(2, 14),\n                                               new ECB(19, 15)))));\n  VERSIONS.push_back(Ref<Version>(new Version(19, intArray(4, 6, 30, 58, 86),\n                                  new ECBlocks(28, new ECB(3, 113),\n                                               new ECB(4, 114)),\n                                  new ECBlocks(26, new ECB(3, 44),\n                                               new ECB(11, 45)),\n                                  new ECBlocks(26, new ECB(17, 21),\n                                               new ECB(4, 22)),\n                                  new ECBlocks(26, new ECB(9, 13),\n                                               new ECB(16, 14)))));\n  VERSIONS.push_back(Ref<Version>(new Version(20, intArray(4, 6, 34, 62, 90),\n                                  new ECBlocks(28, new ECB(3, 107),\n                                               new ECB(5, 108)),\n                                  new ECBlocks(26, new ECB(3, 41),\n                                               new ECB(13, 42)),\n                                  new ECBlocks(30, new ECB(15, 24),\n                                               new ECB(5, 25)),\n                                  new ECBlocks(28, new ECB(15, 15),\n                                               new ECB(10, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(21, intArray(5, 6, 28, 50, 72, 94),\n                                  new ECBlocks(28, new ECB(4, 116),\n                                               new ECB(4, 117)),\n                                  new ECBlocks(26, new ECB(17, 42)),\n                                  new ECBlocks(28, new ECB(17, 22),\n                                               new ECB(6, 23)),\n                                  new ECBlocks(30, new ECB(19, 16),\n                                               new ECB(6, 17)))));\n  VERSIONS.push_back(Ref<Version>(new Version(22, intArray(5, 6, 26, 50, 74, 98),\n                                  new ECBlocks(28, new ECB(2, 111),\n                                               new ECB(7, 112)),\n                                  new ECBlocks(28, new ECB(17, 46)),\n                                  new ECBlocks(30, new ECB(7, 24),\n                                               new ECB(16, 25)),\n                                  new ECBlocks(24, new ECB(34, 13)))));\n  VERSIONS.push_back(Ref<Version>(new Version(23, intArray(5, 6, 30, 54, 78, 102),\n                                  new ECBlocks(30, new ECB(4, 121),\n                                               new ECB(5, 122)),\n                                  new ECBlocks(28, new ECB(4, 47),\n                                               new ECB(14, 48)),\n                                  new ECBlocks(30, new ECB(11, 24),\n                                               new ECB(14, 25)),\n                                  new ECBlocks(30, new ECB(16, 15),\n                                               new ECB(14, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(24, intArray(5, 6, 28, 54, 80, 106),\n                                  new ECBlocks(30, new ECB(6, 117),\n                                               new ECB(4, 118)),\n                                  new ECBlocks(28, new ECB(6, 45),\n                                               new ECB(14, 46)),\n                                  new ECBlocks(30, new ECB(11, 24),\n                                               new ECB(16, 25)),\n                                  new ECBlocks(30, new ECB(30, 16),\n                                               new ECB(2, 17)))));\n  VERSIONS.push_back(Ref<Version>(new Version(25, intArray(5, 6, 32, 58, 84, 110),\n                                  new ECBlocks(26, new ECB(8, 106),\n                                               new ECB(4, 107)),\n                                  new ECBlocks(28, new ECB(8, 47),\n                                               new ECB(13, 48)),\n                                  new ECBlocks(30, new ECB(7, 24),\n                                               new ECB(22, 25)),\n                                  new ECBlocks(30, new ECB(22, 15),\n                                               new ECB(13, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(26, intArray(5, 6, 30, 58, 86, 114),\n                                  new ECBlocks(28, new ECB(10, 114),\n                                               new ECB(2, 115)),\n                                  new ECBlocks(28, new ECB(19, 46),\n                                               new ECB(4, 47)),\n                                  new ECBlocks(28, new ECB(28, 22),\n                                               new ECB(6, 23)),\n                                  new ECBlocks(30, new ECB(33, 16),\n                                               new ECB(4, 17)))));\n  VERSIONS.push_back(Ref<Version>(new Version(27, intArray(5, 6, 34, 62, 90, 118),\n                                  new ECBlocks(30, new ECB(8, 122),\n                                               new ECB(4, 123)),\n                                  new ECBlocks(28, new ECB(22, 45),\n                                               new ECB(3, 46)),\n                                  new ECBlocks(30, new ECB(8, 23),\n                                               new ECB(26, 24)),\n                                  new ECBlocks(30, new ECB(12, 15),\n                                               new ECB(28, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(28, intArray(6, 6, 26, 50, 74, 98, 122),\n                                  new ECBlocks(30, new ECB(3, 117),\n                                               new ECB(10, 118)),\n                                  new ECBlocks(28, new ECB(3, 45),\n                                               new ECB(23, 46)),\n                                  new ECBlocks(30, new ECB(4, 24),\n                                               new ECB(31, 25)),\n                                  new ECBlocks(30, new ECB(11, 15),\n                                               new ECB(31, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(29, intArray(6, 6, 30, 54, 78, 102, 126),\n                                  new ECBlocks(30, new ECB(7, 116),\n                                               new ECB(7, 117)),\n                                  new ECBlocks(28, new ECB(21, 45),\n                                               new ECB(7, 46)),\n                                  new ECBlocks(30, new ECB(1, 23),\n                                               new ECB(37, 24)),\n                                  new ECBlocks(30, new ECB(19, 15),\n                                               new ECB(26, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(30, intArray(6, 6, 26, 52, 78, 104, 130),\n                                  new ECBlocks(30, new ECB(5, 115),\n                                               new ECB(10, 116)),\n                                  new ECBlocks(28, new ECB(19, 47),\n                                               new ECB(10, 48)),\n                                  new ECBlocks(30, new ECB(15, 24),\n                                               new ECB(25, 25)),\n                                  new ECBlocks(30, new ECB(23, 15),\n                                               new ECB(25, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(31, intArray(6, 6, 30, 56, 82, 108, 134),\n                                  new ECBlocks(30, new ECB(13, 115),\n                                               new ECB(3, 116)),\n                                  new ECBlocks(28, new ECB(2, 46),\n                                               new ECB(29, 47)),\n                                  new ECBlocks(30, new ECB(42, 24),\n                                               new ECB(1, 25)),\n                                  new ECBlocks(30, new ECB(23, 15),\n                                               new ECB(28, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(32, intArray(6, 6, 34, 60, 86, 112, 138),\n                                  new ECBlocks(30, new ECB(17, 115)),\n                                  new ECBlocks(28, new ECB(10, 46),\n                                               new ECB(23, 47)),\n                                  new ECBlocks(30, new ECB(10, 24),\n                                               new ECB(35, 25)),\n                                  new ECBlocks(30, new ECB(19, 15),\n                                               new ECB(35, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(33, intArray(6, 6, 30, 58, 86, 114, 142),\n                                  new ECBlocks(30, new ECB(17, 115),\n                                               new ECB(1, 116)),\n                                  new ECBlocks(28, new ECB(14, 46),\n                                               new ECB(21, 47)),\n                                  new ECBlocks(30, new ECB(29, 24),\n                                               new ECB(19, 25)),\n                                  new ECBlocks(30, new ECB(11, 15),\n                                               new ECB(46, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(34, intArray(6, 6, 34, 62, 90, 118, 146),\n                                  new ECBlocks(30, new ECB(13, 115),\n                                               new ECB(6, 116)),\n                                  new ECBlocks(28, new ECB(14, 46),\n                                               new ECB(23, 47)),\n                                  new ECBlocks(30, new ECB(44, 24),\n                                               new ECB(7, 25)),\n                                  new ECBlocks(30, new ECB(59, 16),\n                                               new ECB(1, 17)))));\n  VERSIONS.push_back(Ref<Version>(new Version(35, intArray(7, 6, 30, 54, 78,\n                                  102, 126, 150),\n                                  new ECBlocks(30, new ECB(12, 121),\n                                               new ECB(7, 122)),\n                                  new ECBlocks(28, new ECB(12, 47),\n                                               new ECB(26, 48)),\n                                  new ECBlocks(30, new ECB(39, 24),\n                                               new ECB(14, 25)),\n                                  new ECBlocks(30, new ECB(22, 15),\n                                               new ECB(41, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(36, intArray(7, 6, 24, 50, 76,\n                                  102, 128, 154),\n                                  new ECBlocks(30, new ECB(6, 121),\n                                               new ECB(14, 122)),\n                                  new ECBlocks(28, new ECB(6, 47),\n                                               new ECB(34, 48)),\n                                  new ECBlocks(30, new ECB(46, 24),\n                                               new ECB(10, 25)),\n                                  new ECBlocks(30, new ECB(2, 15),\n                                               new ECB(64, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(37, intArray(7, 6, 28, 54, 80,\n                                  106, 132, 158),\n                                  new ECBlocks(30, new ECB(17, 122),\n                                               new ECB(4, 123)),\n                                  new ECBlocks(28, new ECB(29, 46),\n                                               new ECB(14, 47)),\n                                  new ECBlocks(30, new ECB(49, 24),\n                                               new ECB(10, 25)),\n                                  new ECBlocks(30, new ECB(24, 15),\n                                               new ECB(46, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(38, intArray(7, 6, 32, 58, 84,\n                                  110, 136, 162),\n                                  new ECBlocks(30, new ECB(4, 122),\n                                               new ECB(18, 123)),\n                                  new ECBlocks(28, new ECB(13, 46),\n                                               new ECB(32, 47)),\n                                  new ECBlocks(30, new ECB(48, 24),\n                                               new ECB(14, 25)),\n                                  new ECBlocks(30, new ECB(42, 15),\n                                               new ECB(32, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(39, intArray(7, 6, 26, 54, 82,\n                                  110, 138, 166),\n                                  new ECBlocks(30, new ECB(20, 117),\n                                               new ECB(4, 118)),\n                                  new ECBlocks(28, new ECB(40, 47),\n                                               new ECB(7, 48)),\n                                  new ECBlocks(30, new ECB(43, 24),\n                                               new ECB(22, 25)),\n                                  new ECBlocks(30, new ECB(10, 15),\n                                               new ECB(67, 16)))));\n  VERSIONS.push_back(Ref<Version>(new Version(40, intArray(7, 6, 30, 58, 86,\n                                  114, 142, 170),\n                                  new ECBlocks(30, new ECB(19, 118),\n                                               new ECB(6, 119)),\n                                  new ECBlocks(28, new ECB(18, 47),\n                                               new ECB(31, 48)),\n                                  new ECBlocks(30, new ECB(34, 24),\n                                               new ECB(34, 25)),\n                                  new ECBlocks(30, new ECB(20, 15),\n                                               new ECB(61, 16)))));\n  return VERSIONS.size();\n}\n}\n}\n\n// file: zxing/qrcode/decoder/BitMatrixParser.cpp\n\n/*\n *  BitMatrixParser.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 20/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/decoder/BitMatrixParser.h>\n// #include <zxing/qrcode/decoder/DataMask.h>\n\n\nnamespace zxing {\nnamespace qrcode {\n\nint BitMatrixParser::copyBit(size_t x, size_t y, int versionBits) {\n  return bitMatrix_->get(x, y) ? (versionBits << 1) | 0x1 : versionBits << 1;\n}\n\nBitMatrixParser::BitMatrixParser(Ref<BitMatrix> bitMatrix) :\n    bitMatrix_(bitMatrix), parsedVersion_(0), parsedFormatInfo_() {\n  size_t dimension = bitMatrix->getDimension();\n  if ((dimension < 21) || (dimension & 0x03) != 1) {\n    throw ReaderException(\"Dimension must be 1 mod 4 and >= 21\");\n  }\n}\n\nRef<FormatInformation> BitMatrixParser::readFormatInformation() {\n  if (parsedFormatInfo_ != 0) {\n    return parsedFormatInfo_;\n  }\n\n  // Read top-left format info bits\n  int formatInfoBits1 = 0;\n  for (int i = 0; i < 6; i++) {\n    formatInfoBits1 = copyBit(i, 8, formatInfoBits1);\n  }\n  // .. and skip a bit in the timing pattern ...\n  formatInfoBits1 = copyBit(7, 8, formatInfoBits1);\n  formatInfoBits1 = copyBit(8, 8, formatInfoBits1);\n  formatInfoBits1 = copyBit(8, 7, formatInfoBits1);\n  // .. and skip a bit in the timing pattern ...\n  for (int j = 5; j >= 0; j--) {\n    formatInfoBits1 = copyBit(8, j, formatInfoBits1);\n  }\n\n  // Read the top-right/bottom-left pattern\n  int dimension = bitMatrix_->getDimension();\n  int formatInfoBits2 = 0;\n  int jMin = dimension - 7;\n  for (int j = dimension - 1; j >= jMin; j--) {\n    formatInfoBits2 = copyBit(8, j, formatInfoBits2);\n  }\n  for (int i = dimension - 8; i < dimension; i++) {\n    formatInfoBits2 = copyBit(i, 8, formatInfoBits2);\n  }\n\n  parsedFormatInfo_ = FormatInformation::decodeFormatInformation(formatInfoBits1,formatInfoBits2);\n  if (parsedFormatInfo_ != 0) {\n    return parsedFormatInfo_;\n  }\n  throw ReaderException(\"Could not decode format information\");\n}\n\nVersion *BitMatrixParser::readVersion() {\n  if (parsedVersion_ != 0) {\n    return parsedVersion_;\n  }\n\n  int dimension = bitMatrix_->getDimension();\n\n  int provisionalVersion = (dimension - 17) >> 2;\n  if (provisionalVersion <= 6) {\n    return Version::getVersionForNumber(provisionalVersion);\n  }\n\n  // Read top-right version info: 3 wide by 6 tall\n  int versionBits = 0;\n  for (int y = 5; y >= 0; y--) {\n    int xMin = dimension - 11;\n    for (int x = dimension - 9; x >= xMin; x--) {\n      versionBits = copyBit(x, y, versionBits);\n    }\n  }\n\n  parsedVersion_ = Version::decodeVersionInformation(versionBits);\n  if (parsedVersion_ != 0 && parsedVersion_->getDimensionForVersion() == dimension) {\n    return parsedVersion_;\n  }\n\n  // Hmm, failed. Try bottom left: 6 wide by 3 tall\n  versionBits = 0;\n  for (int x = 5; x >= 0; x--) {\n    int yMin = dimension - 11;\n    for (int y = dimension - 9; y >= yMin; y--) {\n      versionBits = copyBit(x, y, versionBits);\n    }\n  }\n\n  parsedVersion_ = Version::decodeVersionInformation(versionBits);\n  if (parsedVersion_ != 0 && parsedVersion_->getDimensionForVersion() == dimension) {\n    return parsedVersion_;\n  }\n  throw ReaderException(\"Could not decode version\");\n}\n\nArrayRef<unsigned char> BitMatrixParser::readCodewords() {\n  Ref<FormatInformation> formatInfo = readFormatInformation();\n  Version *version = readVersion();\n\n\n  //\tcerr << *bitMatrix_ << endl;\n  //\tcerr << bitMatrix_->getDimension() << endl;\n\n  // Get the data mask for the format used in this QR Code. This will exclude\n  // some bits from reading as we wind through the bit matrix.\n  DataMask &dataMask = DataMask::forReference((int)formatInfo->getDataMask());\n  //\tcout << (int)formatInfo->getDataMask() << endl;\n  int dimension = bitMatrix_->getDimension();\n  dataMask.unmaskBitMatrix(*bitMatrix_, dimension);\n\n\n  //\t\tcerr << *bitMatrix_ << endl;\n  //\tcerr << version->getTotalCodewords() << endl;\n\n  Ref<BitMatrix> functionPattern = version->buildFunctionPattern();\n\n\n  //\tcout << *functionPattern << endl;\n\n  bool readingUp = true;\n  ArrayRef<unsigned char> result(version->getTotalCodewords());\n  int resultOffset = 0;\n  int currentByte = 0;\n  int bitsRead = 0;\n  // Read columns in pairs, from right to left\n  for (int x = dimension - 1; x > 0; x -= 2) {\n    if (x == 6) {\n      // Skip whole column with vertical alignment pattern;\n      // saves time and makes the other code proceed more cleanly\n      x--;\n    }\n    // Read alternatingly from bottom to top then top to bottom\n    for (int counter = 0; counter < dimension; counter++) {\n      int y = readingUp ? dimension - 1 - counter : counter;\n      for (int col = 0; col < 2; col++) {\n        // Ignore bits covered by the function pattern\n        if (!functionPattern->get(x - col, y)) {\n          // Read a bit\n          bitsRead++;\n          currentByte <<= 1;\n          if (bitMatrix_->get(x - col, y)) {\n            currentByte |= 1;\n          }\n          // If we've made a whole byte, save it off\n          if (bitsRead == 8) {\n            result[resultOffset++] = (unsigned char)currentByte;\n            bitsRead = 0;\n            currentByte = 0;\n          }\n        }\n      }\n    }\n    readingUp = !readingUp; // switch directions\n  }\n\n  if (resultOffset != version->getTotalCodewords()) {\n    throw ReaderException(\"Did not read all codewords\");\n  }\n  return result;\n}\n\n}\n}\n\n// file: zxing/qrcode/decoder/DataBlock.cpp\n\n/*\n *  DataBlock.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 19/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/decoder/DataBlock.h>\n// #include <zxing/common/IllegalArgumentException.h>\n\nnamespace zxing {\nnamespace qrcode {\n\nusing namespace std;\n\nDataBlock::DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords) :\n    numDataCodewords_(numDataCodewords), codewords_(codewords) {\n}\n\nint DataBlock::getNumDataCodewords() {\n  return numDataCodewords_;\n}\n\nArrayRef<unsigned char> DataBlock::getCodewords() {\n  return codewords_;\n}\n\n\nstd::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version,\n    ErrorCorrectionLevel &ecLevel) {\n\n\n  // Figure out the number and size of data blocks used by this version and\n  // error correction level\n  ECBlocks &ecBlocks = version->getECBlocksForLevel(ecLevel);\n\n\n  // First count the total number of data blocks\n  int totalBlocks = 0;\n  vector<ECB*> ecBlockArray = ecBlocks.getECBlocks();\n  for (size_t i = 0; i < ecBlockArray.size(); i++) {\n    totalBlocks += ecBlockArray[i]->getCount();\n  }\n\n  // Now establish DataBlocks of the appropriate size and number of data codewords\n  std::vector<Ref<DataBlock> > result(totalBlocks);\n  int numResultBlocks = 0;\n  for (size_t j = 0; j < ecBlockArray.size(); j++) {\n    ECB *ecBlock = ecBlockArray[j];\n    for (int i = 0; i < ecBlock->getCount(); i++) {\n      int numDataCodewords = ecBlock->getDataCodewords();\n      int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords;\n      ArrayRef<unsigned char> buffer(numBlockCodewords);\n      Ref<DataBlock> blockRef(new DataBlock(numDataCodewords, buffer));\n      result[numResultBlocks++] = blockRef;\n    }\n  }\n\n  // All blocks have the same amount of data, except that the last n\n  // (where n may be 0) have 1 more byte. Figure out where these start.\n  int shorterBlocksTotalCodewords = result[0]->codewords_.size();\n  int longerBlocksStartAt = result.size() - 1;\n  while (longerBlocksStartAt >= 0) {\n    int numCodewords = result[longerBlocksStartAt]->codewords_.size();\n    if (numCodewords == shorterBlocksTotalCodewords) {\n      break;\n    }\n    if (numCodewords != shorterBlocksTotalCodewords + 1) {\n      throw IllegalArgumentException(\"Data block sizes differ by more than 1\");\n    }\n    longerBlocksStartAt--;\n  }\n  longerBlocksStartAt++;\n\n  int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewords();\n  // The last elements of result may be 1 element longer;\n  // first fill out as many elements as all of them have\n  int rawCodewordsOffset = 0;\n  for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {\n    for (int j = 0; j < numResultBlocks; j++) {\n      result[j]->codewords_[i] = rawCodewords[rawCodewordsOffset++];\n    }\n  }\n  // Fill out the last data block in the longer ones\n  for (int j = longerBlocksStartAt; j < numResultBlocks; j++) {\n    result[j]->codewords_[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];\n  }\n  // Now add in error correction blocks\n  int max = result[0]->codewords_.size();\n  for (int i = shorterBlocksNumDataCodewords; i < max; i++) {\n    for (int j = 0; j < numResultBlocks; j++) {\n      int iOffset = j < longerBlocksStartAt ? i : i + 1;\n      result[j]->codewords_[iOffset] = rawCodewords[rawCodewordsOffset++];\n    }\n  }\n\n  if ((size_t)rawCodewordsOffset != rawCodewords.size()) {\n    throw IllegalArgumentException(\"rawCodewordsOffset != rawCodewords.length\");\n  }\n\n  return result;\n}\n\n}\n}\n\n// file: zxing/qrcode/decoder/DataMask.cpp\n\n/*\n *  DataMask.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 19/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/decoder/DataMask.h>\n\n// #include <zxing/common/IllegalArgumentException.h>\n\nnamespace zxing {\nnamespace qrcode {\n\nusing namespace std;\n\nDataMask::DataMask() {\n}\n\nDataMask::~DataMask() {\n}\n\nvector<Ref<DataMask> > DataMask::DATA_MASKS;\nstatic int N_DATA_MASKS = DataMask::buildDataMasks();\n\nDataMask &DataMask::forReference(int reference) {\n  if (reference < 0 || reference > 7) {\n    throw IllegalArgumentException(\"reference must be between 0 and 7\");\n  }\n  return *DATA_MASKS[reference];\n}\n\nvoid DataMask::unmaskBitMatrix(BitMatrix& bits, size_t dimension) {\n  for (size_t y = 0; y < dimension; y++) {\n    for (size_t x = 0; x < dimension; x++) {\n      // TODO: check why the coordinates have to be swapped\n      if (isMasked(y, x)) {\n        bits.flip(x, y);\n      }\n    }\n  }\n}\n\n/**\n * 000: mask bits for which (x + y) mod 2 == 0\n */\nclass DataMask000 : public DataMask {\npublic:\n  bool isMasked(size_t x, size_t y) {\n    //\t\treturn ((x + y) & 0x01) == 0;\n    return ((x + y) % 2) == 0;\n  }\n};\n\n/**\n * 001: mask bits for which x mod 2 == 0\n */\nclass DataMask001 : public DataMask {\npublic:\n  bool isMasked(size_t x, size_t) {\n    //\t\treturn (x & 0x01) == 0;\n    return (x % 2) == 0;\n  }\n};\n\n/**\n * 010: mask bits for which y mod 3 == 0\n */\nclass DataMask010 : public DataMask {\npublic:\n  bool isMasked(size_t, size_t y) {\n    return y % 3 == 0;\n  }\n};\n\n/**\n * 011: mask bits for which (x + y) mod 3 == 0\n */\nclass DataMask011 : public DataMask {\npublic:\n  bool isMasked(size_t x, size_t y) {\n    return (x + y) % 3 == 0;\n  }\n};\n\n/**\n * 100: mask bits for which (x/2 + y/3) mod 2 == 0\n */\nclass DataMask100 : public DataMask {\npublic:\n  bool isMasked(size_t x, size_t y) {\n    //\t\treturn (((x >> 1) + (y / 3)) & 0x01) == 0;\n    return (((x >> 1) + (y / 3)) % 2) == 0;\n  }\n};\n\n/**\n * 101: mask bits for which xy mod 2 + xy mod 3 == 0\n */\nclass DataMask101 : public DataMask {\npublic:\n  bool isMasked(size_t x, size_t y) {\n    size_t temp = x * y;\n    //\t\treturn (temp & 0x01) + (temp % 3) == 0;\n    return (temp % 2) + (temp % 3) == 0;\n\n  }\n};\n\n/**\n * 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0\n */\nclass DataMask110 : public DataMask {\npublic:\n  bool isMasked(size_t x, size_t y) {\n    size_t temp = x * y;\n    //\t\treturn (((temp & 0x01) + (temp % 3)) & 0x01) == 0;\n    return (((temp % 2) + (temp % 3)) % 2) == 0;\n  }\n};\n\n/**\n * 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0\n */\nclass DataMask111 : public DataMask {\npublic:\n  bool isMasked(size_t x, size_t y) {\n    //\t\treturn ((((x + y) & 0x01) + ((x * y) % 3)) & 0x01) == 0;\n    return ((((x + y) % 2) + ((x * y) % 3)) % 2) == 0;\n  }\n};\n\nint DataMask::buildDataMasks() {\n  DATA_MASKS.push_back(Ref<DataMask> (new DataMask000()));\n  DATA_MASKS.push_back(Ref<DataMask> (new DataMask001()));\n  DATA_MASKS.push_back(Ref<DataMask> (new DataMask010()));\n  DATA_MASKS.push_back(Ref<DataMask> (new DataMask011()));\n  DATA_MASKS.push_back(Ref<DataMask> (new DataMask100()));\n  DATA_MASKS.push_back(Ref<DataMask> (new DataMask101()));\n  DATA_MASKS.push_back(Ref<DataMask> (new DataMask110()));\n  DATA_MASKS.push_back(Ref<DataMask> (new DataMask111()));\n  return DATA_MASKS.size();\n}\n\n}\n}\n\n// file: zxing/qrcode/decoder/DecodedBitStreamParser.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  DecodedBitStreamParser.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 20/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/decoder/DecodedBitStreamParser.h>\n// #include <zxing/common/CharacterSetECI.h>\n// #include <zxing/FormatException.h>\n// #include <zxing/common/StringUtils.h>\n// #include <iostream>\n#ifndef NO_ICONV\n// #include <iconv.h>\n#endif\n\n// Required for compatibility. TODO: test on Symbian\n#ifdef ZXING_ICONV_CONST\n#undef ICONV_CONST\n#define ICONV_CONST const\n#endif\n\n#ifndef ICONV_CONST\n#define ICONV_CONST /**/\n#endif\n\nusing namespace std;\nusing namespace zxing;\nusing namespace zxing::qrcode;\nusing namespace zxing::common;\n\nconst char DecodedBitStreamParser::ALPHANUMERIC_CHARS[] =\n{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',\n  'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',\n  'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',\n  'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':'\n};\n\nnamespace {int GB2312_SUBSET = 1;}\n\nvoid DecodedBitStreamParser::append(std::string &result,\n                                    string const& in,\n                                    const char *src) {\n  append(result, (unsigned char const*)in.c_str(), in.length(), src);\n}\n\nvoid DecodedBitStreamParser::append(std::string &result,\n                                    const unsigned char *bufIn,\n                                    size_t nIn,\n                                    const char *src) {\n#ifndef NO_ICONV\n  if (nIn == 0) {\n    return;\n  }\n\n  iconv_t cd = iconv_open(StringUtils::UTF8, src);\n  if (cd == (iconv_t)-1) {\n    result.append((const char *)bufIn, nIn);\n    return;\n  }\n\n  const int maxOut = 4 * nIn + 1;\n  unsigned char* bufOut = new unsigned char[maxOut];\n\n  ICONV_CONST char *fromPtr = (ICONV_CONST char *)bufIn;\n  size_t nFrom = nIn;\n  char *toPtr = (char *)bufOut;\n  size_t nTo = maxOut;\n\n  while (nFrom > 0) {\n    size_t oneway = iconv(cd, &fromPtr, &nFrom, &toPtr, &nTo);\n    if (oneway == (size_t)(-1)) {\n      iconv_close(cd);\n      delete[] bufOut;\n      throw ReaderException(\"error converting characters\");\n    }\n  }\n  iconv_close(cd);\n\n  int nResult = maxOut - nTo;\n  bufOut[nResult] = '\\0';\n  result.append((const char *)bufOut);\n  delete[] bufOut;\n#else\n  result.append((const char *)bufIn, nIn);\n#endif\n}\n\nvoid DecodedBitStreamParser::decodeHanziSegment(Ref<BitSource> bits_,\n                                                string& result,\n                                                int count) {\n    BitSource& bits (*bits_);\n    // Don't crash trying to read more bits than we have available.\n    if (count * 13 > bits.available()) {\n      throw FormatException();\n    }\n\n    // Each character will require 2 bytes. Read the characters as 2-byte pairs\n    // and decode as GB2312 afterwards\n    size_t nBytes = 2 * count;\n    unsigned char* buffer = new unsigned char[nBytes];\n    int offset = 0;\n    while (count > 0) {\n      // Each 13 bits encodes a 2-byte character\n      int twoBytes = bits.readBits(13);\n      int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060);\n      if (assembledTwoBytes < 0x003BF) {\n        // In the 0xA1A1 to 0xAAFE range\n        assembledTwoBytes += 0x0A1A1;\n      } else {\n        // In the 0xB0A1 to 0xFAFE range\n        assembledTwoBytes += 0x0A6A1;\n      }\n      buffer[offset] = (unsigned char) ((assembledTwoBytes >> 8) & 0xFF);\n      buffer[offset + 1] = (unsigned char) (assembledTwoBytes & 0xFF);\n      offset += 2;\n      count--;\n    }\n\n    try {\n      append(result, buffer, nBytes, StringUtils::GB2312);\n    } catch (ReaderException const& re) {\n      delete [] buffer;\n      throw FormatException();\n    }\n\n    delete [] buffer;\n  }\n\nvoid DecodedBitStreamParser::decodeKanjiSegment(Ref<BitSource> bits, std::string &result, int count) {\n  // Each character will require 2 bytes. Read the characters as 2-byte pairs\n  // and decode as Shift_JIS afterwards\n  size_t nBytes = 2 * count;\n  unsigned char* buffer = new unsigned char[nBytes];\n  int offset = 0;\n  while (count > 0) {\n    // Each 13 bits encodes a 2-byte character\n\n    int twoBytes = bits->readBits(13);\n    int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0);\n    if (assembledTwoBytes < 0x01F00) {\n      // In the 0x8140 to 0x9FFC range\n      assembledTwoBytes += 0x08140;\n    } else {\n      // In the 0xE040 to 0xEBBF range\n      assembledTwoBytes += 0x0C140;\n    }\n    buffer[offset] = (unsigned char)(assembledTwoBytes >> 8);\n    buffer[offset + 1] = (unsigned char)assembledTwoBytes;\n    offset += 2;\n    count--;\n  }\n\n  append(result, buffer, nBytes, StringUtils::SHIFT_JIS);\n  delete[] buffer;\n}\n\nvoid DecodedBitStreamParser::decodeByteSegment(Ref<BitSource> bits_,\n                                               string& result,\n                                               int count,\n                                               CharacterSetECI* currentCharacterSetECI,\n                                               ArrayRef< ArrayRef<unsigned char> >& byteSegments,\n                                               Hashtable const& hints) {\n  int nBytes = count;\n  BitSource& bits (*bits_);\n  // Don't crash trying to read more bits than we have available.\n  if (count << 3 > bits.available()) {\n    throw FormatException();\n  }\n\n  ArrayRef<unsigned char> bytes_ (count);\n  unsigned char* readBytes = &(*bytes_)[0];\n  for (int i = 0; i < count; i++) {\n    readBytes[i] = (unsigned char) bits.readBits(8);\n  }\n  string encoding;\n  if (currentCharacterSetECI == 0) {\n    // The spec isn't clear on this mode; see\n    // section 6.4.5: t does not say which encoding to assuming\n    // upon decoding. I have seen ISO-8859-1 used as well as\n    // Shift_JIS -- without anything like an ECI designator to\n    // give a hint.\n    encoding = StringUtils::guessEncoding(readBytes, count, hints);\n  } else {\n    encoding = currentCharacterSetECI->getEncodingName();\n  }\n  try {\n    append(result, readBytes, nBytes, encoding.c_str());\n  } catch (ReaderException const& re) {\n    throw FormatException();\n  }\n  byteSegments->values().push_back(bytes_);\n}\n\nvoid DecodedBitStreamParser::decodeNumericSegment(Ref<BitSource> bits, std::string &result, int count) {\n  int nBytes = count;\n  unsigned char* bytes = new unsigned char[nBytes];\n  int i = 0;\n  // Read three digits at a time\n  while (count >= 3) {\n    // Each 10 bits encodes three digits\n    if (bits->available() < 10) {\n      throw ReaderException(\"format exception\");\n    }\n    int threeDigitsBits = bits->readBits(10);\n    if (threeDigitsBits >= 1000) {\n      ostringstream s;\n      s << \"Illegal value for 3-digit unit: \" << threeDigitsBits;\n      delete[] bytes;\n      throw ReaderException(s.str().c_str());\n    }\n    bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits / 100];\n    bytes[i++] = ALPHANUMERIC_CHARS[(threeDigitsBits / 10) % 10];\n    bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits % 10];\n    count -= 3;\n  }\n  if (count == 2) {\n    if (bits->available() < 7) {\n      throw ReaderException(\"format exception\");\n    }\n    // Two digits left over to read, encoded in 7 bits\n    int twoDigitsBits = bits->readBits(7);\n    if (twoDigitsBits >= 100) {\n      ostringstream s;\n      s << \"Illegal value for 2-digit unit: \" << twoDigitsBits;\n      delete[] bytes;\n      throw ReaderException(s.str().c_str());\n    }\n    bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits / 10];\n    bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits % 10];\n  } else if (count == 1) {\n    if (bits->available() < 4) {\n      throw ReaderException(\"format exception\");\n    }\n    // One digit left over to read\n    int digitBits = bits->readBits(4);\n    if (digitBits >= 10) {\n      ostringstream s;\n      s << \"Illegal value for digit unit: \" << digitBits;\n      delete[] bytes;\n      throw ReaderException(s.str().c_str());\n    }\n    bytes[i++] = ALPHANUMERIC_CHARS[digitBits];\n  }\n  append(result, bytes, nBytes, StringUtils::ASCII);\n  delete[] bytes;\n}\n\nchar DecodedBitStreamParser::toAlphaNumericChar(size_t value) {\n  if (value >= sizeof(DecodedBitStreamParser::ALPHANUMERIC_CHARS)) {\n    throw FormatException();\n  }\n  return ALPHANUMERIC_CHARS[value];\n}\n\nvoid DecodedBitStreamParser::decodeAlphanumericSegment(Ref<BitSource> bits_,\n                                                       string& result,\n                                                       int count,\n                                                       bool fc1InEffect) {\n  BitSource& bits (*bits_);\n  ostringstream bytes;\n  // Read two characters at a time\n  while (count > 1) {\n    int nextTwoCharsBits = bits.readBits(11);\n    bytes << toAlphaNumericChar(nextTwoCharsBits / 45);\n    bytes << toAlphaNumericChar(nextTwoCharsBits % 45);\n    count -= 2;\n  }\n  if (count == 1) {\n    // special case: one character left\n    bytes << toAlphaNumericChar(bits.readBits(6));\n  }\n  // See section 6.4.8.1, 6.4.8.2\n  string s = bytes.str();\n  if (fc1InEffect) {\n    // We need to massage the result a bit if in an FNC1 mode:\n    ostringstream r;\n    for (size_t i = 0; i < s.length(); i++) {\n      if (s[i] != '%') {\n        r << s[i];\n      } else {\n        if (i < s.length() - 1 && s[i + 1] == '%') {\n          // %% is rendered as %\n          r << s[i++];\n        } else {\n          // In alpha mode, % should be converted to FNC1 separator 0x1D\n          r << (char)0x1D;\n        }\n      }\n    }\n    s = r.str();\n  }\n  append(result, s, StringUtils::ASCII);\n}\n\nnamespace {\n  int parseECIValue(BitSource bits) {\n    int firstByte = bits.readBits(8);\n    if ((firstByte & 0x80) == 0) {\n      // just one byte\n      return firstByte & 0x7F;\n    }\n    if ((firstByte & 0xC0) == 0x80) {\n      // two bytes\n      int secondByte = bits.readBits(8);\n      return ((firstByte & 0x3F) << 8) | secondByte;\n    }\n    if ((firstByte & 0xE0) == 0xC0) {\n      // three bytes\n      int secondThirdBytes = bits.readBits(16);\n      return ((firstByte & 0x1F) << 16) | secondThirdBytes;\n    }\n    throw IllegalArgumentException(\"Bad ECI bits starting with byte \");\n  }\n}\n\nRef<DecoderResult>\nDecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes,\n                               Version* version,\n                               ErrorCorrectionLevel const& ecLevel,\n                               Hashtable const& hints) {\n  Ref<BitSource> bits_ (new BitSource(bytes));\n  BitSource& bits (*bits_);\n  string result;\n  CharacterSetECI* currentCharacterSetECI = 0;\n  bool fc1InEffect = false;\n  ArrayRef< ArrayRef<unsigned char> > byteSegments (size_t(0));\n  Mode* mode = 0;\n  do {\n    // While still another segment to read...\n    if (bits.available() < 4) {\n      // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here\n      mode = &Mode::TERMINATOR;\n    } else {\n      try {\n        mode = &Mode::forBits(bits.readBits(4)); // mode is encoded by 4 bits\n      } catch (IllegalArgumentException const& iae) {\n        throw iae;\n        // throw FormatException.getFormatInstance();\n      }\n    }\n    if (mode != &Mode::TERMINATOR) {\n      if ((mode == &Mode::FNC1_FIRST_POSITION) || (mode == &Mode::FNC1_SECOND_POSITION)) {\n        // We do little with FNC1 except alter the parsed result a bit according to the spec\n        fc1InEffect = true;\n      } else if (mode == &Mode::STRUCTURED_APPEND) {\n        // not really supported; all we do is ignore it\n        // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue\n        bits.readBits(16);\n      } else if (mode == &Mode::ECI) {\n        // Count doesn't apply to ECI\n        int value = parseECIValue(bits);\n        currentCharacterSetECI = CharacterSetECI::getCharacterSetECIByValue(value);\n        if (currentCharacterSetECI == 0) {\n          throw FormatException();\n        }\n      } else {\n        // First handle Hanzi mode which does not start with character count\n        if (mode == &Mode::HANZI) {\n          //chinese mode contains a sub set indicator right after mode indicator\n          int subset = bits.readBits(4);\n          int countHanzi = bits.readBits(mode->getCharacterCountBits(version));\n          if (subset == GB2312_SUBSET) {\n            decodeHanziSegment(bits_, result, countHanzi);\n          }\n        } else {\n          // \"Normal\" QR code modes:\n          // How many characters will follow, encoded in this mode?\n          int count = bits.readBits(mode->getCharacterCountBits(version));\n          if (mode == &Mode::NUMERIC) {\n            decodeNumericSegment(bits_, result, count);\n          } else if (mode == &Mode::ALPHANUMERIC) {\n            decodeAlphanumericSegment(bits_, result, count, fc1InEffect);\n          } else if (mode == &Mode::BYTE) {\n            decodeByteSegment(bits_, result, count, currentCharacterSetECI, byteSegments, hints);\n          } else if (mode == &Mode::KANJI) {\n            decodeKanjiSegment(bits_, result, count);\n          } else {\n            throw FormatException();\n          }\n        }\n      }\n    }\n  } while (mode != &Mode::TERMINATOR);\n\n  return Ref<DecoderResult>(new DecoderResult(bytes, Ref<String>(new String(result)), byteSegments, (string)ecLevel));\n}\n\n\n// file: zxing/qrcode/decoder/Decoder.cpp\n\n/*\n *  Decoder.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 20/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/decoder/Decoder.h>\n// #include <zxing/qrcode/decoder/BitMatrixParser.h>\n// #include <zxing/qrcode/ErrorCorrectionLevel.h>\n// #include <zxing/qrcode/Version.h>\n// #include <zxing/qrcode/decoder/DataBlock.h>\n// #include <zxing/qrcode/decoder/DecodedBitStreamParser.h>\n// #include <zxing/ReaderException.h>\n// #include <zxing/common/reedsolomon/ReedSolomonException.h>\n\nnamespace zxing {\nnamespace qrcode {\n\nusing namespace std;\n\nDecoder::Decoder() :\n    rsDecoder_(GF256::QR_CODE_FIELD) {\n}\n\nvoid Decoder::correctErrors(ArrayRef<unsigned char> codewordBytes, int numDataCodewords) {\n  int numCodewords = codewordBytes->size();\n  ArrayRef<int> codewordInts(numCodewords);\n  for (int i = 0; i < numCodewords; i++) {\n    codewordInts[i] = codewordBytes[i] & 0xff;\n  }\n  int numECCodewords = numCodewords - numDataCodewords;\n\n  try {\n    rsDecoder_.decode(codewordInts, numECCodewords);\n  } catch (ReedSolomonException const& ex) {\n    ReaderException rex(ex.what());\n    throw rex;\n  }\n\n  for (int i = 0; i < numDataCodewords; i++) {\n    codewordBytes[i] = (unsigned char)codewordInts[i];\n  }\n}\n\nRef<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {\n  // Construct a parser and read version, error-correction level\n  BitMatrixParser parser(bits);\n\n  Version *version = parser.readVersion();\n  ErrorCorrectionLevel &ecLevel = parser.readFormatInformation()->getErrorCorrectionLevel();\n\n\n  // Read codewords\n  ArrayRef<unsigned char> codewords(parser.readCodewords());\n\n\n  // Separate into data blocks\n  std::vector<Ref<DataBlock> > dataBlocks(DataBlock::getDataBlocks(codewords, version, ecLevel));\n\n\n  // Count total number of data bytes\n  int totalBytes = 0;\n  for (size_t i = 0; i < dataBlocks.size(); i++) {\n    totalBytes += dataBlocks[i]->getNumDataCodewords();\n  }\n  ArrayRef<unsigned char> resultBytes(totalBytes);\n  int resultOffset = 0;\n\n\n  // Error-correct and copy data blocks together into a stream of bytes\n  for (size_t j = 0; j < dataBlocks.size(); j++) {\n    Ref<DataBlock> dataBlock(dataBlocks[j]);\n    ArrayRef<unsigned char> codewordBytes = dataBlock->getCodewords();\n    int numDataCodewords = dataBlock->getNumDataCodewords();\n    correctErrors(codewordBytes, numDataCodewords);\n    for (int i = 0; i < numDataCodewords; i++) {\n      resultBytes[resultOffset++] = codewordBytes[i];\n    }\n  }\n\n  return DecodedBitStreamParser::decode(resultBytes,\n                                        version,\n                                        ecLevel,\n                                        DecodedBitStreamParser::Hashtable());\n}\n\n}\n}\n\n// file: zxing/qrcode/decoder/Mode.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Mode.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 19/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/decoder/Mode.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/ReaderException.h>\n// #include <zxing/qrcode/Version.h>\n// #include <sstream>\n\nusing zxing::qrcode::Mode;\nusing std::ostringstream;\n\nMode Mode::TERMINATOR(0, 0, 0, 0x00, \"TERMINATOR\");\nMode Mode::NUMERIC(10, 12, 14, 0x01, \"NUMERIC\");\nMode Mode::ALPHANUMERIC(9, 11, 13, 0x02, \"ALPHANUMERIC\");\nMode Mode::STRUCTURED_APPEND(0, 0, 0, 0x03, \"STRUCTURED_APPEND\");\nMode Mode::BYTE(8, 16, 16, 0x04, \"BYTE\");\nMode Mode::ECI(0, 0, 0, 0x07, \"ECI\");\nMode Mode::KANJI(8, 10, 12, 0x08, \"KANJI\");\nMode Mode::FNC1_FIRST_POSITION(0, 0, 0, 0x05, \"FNC1_FIRST_POSITION\");\nMode Mode::FNC1_SECOND_POSITION(0, 0, 0, 0x09, \"FNC1_SECOND_POSITION\");\nMode Mode::HANZI(8, 10, 12, 0x0D, \"HANZI\");\n\nMode::Mode(int cbv0_9, int cbv10_26, int cbv27, int bits, char const* name) :\n    characterCountBitsForVersions0To9_(cbv0_9), characterCountBitsForVersions10To26_(cbv10_26),\n    characterCountBitsForVersions27AndHigher_(cbv27), bits_(bits), name_(name) {\n}\n\nMode& Mode::forBits(int bits) {\n    switch (bits) {\n    case 0x0:\n        return TERMINATOR;\n    case 0x1:\n        return NUMERIC;\n    case 0x2:\n        return ALPHANUMERIC;\n    case 0x3:\n        return STRUCTURED_APPEND;\n    case 0x4:\n        return BYTE;\n    case 0x5:\n        return FNC1_FIRST_POSITION;\n    case 0x7:\n        return ECI;\n    case 0x8:\n        return KANJI;\n    case 0x9:\n        return FNC1_SECOND_POSITION;\n    case 0xD:\n        // 0xD is defined in GBT 18284-2000, may not be supported in foreign country\n        return HANZI;\n    default:\n        ostringstream s;\n        s << \"Illegal mode bits: \" << bits;\n        throw ReaderException(s.str().c_str());\n    }\n}\n\nint Mode::getCharacterCountBits(Version *version) {\n  int number = version->getVersionNumber();\n  if (number <= 9) {\n    return characterCountBitsForVersions0To9_;\n  } else if (number <= 26) {\n    return characterCountBitsForVersions10To26_;\n  } else {\n    return characterCountBitsForVersions27AndHigher_;\n  }\n}\n\n// file: zxing/qrcode/detector/AlignmentPattern.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  AlignmentPattern.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 13/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/detector/AlignmentPattern.h>\n\nnamespace zxing {\nnamespace qrcode {\n\nusing namespace std;\n\nAlignmentPattern::AlignmentPattern(float posX, float posY, float estimatedModuleSize) :\n    ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize) {\n}\n\nbool AlignmentPattern::aboutEquals(float moduleSize, float i, float j) const {\n  if (abs(i - getY()) <= moduleSize && abs(j - getX()) <= moduleSize) {\n    float moduleSizeDiff = abs(moduleSize - estimatedModuleSize_);\n    return moduleSizeDiff <= 1.0f || moduleSizeDiff <= estimatedModuleSize_;\n  }\n  return false;\n}\n\nRef<AlignmentPattern> AlignmentPattern::combineEstimate(float i, float j, float newModuleSize) const {\n  float combinedX = (getX() + j) / 2.0f;\n  float combinedY = (getY() + i) / 2.0f;\n  float combinedModuleSize = (estimatedModuleSize_ + newModuleSize) / 2.0f;\n  Ref<AlignmentPattern> result\n    (new AlignmentPattern(combinedX, combinedY, combinedModuleSize));\n  return result;\n}\n\n}\n}\n\n// file: zxing/qrcode/detector/AlignmentPatternFinder.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  AlignmentPatternFinder.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 14/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include \"AlignmentPatternFinder.h\"\n// #include <zxing/ReaderException.h>\n// #include <zxing/common/BitArray.h>\n// #include <vector>\n// #include <cmath>\n// #include <cstdlib>\n\nnamespace zxing {\nnamespace qrcode {\n\nusing namespace std;\n\nfloat AlignmentPatternFinder::centerFromEnd(vector<int> &stateCount, int end) {\n  return (float)(end - stateCount[2]) - stateCount[1] / 2.0f;\n}\n\nbool AlignmentPatternFinder::foundPatternCross(vector<int> &stateCount) {\n  float maxVariance = moduleSize_ / 2.0f;\n  for (size_t i = 0; i < 3; i++) {\n    if (abs(moduleSize_ - stateCount[i]) >= maxVariance) {\n      return false;\n    }\n  }\n  return true;\n}\n\nfloat AlignmentPatternFinder::crossCheckVertical(size_t startI, size_t centerJ, int maxCount,\n    int originalStateCountTotal) {\n  int maxI = image_->getHeight();\n  vector<int> stateCount(3, 0);\n\n\n  // Start counting up from center\n  int i = startI;\n  while (i >= 0 && image_->get(centerJ, i) && stateCount[1] <= maxCount) {\n    stateCount[1]++;\n    i--;\n  }\n  // If already too many modules in this state or ran off the edge:\n  if (i < 0 || stateCount[1] > maxCount) {\n    return NAN;\n  }\n  while (i >= 0 && !image_->get(centerJ, i) && stateCount[0] <= maxCount) {\n    stateCount[0]++;\n    i--;\n  }\n  if (stateCount[0] > maxCount) {\n    return NAN;\n  }\n\n  // Now also count down from center\n  i = startI + 1;\n  while (i < maxI && image_->get(centerJ, i) && stateCount[1] <= maxCount) {\n    stateCount[1]++;\n    i++;\n  }\n  if (i == maxI || stateCount[1] > maxCount) {\n    return NAN;\n  }\n  while (i < maxI && !image_->get(centerJ, i) && stateCount[2] <= maxCount) {\n    stateCount[2]++;\n    i++;\n  }\n  if (stateCount[2] > maxCount) {\n    return NAN;\n  }\n\n  int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];\n  if (5 * abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) {\n    return NAN;\n  }\n\n  return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : NAN;\n}\n\nRef<AlignmentPattern> AlignmentPatternFinder::handlePossibleCenter(vector<int> &stateCount, size_t i, size_t j) {\n  int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];\n  float centerJ = centerFromEnd(stateCount, j);\n  float centerI = crossCheckVertical(i, (int)centerJ, 2 * stateCount[1], stateCountTotal);\n  if (!isnan(centerI)) {\n    float estimatedModuleSize = (float)(stateCount[0] + stateCount[1] + stateCount[2]) / 3.0f;\n    int max = possibleCenters_->size();\n    for (int index = 0; index < max; index++) {\n      Ref<AlignmentPattern> center((*possibleCenters_)[index]);\n      // Look for about the same center and module size:\n      if (center->aboutEquals(estimatedModuleSize, centerI, centerJ)) {\n        return center->combineEstimate(centerI, centerJ, estimatedModuleSize);\n      }\n    }\n    AlignmentPattern *tmp = new AlignmentPattern(centerJ, centerI, estimatedModuleSize);\n    // Hadn't found this before; save it\n    tmp->retain();\n    possibleCenters_->push_back(tmp);\n    if (callback_ != 0) {\n      callback_->foundPossibleResultPoint(*tmp);\n    }\n  }\n  Ref<AlignmentPattern> result;\n  return result;\n}\n\nAlignmentPatternFinder::AlignmentPatternFinder(Ref<BitMatrix> image, size_t startX, size_t startY, size_t width,\n                                               size_t height, float moduleSize,\n                                               Ref<ResultPointCallback>const& callback) :\n    image_(image), possibleCenters_(new vector<AlignmentPattern *> ()), startX_(startX), startY_(startY),\n    width_(width), height_(height), moduleSize_(moduleSize), callback_(callback) {\n}\n\nAlignmentPatternFinder::~AlignmentPatternFinder() {\n  for (size_t i = 0; i < possibleCenters_->size(); i++) {\n    (*possibleCenters_)[i]->release();\n    (*possibleCenters_)[i] = 0;\n  }\n  delete possibleCenters_;\n}\n\nRef<AlignmentPattern> AlignmentPatternFinder::find() {\n  size_t maxJ = startX_ + width_;\n  size_t middleI = startY_ + (height_ >> 1);\n  //      Ref<BitArray> luminanceRow(new BitArray(width_));\n  // We are looking for black/white/black modules in 1:1:1 ratio;\n  // this tracks the number of black/white/black modules seen so far\n  vector<int> stateCount(3, 0);\n  for (size_t iGen = 0; iGen < height_; iGen++) {\n    // Search from middle outwards\n    size_t i = middleI + ((iGen & 0x01) == 0 ? ((iGen + 1) >> 1) : -((iGen + 1) >> 1));\n    //        image_->getBlackRow(i, luminanceRow, startX_, width_);\n    stateCount[0] = 0;\n    stateCount[1] = 0;\n    stateCount[2] = 0;\n    size_t j = startX_;\n    // Burn off leading white pixels before anything else; if we start in the middle of\n    // a white run, it doesn't make sense to count its length, since we don't know if the\n    // white run continued to the left of the start point\n    while (j < maxJ && !image_->get(j, i)) {\n      j++;\n    }\n    int currentState = 0;\n    while (j < maxJ) {\n      if (image_->get(j, i)) {\n        // Black pixel\n        if (currentState == 1) { // Counting black pixels\n          stateCount[currentState]++;\n        } else { // Counting white pixels\n          if (currentState == 2) { // A winner?\n            if (foundPatternCross(stateCount)) { // Yes\n              Ref<AlignmentPattern> confirmed(handlePossibleCenter(stateCount, i, j));\n              if (confirmed != 0) {\n                return confirmed;\n              }\n            }\n            stateCount[0] = stateCount[2];\n            stateCount[1] = 1;\n            stateCount[2] = 0;\n            currentState = 1;\n          } else {\n            stateCount[++currentState]++;\n          }\n        }\n      } else { // White pixel\n        if (currentState == 1) { // Counting black pixels\n          currentState++;\n        }\n        stateCount[currentState]++;\n      }\n      j++;\n    }\n    if (foundPatternCross(stateCount)) {\n      Ref<AlignmentPattern> confirmed(handlePossibleCenter(stateCount, i, maxJ));\n      if (confirmed != 0) {\n        return confirmed;\n      }\n    }\n\n  }\n\n  // Hmm, nothing we saw was observed and confirmed twice. If we had\n  // any guess at all, return it.\n  if (possibleCenters_->size() > 0) {\n    Ref<AlignmentPattern> center((*possibleCenters_)[0]);\n    return center;\n  }\n\n  throw zxing::ReaderException(\"Could not find alignment pattern\");\n}\n\n}\n}\n\n// file: zxing/qrcode/detector/Detector.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Detector.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 14/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/detector/Detector.h>\n// #include <zxing/qrcode/detector/FinderPatternFinder.h>\n// #include <zxing/qrcode/detector/FinderPattern.h>\n// #include <zxing/qrcode/detector/AlignmentPattern.h>\n// #include <zxing/qrcode/detector/AlignmentPatternFinder.h>\n// #include <zxing/qrcode/Version.h>\n// #include <zxing/common/GridSampler.h>\n// #include <zxing/DecodeHints.h>\n// #include <cmath>\n// #include <sstream>\n// #include <cstdlib>\n\nnamespace zxing {\nnamespace qrcode {\n\nusing namespace std;\n\nDetector::Detector(Ref<BitMatrix> image) :\n    image_(image) {\n}\n\nRef<BitMatrix> Detector::getImage() {\n   return image_;\n}\n\nRef<DetectorResult> Detector::detect(DecodeHints const& hints) {\n  callback_ = hints.getResultPointCallback();\n  FinderPatternFinder finder(image_, hints.getResultPointCallback());\n  Ref<FinderPatternInfo> info(finder.find(hints));\n  return processFinderPatternInfo(info);\n}\n\nRef<DetectorResult> Detector::processFinderPatternInfo(Ref<FinderPatternInfo> info){\n  Ref<FinderPattern> topLeft(info->getTopLeft());\n  Ref<FinderPattern> topRight(info->getTopRight());\n  Ref<FinderPattern> bottomLeft(info->getBottomLeft());\n\n  float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft);\n  if (moduleSize < 1.0f) {\n    throw zxing::ReaderException(\"bad module size\");\n  }\n  int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize);\n  Version *provisionalVersion = Version::getProvisionalVersionForDimension(dimension);\n  int modulesBetweenFPCenters = provisionalVersion->getDimensionForVersion() - 7;\n\n  Ref<AlignmentPattern> alignmentPattern;\n  // Anything above version 1 has an alignment pattern\n  if (provisionalVersion->getAlignmentPatternCenters().size() > 0) {\n\n\n    // Guess where a \"bottom right\" finder pattern would have been\n    float bottomRightX = topRight->getX() - topLeft->getX() + bottomLeft->getX();\n    float bottomRightY = topRight->getY() - topLeft->getY() + bottomLeft->getY();\n\n\n    // Estimate that alignment pattern is closer by 3 modules\n    // from \"bottom right\" to known top left location\n    float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters;\n    int estAlignmentX = (int)(topLeft->getX() + correctionToTopLeft * (bottomRightX - topLeft->getX()));\n    int estAlignmentY = (int)(topLeft->getY() + correctionToTopLeft * (bottomRightY - topLeft->getY()));\n\n\n    // Kind of arbitrary -- expand search radius before giving up\n    for (int i = 4; i <= 16; i <<= 1) {\n      try {\n        alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i);\n        break;\n      } catch (zxing::ReaderException const& re) {\n        // try next round\n      }\n    }\n    if (alignmentPattern == 0) {\n      // Try anyway\n    }\n\n  }\n\n  Ref<PerspectiveTransform> transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension);\n  Ref<BitMatrix> bits(sampleGrid(image_, dimension, transform));\n  std::vector<Ref<ResultPoint> > points(alignmentPattern == 0 ? 3 : 4);\n  points[0].reset(bottomLeft);\n  points[1].reset(topLeft);\n  points[2].reset(topRight);\n  if (alignmentPattern != 0) {\n    points[3].reset(alignmentPattern);\n  }\n\n  Ref<DetectorResult> result(new DetectorResult(bits, points, transform));\n  return result;\n}\n\nRef<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <\n    ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension) {\n\n  float dimMinusThree = (float)dimension - 3.5f;\n  float bottomRightX;\n  float bottomRightY;\n  float sourceBottomRightX;\n  float sourceBottomRightY;\n  if (alignmentPattern != 0) {\n    bottomRightX = alignmentPattern->getX();\n    bottomRightY = alignmentPattern->getY();\n    sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f;\n  } else {\n    // Don't have an alignment pattern, just make up the bottom-right point\n    bottomRightX = (topRight->getX() - topLeft->getX()) + bottomLeft->getX();\n    bottomRightY = (topRight->getY() - topLeft->getY()) + bottomLeft->getY();\n    sourceBottomRightX = sourceBottomRightY = dimMinusThree;\n  }\n\n  Ref<PerspectiveTransform> transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX,\n                                      sourceBottomRightY, 3.5f, dimMinusThree, topLeft->getX(), topLeft->getY(), topRight->getX(),\n                                      topRight->getY(), bottomRightX, bottomRightY, bottomLeft->getX(), bottomLeft->getY()));\n\n  return transform;\n}\n\nRef<BitMatrix> Detector::sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform) {\n  GridSampler &sampler = GridSampler::getInstance();\n  return sampler.sampleGrid(image, dimension, transform);\n}\n\nint Detector::computeDimension(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft,\n                               float moduleSize) {\n  int tltrCentersDimension = int(FinderPatternFinder::distance(topLeft, topRight) / moduleSize + 0.5f);\n  int tlblCentersDimension = int(FinderPatternFinder::distance(topLeft, bottomLeft) / moduleSize + 0.5f);\n  int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7;\n  switch (dimension & 0x03) { // mod 4\n  case 0:\n    dimension++;\n    break;\n    // 1? do nothing\n  case 2:\n    dimension--;\n    break;\n  case 3:\n    ostringstream s;\n    s << \"Bad dimension: \" << dimension;\n    throw zxing::ReaderException(s.str().c_str());\n  }\n  return dimension;\n}\n\nfloat Detector::calculateModuleSize(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft) {\n  // Take the average\n  return (calculateModuleSizeOneWay(topLeft, topRight) + calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f;\n}\n\nfloat Detector::calculateModuleSizeOneWay(Ref<ResultPoint> pattern, Ref<ResultPoint> otherPattern) {\n  float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int)pattern->getX(), (int)pattern->getY(),\n                         (int)otherPattern->getX(), (int)otherPattern->getY());\n  float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int)otherPattern->getX(), (int)otherPattern->getY(),\n                         (int)pattern->getX(), (int)pattern->getY());\n  if (isnan(moduleSizeEst1)) {\n    return moduleSizeEst2;\n  }\n  if (isnan(moduleSizeEst2)) {\n    return moduleSizeEst1;\n  }\n  // Average them, and divide by 7 since we've counted the width of 3 black modules,\n  // and 1 white and 1 black module on either side. Ergo, divide sum by 14.\n  return (moduleSizeEst1 + moduleSizeEst2) / 14.0f;\n}\n\nfloat Detector::sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY) {\n\n    float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);\n\n    // Now count other way -- don't run off image though of course\n    float scale = 1.0f;\n    int otherToX = fromX - (toX - fromX);\n    if (otherToX < 0) {\n      scale = (float) fromX / (float) (fromX - otherToX);\n      otherToX = 0;\n    } else if (otherToX >= (int)image_->getWidth()) {\n      scale = (float) (image_->getWidth() - 1 - fromX) / (float) (otherToX - fromX);\n      otherToX = image_->getWidth() - 1;\n    }\n    int otherToY = (int) (fromY - (toY - fromY) * scale);\n\n    scale = 1.0f;\n    if (otherToY < 0) {\n      scale = (float) fromY / (float) (fromY - otherToY);\n      otherToY = 0;\n    } else if (otherToY >= (int)image_->getHeight()) {\n      scale = (float) (image_->getHeight() - 1 - fromY) / (float) (otherToY - fromY);\n      otherToY = image_->getHeight() - 1;\n    }\n    otherToX = (int) (fromX + (otherToX - fromX) * scale);\n\n    result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY);\n\n    // Middle pixel is double-counted this way; subtract 1\n    return result - 1.0f;\n}\n\nfloat Detector::sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY) {\n    // Mild variant of Bresenham's algorithm;\n    // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm\n    bool steep = abs(toY - fromY) > abs(toX - fromX);\n    if (steep) {\n      int temp = fromX;\n      fromX = fromY;\n      fromY = temp;\n      temp = toX;\n      toX = toY;\n      toY = temp;\n    }\n\n    int dx = abs(toX - fromX);\n    int dy = abs(toY - fromY);\n    int error = -dx >> 1;\n    int xstep = fromX < toX ? 1 : -1;\n    int ystep = fromY < toY ? 1 : -1;\n\n    // In black pixels, looking for white, first or second time.\n    int state = 0;\n    // Loop up until x == toX, but not beyond\n    int xLimit = toX + xstep;\n    for (int x = fromX, y = fromY; x != xLimit; x += xstep) {\n      int realX = steep ? y : x;\n      int realY = steep ? x : y;\n\n      // Does current pixel mean we have moved white to black or vice versa?\n      if (!((state == 1) ^ image_->get(realX, realY))) {\n        if (state == 2) {\n          int diffX = x - fromX;\n          int diffY = y - fromY;\n          return (float) sqrt((double) (diffX * diffX + diffY * diffY));\n        }\n        state++;\n      }\n\n      error += dy;\n      if (error > 0) {\n        if (y == toY) {\n          break;\n        }\n        y += ystep;\n        error -= dx;\n      }\n    }\n    // Found black-white-black; give the benefit of the doubt that the next pixel outside the image\n    // is \"white\" so this last point at (toX+xStep,toY) is the right ending. This is really a\n    // small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this.\n    if (state == 2) {\n      int diffX = toX + xstep - fromX;\n      int diffY = toY - fromY;\n      return (float) sqrt((double) (diffX * diffX + diffY * diffY));\n    }\n    // else we didn't find even black-white-black; no estimate is really possible\n    return NAN;\n}\n\nRef<AlignmentPattern> Detector::findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY,\n    float allowanceFactor) {\n  // Look for an alignment pattern (3 modules in size) around where it\n  // should be\n  int allowance = (int)(allowanceFactor * overallEstModuleSize);\n  int alignmentAreaLeftX = max(0, estAlignmentX - allowance);\n  int alignmentAreaRightX = min((int)(image_->getWidth() - 1), estAlignmentX + allowance);\n  if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) {\n      throw zxing::ReaderException(\"region too small to hold alignment pattern\");\n  }\n  int alignmentAreaTopY = max(0, estAlignmentY - allowance);\n  int alignmentAreaBottomY = min((int)(image_->getHeight() - 1), estAlignmentY + allowance);\n  if (alignmentAreaBottomY - alignmentAreaTopY < overallEstModuleSize * 3) {\n      throw zxing::ReaderException(\"region too small to hold alignment pattern\");\n  }\n\n  AlignmentPatternFinder alignmentFinder(image_, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX\n                                         - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, callback_);\n  return alignmentFinder.find();\n}\n\n}\n}\n\n// file: zxing/qrcode/detector/FinderPattern.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  FinderPattern.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 13/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/detector/FinderPattern.h>\n\nnamespace zxing {\n\tnamespace qrcode {\n\n\t\tusing namespace std;\n\n\t\tFinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize) :\n\t\tResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(1) {\n\t\t}\n\n\t\tFinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize, int count) :\n\t\tResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(count) {\n\t\t}\n\n\t\tint FinderPattern::getCount() const {\n\t\t\treturn count_;\n\t\t}\n\n\t\tfloat FinderPattern::getEstimatedModuleSize() const {\n\t\t\treturn estimatedModuleSize_;\n\t\t}\n\n\t\tvoid FinderPattern::incrementCount() {\n\t\t\tcount_++;\n\t\t}\n\n/*\n\t\tbool FinderPattern::aboutEquals(float moduleSize, float i, float j) const {\n\t\t\treturn abs(i - posY_) <= moduleSize && abs(j - posX_) <= moduleSize && (abs(moduleSize - estimatedModuleSize_)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<= 1.0f || abs(moduleSize - estimatedModuleSize_) / estimatedModuleSize_ <= 0.1f);\n\t\t}\n*/\n    bool FinderPattern::aboutEquals(float moduleSize, float i, float j) const {\n      if (abs(i - getY()) <= moduleSize && abs(j - getX()) <= moduleSize) {\n        float moduleSizeDiff = abs(moduleSize - estimatedModuleSize_);\n        return moduleSizeDiff <= 1.0f || moduleSizeDiff <= estimatedModuleSize_;\n      }\n      return false;\n    }\n\n    Ref<FinderPattern> FinderPattern::combineEstimate(float i, float j, float newModuleSize) const {\n      int combinedCount = count_ + 1;\n      float combinedX = (count_ * getX() + j) / combinedCount;\n      float combinedY = (count_ * getY() + i) / combinedCount;\n      float combinedModuleSize = (count_ * getEstimatedModuleSize() + newModuleSize) / combinedCount;\n      return Ref<FinderPattern>(new FinderPattern(combinedX, combinedY, combinedModuleSize, combinedCount));\n    }\n\t}\n}\n\n// file: zxing/qrcode/detector/FinderPatternFinder.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  FinderPatternFinder.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 13/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/detector/FinderPatternFinder.h>\n// #include <zxing/ReaderException.h>\n// #include <zxing/DecodeHints.h>\n// #include <vector>\n// #include <cmath>\n// #include <cstdlib>\n// #include <algorithm>\n\nnamespace zxing {\nnamespace qrcode {\n\nusing namespace std;\n\nclass FurthestFromAverageComparator {\nprivate:\n  const float averageModuleSize_;\npublic:\n  FurthestFromAverageComparator(float averageModuleSize) :\n    averageModuleSize_(averageModuleSize) {\n  }\n  bool operator()(Ref<FinderPattern> a, Ref<FinderPattern> b) {\n    float dA = abs(a->getEstimatedModuleSize() - averageModuleSize_);\n    float dB = abs(b->getEstimatedModuleSize() - averageModuleSize_);\n    return dA > dB;\n  }\n};\n\nclass CenterComparator {\n  const float averageModuleSize_;\npublic:\n  CenterComparator(float averageModuleSize) :\n    averageModuleSize_(averageModuleSize) {\n  }\n  bool operator()(Ref<FinderPattern> a, Ref<FinderPattern> b) {\n    // N.B.: we want the result in descending order ...\n    if (a->getCount() != b->getCount()) {\n      return a->getCount() > b->getCount();\n    } else {\n      float dA = abs(a->getEstimatedModuleSize() - averageModuleSize_);\n      float dB = abs(b->getEstimatedModuleSize() - averageModuleSize_);\n      return dA < dB;\n    }\n  }\n};\n\nint FinderPatternFinder::CENTER_QUORUM = 2;\nint FinderPatternFinder::MIN_SKIP = 3;\nint FinderPatternFinder::MAX_MODULES = 57;\n\nfloat FinderPatternFinder::centerFromEnd(int* stateCount, int end) {\n  return (float)(end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0f;\n}\n\nbool FinderPatternFinder::foundPatternCross(int* stateCount) {\n  int totalModuleSize = 0;\n  for (int i = 0; i < 5; i++) {\n    if (stateCount[i] == 0) {\n      return false;\n    }\n    totalModuleSize += stateCount[i];\n  }\n  if (totalModuleSize < 7) {\n    return false;\n  }\n  float moduleSize = (float)totalModuleSize / 7.0f;\n  float maxVariance = moduleSize / 2.0f;\n  // Allow less than 50% variance from 1-1-3-1-1 proportions\n  return abs(moduleSize - stateCount[0]) < maxVariance && abs(moduleSize - stateCount[1]) < maxVariance && abs(3.0f\n         * moduleSize - stateCount[2]) < 3.0f * maxVariance && abs(moduleSize - stateCount[3]) < maxVariance && abs(\n           moduleSize - stateCount[4]) < maxVariance;\n}\n\nfloat FinderPatternFinder::crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal) {\n\n  int maxI = image_->getHeight();\n  int stateCount[5];\n  for (int i = 0; i < 5; i++)\n    stateCount[i] = 0;\n\n\n  // Start counting up from center\n  int i = startI;\n  while (i >= 0 && image_->get(centerJ, i)) {\n    stateCount[2]++;\n    i--;\n  }\n  if (i < 0) {\n    return NAN;\n  }\n  while (i >= 0 && !image_->get(centerJ, i) && stateCount[1] <= maxCount) {\n    stateCount[1]++;\n    i--;\n  }\n  // If already too many modules in this state or ran off the edge:\n  if (i < 0 || stateCount[1] > maxCount) {\n    return NAN;\n  }\n  while (i >= 0 && image_->get(centerJ, i) && stateCount[0] <= maxCount) {\n    stateCount[0]++;\n    i--;\n  }\n  if (stateCount[0] > maxCount) {\n    return NAN;\n  }\n\n  // Now also count down from center\n  i = startI + 1;\n  while (i < maxI && image_->get(centerJ, i)) {\n    stateCount[2]++;\n    i++;\n  }\n  if (i == maxI) {\n    return NAN;\n  }\n  while (i < maxI && !image_->get(centerJ, i) && stateCount[3] < maxCount) {\n    stateCount[3]++;\n    i++;\n  }\n  if (i == maxI || stateCount[3] >= maxCount) {\n    return NAN;\n  }\n  while (i < maxI && image_->get(centerJ, i) && stateCount[4] < maxCount) {\n    stateCount[4]++;\n    i++;\n  }\n  if (stateCount[4] >= maxCount) {\n    return NAN;\n  }\n\n  // If we found a finder-pattern-like section, but its size is more than 40% different than\n  // the original, assume it's a false positive\n  int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];\n  if (5 * abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) {\n    return NAN;\n  }\n\n  return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : NAN;\n}\n\nfloat FinderPatternFinder::crossCheckHorizontal(size_t startJ, size_t centerI, int maxCount,\n    int originalStateCountTotal) {\n\n  int maxJ = image_->getWidth();\n  int stateCount[5];\n  for (int i = 0; i < 5; i++)\n    stateCount[i] = 0;\n\n  int j = startJ;\n  while (j >= 0 && image_->get(j, centerI)) {\n    stateCount[2]++;\n    j--;\n  }\n  if (j < 0) {\n    return NAN;\n  }\n  while (j >= 0 && !image_->get(j, centerI) && stateCount[1] <= maxCount) {\n    stateCount[1]++;\n    j--;\n  }\n  if (j < 0 || stateCount[1] > maxCount) {\n    return NAN;\n  }\n  while (j >= 0 && image_->get(j, centerI) && stateCount[0] <= maxCount) {\n    stateCount[0]++;\n    j--;\n  }\n  if (stateCount[0] > maxCount) {\n    return NAN;\n  }\n\n  j = startJ + 1;\n  while (j < maxJ && image_->get(j, centerI)) {\n    stateCount[2]++;\n    j++;\n  }\n  if (j == maxJ) {\n    return NAN;\n  }\n  while (j < maxJ && !image_->get(j, centerI) && stateCount[3] < maxCount) {\n    stateCount[3]++;\n    j++;\n  }\n  if (j == maxJ || stateCount[3] >= maxCount) {\n    return NAN;\n  }\n  while (j < maxJ && image_->get(j, centerI) && stateCount[4] < maxCount) {\n    stateCount[4]++;\n    j++;\n  }\n  if (stateCount[4] >= maxCount) {\n    return NAN;\n  }\n\n  // If we found a finder-pattern-like section, but its size is significantly different than\n  // the original, assume it's a false positive\n  int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];\n  if (5 * abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) {\n    return NAN;\n  }\n\n  return foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : NAN;\n}\n\nbool FinderPatternFinder::handlePossibleCenter(int* stateCount, size_t i, size_t j) {\n  int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];\n  float centerJ = centerFromEnd(stateCount, j);\n  float centerI = crossCheckVertical(i, (size_t)centerJ, stateCount[2], stateCountTotal);\n  if (!isnan(centerI)) {\n    // Re-cross check\n    centerJ = crossCheckHorizontal((size_t)centerJ, (size_t)centerI, stateCount[2], stateCountTotal);\n    if (!isnan(centerJ)) {\n      float estimatedModuleSize = (float)stateCountTotal / 7.0f;\n      bool found = false;\n      size_t max = possibleCenters_.size();\n      for (size_t index = 0; index < max; index++) {\n        Ref<FinderPattern> center = possibleCenters_[index];\n        // Look for about the same center and module size:\n        if (center->aboutEquals(estimatedModuleSize, centerI, centerJ)) {\n          possibleCenters_[index] = center->combineEstimate(centerI, centerJ, estimatedModuleSize);\n          found = true;\n          break;\n        }\n      }\n      if (!found) {\n        Ref<FinderPattern> newPattern(new FinderPattern(centerJ, centerI, estimatedModuleSize));\n        possibleCenters_.push_back(newPattern);\n        if (callback_ != 0) {\n          callback_->foundPossibleResultPoint(*newPattern);\n        }\n      }\n      return true;\n    }\n  }\n  return false;\n}\n\nint FinderPatternFinder::findRowSkip() {\n  size_t max = possibleCenters_.size();\n  if (max <= 1) {\n    return 0;\n  }\n  Ref<FinderPattern> firstConfirmedCenter;\n  for (size_t i = 0; i < max; i++) {\n    Ref<FinderPattern> center = possibleCenters_[i];\n    if (center->getCount() >= CENTER_QUORUM) {\n      if (firstConfirmedCenter == 0) {\n        firstConfirmedCenter = center;\n      } else {\n        // We have two confirmed centers\n        // How far down can we skip before resuming looking for the next\n        // pattern? In the worst case, only the difference between the\n        // difference in the x / y coordinates of the two centers.\n        // This is the case where you find top left first. Draw it out.\n        hasSkipped_ = true;\n        return (int)(abs(firstConfirmedCenter->getX() - center->getX()) - abs(firstConfirmedCenter->getY()\n                     - center->getY()))/2;\n      }\n    }\n  }\n  return 0;\n}\n\nbool FinderPatternFinder::haveMultiplyConfirmedCenters() {\n  int confirmedCount = 0;\n  float totalModuleSize = 0.0f;\n  size_t max = possibleCenters_.size();\n  for (size_t i = 0; i < max; i++) {\n    Ref<FinderPattern> pattern = possibleCenters_[i];\n    if (pattern->getCount() >= CENTER_QUORUM) {\n      confirmedCount++;\n      totalModuleSize += pattern->getEstimatedModuleSize();\n    }\n  }\n  if (confirmedCount < 3) {\n    return false;\n  }\n  // OK, we have at least 3 confirmed centers, but, it's possible that one is a \"false positive\"\n  // and that we need to keep looking. We detect this by asking if the estimated module sizes\n  // vary too much. We arbitrarily say that when the total deviation from average exceeds\n  // 5% of the total module size estimates, it's too much.\n  float average = totalModuleSize / max;\n  float totalDeviation = 0.0f;\n  for (size_t i = 0; i < max; i++) {\n    Ref<FinderPattern> pattern = possibleCenters_[i];\n    totalDeviation += abs(pattern->getEstimatedModuleSize() - average);\n  }\n  return totalDeviation <= 0.05f * totalModuleSize;\n}\n\nvector<Ref<FinderPattern> > FinderPatternFinder::selectBestPatterns() {\n  size_t startSize = possibleCenters_.size();\n\n  if (startSize < 3) {\n    // Couldn't find enough finder patterns\n    throw zxing::ReaderException(\"Could not find three finder patterns\");\n  }\n\n  // Filter outlier possibilities whose module size is too different\n  if (startSize > 3) {\n    // But we can only afford to do so if we have at least 4 possibilities to choose from\n    float totalModuleSize = 0.0f;\n    float square = 0.0f;\n    for (size_t i = 0; i < startSize; i++) {\n      float size = possibleCenters_[i]->getEstimatedModuleSize();\n      totalModuleSize += size;\n      square += size * size;\n    }\n    float average = totalModuleSize / (float) startSize;\n    float stdDev = (float)sqrt(square / startSize - average * average);\n\n    sort(possibleCenters_.begin(), possibleCenters_.end(), FurthestFromAverageComparator(average));\n\n    float limit = max(0.2f * average, stdDev);\n\n    for (size_t i = 0; i < possibleCenters_.size() && possibleCenters_.size() > 3; i++) {\n      if (abs(possibleCenters_[i]->getEstimatedModuleSize() - average) > limit) {\n        possibleCenters_.erase(possibleCenters_.begin()+i);\n        i--;\n      }\n    }\n  }\n\n  if (possibleCenters_.size() > 3) {\n    // Throw away all but those first size candidate points we found.\n    float totalModuleSize = 0.0f;\n    for (size_t i = 0; i < possibleCenters_.size(); i++) {\n      float size = possibleCenters_[i]->getEstimatedModuleSize();\n      totalModuleSize += size;\n    }\n    float average = totalModuleSize / (float) possibleCenters_.size();\n    sort(possibleCenters_.begin(), possibleCenters_.end(), CenterComparator(average));\n  }\n\n  if (possibleCenters_.size() > 3) {\n    possibleCenters_.erase(possibleCenters_.begin()+3,possibleCenters_.end());\n  }\n\n  vector<Ref<FinderPattern> > result(3);\n  result[0] = possibleCenters_[0];\n  result[1] = possibleCenters_[1];\n  result[2] = possibleCenters_[2];\n  return result;\n}\n\nvector<Ref<FinderPattern> > FinderPatternFinder::orderBestPatterns(vector<Ref<FinderPattern> > patterns) {\n  // Find distances between pattern centers\n  float abDistance = distance(patterns[0], patterns[1]);\n  float bcDistance = distance(patterns[1], patterns[2]);\n  float acDistance = distance(patterns[0], patterns[2]);\n\n  Ref<FinderPattern> topLeft;\n  Ref<FinderPattern> topRight;\n  Ref<FinderPattern> bottomLeft;\n  // Assume one closest to other two is top left;\n  // topRight and bottomLeft will just be guesses below at first\n  if (bcDistance >= abDistance && bcDistance >= acDistance) {\n    topLeft = patterns[0];\n    topRight = patterns[1];\n    bottomLeft = patterns[2];\n  } else if (acDistance >= bcDistance && acDistance >= abDistance) {\n    topLeft = patterns[1];\n    topRight = patterns[0];\n    bottomLeft = patterns[2];\n  } else {\n    topLeft = patterns[2];\n    topRight = patterns[0];\n    bottomLeft = patterns[1];\n  }\n\n  // Use cross product to figure out which of other1/2 is the bottom left\n  // pattern. The vector \"top-left -> bottom-left\" x \"top-left -> top-right\"\n  // should yield a vector with positive z component\n  if ((bottomLeft->getY() - topLeft->getY()) * (topRight->getX() - topLeft->getX()) < (bottomLeft->getX()\n      - topLeft->getX()) * (topRight->getY() - topLeft->getY())) {\n    Ref<FinderPattern> temp = topRight;\n    topRight = bottomLeft;\n    bottomLeft = temp;\n  }\n\n  vector<Ref<FinderPattern> > results(3);\n  results[0] = bottomLeft;\n  results[1] = topLeft;\n  results[2] = topRight;\n  return results;\n}\n\nfloat FinderPatternFinder::distance(Ref<ResultPoint> p1, Ref<ResultPoint> p2) {\n  float dx = p1->getX() - p2->getX();\n  float dy = p1->getY() - p2->getY();\n  return (float)sqrt(dx * dx + dy * dy);\n}\n\nFinderPatternFinder::FinderPatternFinder(Ref<BitMatrix> image,\n                                           Ref<ResultPointCallback>const& callback) :\n    image_(image), possibleCenters_(), hasSkipped_(false), callback_(callback) {\n}\n\nRef<FinderPatternInfo> FinderPatternFinder::find(DecodeHints const& hints) {\n  bool tryHarder = hints.getTryHarder();\n\n  size_t maxI = image_->getHeight();\n  size_t maxJ = image_->getWidth();\n\n\n  // We are looking for black/white/black/white/black modules in\n  // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far\n\n  // As this is used often, we use an integer array instead of vector\n  int stateCount[5];\n  bool done = false;\n\n\n  // Let's assume that the maximum version QR Code we support takes up 1/4\n  // the height of the image, and then account for the center being 3\n  // modules in size. This gives the smallest number of pixels the center\n  // could be, so skip this often. When trying harder, look for all\n  // QR versions regardless of how dense they are.\n  int iSkip = (3 * maxI) / (4 * MAX_MODULES);\n  if (iSkip < MIN_SKIP || tryHarder) {\n      iSkip = MIN_SKIP;\n  }\n\n  // This is slightly faster than using the Ref. Efficiency is important here\n  BitMatrix& matrix = *image_;\n\n  for (size_t i = iSkip - 1; i < maxI && !done; i += iSkip) {\n    // Get a row of black/white values\n\n    stateCount[0] = 0;\n    stateCount[1] = 0;\n    stateCount[2] = 0;\n    stateCount[3] = 0;\n    stateCount[4] = 0;\n    int currentState = 0;\n    for (size_t j = 0; j < maxJ; j++) {\n      if (matrix.get(j, i)) {\n        // Black pixel\n        if ((currentState & 1) == 1) { // Counting white pixels\n          currentState++;\n        }\n        stateCount[currentState]++;\n      } else { // White pixel\n        if ((currentState & 1) == 0) { // Counting black pixels\n          if (currentState == 4) { // A winner?\n            if (foundPatternCross(stateCount)) { // Yes\n              bool confirmed = handlePossibleCenter(stateCount, i, j);\n              if (confirmed) {\n                // Start examining every other line. Checking each line turned out to be too\n                // expensive and didn't improve performance.\n                iSkip = 2;\n                if (hasSkipped_) {\n                  done = haveMultiplyConfirmedCenters();\n                } else {\n                  int rowSkip = findRowSkip();\n                  if (rowSkip > stateCount[2]) {\n                    // Skip rows between row of lower confirmed center\n                    // and top of presumed third confirmed center\n                    // but back up a bit to get a full chance of detecting\n                    // it, entire width of center of finder pattern\n\n                    // Skip by rowSkip, but back off by stateCount[2] (size\n                    // of last center of pattern we saw) to be conservative,\n                    // and also back off by iSkip which is about to be\n                    // re-added\n                    i += rowSkip - stateCount[2] - iSkip;\n                    j = maxJ - 1;\n                  }\n                }\n              } else {\n                stateCount[0] = stateCount[2];\n                stateCount[1] = stateCount[3];\n                stateCount[2] = stateCount[4];\n                stateCount[3] = 1;\n                stateCount[4] = 0;\n                currentState = 3;\n                continue;\n              }\n              // Clear state to start looking again\n              currentState = 0;\n              stateCount[0] = 0;\n              stateCount[1] = 0;\n              stateCount[2] = 0;\n              stateCount[3] = 0;\n              stateCount[4] = 0;\n            } else { // No, shift counts back by two\n              stateCount[0] = stateCount[2];\n              stateCount[1] = stateCount[3];\n              stateCount[2] = stateCount[4];\n              stateCount[3] = 1;\n              stateCount[4] = 0;\n              currentState = 3;\n            }\n          } else {\n            stateCount[++currentState]++;\n          }\n        } else { // Counting white pixels\n          stateCount[currentState]++;\n        }\n      }\n    }\n    if (foundPatternCross(stateCount)) {\n      bool confirmed = handlePossibleCenter(stateCount, i, maxJ);\n      if (confirmed) {\n        iSkip = stateCount[0];\n        if (hasSkipped_) {\n          // Found a third one\n          done = haveMultiplyConfirmedCenters();\n        }\n      }\n    }\n  }\n\n  vector<Ref<FinderPattern> > patternInfo = selectBestPatterns();\n  patternInfo = orderBestPatterns(patternInfo);\n\n  Ref<FinderPatternInfo> result(new FinderPatternInfo(patternInfo));\n  return result;\n}\n}\n}\n\n// file: zxing/qrcode/detector/FinderPatternInfo.cpp\n\n/*\n *  FinderPatternInfo.cpp\n *  zxing\n *\n *  Created by Christian Brunschen on 13/05/2008.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/detector/FinderPatternInfo.h>\n\nnamespace zxing {\nnamespace qrcode {\n\nFinderPatternInfo::FinderPatternInfo(std::vector<Ref<FinderPattern> > patternCenters) :\n    bottomLeft_(patternCenters[0]), topLeft_(patternCenters[1]), topRight_(patternCenters[2]) {\n}\n\nRef<FinderPattern> FinderPatternInfo::getBottomLeft() {\n  return bottomLeft_;\n}\nRef<FinderPattern> FinderPatternInfo::getTopLeft() {\n  return topLeft_;\n}\nRef<FinderPattern> FinderPatternInfo::getTopRight() {\n  return topRight_;\n}\n\n}\n}\n\n// file: zxing/qrcode/detector/QREdgeDetector.cpp\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n/*\n *  Created by Ralf Kistner on 7/12/2009.\n *  Copyright 2008 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/detector/QREdgeDetector.h>\n// #include <zxing/common/EdgeDetector.h>\n// #include <cstdlib>\n\nusing namespace std;\n\nnamespace zxing {\nnamespace qrcode {\n\nstatic const float patternEdgeThreshold = 2;\nstatic const int patternEdgeWidth = 3;\nstatic const float patternEdgeSearchRatio = 1.1;\nstatic const int patternEdgeSkip = 2;\n\nstatic const float accurateEdgeThreshold = 3.3;\nstatic const int accurateEdgeWidth = 7;\nstatic const int accurateEdgeSkip = 2;\n\nstatic Point guessLastPattern(Point topLeft, Point topRight, Point bottomLeft) {\n  return Point(topRight.x - topLeft.x + bottomLeft.x, topRight.y - topLeft.y + bottomLeft.y);\n}\n\nstatic Point rp(Ref<ResultPoint> rp) {\n  return Point(rp->getX(), rp->getY());\n}\n\nQREdgeDetector::QREdgeDetector(Ref<BitMatrix> image) : Detector(image) { }\n\nRef<PerspectiveTransform> QREdgeDetector::createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <\n      ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension) {\n\n  if(alignmentPattern == NULL) {\n    Point corner = findCorner(*Detector::getImage(), rp(topLeft), rp(topRight), rp(bottomLeft), dimension);\n    return get1CornerTransform(rp(topLeft), rp(topRight), rp(bottomLeft), corner, dimension);\n  } else {\n    return Detector::createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension);\n  }\n}\n\n\n\n\nPoint QREdgeDetector::findCorner(const BitMatrix& image, Point topLeft, Point topRight, Point bottomLeft, int dimension) {\n  (void)dimension;\n  Point bottomRight = guessLastPattern(topLeft, topRight, bottomLeft);\n\n  Line bottomEst = findPatternEdge(image, bottomLeft, topLeft, bottomRight, false);\n  Line rightEst = findPatternEdge(image, topRight, topLeft, bottomRight, true);\n\n  //return EdgeDetector::intersection(bottomEst, rightEst);\n\n  Line bottom = EdgeDetector::findLine(image, bottomEst, false, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip);\n  Line right = EdgeDetector::findLine(image, rightEst, true, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip);\n\n\n  return EdgeDetector::intersection(bottom, right);\n}\n\nLine QREdgeDetector::findPatternEdge(const BitMatrix& image, Point pattern, Point opposite, Point direction, bool invert) {\n  Point start = endOfReverseBlackWhiteBlackRun(image, pattern, opposite);\n\n  float dx = pattern.x - start.x;\n  float dy = pattern.y - start.y;\n  float dist = sqrt(dx*dx + dy*dy);\n\n  float dirX = direction.x - pattern.x;\n  float dirY = direction.y - pattern.y;\n  float dirSize = sqrt(dirX*dirX + dirY*dirY);\n\n  float nx = dirX/dirSize;\n  float ny = dirY/dirSize;\n\n  float search = dist * patternEdgeSearchRatio;\n  Point a(start.x + nx*search, start.y + ny*search);\n  Point b(start.x - nx*search, start.y - ny*search);\n\n  return EdgeDetector::findLine(image, Line(a, b), invert, patternEdgeWidth, patternEdgeThreshold, patternEdgeSkip);\n}\n\n\nRef<PerspectiveTransform> QREdgeDetector::get1CornerTransform(Point topLeft, Point topRight, Point bottomLeft, Point corner, int dimension) {\n  float dimMinusThree = (float) dimension - 3.5f;\n\n  Ref<PerspectiveTransform> transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, dimension,\n                                      dimension, 3.5f, dimMinusThree, topLeft.x, topLeft.y, topRight.x,\n                                      topRight.y, corner.x, corner.y, bottomLeft.x, bottomLeft.y));\n\n  return transform;\n}\n\n// Adapted from \"sizeOfBlackWhiteBlackRun\" in zxing::qrcode::Detector\nPoint QREdgeDetector::endOfReverseBlackWhiteBlackRun(const BitMatrix& image, Point from, Point to) {\n  int fromX = (int)from.x;\n  int fromY = (int)from.y;\n  int toX = (int)to.x;\n  int toY = (int)to.y;\n\n  bool steep = abs(toY - fromY) > abs(toX - fromX);\n  if (steep) {\n    int temp = fromX;\n    fromX = fromY;\n    fromY = temp;\n    temp = toX;\n    toX = toY;\n    toY = temp;\n  }\n\n  int dx = abs(toX - fromX);\n  int dy = abs(toY - fromY);\n  int error = -dx >> 1;\n  int ystep = fromY < toY ? -1 : 1;\n  int xstep = fromX < toX ? -1 : 1;\n  int state = 0; // In black pixels, looking for white, first or second time\n\n  // In case there are no points, prepopulate to from\n  int realX = fromX;\n  int realY = fromY;\n  for (int x = fromX, y = fromY; x != toX; x += xstep) {\n    realX = steep ? y : x;\n    realY = steep ? x : y;\n\n    if(realX < 0 || realY < 0 || realX >= (int)image.getWidth() || realY >= (int)image.getHeight())\n      break;\n\n    if (state == 1) { // In white pixels, looking for black\n      if (image.get(realX, realY)) {\n        state++;\n      }\n    } else {\n      if (!image.get(realX, realY)) {\n        state++;\n      }\n    }\n\n    if (state == 3) { // Found black, white, black, and stumbled back onto white; done\n      return Point(realX, realY);\n    }\n    error += dy;\n    if (error > 0) {\n      y += ystep;\n      error -= dx;\n    }\n  }\n\n  // B-W-B run not found, return the last point visited.\n  return Point(realX, realY);\n}\n\n} // namespace qrcode\n} // namespace zxing\n\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/ios/zxing-all-in-one.h",
    "content": "#include <map>\n#include <exception>\n#include <algorithm>\n#include <typeinfo>\n#include <string>\n#include <limits>\n#include <limits.h>\n#include <sstream>\n#include <cstdarg>\n#include <math.h>\n#include <vector>\n#include <cmath>\n#include <string.h>\n#include <memory>\n#include <cstdlib>\n#include <iostream>\n#include <stdlib.h>\n#include <iconv.h>\n\n// file: zxing/Exception.h\n\n#ifndef __EXCEPTION_H__\n// #define __EXCEPTION_H__\n\n/*\n *  Exception.h\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <string>\n// #include <exception>\n\nnamespace zxing {\n\nclass Exception : public std::exception {\nprivate:\n  std::string message;\n\npublic:\n  Exception();\n  Exception(const char *msg);\n  virtual const char* what() const throw();\n  virtual ~Exception() throw();\n};\n\n}\n#endif // __EXCEPTION_H__\n\n// file: zxing/common/IllegalArgumentException.h\n\n#ifndef __ILLEGAL_ARGUMENT_EXCEPTION_H__\n// #define __ILLEGAL_ARGUMENT_EXCEPTION_H__\n\n/*\n *  IllegalArgumentException.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/Exception.h>\n\nnamespace zxing {\nclass IllegalArgumentException : public zxing::Exception {\npublic:\n  IllegalArgumentException(const char *msg);\n  ~IllegalArgumentException() throw();\n};\n}\n\n#endif // __ILLEGAL_ARGUMENT_EXCEPTION_H__\n\n// file: zxing/common/Counted.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __COUNTED_H__\n// #define __COUNTED_H__\n\n/*\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n//#define DEBUG_COUNTING\n\n// #include <iostream>\n\n#ifdef DEBUG_COUNTING\n// #include <typeinfo>\n#endif\n\nnamespace zxing {\n\n/* base class for reference-counted objects */\nclass Counted {\nprivate:\n  unsigned int count_;\npublic:\n  Counted() :\n      count_(0) {\n#ifdef DEBUG_COUNTING\n    cout << \"instantiating \" << typeid(*this).name() << \" \" << this <<\n         \" @ \" << count_ << \"\\n\";\n#endif\n  }\n  virtual ~Counted() {\n  }\n  Counted *retain() {\n#ifdef DEBUG_COUNTING\n    cout << \"retaining \" << typeid(*this).name() << \" \" << this <<\n         \" @ \" << count_;\n#endif\n    count_++;\n#ifdef DEBUG_COUNTING\n    cout << \"->\" << count_ << \"\\n\";\n#endif\n    return this;\n  }\n  void release() {\n#ifdef DEBUG_COUNTING\n    cout << \"releasing \" << typeid(*this).name() << \" \" << this <<\n         \" @ \" << count_;\n#endif\n    if (count_ == 0 || count_ == 54321) {\n#ifdef DEBUG_COUNTING\n      cout << \"\\nOverreleasing already-deleted object \" << this << \"!!!\\n\";\n#endif\n      throw 4711;\n    }\n    count_--;\n#ifdef DEBUG_COUNTING\n    cout << \"->\" << count_ << \"\\n\";\n#endif\n    if (count_ == 0) {\n#ifdef DEBUG_COUNTING\n      cout << \"deleting \" << typeid(*this).name() << \" \" << this << \"\\n\";\n#endif\n      count_ = 0xDEADF001;\n      delete this;\n    }\n  }\n\n\n  /* return the current count for denugging purposes or similar */\n  int count() const {\n    return count_;\n  }\n};\n\n/* counting reference to reference-counted objects */\ntemplate<typename T> class Ref {\nprivate:\npublic:\n  T *object_;\n  explicit Ref(T *o = 0) :\n      object_(0) {\n#ifdef DEBUG_COUNTING\n    cout << \"instantiating Ref \" << this << \" from pointer\" << o << \"\\n\";\n#endif\n    reset(o);\n  }\n\n  explicit Ref(const T &o) :\n      object_(0) {\n#ifdef DEBUG_COUNTING\n    cout << \"instantiating Ref \" << this << \" from reference\\n\";\n#endif\n    reset(const_cast<T *>(&o));\n  }\n\n  Ref(const Ref &other) :\n      object_(0) {\n#ifdef DEBUG_COUNTING\n    cout << \"instantiating Ref \" << this << \" from Ref \" << &other << \"\\n\";\n#endif\n    reset(other.object_);\n  }\n\n  template<class Y>\n  Ref(const Ref<Y> &other) :\n      object_(0) {\n#ifdef DEBUG_COUNTING\n    cout << \"instantiating Ref \" << this << \" from reference\\n\";\n#endif\n    reset(other.object_);\n  }\n\n  ~Ref() {\n#ifdef DEBUG_COUNTING\n    cout << \"destroying Ref \" << this << \" with \" <<\n         (object_ ? typeid(*object_).name() : \"NULL\") << \" \" << object_ << \"\\n\";\n#endif\n    if (object_) {\n      object_->release();\n    }\n  }\n\n  void reset(T *o) {\n#ifdef DEBUG_COUNTING\n    cout << \"resetting Ref \" << this << \" from \" <<\n         (object_ ? typeid(*object_).name() : \"NULL\") << \" \" << object_ <<\n         \" to \" << (o ? typeid(*o).name() : \"NULL\") << \" \" << o << \"\\n\";\n#endif\n    if (o) {\n      o->retain();\n    }\n    if (object_ != 0) {\n      object_->release();\n    }\n    object_ = o;\n  }\n  Ref& operator=(const Ref &other) {\n    reset(other.object_);\n    return *this;\n  }\n  template<class Y>\n  Ref& operator=(const Ref<Y> &other) {\n    reset(other.object_);\n    return *this;\n  }\n  Ref& operator=(T* o) {\n    reset(o);\n    return *this;\n  }\n  template<class Y>\n  Ref& operator=(Y* o) {\n    reset(o);\n    return *this;\n  }\n\n  T& operator*() {\n    return *object_;\n  }\n  T* operator->() const {\n    return object_;\n  }\n  operator T*() const {\n    return object_;\n  }\n\n  bool operator==(const T* that) {\n    return object_ == that;\n  }\n  bool operator==(const Ref &other) const {\n    return object_ == other.object_ || *object_ == *(other.object_);\n  }\n  template<class Y>\n  bool operator==(const Ref<Y> &other) const {\n    return object_ == other.object_ || *object_ == *(other.object_);\n  }\n\n  bool operator!=(const T* that) {\n    return !(*this == that);\n  }\n\n  bool empty() const {\n    return object_ == 0;\n  }\n\n  template<class Y>\n  friend std::ostream& operator<<(std::ostream &out, Ref<Y>& ref);\n};\n}\n\n#endif // __COUNTED_H__\n\n// file: zxing/common/BitArray.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __BIT_ARRAY_H__\n// #define __BIT_ARRAY_H__\n\n/*\n *  Copyright 2010 ZXing authors. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/IllegalArgumentException.h>\n// #include <vector>\n// #include <limits>\n\nnamespace zxing {\n\n#define ZX_LOG_DIGITS(digits) \\\n    ((digits == 8) ? 3 : \\\n     ((digits == 16) ? 4 : \\\n      ((digits == 32) ? 5 : \\\n       ((digits == 64) ? 6 : \\\n        ((digits == 128) ? 7 : \\\n         (-1))))))\n\nclass BitArray : public Counted {\nprivate:\n  size_t size_;\n  std::vector<unsigned int> bits_;\n  static const unsigned int bitsPerWord_ =\n    std::numeric_limits<unsigned int>::digits;\n  static const unsigned int logBits_ = ZX_LOG_DIGITS(bitsPerWord_);\n  static const unsigned int bitsMask_ = (1 << logBits_) - 1;\n  static size_t wordsForBits(size_t bits);\n  explicit BitArray();\n\npublic:\n  BitArray(size_t size);\n  ~BitArray();\n  size_t getSize();\n\n  bool get(size_t i) {\n    return (bits_[i >> logBits_] & (1 << (i & bitsMask_))) != 0;\n  }\n\n  void set(size_t i) {\n    bits_[i >> logBits_] |= 1 << (i & bitsMask_);\n  }\n\n  void setBulk(size_t i, unsigned int newBits);\n  void setRange(int start, int end);\n  void clear();\n  bool isRange(size_t start, size_t end, bool value);\n  std::vector<unsigned int>& getBitArray();\n  void reverse();\n};\n\n}\n\n#endif // __BIT_ARRAY_H__\n\n// file: zxing/common/BitMatrix.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __BIT_MATRIX_H__\n// #define __BIT_MATRIX_H__\n\n/*\n *  BitMatrix.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/BitArray.h>\n// #include <limits>\n\nnamespace zxing {\n\nclass BitMatrix : public Counted {\nprivate:\n  size_t width_;\n  size_t height_;\n  size_t words_;\n  unsigned int* bits_;\n\n#define ZX_LOG_DIGITS(digits) \\\n    ((digits == 8) ? 3 : \\\n     ((digits == 16) ? 4 : \\\n      ((digits == 32) ? 5 : \\\n       ((digits == 64) ? 6 : \\\n        ((digits == 128) ? 7 : \\\n         (-1))))))\n\n  static const unsigned int bitsPerWord =\n    std::numeric_limits<unsigned int>::digits;\n  static const unsigned int logBits = ZX_LOG_DIGITS(bitsPerWord);\n  static const unsigned int bitsMask = (1 << logBits) - 1;\n\npublic:\n  BitMatrix(size_t dimension);\n  BitMatrix(size_t width, size_t height);\n\n  ~BitMatrix();\n\n  bool get(size_t x, size_t y) const {\n    size_t offset = x + width_ * y;\n    return ((bits_[offset >> logBits] >> (offset & bitsMask)) & 0x01) != 0;\n  }\n\n  void set(size_t x, size_t y) {\n    size_t offset = x + width_ * y;\n    bits_[offset >> logBits] |= 1 << (offset & bitsMask);\n  }\n\n  void flip(size_t x, size_t y);\n  void clear();\n  void setRegion(size_t left, size_t top, size_t width, size_t height);\n  Ref<BitArray> getRow(int y, Ref<BitArray> row);\n\n  size_t getDimension() const;\n  size_t getWidth() const;\n  size_t getHeight() const;\n\n  unsigned int* getBits() const;\n\n  friend std::ostream& operator<<(std::ostream &out, const BitMatrix &bm);\n  const char *description();\n\nprivate:\n  BitMatrix(const BitMatrix&);\n  BitMatrix& operator =(const BitMatrix&);\n};\n\n}\n\n#endif // __BIT_MATRIX_H__\n\n// file: zxing/common/Array.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __ARRAY_H__\n// #define __ARRAY_H__\n\n/*\n *  Array.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <vector>\n\n#ifdef DEBUG_COUNTING\n// #include <iostream>\n// #include <typeinfo>\n#endif\n\n// #include <zxing/common/Counted.h>\n\n\nnamespace zxing {\n\ntemplate<typename T> class Array : public Counted {\nprotected:\npublic:\n  std::vector<T> values_;\n  Array(size_t n) :\n      Counted(), values_(n, T()) {\n  }\n  Array(T *ts, size_t n) :\n      Counted(), values_(ts, ts+n) {\n  }\n  Array(T v, size_t n) :\n      Counted(), values_(n, v) {\n  }\n  Array(std::vector<T> &v) :\n      Counted(), values_(v) {\n  }\n  Array(Array<T> &other) :\n      Counted(), values_(other.values_) {\n  }\n  Array(Array<T> *other) :\n      Counted(), values_(other->values_) {\n  }\n  virtual ~Array() {\n  }\n  Array<T>& operator=(const Array<T> &other) {\n#ifdef DEBUG_COUNTING\n    cout << \"assigning values from Array \" << &other << \" to this Array \" << this << \", \";\n#endif\n    values_ = other.values_;\n#ifdef DEBUG_COUNTING\n    cout << \"new size = \" << values_.size() << \"\\n\";\n#endif\n    return *this;\n  }\n  Array<T>& operator=(const std::vector<T> &array) {\n#ifdef DEBUG_COUNTING\n    cout << \"assigning values from Array \" << &array << \" to this Array \" << this << \", \";\n#endif\n    values_ = array;\n#ifdef DEBUG_COUNTING\n    cout << \"new size = \" << values_.size() << \"\\n\";\n#endif\n    return *this;\n  }\n  T operator[](size_t i) const {\n    return values_[i];\n  }\n  T& operator[](size_t i) {\n    return values_[i];\n  }\n  size_t size() const {\n    return values_.size();\n  }\n  std::vector<T> values() const {\n    return values_;\n  }\n  std::vector<T>& values() {\n    return values_;\n  }\n};\n\ntemplate<typename T> class ArrayRef : public Counted {\nprivate:\npublic:\n  Array<T> *array_;\n  ArrayRef() :\n      array_(0) {\n#ifdef DEBUG_COUNTING\n    cout << \"instantiating empty ArrayRef \" << this << \"\\n\";\n#endif\n  }\n  ArrayRef(size_t n) :\n      array_(0) {\n#ifdef DEBUG_COUNTING\n    cout << \"instantiating ArrayRef \" << this << \"with size \" << n << \"\\n\";\n#endif\n    reset(new Array<T> (n));\n  }\n  ArrayRef(T *ts, size_t n) :\n      array_(0) {\n#ifdef DEBUG_COUNTING\n    cout << \"instantiating ArrayRef \" << this << \"with \" << n << \" elements at \" << (void *)ts << \"\\n\";\n#endif\n    reset(new Array<T> (ts, n));\n  }\n  ArrayRef(Array<T> *a) :\n      array_(0) {\n#ifdef DEBUG_COUNTING\n    cout << \"instantiating ArrayRef \" << this << \" from pointer:\\n\";\n#endif\n    reset(a);\n  }\n  ArrayRef(const Array<T> &a) :\n      array_(0) {\n#ifdef DEBUG_COUNTING\n    cout << \"instantiating ArrayRef \" << this << \" from reference to Array \" << (void *)&a << \":\\n\";\n#endif\n    reset(const_cast<Array<T> *>(&a));\n  }\n  ArrayRef(const ArrayRef &other) :\n      Counted(), array_(0) {\n#ifdef DEBUG_COUNTING\n    cout << \"instantiating ArrayRef \" << this << \" from ArrayRef \" << &other << \":\\n\";\n#endif\n    reset(other.array_);\n  }\n\n  template<class Y>\n  ArrayRef(const ArrayRef<Y> &other) :\n      array_(0) {\n#ifdef DEBUG_COUNTING\n    cout << \"instantiating ArrayRef \" << this << \" from ArrayRef \" << &other << \":\\n\";\n#endif\n    reset(static_cast<const Array<T> *>(other.array_));\n  }\n\n  ~ArrayRef() {\n#ifdef DEBUG_COUNTING\n    cout << \"destroying ArrayRef \" << this << \" with \" << (array_ ? typeid(*array_).name() : \"NULL\") << \" \"\n         << array_ << \"\\n\";\n#endif\n    if (array_) {\n      array_->release();\n    }\n    array_ = 0;\n  }\n\n  T operator[](size_t i) const {\n    return (*array_)[i];\n  }\n  T& operator[](size_t i) {\n    return (*array_)[i];\n  }\n  size_t size() const {\n    return array_->size();\n  }\n\n  void reset(Array<T> *a) {\n#ifdef DEBUG_COUNTING\n    cout << \"resetting ArrayRef \" << this << \" from \" << (array_ ? typeid(*array_).name() : \"NULL\") << \" \"\n         << array_ << \" to \" << (a ? typeid(*a).name() : \"NULL\") << \" \" << a << \"\\n\";\n#endif\n    if (a) {\n      a->retain();\n    }\n    if (array_) {\n      array_->release();\n    }\n    array_ = a;\n  }\n  void reset(const ArrayRef<T> &other) {\n    reset(other.array_);\n  }\n  ArrayRef<T>& operator=(const ArrayRef<T> &other) {\n    reset(other);\n    return *this;\n  }\n  ArrayRef<T>& operator=(Array<T> *a) {\n    reset(a);\n    return *this;\n  }\n\n  Array<T>& operator*() {\n    return *array_;\n  }\n  Array<T>* operator->() {\n    return array_;\n  }\n};\n\n} // namespace zxing\n\n#endif // __ARRAY_H__\n\n// file: zxing/common/Str.h\n\n#ifndef __STR_H__\n// #define __STR_H__\n\n/*\n *  Str.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <string>\n// #include <iostream>\n// #include <zxing/common/Counted.h>\n\nnamespace zxing {\n\nclass String : public Counted {\nprivate:\n  std::string text_;\npublic:\n  String(const std::string &text);\n  const std::string &getText() const;\n  friend std::ostream &operator<<(std::ostream &out, const String &s);\n};\n\n}\n\n#endif // __COMMON__STRING_H__\n\n// file: zxing/common/BitSource.h\n\n#ifndef __BIT_SOURCE_H__\n// #define __BIT_SOURCE_H__\n\n/*\n *  BitSource.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Array.h>\n\nnamespace zxing {\n/**\n * <p>This provides an easy abstraction to read bits at a time from a sequence of bytes, where the\n * number of bits read is not often a multiple of 8.</p>\n *\n * <p>This class is not thread-safe.</p>\n *\n * @author srowen@google.com (Sean Owen)\n * @author christian.brunschen@gmail.com (Christian Brunschen)\n */\nclass BitSource : public Counted {\n  typedef unsigned char byte;\nprivate:\n  ArrayRef<byte> bytes_;\n  int byteOffset_;\n  int bitOffset_;\npublic:\n  /**\n   * @param bytes bytes from which this will read bits. Bits will be read from the first byte first.\n   * Bits are read within a byte from most-significant to least-significant bit.\n   */\n  BitSource(ArrayRef<byte> &bytes) :\n      bytes_(bytes), byteOffset_(0), bitOffset_(0) {\n  }\n\n  int getByteOffset() {\n    return byteOffset_;\n  }\n\n  /**\n   * @param numBits number of bits to read\n   * @return int representing the bits read. The bits will appear as the least-significant\n   *         bits of the int\n   * @throws IllegalArgumentException if numBits isn't in [1,32]\n   */\n  int readBits(int numBits);\n\n  /**\n   * @return number of bits that can be read successfully\n   */\n  int available();\n};\n\n}\n\n#endif // __BIT_SOURCE_H__\n\n// file: zxing/common/DecoderResult.h\n\n#ifndef __DECODER_RESULT_H__\n// #define __DECODER_RESULT_H__\n\n/*\n *  DecoderResult.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/Array.h>\n// #include <string>\n// #include <zxing/common/Str.h>\n\nnamespace zxing {\n\nclass DecoderResult : public Counted {\nprivate:\n  ArrayRef<unsigned char> rawBytes_;\n  Ref<String> text_;\n  ArrayRef< ArrayRef<unsigned char> > byteSegments_;\n  std::string ecLevel_;\n\npublic:\n  DecoderResult(ArrayRef<unsigned char> rawBytes,\n                Ref<String> text,\n                ArrayRef< ArrayRef<unsigned char> >& byteSegments,\n                std::string const& ecLevel);\n\n  DecoderResult(ArrayRef<unsigned char> rawBytes, Ref<String> text);\n\n  ArrayRef<unsigned char> getRawBytes();\n  Ref<String> getText();\n};\n\n}\n\n#endif // __DECODER_RESULT_H__\n\n// file: zxing/common/PerspectiveTransform.h\n\n#ifndef __PERSPECTIVE_TANSFORM_H__\n// #define __PERSPECTIVE_TANSFORM_H__\n\n/*\n *  PerspectiveTransform.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n// #include <vector>\n\nnamespace zxing {\nclass PerspectiveTransform : public Counted {\nprivate:\n  float a11, a12, a13, a21, a22, a23, a31, a32, a33;\n  PerspectiveTransform(float a11, float a21, float a31, float a12, float a22, float a32, float a13, float a23,\n                       float a33);\n\npublic:\n  static Ref<PerspectiveTransform>\n  quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3,\n                               float x0p, float y0p, float x1p, float y1p, float x2p, float y2p, float x3p, float y3p);\n  static Ref<PerspectiveTransform> squareToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2,\n      float x3, float y3);\n  static Ref<PerspectiveTransform> quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2, float y2,\n      float x3, float y3);\n  Ref<PerspectiveTransform> buildAdjoint();\n  Ref<PerspectiveTransform> times(Ref<PerspectiveTransform> other);\n  void transformPoints(std::vector<float> &points);\n\n  friend std::ostream& operator<<(std::ostream& out, const PerspectiveTransform &pt);\n};\n}\n\n#endif // __PERSPECTIVE_TANSFORM_H__\n\n// file: zxing/ResultPoint.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __RESULT_POINT_H__\n// #define __RESULT_POINT_H__\n\n/*\n *  ResultPoint.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n// #include <vector>\n\nnamespace zxing {\n\nclass ResultPoint : public Counted {\nprotected:\n  float posX_;\n  float posY_;\n\npublic:\n  ResultPoint();\n  ResultPoint(float x, float y);\n  virtual ~ResultPoint();\n\n  virtual float getX() const;\n  virtual float getY() const;\n\n  bool equals(Ref<ResultPoint> other);\n\n  static void orderBestPatterns(std::vector<Ref<ResultPoint> > &patterns);\n  static float distance(Ref<ResultPoint> point1, Ref<ResultPoint> point2);\n  static float distance(float x1, float x2, float y1, float y2);\n\nprivate:\n  static float crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC);\n};\n\n}\n\n#endif // __RESULT_POINT_H__\n\n// file: zxing/common/DetectorResult.h\n\n#ifndef __DETECTOR_RESULT_H__\n// #define __DETECTOR_RESULT_H__\n\n/*\n *  DetectorResult.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <vector>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/Array.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/ResultPoint.h>\n// #include <zxing/common/PerspectiveTransform.h>\n\nnamespace zxing {\n\nclass DetectorResult : public Counted {\nprivate:\n  Ref<BitMatrix> bits_;\n  std::vector<Ref<ResultPoint> > points_;\n  Ref<PerspectiveTransform> transform_;\n\npublic:\n  DetectorResult(Ref<BitMatrix> bits, std::vector<Ref<ResultPoint> > points, Ref<PerspectiveTransform> transform);\n  Ref<BitMatrix> getBits();\n  std::vector<Ref<ResultPoint> > getPoints();\n  Ref<PerspectiveTransform> getTransform();\n};\n}\n\n#endif // __DETECTOR_RESULT_H__\n\n// file: zxing/common/Point.h\n\n#ifndef __POINT_H__\n// #define __POINT_H__\n\n/*\n *  Point.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nnamespace zxing {\nclass PointI {\npublic:\n  int x;\n  int y;\n};\n\nclass Point {\npublic:\n  Point() : x(0.0f), y(0.0f) {};\n  Point(float x_, float y_) : x(x_), y(y_) {};\n\n  float x;\n  float y;\n};\n\nclass Line {\npublic:\n  Line(Point start_, Point end_) : start(start_), end(end_) {};\n\n  Point start;\n  Point end;\n};\n}\n#endif // POINT_H_\n\n// file: zxing/common/EdgeDetector.h\n\n#ifndef __EDGEDETECTOR_H__\n// #define __EDGEDETECTOR_H__\n/*\n *  EdgeDetector.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n// #include <vector>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/common/Point.h>\n\nnamespace zxing {\nnamespace EdgeDetector {\n\nvoid findEdgePoints(std::vector<Point>& points, const BitMatrix& image, Point start, Point end, bool invert, int skip, float deviation);\nLine findLine(const BitMatrix& image, Line estimate, bool invert, int deviation, float threshold, int skip);\n\nPoint intersection(Line a, Line b);\n\n}\n}\n#endif /* EDGEDETECTOR_H_ */\n\n// file: zxing/LuminanceSource.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __LUMINANCESOURCE_H__\n// #define __LUMINANCESOURCE_H__\n/*\n *  LuminanceSource.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n// #include <string.h>\n\nnamespace zxing {\n\nclass LuminanceSource : public Counted {\npublic:\n  LuminanceSource();\n  virtual ~LuminanceSource();\n\n  virtual int getWidth() const = 0;\n  virtual int getHeight() const = 0;\n\n  // Callers take ownership of the returned memory and must call delete [] on it themselves.\n  virtual unsigned char* getRow(int y, unsigned char* row) = 0;\n  virtual unsigned char* getMatrix() = 0;\n\n  virtual bool isCropSupported() const;\n  virtual Ref<LuminanceSource> crop(int left, int top, int width, int height);\n\n  virtual bool isRotateSupported() const;\n  virtual Ref<LuminanceSource> rotateCounterClockwise();\n\n  operator std::string (); // should be const but don't want to make sure a\n                           // large breaking change right now\n};\n\n}\n\n#endif /* LUMINANCESOURCE_H_ */\n\n// file: zxing/Binarizer.h\n\n#ifndef BINARIZER_H_\n#define BINARIZER_H_\n\n/*\n *  Binarizer.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/LuminanceSource.h>\n// #include <zxing/common/BitArray.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/common/Counted.h>\n\nnamespace zxing {\n\nclass Binarizer : public Counted {\n private:\n  Ref<LuminanceSource> source_;\n\n public:\n  Binarizer(Ref<LuminanceSource> source);\n  virtual ~Binarizer();\n\n  virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row) = 0;\n  virtual Ref<BitMatrix> getBlackMatrix() = 0;\n\n  Ref<LuminanceSource> getLuminanceSource() const ;\n  virtual Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) = 0;\n};\n\n}\n#endif /* BINARIZER_H_ */\n\n// file: zxing/common/GlobalHistogramBinarizer.h\n\n#ifndef __GLOBALHISTOGRAMBINARIZER_H__\n// #define __GLOBALHISTOGRAMBINARIZER_H__\n/*\n *  GlobalHistogramBinarizer.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <vector>\n// #include <zxing/Binarizer.h>\n// #include <zxing/common/BitArray.h>\n// #include <zxing/common/BitMatrix.h>\n\nnamespace zxing {\n\n\tclass GlobalHistogramBinarizer : public Binarizer {\n\t private:\n    Ref<BitMatrix> cached_matrix_;\n\t  Ref<BitArray> cached_row_;\n\t  int cached_row_num_;\n\n\tpublic:\n\t\tGlobalHistogramBinarizer(Ref<LuminanceSource> source);\n\t\tvirtual ~GlobalHistogramBinarizer();\n\n\t\tvirtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row);\n\t\tvirtual Ref<BitMatrix> getBlackMatrix();\n\t\tstatic int estimate(std::vector<int> &histogram);\n\t\tRef<Binarizer> createBinarizer(Ref<LuminanceSource> source);\n\t};\n\n}\n\n#endif /* GLOBALHISTOGRAMBINARIZER_H_ */\n\n// file: zxing/common/GreyscaleLuminanceSource.h\n\n#ifndef __GREYSCALE_LUMINANCE_SOURCE__\n#define __GREYSCALE_LUMINANCE_SOURCE__\n/*\n *  GreyscaleLuminanceSource.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/LuminanceSource.h>\n\nnamespace zxing {\n\nclass GreyscaleLuminanceSource : public LuminanceSource {\n\n private:\n  unsigned char* greyData_;\n  int dataWidth_;\n  int dataHeight_;\n  int left_;\n  int top_;\n  int width_;\n  int height_;\n\n public:\n  GreyscaleLuminanceSource(unsigned char* greyData, int dataWidth, int dataHeight, int left,\n      int top, int width, int height);\n\n  unsigned char* getRow(int y, unsigned char* row);\n  unsigned char* getMatrix();\n\n  bool isRotateSupported() const {\n    return true;\n  }\n\n  int getWidth() const {\n    return width_;\n  }\n\n  int getHeight() const {\n    return height_;\n  }\n\n  Ref<LuminanceSource> rotateCounterClockwise();\n\n};\n\n} /* namespace */\n\n#endif\n\n// file: zxing/common/GreyscaleRotatedLuminanceSource.h\n\n#ifndef __GREYSCALE_ROTATED_LUMINANCE_SOURCE__\n#define __GREYSCALE_ROTATED_LUMINANCE_SOURCE__\n/*\n *  GreyscaleRotatedLuminanceSource.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n// #include <zxing/LuminanceSource.h>\n\nnamespace zxing {\n\nclass GreyscaleRotatedLuminanceSource : public LuminanceSource {\n private:\n  unsigned char* greyData_;\n  int dataWidth_;\n  int dataHeight_;\n  int left_;\n  int top_;\n  int width_;\n  int height_;\n\npublic:\n  GreyscaleRotatedLuminanceSource(unsigned char* greyData, int dataWidth, int dataHeight,\n      int left, int top, int width, int height);\n\n  unsigned char* getRow(int y, unsigned char* row);\n  unsigned char* getMatrix();\n\n  bool isRotateSupported() const {\n    return false;\n  }\n\n  int getWidth() const {\n    return width_;\n  }\n\n  int getHeight() const {\n    return height_;\n  }\n\n};\n\n} /* namespace */\n\n#endif\n\n// file: zxing/common/GridSampler.h\n\n#ifndef __GRID_SAMPLER_H__\n// #define __GRID_SAMPLER_H__\n\n/*\n *  GridSampler.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/common/PerspectiveTransform.h>\n\nnamespace zxing {\nclass GridSampler {\nprivate:\n  static GridSampler gridSampler;\n  GridSampler();\n\npublic:\n  Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform);\n  Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimensionX, int dimensionY, Ref<PerspectiveTransform> transform);\n\n  Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension, float p1ToX, float p1ToY, float p2ToX, float p2ToY,\n                            float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX,\n                            float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY);\n  static void checkAndNudgePoints(Ref<BitMatrix> image, std::vector<float> &points);\n  static GridSampler &getInstance();\n};\n}\n\n#endif // __GRID_SAMPLER_H__\n\n// file: zxing/common/HybridBinarizer.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __HYBRIDBINARIZER_H__\n// #define __HYBRIDBINARIZER_H__\n/*\n *  HybridBinarizer.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <vector>\n// #include <zxing/Binarizer.h>\n// #include <zxing/common/GlobalHistogramBinarizer.h>\n// #include <zxing/common/BitArray.h>\n// #include <zxing/common/BitMatrix.h>\n\nnamespace zxing {\n\n\tclass HybridBinarizer : public GlobalHistogramBinarizer {\n\t private:\n    Ref<BitMatrix> matrix_;\n\t  Ref<BitArray> cached_row_;\n\t  int cached_row_num_;\n\n\tpublic:\n\t\tHybridBinarizer(Ref<LuminanceSource> source);\n\t\tvirtual ~HybridBinarizer();\n\n\t\tvirtual Ref<BitMatrix> getBlackMatrix();\n\t\tRef<Binarizer> createBinarizer(Ref<LuminanceSource> source);\n  private:\n    // We'll be using one-D arrays because C++ can't dynamically allocate 2D\n    // arrays\n    int* calculateBlackPoints(unsigned char* luminances,\n                              int subWidth,\n                              int subHeight,\n                              int width,\n                              int height);\n    void calculateThresholdForBlock(unsigned char* luminances,\n                                    int subWidth,\n                                    int subHeight,\n                                    int width,\n                                    int height,\n                                    int blackPoints[],\n                                    Ref<BitMatrix> const& matrix);\n    void threshold8x8Block(unsigned char* luminances,\n                           int xoffset,\n                           int yoffset,\n                           int threshold,\n                           int stride,\n                           Ref<BitMatrix> const& matrix);\n\t};\n\n}\n\n#endif\n\n// file: zxing/common/reedsolomon/GF256.h\n\n#ifndef __GF256_H__\n// #define __GF256_H__\n\n/*\n *  GF256.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <memory>\n// #include <vector>\n// #include <zxing/common/Counted.h>\n\nnamespace zxing {\nclass GF256Poly;\n\nclass GF256 {\n  /**\n   * <p>This class contains utility methods for performing mathematical\n   * operations over the Galois Field GF(256). Operations use a given\n   * primitive polynomial in calculations.</p>\n   *\n   * <p>Throughout this package, elements of GF(256) are represented as an\n   * <code>int</code> for convenience and speed (but at the cost of memory).\n   * Only the bottom 8 bits are really used.</p>\n   *\n   * @author srowen@google.com (Sean Owen)\n   * @author christian.brunschen@gmail.com (Christian Brunschen)\n   */\nprivate:\n  std::vector<int> exp_;\n  std::vector<int> log_;\n  Ref<GF256Poly> zero_;\n  Ref<GF256Poly> one_;\n\n  GF256(int primitive);\n\npublic:\n  Ref<GF256Poly> getZero();\n  Ref<GF256Poly> getOne();\n  Ref<GF256Poly> buildMonomial(int degree, int coefficient);\n  static int addOrSubtract(int a, int b);\n  int exp(int a);\n  int log(int a);\n  int inverse(int a);\n  int multiply(int a, int b);\n\n  static GF256 QR_CODE_FIELD;\n  static GF256 DATA_MATRIX_FIELD;\n\n  friend std::ostream& operator<<(std::ostream& out, const GF256& field);\n};\n}\n\n#endif // __GF256_H__\n\n// file: zxing/common/reedsolomon/GF256Poly.h\n\n#ifndef __GF256_POLY_H__\n// #define __GF256_POLY_H__\n\n/*\n *  GF256Poly.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <memory>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/Array.h>\n\nnamespace zxing {\nclass GF256;\n\nclass GF256Poly : public Counted {\nprivate:\n  GF256 &field;\n  ArrayRef<int> coefficients;\n  void fixCoefficients();\npublic:\n  GF256Poly(GF256 &field, ArrayRef<int> c);\n  ~GF256Poly();\n\n  int getDegree();\n  bool isZero();\n  int getCoefficient(int degree);\n  int evaluateAt(int a);\n  Ref<GF256Poly> addOrSubtract(Ref<GF256Poly> other);\n  Ref<GF256Poly> multiply(Ref<GF256Poly> other);\n  Ref<GF256Poly> multiply(int scalar);\n  Ref<GF256Poly> multiplyByMonomial(int degree, int coefficient);\n  const char *description() const;\n  friend std::ostream& operator<<(std::ostream& out, const GF256Poly& poly);\n\n};\n}\n\n#endif // __GF256_POLY_H__\n\n// file: zxing/common/reedsolomon/ReedSolomonDecoder.h\n\n#ifndef __REED_SOLOMON_DECODER_H__\n// #define __REED_SOLOMON_DECODER_H__\n\n/*\n *  ReedSolomonDecoder.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <memory>\n// #include <vector>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/Array.h>\n\nnamespace zxing {\nclass GF256;\nclass GF256Poly;\n\nclass ReedSolomonDecoder {\nprivate:\n  GF256 &field;\npublic:\n  ReedSolomonDecoder(GF256 &fld);\n  ~ReedSolomonDecoder();\n  void decode(ArrayRef<int> received, int twoS);\nprivate:\n  std::vector<Ref<GF256Poly> > runEuclideanAlgorithm(Ref<GF256Poly> a, Ref<GF256Poly> b, int R);\n  ArrayRef<int> findErrorLocations(Ref<GF256Poly> errorLocator);\n  ArrayRef<int> findErrorMagnitudes(Ref<GF256Poly> errorEvaluator, ArrayRef<int> errorLocations, bool dataMatrix);\n};\n}\n\n#endif // __REED_SOLOMON_DECODER_H__\n\n// file: zxing/common/reedsolomon/ReedSolomonException.h\n\n#ifndef __REED_SOLOMON_EXCEPTION_H__\n// #define __REED_SOLOMON_EXCEPTION_H__\n\n/*\n *  ReedSolomonException.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/Exception.h>\n\nnamespace zxing {\nclass ReedSolomonException : public Exception {\npublic:\n  ReedSolomonException(const char *msg) throw();\n  ~ReedSolomonException() throw();\n};\n}\n\n#endif // __REED_SOLOMON_EXCEPTION_H__\n\n// file: zxing/BarcodeFormat.h\n\n#ifndef __BARCODE_FORMAT_H__\n// #define __BARCODE_FORMAT_H__\n\n/*\n *  BarcodeFormat.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nnamespace zxing {\n\n\ttypedef enum BarcodeFormat {\n\t\tBarcodeFormat_None = 0,\n\t\tBarcodeFormat_QR_CODE,\n\t\tBarcodeFormat_DATA_MATRIX,\n\t\tBarcodeFormat_UPC_E,\n\t\tBarcodeFormat_UPC_A,\n\t\tBarcodeFormat_EAN_8,\n\t\tBarcodeFormat_EAN_13,\n\t\tBarcodeFormat_CODE_128,\n\t\tBarcodeFormat_CODE_39,\n\t\tBarcodeFormat_ITF\n\t} BarcodeFormat;\n\n\t/* if you update the enum, please update the name in BarcodeFormat.cpp */\n\textern const char *barcodeFormatNames[];\n}\n\n#endif // __BARCODE_FORMAT_H__\n\n// file: zxing/BinaryBitmap.h\n\n#ifndef __BINARYBITMAP_H__\n// #define __BINARYBITMAP_H__\n\n/*\n *  BinaryBitmap.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/common/BitArray.h>\n// #include <zxing/Binarizer.h>\n\nnamespace zxing {\n\n\tclass BinaryBitmap : public Counted {\n\tprivate:\n\t\tRef<Binarizer> binarizer_;\n\t\tint cached_y_;\n\n\tpublic:\n\t\tBinaryBitmap(Ref<Binarizer> binarizer);\n\t\tvirtual ~BinaryBitmap();\n\n\t\tRef<BitArray> getBlackRow(int y, Ref<BitArray> row);\n\t\tRef<BitMatrix> getBlackMatrix();\n\n\t\tRef<LuminanceSource> getLuminanceSource() const;\n\n\t\tint getWidth() const;\n\t\tint getHeight() const;\n\n\t\tbool isRotateSupported() const;\n\t\tRef<BinaryBitmap> rotateCounterClockwise();\n\n\t\tbool isCropSupported() const;\n\t\tRef<BinaryBitmap> crop(int left, int top, int width, int height);\n\n\t};\n\n}\n\n#endif /* BINARYBITMAP_H_ */\n\n// file: zxing/ResultPointCallback.h\n\n#ifndef __RESULT_POINT_CALLBACK_H__\n// #define __RESULT_POINT_CALLBACK_H__\n\n/*\n *  ResultPointCallback.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n\nnamespace zxing {\n\nclass ResultPoint;\n\nclass ResultPointCallback : public Counted {\nprotected:\n  ResultPointCallback() {}\npublic:\n  virtual void foundPossibleResultPoint(ResultPoint const& point) = 0;\n  virtual ~ResultPointCallback();\n};\n\n}\n\n#endif // __RESULT_POINT_CALLBACK_H__\n\n// file: zxing/DecodeHints.h\n\n#ifndef __DECODEHINTS_H_\n#define __DECODEHINTS_H_\n/*\n *  DecodeHintType.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/BarcodeFormat.h>\n// #include <zxing/ResultPointCallback.h>\n\nnamespace zxing {\n\ntypedef unsigned int DecodeHintType;\n\nclass DecodeHints {\n\n private:\n\n  DecodeHintType hints;\n\n  Ref<ResultPointCallback> callback;\n\n public:\n\n  static const DecodeHintType BARCODEFORMAT_QR_CODE_HINT = 1 << BarcodeFormat_QR_CODE;\n  static const DecodeHintType BARCODEFORMAT_DATA_MATRIX_HINT = 1 << BarcodeFormat_DATA_MATRIX;\n  static const DecodeHintType BARCODEFORMAT_UPC_E_HINT = 1 << BarcodeFormat_UPC_E;\n  static const DecodeHintType BARCODEFORMAT_UPC_A_HINT = 1 << BarcodeFormat_UPC_A;\n  static const DecodeHintType BARCODEFORMAT_EAN_8_HINT = 1 << BarcodeFormat_EAN_8;\n  static const DecodeHintType BARCODEFORMAT_EAN_13_HINT = 1 << BarcodeFormat_EAN_13;\n  static const DecodeHintType BARCODEFORMAT_CODE_128_HINT = 1 << BarcodeFormat_CODE_128;\n  static const DecodeHintType BARCODEFORMAT_CODE_39_HINT = 1 << BarcodeFormat_CODE_39;\n  static const DecodeHintType BARCODEFORMAT_ITF_HINT = 1 << BarcodeFormat_ITF;\n  static const DecodeHintType CHARACTER_SET = 1 << 30;\n  static const DecodeHintType TRYHARDER_HINT = 1 << 31;\n\n  static const DecodeHints PRODUCT_HINT;\n  static const DecodeHints ONED_HINT;\n  static const DecodeHints DEFAULT_HINT;\n\n  DecodeHints();\n  DecodeHints(DecodeHintType init);\n\n  void addFormat(BarcodeFormat toadd);\n  bool containsFormat(BarcodeFormat tocheck) const;\n  void setTryHarder(bool toset);\n  bool getTryHarder() const;\n\n  void setResultPointCallback(Ref<ResultPointCallback> const&);\n  Ref<ResultPointCallback> getResultPointCallback() const;\n\n};\n\n}\n\n#endif\n\n// file: zxing/Result.h\n\n#ifndef __RESULT_H__\n// #define __RESULT_H__\n\n/*\n *  Result.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <string>\n// #include <vector>\n// #include <zxing/common/Array.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/Str.h>\n// #include <zxing/ResultPoint.h>\n// #include <zxing/BarcodeFormat.h>\n\nnamespace zxing {\n\nclass Result : public Counted {\nprivate:\n  Ref<String> text_;\n  ArrayRef<unsigned char> rawBytes_;\n  std::vector<Ref<ResultPoint> > resultPoints_;\n  BarcodeFormat format_;\n\npublic:\n  Result(Ref<String> text, ArrayRef<unsigned char> rawBytes, std::vector<Ref<ResultPoint> > resultPoints,\n         BarcodeFormat format);\n  ~Result();\n  Ref<String> getText();\n  ArrayRef<unsigned char> getRawBytes();\n  const std::vector<Ref<ResultPoint> >& getResultPoints() const;\n  std::vector<Ref<ResultPoint> >& getResultPoints();\n  BarcodeFormat getBarcodeFormat() const;\n\n  friend std::ostream& operator<<(std::ostream &out, Result& result);\n};\n\n}\n#endif // __RESULT_H__\n\n// file: zxing/Reader.h\n\n#ifndef __READER_H__\n// #define __READER_H__\n\n/*\n *  Reader.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/BinaryBitmap.h>\n// #include <zxing/Result.h>\n// #include <zxing/DecodeHints.h>\n\nnamespace zxing {\n\n class Reader : public Counted {\n  protected:\n   Reader() {}\n  public:\n   virtual Ref<Result> decode(Ref<BinaryBitmap> image);\n   virtual Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints) = 0;\n   virtual ~Reader();\n};\n\n}\n\n#endif // __READER_H__\n\n// file: zxing/MultiFormatReader.h\n\n#ifndef __MULTI_FORMAT_READER_H__\n// #define __MULTI_FORMAT_READER_H__\n\n/*\n *  MultiFormatBarcodeReader.h\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n// #include <zxing/Reader.h>\n// #include <zxing/common/BitArray.h>\n// #include <zxing/Result.h>\n// #include <zxing/DecodeHints.h>\n\nnamespace zxing {\n  class MultiFormatReader : public Reader {\n\n  private:\n    Ref<Result> decodeInternal(Ref<BinaryBitmap> image);\n\n    std::vector<Ref<Reader> > readers_;\n    DecodeHints hints_;\n\n  public:\n    MultiFormatReader();\n\n    Ref<Result> decode(Ref<BinaryBitmap> image);\n    Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);\n    Ref<Result> decodeWithState(Ref<BinaryBitmap> image);\n    void setHints(DecodeHints hints);\n    ~MultiFormatReader();\n  };\n}\n\n#endif\n\n// file: zxing/ReaderException.h\n\n#ifndef __READER_EXCEPTION_H__\n// #define __READER_EXCEPTION_H__\n\n/*\n *  ReaderException.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/Exception.h>\n\nnamespace zxing {\n\nclass ReaderException : public Exception {\npublic:\n  ReaderException();\n  ReaderException(const char *msg);\n  ~ReaderException() throw();\n};\n\n}\n#endif // __READER_EXCEPTION_H__\n\n// file: zxing/datamatrix/decoder/Decoder.h\n\n#ifndef __DECODER_DM_H__\n// #define __DECODER_DM_H__\n\n/*\n *  Decoder.h\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/reedsolomon/ReedSolomonDecoder.h>\n// #include <zxing/common/reedsolomon/GF256.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/Array.h>\n// #include <zxing/common/DecoderResult.h>\n// #include <zxing/common/BitMatrix.h>\n\n\nnamespace zxing {\nnamespace datamatrix {\n\nclass Decoder {\nprivate:\n  ReedSolomonDecoder rsDecoder_;\n\n  void correctErrors(ArrayRef<unsigned char> bytes, int numDataCodewords);\n\npublic:\n  Decoder();\n\n  Ref<DecoderResult> decode(Ref<BitMatrix> bits);\n};\n\n}\n}\n\n#endif // __DECODER_DM_H__\n\n// file: zxing/datamatrix/DataMatrixReader.h\n\n#ifndef __DATA_MATRIX_READER_H__\n// #define __DATA_MATRIX_READER_H__\n\n/*\n *  DataMatrixReader.h\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/Reader.h>\n// #include <zxing/DecodeHints.h>\n// #include <zxing/datamatrix/decoder/Decoder.h>\n\nnamespace zxing {\nnamespace datamatrix {\n\nclass DataMatrixReader : public Reader {\nprivate:\n  Decoder decoder_;\n\npublic:\n  DataMatrixReader();\n  virtual Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);\n  virtual ~DataMatrixReader();\n\n};\n\n}\n}\n\n#endif // __DATA_MATRIX_READER_H__\n\n// file: zxing/datamatrix/Version.h\n\n#ifndef __VERSION_H__\n// #define __VERSION_H__\n\n/*\n *  Version.h\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ReaderException.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/common/Counted.h>\n// #include <vector>\n\nnamespace zxing {\nnamespace datamatrix {\n\nclass ECB {\nprivate:\n  int count_;\n  int dataCodewords_;\npublic:\n  ECB(int count, int dataCodewords);\n  int getCount();\n  int getDataCodewords();\n};\n\nclass ECBlocks {\nprivate:\n  int ecCodewords_;\n  std::vector<ECB*> ecBlocks_;\npublic:\n  ECBlocks(int ecCodewords, ECB *ecBlocks);\n  ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2);\n  int getECCodewords();\n  std::vector<ECB*>& getECBlocks();\n  ~ECBlocks();\n};\n\nclass Version : public Counted {\nprivate:\n  int versionNumber_;\n  int symbolSizeRows_;\n  int symbolSizeColumns_;\n  int dataRegionSizeRows_;\n  int dataRegionSizeColumns_;\n  ECBlocks* ecBlocks_;\n  int totalCodewords_;\n  Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows,\n\t\t  int dataRegionSizeColumns, ECBlocks *ecBlocks);\n\npublic:\n  static std::vector<Ref<Version> > VERSIONS;\n\n  ~Version();\n  int getVersionNumber();\n  int getSymbolSizeRows();\n  int getSymbolSizeColumns();\n  int getDataRegionSizeRows();\n  int getDataRegionSizeColumns();\n  int getTotalCodewords();\n  ECBlocks* getECBlocks();\n  static int  buildVersions();\n  Ref<Version> getVersionForDimensions(int numRows, int numColumns);\n\nprivate:\n  Version(const Version&);\n  Version & operator=(const Version&);\n};\n}\n}\n\n#endif // __VERSION_H__\n\n// file: zxing/datamatrix/decoder/BitMatrixParser.h\n\n#ifndef __BIT_MATRIX_PARSER_DM_H__\n// #define __BIT_MATRIX_PARSER_DM_H__\n\n/*\n *  BitMatrixParser.h\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ReaderException.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/Array.h>\n// #include <zxing/datamatrix/Version.h>\n\nnamespace zxing {\nnamespace datamatrix {\n\nclass BitMatrixParser : public Counted {\nprivate:\n  Ref<BitMatrix> bitMatrix_;\n  Ref<Version> parsedVersion_;\n  Ref<BitMatrix> readBitMatrix_;\n\n  int copyBit(size_t x, size_t y, int versionBits);\n\npublic:\n  BitMatrixParser(Ref<BitMatrix> bitMatrix);\n  Ref<Version> readVersion(Ref<BitMatrix> bitMatrix);\n  ArrayRef<unsigned char> readCodewords();\n  bool readModule(int row, int column, int numRows, int numColumns);\n\nprivate:\n  int readUtah(int row, int column, int numRows, int numColumns);\n  int readCorner1(int numRows, int numColumns);\n  int readCorner2(int numRows, int numColumns);\n  int readCorner3(int numRows, int numColumns);\n  int readCorner4(int numRows, int numColumns);\n  Ref<BitMatrix> extractDataRegion(Ref<BitMatrix> bitMatrix);\n};\n\n}\n}\n\n#endif // __BIT_MATRIX_PARSER_DM_H__\n\n// file: zxing/datamatrix/decoder/DataBlock.h\n\n#ifndef __DATA_BLOCK_DM_H__\n// #define __DATA_BLOCK_DM_H__\n\n/*\n *  DataBlock.h\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <vector>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/Array.h>\n// #include <zxing/datamatrix/Version.h>\n\nnamespace zxing {\nnamespace datamatrix {\n\nclass DataBlock : public Counted {\nprivate:\n  int numDataCodewords_;\n  ArrayRef<unsigned char> codewords_;\n\n  DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords);\n\npublic:\n  static std::vector<Ref<DataBlock> > getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version);\n\n  int getNumDataCodewords();\n  ArrayRef<unsigned char> getCodewords();\n};\n\n}\n}\n\n#endif // __DATA_BLOCK_DM_H__\n\n// file: zxing/datamatrix/decoder/DecodedBitStreamParser.h\n\n#ifndef __DECODED_BIT_STREAM_PARSER_DM_H__\n// #define __DECODED_BIT_STREAM_PARSER_DM_H__\n\n/*\n *  DecodedBitStreamParser.h\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <string>\n// #include <sstream>\n// #include <zxing/common/Array.h>\n// #include <zxing/common/BitSource.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/DecoderResult.h>\n\n\nnamespace zxing {\nnamespace datamatrix {\n\nclass DecodedBitStreamParser {\nprivate:\n  static const int PAD_ENCODE = 0;  // Not really an encoding\n  static const int ASCII_ENCODE = 1;\n  static const int C40_ENCODE = 2;\n  static const int TEXT_ENCODE = 3;\n  static const int ANSIX12_ENCODE = 4;\n  static const int EDIFACT_ENCODE = 5;\n  static const int BASE256_ENCODE = 6;\n\n  /**\n   * See ISO 16022:2006, Annex C Table C.1\n   * The C40 Basic Character Set (*'s used for placeholders for the shift values)\n   */\n  static const char C40_BASIC_SET_CHARS[];\n\n  static const char C40_SHIFT2_SET_CHARS[];\n  /**\n   * See ISO 16022:2006, Annex C Table C.2\n   * The Text Basic Character Set (*'s used for placeholders for the shift values)\n   */\n  static const char TEXT_BASIC_SET_CHARS[];\n\n  static const char TEXT_SHIFT3_SET_CHARS[];\n  /**\n   * See ISO 16022:2006, 5.2.3 and Annex C, Table C.2\n   */\n  int decodeAsciiSegment(Ref<BitSource> bits, std::ostringstream &result, std::ostringstream &resultTrailer);\n  /**\n   * See ISO 16022:2006, 5.2.5 and Annex C, Table C.1\n   */\n  void decodeC40Segment(Ref<BitSource> bits, std::ostringstream &result);\n  /**\n   * See ISO 16022:2006, 5.2.6 and Annex C, Table C.2\n   */\n  void decodeTextSegment(Ref<BitSource> bits, std::ostringstream &result);\n  /**\n   * See ISO 16022:2006, 5.2.7\n   */\n  void decodeAnsiX12Segment(Ref<BitSource> bits, std::ostringstream &result);\n  /**\n   * See ISO 16022:2006, 5.2.8 and Annex C Table C.3\n   */\n  void decodeEdifactSegment(Ref<BitSource> bits, std::ostringstream &result);\n  /**\n   * See ISO 16022:2006, 5.2.9 and Annex B, B.2\n   */\n  void decodeBase256Segment(Ref<BitSource> bits, std::ostringstream &result, std::vector<unsigned char> byteSegments);\n\n  void parseTwoBytes(int firstByte, int secondByte, int*& result);\n  /**\n   * See ISO 16022:2006, Annex B, B.2\n   */\n  unsigned char unrandomize255State(int randomizedBase256Codeword,\n                                          int base256CodewordPosition) {\n    int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1;\n    int tempVariable = randomizedBase256Codeword - pseudoRandomNumber;\n    return (unsigned char) (tempVariable >= 0 ? tempVariable : (tempVariable + 256));\n  };\n  void append(std::ostream &ost, const unsigned char *bufIn, size_t nIn, const char *src);\n\npublic:\n  DecodedBitStreamParser() { };\n  Ref<DecoderResult> decode(ArrayRef<unsigned char> bytes);\n};\n\n}\n}\n\n#endif // __DECODED_BIT_STREAM_PARSER_DM_H__\n\n// file: zxing/datamatrix/detector/CornerPoint.h\n\n#ifndef __CORNER_FINDER_H__\n// #define __CORNER_FINDER_H__\n\n/*\n *  CornerPoint.h\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ResultPoint.h>\n// #include <cmath>\n\nnamespace zxing {\n\tnamespace datamatrix {\n\n\t\tclass CornerPoint : public ResultPoint {\n\t\tprivate:\n\t\t\tint counter_;\n\n\t\tpublic:\n\t\t\tCornerPoint(float posX, float posY);\n\t\t\tint getCount() const;\n\t\t\tvoid incrementCount();\n\t\t\tbool equals(Ref<CornerPoint> other) const;\n\t\t};\n\t}\n}\n\n#endif // __CORNER_FINDER_H__\n\n// file: zxing/datamatrix/detector/MonochromeRectangleDetector.h\n\n#ifndef __MONOCHROMERECTANGLEDETECTOR_H__\n// #define __MONOCHROMERECTANGLEDETECTOR_H__\n\n/*\n *  MonochromeRectangleDetector.h\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <vector>\n// #include <zxing/ReaderException.h>\n// #include <zxing/ResultPoint.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/datamatrix/detector/CornerPoint.h>\n\nnamespace zxing {\nnamespace datamatrix {\n\nstruct TwoInts: public Counted {\n\tint start;\n\tint end;\n};\n\nclass MonochromeRectangleDetector : public Counted {\nprivate:\n  static const int MAX_MODULES = 32;\n  Ref<BitMatrix> image_;\n\npublic:\n  MonochromeRectangleDetector(Ref<BitMatrix> image) : image_(image) {  };\n\n  std::vector<Ref<CornerPoint> > detect();\n\nprivate:\n  Ref<CornerPoint> findCornerFromCenter(int centerX, int deltaX, int left, int right,\n      int centerY, int deltaY, int top, int bottom, int maxWhiteRun);\n\n  Ref<TwoInts> blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim,\n      bool horizontal);\n\n  int max(int a, float b) { return (float) a > b ? a : (int) b;};\n};\n}\n}\n\n#endif // __MONOCHROMERECTANGLEDETECTOR_H__\n\n// file: zxing/datamatrix/detector/Detector.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __DETECTOR_H__\n// #define __DETECTOR_H__\n\n/*\n *  Detector.h\n *  zxing\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/DetectorResult.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/common/PerspectiveTransform.h>\n// #include <zxing/common/detector/WhiteRectangleDetector.h>\n\nnamespace zxing {\nnamespace datamatrix {\n\nclass ResultPointsAndTransitions: public Counted {\n  private:\n    Ref<ResultPoint> to_;\n    Ref<ResultPoint> from_;\n    int transitions_;\n\n  public:\n    ResultPointsAndTransitions();\n    ResultPointsAndTransitions(Ref<ResultPoint> from, Ref<ResultPoint> to, int transitions);\n    Ref<ResultPoint> getFrom();\n    Ref<ResultPoint> getTo();\n    int getTransitions();\n};\n\nclass Detector: public Counted {\n  private:\n    Ref<BitMatrix> image_;\n\n  protected:\n    Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimensionX, int dimensionY,\n        Ref<PerspectiveTransform> transform);\n\n    void insertionSort(std::vector<Ref<ResultPointsAndTransitions> >& vector);\n\n    Ref<ResultPoint> correctTopRightRectangular(Ref<ResultPoint> bottomLeft,\n        Ref<ResultPoint> bottomRight, Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight,\n        int dimensionTop, int dimensionRight);\n    Ref<ResultPoint> correctTopRight(Ref<ResultPoint> bottomLeft, Ref<ResultPoint> bottomRight,\n        Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, int dimension);\n    bool isValid(Ref<ResultPoint> p);\n    int distance(Ref<ResultPoint> a, Ref<ResultPoint> b);\n    Ref<ResultPointsAndTransitions> transitionsBetween(Ref<ResultPoint> from, Ref<ResultPoint> to);\n    int min(int a, int b) {\n      return a > b ? b : a;\n    }\n    /**\n     * Ends up being a bit faster than round(). This merely rounds its\n     * argument to the nearest int, where x.5 rounds up.\n     */\n    int round(float d) {\n      return (int) (d + 0.5f);\n    }\n\n  public:\n    Ref<BitMatrix> getImage();\n    Detector(Ref<BitMatrix> image);\n\n    virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft,\n        Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft, Ref<ResultPoint> bottomRight,\n        int dimensionX, int dimensionY);\n\n    Ref<DetectorResult> detect();\n\n  private:\n    int compare(Ref<ResultPointsAndTransitions> a, Ref<ResultPointsAndTransitions> b);\n};\n\n}\n}\n\n#endif // __DETECTOR_H__\n\n// file: zxing/oned/OneDReader.h\n\n#ifndef __ONED_READER_H__\n// #define __ONED_READER_H__\n\n/*\n *  OneDReader.h\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/Reader.h>\n\nnamespace zxing {\n\tnamespace oned {\n\t\tclass OneDReader : public Reader {\n\t\tprivate:\n\t\t\tstatic const int INTEGER_MATH_SHIFT = 8;\n\n\t\t\tRef<Result> doDecode(Ref<BinaryBitmap> image, DecodeHints hints);\n\t\tpublic:\n\t\t\tstatic const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT;\n\n\t\t\tOneDReader();\n\t\t\tvirtual Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);\n\n\t\t\t// Implementations must not throw any exceptions. If a barcode is not found on this row,\n\t\t\t// a empty ref should be returned e.g. return Ref<Result>();\n\t\t\tvirtual Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row) = 0;\n\n\t\t\tstatic unsigned int patternMatchVariance(int counters[], int countersSize,\n\t\t\t    const int pattern[], int maxIndividualVariance);\n\t\t\tstatic bool recordPattern(Ref<BitArray> row, int start, int counters[], int countersCount);\n\t\t\tvirtual ~OneDReader();\n\t\t};\n\t}\n}\n\n#endif\n\n// file: zxing/oned/Code128Reader.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __CODE_128_READER_H__\n// #define __CODE_128_READER_H__\n/*\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/oned/OneDReader.h>\n// #include <zxing/common/BitArray.h>\n// #include <zxing/Result.h>\n\nnamespace zxing {\n\tnamespace oned {\n\t\tclass Code128Reader : public OneDReader {\n\n\t\tprivate:\n      enum {MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 250/1000)};\n      enum {MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 700/1000)};\n\t\t\tstatic const int CODE_SHIFT = 98;\n\n\t\t\tstatic const int CODE_CODE_C = 99;\n\t\t\tstatic const int CODE_CODE_B = 100;\n\t\t\tstatic const int CODE_CODE_A = 101;\n\n\t\t\tstatic const int CODE_FNC_1 = 102;\n\t\t\tstatic const int CODE_FNC_2 = 97;\n\t\t\tstatic const int CODE_FNC_3 = 96;\n\t\t\tstatic const int CODE_FNC_4_A = 101;\n\t\t\tstatic const int CODE_FNC_4_B = 100;\n\n\t\t\tstatic const int CODE_START_A = 103;\n\t\t\tstatic const int CODE_START_B = 104;\n\t\t\tstatic const int CODE_START_C = 105;\n\t\t\tstatic const int CODE_STOP = 106;\n\n\t\t\tstatic int* findStartPattern(Ref<BitArray> row);\n\t\t\tstatic int decodeCode(Ref<BitArray> row, int counters[], int countersCount, int rowOffset);\n\n\t\t\tvoid append(char* s, char c);\n\t\tpublic:\n\t\t\tRef<Result> decodeRow(int rowNumber, Ref<BitArray> row);\n\t\t\tCode128Reader();\n\t\t\t~Code128Reader();\n\t\t};\n\t}\n}\n\n#endif\n\n// file: zxing/oned/Code39Reader.h\n\n#ifndef __CODE_39_READER_H__\n// #define __CODE_39_READER_H__\n/*\n *  Code39Reader.h\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/oned/OneDReader.h>\n// #include <zxing/common/BitArray.h>\n// #include <zxing/Result.h>\n\nnamespace zxing {\n\tnamespace oned {\n\n\t\t/**\n\t\t * <p>Decodes Code 39 barcodes. This does not support \"Full ASCII Code 39\" yet.</p>\n\t\t * Ported form Java (author Sean Owen)\n\t\t * @author Lukasz Warchol\n\t\t */\n\t\tclass Code39Reader : public OneDReader {\n\n\t\tprivate:\n\t\t\tstd::string alphabet_string;\n\n\t\t\tbool usingCheckDigit;\n\t\t\tbool extendedMode;\n\n\t\t\tstatic int* findAsteriskPattern(Ref<BitArray> row);\t\t\t\t\t\t\t\t\t\t\t\t\t\t//throws ReaderException\n\t\t\tstatic int toNarrowWidePattern(int counters[], int countersLen);\n\t\t\tstatic char patternToChar(int pattern);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//throws ReaderException\n\t\t\tstatic Ref<String> decodeExtended(std::string encoded);\t\t\t\t\t\t\t\t\t\t\t\t\t//throws ReaderException\n\n\t\t\tvoid append(char* s, char c);\n\t\tpublic:\n\t\t\tCode39Reader();\n\t\t\tCode39Reader(bool usingCheckDigit_);\n\t\t\tCode39Reader(bool usingCheckDigit_, bool extendedMode_);\n\n\t\t\tRef<Result> decodeRow(int rowNumber, Ref<BitArray> row);\n    };\n\t}\n}\n\n#endif\n\n// file: zxing/oned/UPCEANReader.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __UPC_EAN_READER_H__\n// #define __UPC_EAN_READER_H__\n\n/*\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/oned/OneDReader.h>\n// #include <zxing/common/BitArray.h>\n// #include <zxing/Result.h>\n\ntypedef enum UPC_EAN_PATTERNS {\n\tUPC_EAN_PATTERNS_L_PATTERNS = 0,\n\tUPC_EAN_PATTERNS_L_AND_G_PATTERNS\n} UPC_EAN_PATTERNS;\n\nnamespace zxing {\n\tnamespace oned {\n\t\tclass UPCEANReader : public OneDReader {\n\n\t\tprivate:\n      enum {MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 420/1000)};\n      enum {MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 700/1000)};\n\n\t\t\tstatic bool findStartGuardPattern(Ref<BitArray> row, int* rangeStart, int* rangeEnd);\n\n\t\t\tvirtual bool decodeEnd(Ref<BitArray> row, int endStart, int* endGuardBegin, int* endGuardEnd);\n\n\t\t\tstatic bool checkStandardUPCEANChecksum(std::string s);\n\t\tprotected:\n\t\t\tstatic bool findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst,\n\t\t\t    const int pattern[], int patternLen, int* start, int* end);\n\n\t\t\tvirtual int getMIDDLE_PATTERN_LEN();\n\t\t\tvirtual const int* getMIDDLE_PATTERN();\n\n\t\tpublic:\n\t\t\tUPCEANReader();\n\n      // Returns < 0 on failure, >= 0 on success.\n\t\t\tvirtual int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,\n\t\t\t    std::string& resultString) = 0;\n\n\t\t\tRef<Result> decodeRow(int rowNumber, Ref<BitArray> row);\n\n\t\t\t// TODO(dswitkin): Should this be virtual so that UPCAReader can override it?\n\t\t\tRef<Result> decodeRow(int rowNumber, Ref<BitArray> row, int startGuardBegin,\n          int startGuardEnd);\n\n      // Returns < 0 on failure, >= 0 on success.\n\t\t\tstatic int decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset,\n\t\t\t    UPC_EAN_PATTERNS patternType);\n\n\t\t\tvirtual bool checkChecksum(std::string s);\n\n\t\t\tvirtual BarcodeFormat getBarcodeFormat() = 0;\n\t\t\tvirtual ~UPCEANReader();\n\t\t};\n\t}\n}\n\n#endif\n\n// file: zxing/oned/EAN13Reader.h\n\n#ifndef __EAN_13_READER_H__\n// #define __EAN_13_READER_H__\n\n/*\n *  EAN13Reader.h\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/oned/UPCEANReader.h>\n// #include <zxing/Result.h>\n\nnamespace zxing {\n  namespace oned {\n    class EAN13Reader : public UPCEANReader {\n\n    private:\n      static bool determineFirstDigit(std::string& resultString, int lgPatternFound);\n\n    public:\n      EAN13Reader();\n\n      int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,\n          std::string& resultString);\n\n      BarcodeFormat getBarcodeFormat();\n    };\n  }\n}\n\n#endif\n\n// file: zxing/oned/EAN8Reader.h\n\n#ifndef __EAN_8_READER_H__\n// #define __EAN_8_READER_H__\n\n/*\n *  EAN8Reader.h\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/oned/UPCEANReader.h>\n// #include <zxing/Result.h>\n\nnamespace zxing {\n  namespace oned {\n    class EAN8Reader : public UPCEANReader {\n\n    public:\n      EAN8Reader();\n\n      int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,\n          std::string& resultString);\n\n      BarcodeFormat getBarcodeFormat();\n    };\n  }\n}\n\n#endif\n\n// file: zxing/oned/ITFReader.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __ITF_READER_H__\n// #define __ITF_READER_H__\n\n/*\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/oned/OneDReader.h>\n// #include <zxing/common/BitArray.h>\n// #include <zxing/Result.h>\n\nnamespace zxing {\n\tnamespace oned {\n\t\tclass ITFReader : public OneDReader {\n\n\t\tprivate:\n      enum {MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 420/1000)};\n\t\t\tenum {MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 800/1000)};\n\t\t\t// Stores the actual narrow line width of the image being decoded.\n\t\t\tint narrowLineWidth;\n\n\t\t\tint* decodeStart(Ref<BitArray> row);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//throws ReaderException\n\t\t\tint* decodeEnd(Ref<BitArray> row);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//throws ReaderException\n\t\t\tstatic void decodeMiddle(Ref<BitArray> row, int payloadStart, int payloadEnd, std::string& resultString);\t//throws ReaderException\n\t\t\tvoid validateQuietZone(Ref<BitArray> row, int startPattern);\t\t\t\t\t\t\t\t\t\t\t\t//throws ReaderException\n\t\t\tstatic int skipWhiteSpace(Ref<BitArray> row);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//throws ReaderException\n\n\t\t\tstatic int* findGuardPattern(Ref<BitArray> row, int rowOffset, const int pattern[], int patternLen);\t\t//throws ReaderException\n\t\t\tstatic int decodeDigit(int counters[], int countersLen);\t\t\t\t\t\t\t\t\t\t\t\t\t//throws ReaderException\n\n\t\t\tvoid append(char* s, char c);\n\t\tpublic:\n\t\t\tRef<Result> decodeRow(int rowNumber, Ref<BitArray> row);\t\t\t\t\t\t\t\t\t///throws ReaderException\n\t\t\tITFReader();\n\t\t\t~ITFReader();\n\t\t};\n\t}\n}\n\n#endif\n\n// file: zxing/oned/MultiFormatOneDReader.h\n\n#ifndef __MULTI_FORMAT_ONED_READER_H__\n// #define __MULTI_FORMAT_ONED_READER_H__\n/*\n *  MultiFormatOneDReader.h\n *  ZXing\n *\n  *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/oned/OneDReader.h>\n\nnamespace zxing {\n  namespace oned {\n    class MultiFormatOneDReader : public OneDReader {\n\n    private:\n      std::vector<Ref<OneDReader> > readers;\n    public:\n      MultiFormatOneDReader(DecodeHints hints);\n\n      Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);\n    };\n  }\n}\n\n#endif\n\n// file: zxing/oned/MultiFormatUPCEANReader.h\n\n#ifndef __MULTI_FORMAT_UPC_EAN_READER_H__\n// #define __MULTI_FORMAT_UPC_EAN_READER_H__\n/*\n *  MultiFormatUPCEANReader.h\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/oned/OneDReader.h>\n\nnamespace zxing {\n  namespace oned {\n    class MultiFormatUPCEANReader : public OneDReader {\n\n    private:\n      std::vector<Ref<OneDReader> > readers;\n    public:\n      MultiFormatUPCEANReader(DecodeHints hints);\n\n      Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);\n    };\n  }\n}\n\n#endif\n\n// file: zxing/oned/OneDResultPoint.h\n\n#ifndef __ONED_RESULT_POINT_H__\n// #define __ONED_RESULT_POINT_H__\n/*\n *  OneDResultPoint.h\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n// #include <zxing/ResultPoint.h>\n// #include <cmath>\n\nnamespace zxing {\n\tnamespace oned {\n\n\t\tclass OneDResultPoint : public ResultPoint {\n\n\t\tpublic:\n\t\t\tOneDResultPoint(float posX, float posY);\n\t\t};\n\t}\n}\n\n#endif\n\n// file: zxing/oned/UPCAReader.h\n\n#ifndef __UPCA_READER_H__\n// #define __UPCA_READER_H__\n/*\n *  UPCAReader.h\n *  ZXing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/oned/EAN13Reader.h>\n// #include <zxing/DecodeHints.h>\n\nnamespace zxing {\n  namespace oned {\n    class UPCAReader : public UPCEANReader {\n\n    private:\n      EAN13Reader ean13Reader;\n      static Ref<Result> maybeReturnResult(Ref<Result> result);\n\n    public:\n      UPCAReader();\n\n      int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,\n          std::string& resultString);\n\n      Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);\n      Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row, int startGuardBegin,\n          int startGuardEnd);\n      Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);\n\n      BarcodeFormat getBarcodeFormat();\n    };\n  }\n}\n\n#endif\n\n// file: zxing/oned/UPCEReader.h\n\n#ifndef __UPC_E_READER_H__\n// #define __UPC_E_READER_H__\n\n/*\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/oned/UPCEANReader.h>\n// #include <zxing/Result.h>\n\nnamespace zxing {\n  namespace oned {\n    class UPCEReader : public UPCEANReader {\n\n    private:\n      static bool determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound);\n    protected:\n      bool decodeEnd(Ref<BitArray> row, int endStart, int* endGuardBegin, int* endGuardEnd);\n      bool checkChecksum(std::string s);\n    public:\n      UPCEReader();\n\n      int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,\n          std::string& resultString);\n      static std::string convertUPCEtoUPCA(std::string upce);\n\n      BarcodeFormat getBarcodeFormat();\n    };\n  }\n}\n\n#endif\n\n// file: zxing/qrcode/ErrorCorrectionLevel.h\n\n#ifndef __ERROR_CORRECTION_LEVEL_H__\n// #define __ERROR_CORRECTION_LEVEL_H__\n\n/*\n *  ErrorCorrectionLevel.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ReaderException.h>\n\nnamespace zxing {\nnamespace qrcode {\n\nclass ErrorCorrectionLevel {\nprivate:\n  int ordinal_;\n  int bits_;\n  std::string name_;\n  ErrorCorrectionLevel(int inOrdinal, int bits, char const* name);\n  static ErrorCorrectionLevel *FOR_BITS[];\n  static int N_LEVELS;\npublic:\n  static ErrorCorrectionLevel L;\n  static ErrorCorrectionLevel M;\n  static ErrorCorrectionLevel Q;\n  static ErrorCorrectionLevel H;\n\n  int ordinal() const;\n  int bits() const;\n  std::string const& name() const;\n  operator std::string const& () const;\n\n  static ErrorCorrectionLevel& forBits(int bits);\n};\n}\n}\n\n#endif // __ERROR_CORRECTION_LEVEL_H__\n\n// file: zxing/qrcode/FormatInformation.h\n\n#ifndef __FORMAT_INFORMATION_H__\n// #define __FORMAT_INFORMATION_H__\n\n/*\n *  FormatInformation.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/ErrorCorrectionLevel.h>\n// #include <zxing/common/Counted.h>\n// #include <iostream>\n\nnamespace zxing {\nnamespace qrcode {\n\nclass FormatInformation : public Counted {\nprivate:\n  static int FORMAT_INFO_MASK_QR;\n  static int FORMAT_INFO_DECODE_LOOKUP[][2];\n  static int N_FORMAT_INFO_DECODE_LOOKUPS;\n  static int BITS_SET_IN_HALF_BYTE[];\n\n  ErrorCorrectionLevel &errorCorrectionLevel_;\n  unsigned char dataMask_;\n\n  FormatInformation(int formatInfo);\n\npublic:\n  static int numBitsDiffering(unsigned int a, unsigned int b);\n  static Ref<FormatInformation> decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2);\n  static Ref<FormatInformation> doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2);\n  ErrorCorrectionLevel &getErrorCorrectionLevel();\n  unsigned char getDataMask();\n  friend bool operator==(const FormatInformation &a, const FormatInformation &b);\n  friend std::ostream& operator<<(std::ostream& out, const FormatInformation& fi);\n};\n}\n}\n\n#endif // __FORMAT_INFORMATION_H__\n\n// file: zxing/qrcode/decoder/Decoder.h\n\n#ifndef __DECODER_H__\n// #define __DECODER_H__\n\n/*\n *  Decoder.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/reedsolomon/ReedSolomonDecoder.h>\n// #include <zxing/common/reedsolomon/GF256.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/Array.h>\n// #include <zxing/common/DecoderResult.h>\n// #include <zxing/common/BitMatrix.h>\n\nnamespace zxing {\nnamespace qrcode {\n\nclass Decoder {\nprivate:\n  ReedSolomonDecoder rsDecoder_;\n\n  void correctErrors(ArrayRef<unsigned char> bytes, int numDataCodewords);\n\npublic:\n  Decoder();\n  Ref<DecoderResult> decode(Ref<BitMatrix> bits);\n};\n\n}\n}\n\n#endif // __DECODER_H__\n\n// file: zxing/qrcode/QRCodeReader.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __QR_CODE_READER_H__\n// #define __QR_CODE_READER_H__\n\n/*\n *  QRCodeReader.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/Reader.h>\n// #include <zxing/qrcode/decoder/Decoder.h>\n// #include <zxing/DecodeHints.h>\n\nnamespace zxing {\n\tnamespace qrcode {\n\n\t\tclass QRCodeReader : public Reader {\n\t\tprivate:\n\t\t\tDecoder decoder_;\n\n    protected:\n      Decoder& getDecoder();\n\n\t\tpublic:\n\t\t\tQRCodeReader();\n\t\t\tvirtual Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);\n\t\t\tvirtual ~QRCodeReader();\n\n\t\t};\n\t}\n}\n\n#endif // __QR_CODE_READER_H__\n\n// file: zxing/qrcode/Version.h\n\n#ifndef __VERSION_H__\n// #define __VERSION_H__\n\n/*\n *  Version.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n// #include <zxing/qrcode/ErrorCorrectionLevel.h>\n// #include <zxing/ReaderException.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/common/Counted.h>\n// #include <vector>\n\nnamespace zxing {\nnamespace qrcode {\n\nclass ECB {\nprivate:\n  int count_;\n  int dataCodewords_;\npublic:\n  ECB(int count, int dataCodewords);\n  int getCount();\n  int getDataCodewords();\n};\n\nclass ECBlocks {\nprivate:\n  int ecCodewords_;\n  std::vector<ECB*> ecBlocks_;\npublic:\n  ECBlocks(int ecCodewords, ECB *ecBlocks);\n  ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2);\n  int getECCodewords();\n  std::vector<ECB*>& getECBlocks();\n  ~ECBlocks();\n};\n\nclass Version : public Counted {\n\nprivate:\n  int versionNumber_;\n  std::vector<int> &alignmentPatternCenters_;\n  std::vector<ECBlocks*> ecBlocks_;\n  int totalCodewords_;\n  Version(int versionNumber, std::vector<int> *alignmentPatternCenters, ECBlocks *ecBlocks1, ECBlocks *ecBlocks2,\n          ECBlocks *ecBlocks3, ECBlocks *ecBlocks4);\n\npublic:\n  static unsigned int VERSION_DECODE_INFO[];\n  static int N_VERSION_DECODE_INFOS;\n  static std::vector<Ref<Version> > VERSIONS;\n\n  ~Version();\n  int getVersionNumber();\n  std::vector<int> &getAlignmentPatternCenters();\n  int getTotalCodewords();\n  int getDimensionForVersion();\n  ECBlocks &getECBlocksForLevel(ErrorCorrectionLevel &ecLevel);\n  static Version *getProvisionalVersionForDimension(int dimension);\n  static Version *getVersionForNumber(int versionNumber);\n  static Version *decodeVersionInformation(unsigned int versionBits);\n  Ref<BitMatrix> buildFunctionPattern();\n  static int buildVersions();\n};\n}\n}\n\n#endif // __VERSION_H__\n\n// file: zxing/qrcode/decoder/BitMatrixParser.h\n\n#ifndef __BIT_MATRIX_PARSER_H__\n// #define __BIT_MATRIX_PARSER_H__\n\n/*\n *  BitMatrixParser.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ReaderException.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/Array.h>\n// #include <zxing/qrcode/Version.h>\n// #include <zxing/qrcode/FormatInformation.h>\n\nnamespace zxing {\nnamespace qrcode {\n\nclass BitMatrixParser : public Counted {\nprivate:\n  Ref<BitMatrix> bitMatrix_;\n  Version *parsedVersion_;\n  Ref<FormatInformation> parsedFormatInfo_;\n\n  int copyBit(size_t x, size_t y, int versionBits);\n\npublic:\n  BitMatrixParser(Ref<BitMatrix> bitMatrix);\n  Ref<FormatInformation> readFormatInformation();\n  Version *readVersion();\n  ArrayRef<unsigned char> readCodewords();\n\nprivate:\n  BitMatrixParser(const BitMatrixParser&);\n  BitMatrixParser& operator =(const BitMatrixParser&);\n\n};\n\n}\n}\n\n#endif // __BIT_MATRIX_PARSER_H__\n\n// file: zxing/qrcode/decoder/DataBlock.h\n\n#ifndef __DATA_BLOCK_H__\n// #define __DATA_BLOCK_H__\n\n/*\n *  DataBlock.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <vector>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/Array.h>\n// #include <zxing/qrcode/Version.h>\n// #include <zxing/qrcode/ErrorCorrectionLevel.h>\n\nnamespace zxing {\nnamespace qrcode {\n\nclass DataBlock : public Counted {\nprivate:\n  int numDataCodewords_;\n  ArrayRef<unsigned char> codewords_;\n\n  DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords);\n\npublic:\n  static std::vector<Ref<DataBlock> >\n  getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version, ErrorCorrectionLevel &ecLevel);\n\n  int getNumDataCodewords();\n  ArrayRef<unsigned char> getCodewords();\n};\n\n}\n}\n\n#endif // __DATA_BLOCK_H__\n\n// file: zxing/qrcode/decoder/DataMask.h\n\n#ifndef __DATA_MASK_H__\n// #define __DATA_MASK_H__\n\n/*\n *  DataMask.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Array.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/BitMatrix.h>\n\n// #include <vector>\n\nnamespace zxing {\nnamespace qrcode {\n\nclass DataMask : public Counted {\nprivate:\n  static std::vector<Ref<DataMask> > DATA_MASKS;\n\nprotected:\n\npublic:\n  static int buildDataMasks();\n  DataMask();\n  virtual ~DataMask();\n  void unmaskBitMatrix(BitMatrix& matrix, size_t dimension);\n  virtual bool isMasked(size_t x, size_t y) = 0;\n  static DataMask& forReference(int reference);\n};\n\n}\n}\n\n#endif // __DATA_MASK_H__\n\n// file: zxing/qrcode/decoder/Mode.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __MODE_H__\n// #define __MODE_H__\n\n/*\n *  Mode.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n// #include <zxing/qrcode/Version.h>\n\nnamespace zxing {\nnamespace qrcode {\n\nclass Mode {\nprivate:\n  int characterCountBitsForVersions0To9_;\n  int characterCountBitsForVersions10To26_;\n  int characterCountBitsForVersions27AndHigher_;\n  int bits_;\n  std::string name_;\n\n  Mode(int cbv0_9, int cbv10_26, int cbv27, int bits, char const* name);\n\npublic:\n  static Mode TERMINATOR;\n  static Mode NUMERIC;\n  static Mode ALPHANUMERIC;\n  static Mode STRUCTURED_APPEND;\n  static Mode BYTE;\n  static Mode ECI;\n  static Mode KANJI;\n  static Mode FNC1_FIRST_POSITION;\n  static Mode FNC1_SECOND_POSITION;\n  static Mode HANZI;\n\n  static Mode& forBits(int bits);\n  int getCharacterCountBits(Version *version);\n};\n}\n}\n\n#endif // __MODE_H__\n\n// file: zxing/common/ECI.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n\n#ifndef __ECI__\n#define __ECI__\n\n/*\n * Copyright 2008-2011 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nnamespace zxing {\n  namespace common {\n    class ECI;\n  }\n}\nclass zxing::common::ECI {\nprivate:\n  const int value;\n\nprotected:\n  ECI(int value);\n\npublic:\n  int getValue() const;\n\n  static ECI* getECIByValue(int value);\n};\n\n#endif\n\n// file: zxing/common/CharacterSetECI.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n\n#ifndef __CHARACTERSET_ECI__\n#define __CHARACTERSET_ECI__\n\n/*\n * Copyright 2008-2011 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <map>\n// #include <zxing/common/ECI.h>\n// #include <zxing/DecodeHints.h>\n\nnamespace zxing {\n  namespace common {\n    class CharacterSetECI;\n  }\n}\n\nclass zxing::common::CharacterSetECI : public ECI {\nprivate:\n  static std::map<int, CharacterSetECI*> VALUE_TO_ECI;\n  static std::map<std::string, CharacterSetECI*> NAME_TO_ECI;\n  static const bool inited;\n  static bool init_tables();\n\n  char const* const encodingName;\n\n  CharacterSetECI(int value, char const* encodingName);\n\n  static void addCharacterSet(int value, char const* encodingName);\n  static void addCharacterSet(int value, char const* const* encodingNames);\n\npublic:\n  char const* getEncodingName();\n\n  static CharacterSetECI* getCharacterSetECIByValue(int value);\n  static CharacterSetECI* getCharacterSetECIByName(std::string const& name);\n};\n\n#endif\n\n// file: zxing/qrcode/decoder/DecodedBitStreamParser.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n\n#ifndef __DECODED_BIT_STREAM_PARSER_H__\n// #define __DECODED_BIT_STREAM_PARSER_H__\n\n/*\n *  DecodedBitStreamParser.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <string>\n// #include <sstream>\n// #include <map>\n// #include <zxing/qrcode/decoder/Mode.h>\n// #include <zxing/common/BitSource.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/Array.h>\n// #include <zxing/common/DecoderResult.h>\n// #include <zxing/common/CharacterSetECI.h>\n// #include <zxing/DecodeHints.h>\n\nnamespace zxing {\nnamespace qrcode {\n\nclass DecodedBitStreamParser {\npublic:\n  typedef std::map<DecodeHintType, std::string> Hashtable;\n\nprivate:\n  static char const ALPHANUMERIC_CHARS[];\n  static char toAlphaNumericChar(size_t value);\n\n  static void decodeHanziSegment(Ref<BitSource> bits, std::string &result, int count);\n  static void decodeKanjiSegment(Ref<BitSource> bits, std::string &result, int count);\n  static void decodeByteSegment(Ref<BitSource> bits, std::string &result, int count);\n  static void decodeByteSegment(Ref<BitSource> bits_,\n                                std::string& result,\n                                int count,\n                                zxing::common::CharacterSetECI* currentCharacterSetECI,\n                                ArrayRef< ArrayRef<unsigned char> >& byteSegments,\n                                Hashtable const& hints);\n  static void decodeAlphanumericSegment(Ref<BitSource> bits, std::string &result, int count, bool fc1InEffect);\n  static void decodeNumericSegment(Ref<BitSource> bits, std::string &result, int count);\n\n  static void append(std::string &ost, const unsigned char *bufIn, size_t nIn, const char *src);\n  static void append(std::string &ost, std::string const& in, const char *src);\n\npublic:\n  static Ref<DecoderResult> decode(ArrayRef<unsigned char> bytes,\n                                   Version *version,\n                                   ErrorCorrectionLevel const& ecLevel,\n                                   Hashtable const& hints);\n};\n\n}\n}\n\n#endif // __DECODED_BIT_STREAM_PARSER_H__\n\n// file: zxing/qrcode/detector/AlignmentPattern.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n\n#ifndef __ALIGNMENT_PATTERN_H__\n// #define __ALIGNMENT_PATTERN_H__\n\n/*\n *  AlignmentPattern.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ResultPoint.h>\n// #include <cmath>\n\nnamespace zxing {\n\tnamespace qrcode {\n\n\t\tclass AlignmentPattern : public ResultPoint {\n\t\tprivate:\n\t\t\tfloat estimatedModuleSize_;\n\n\t\tpublic:\n\t\t\tAlignmentPattern(float posX, float posY, float estimatedModuleSize);\n\t\t\tbool aboutEquals(float moduleSize, float i, float j) const;\n      Ref<AlignmentPattern> combineEstimate(float i, float j,\n                                            float newModuleSize) const;\n\t\t};\n\n\t}\n}\n\n#endif // __ALIGNMENT_PATTERN_H__\n\n// file: zxing/qrcode/detector/AlignmentPatternFinder.h\n\n#ifndef __ALIGNMENT_PATTERN_FINDER_H__\n// #define __ALIGNMENT_PATTERN_FINDER_H__\n\n/*\n *  AlignmentPatternFinder.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include \"AlignmentPattern.h\"\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/ResultPointCallback.h>\n// #include <vector>\n\nnamespace zxing {\nnamespace qrcode {\n\nclass AlignmentPatternFinder : public Counted {\nprivate:\n  static int CENTER_QUORUM;\n  static int MIN_SKIP;\n  static int MAX_MODULES;\n\n  Ref<BitMatrix> image_;\n  std::vector<AlignmentPattern *> *possibleCenters_;\n  size_t startX_;\n  size_t startY_;\n  size_t width_;\n  size_t height_;\n  float moduleSize_;\n\n  static float centerFromEnd(std::vector<int> &stateCount, int end);\n  bool foundPatternCross(std::vector<int> &stateCount);\n\n  float crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal);\n\n  Ref<AlignmentPattern> handlePossibleCenter(std::vector<int> &stateCount, size_t i, size_t j);\n\npublic:\n  AlignmentPatternFinder(Ref<BitMatrix> image, size_t startX, size_t startY, size_t width, size_t height,\n                         float moduleSize, Ref<ResultPointCallback>const& callback);\n  ~AlignmentPatternFinder();\n  Ref<AlignmentPattern> find();\n\nprivate:\n  AlignmentPatternFinder(const AlignmentPatternFinder&);\n  AlignmentPatternFinder& operator =(const AlignmentPatternFinder&);\n\n  Ref<ResultPointCallback> callback_;\n};\n}\n}\n\n#endif // __ALIGNMENT_PATTERN_FINDER_H__\n\n// file: zxing/qrcode/detector/FinderPattern.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n#ifndef __FINDER_PATTERN_H__\n// #define __FINDER_PATTERN_H__\n\n/*\n *  FinderPattern.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ResultPoint.h>\n// #include <cmath>\n\nnamespace zxing {\n\tnamespace qrcode {\n\n\t\tclass FinderPattern : public ResultPoint {\n\t\tprivate:\n\t\t\tfloat estimatedModuleSize_;\n\t\t\tint count_;\n\n\t\tpublic:\n\t\t\tFinderPattern(float posX, float posY, float estimatedModuleSize);\n\t\t\tFinderPattern(float posX, float posY, float estimatedModuleSize, int count);\n\t\t\tint getCount() const;\n\t\t\tfloat getEstimatedModuleSize() const;\n\t\t\tvoid incrementCount();\n\t\t\tbool aboutEquals(float moduleSize, float i, float j) const;\n\t\t\tRef<FinderPattern> combineEstimate(float i, float j, float newModuleSize) const;\n\t\t};\n\t}\n}\n\n#endif // __FINDER_PATTERN_H__\n\n// file: zxing/qrcode/detector/FinderPatternInfo.h\n\n#ifndef __FINDER_PATTERN_INFO_H__\n// #define __FINDER_PATTERN_INFO_H__\n\n/*\n *  FinderPatternInfo.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/detector/FinderPattern.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/Array.h>\n// #include <vector>\n\nnamespace zxing {\nnamespace qrcode {\n\nclass FinderPatternInfo : public Counted {\nprivate:\n  Ref<FinderPattern> bottomLeft_;\n  Ref<FinderPattern> topLeft_;\n  Ref<FinderPattern> topRight_;\n\npublic:\n  FinderPatternInfo(std::vector<Ref<FinderPattern> > patternCenters);\n\n  Ref<FinderPattern> getBottomLeft();\n  Ref<FinderPattern> getTopLeft();\n  Ref<FinderPattern> getTopRight();\n};\n}\n}\n\n#endif // __FINDER_PATTERN_INFO_H__\n\n// file: zxing/qrcode/detector/Detector.h\n\n#ifndef __DETECTOR_H__\n// #define __DETECTOR_H__\n\n/*\n *  Detector.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/DetectorResult.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/qrcode/detector/AlignmentPattern.h>\n// #include <zxing/common/PerspectiveTransform.h>\n// #include <zxing/ResultPointCallback.h>\n// #include <zxing/qrcode/detector/FinderPatternInfo.h>\n\nnamespace zxing {\n\nclass DecodeHints;\n\nnamespace qrcode {\n\nclass Detector : public Counted {\nprivate:\n  Ref<BitMatrix> image_;\n  Ref<ResultPointCallback> callback_;\n\nprotected:\n  Ref<BitMatrix> getImage();\n\n  static Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform>);\n  static int computeDimension(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft,\n                              float moduleSize);\n  float calculateModuleSize(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft);\n  float calculateModuleSizeOneWay(Ref<ResultPoint> pattern, Ref<ResultPoint> otherPattern);\n  float sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY);\n  float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY);\n  Ref<AlignmentPattern> findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY,\n      float allowanceFactor);\n  Ref<DetectorResult> processFinderPatternInfo(Ref<FinderPatternInfo> info);\npublic:\n\n  virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <\n      ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension);\n\n  Detector(Ref<BitMatrix> image);\n  Ref<DetectorResult> detect(DecodeHints const& hints);\n};\n}\n}\n\n#endif // __DETECTOR_H__\n\n// file: zxing/qrcode/detector/FinderPatternFinder.h\n\n#ifndef __FINDER_PATTERN_FINDER_H__\n// #define __FINDER_PATTERN_FINDER_H__\n\n/*\n *  FinderPatternFinder.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/detector/FinderPattern.h>\n// #include <zxing/qrcode/detector/FinderPatternInfo.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/ResultPointCallback.h>\n// #include <vector>\n\nnamespace zxing {\n\nclass DecodeHints;\n\nnamespace qrcode {\n\nclass FinderPatternFinder {\nprivate:\n  static int CENTER_QUORUM;\n\nprotected:\n  static int MIN_SKIP;\n  static int MAX_MODULES;\n\n  Ref<BitMatrix> image_;\n  std::vector<Ref<FinderPattern> > possibleCenters_;\n  bool hasSkipped_;\n\n  Ref<ResultPointCallback> callback_;\n\n  /** stateCount must be int[5] */\n  static float centerFromEnd(int* stateCount, int end);\n  static bool foundPatternCross(int* stateCount);\n\n  float crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal);\n  float crossCheckHorizontal(size_t startJ, size_t centerI, int maxCount, int originalStateCountTotal);\n\n  /** stateCount must be int[5] */\n  bool handlePossibleCenter(int* stateCount, size_t i, size_t j);\n  int findRowSkip();\n  bool haveMultiplyConfirmedCenters();\n  std::vector<Ref<FinderPattern> > selectBestPatterns();\n  static std::vector<Ref<FinderPattern> > orderBestPatterns(std::vector<Ref<FinderPattern> > patterns);\npublic:\n  static float distance(Ref<ResultPoint> p1, Ref<ResultPoint> p2);\n  FinderPatternFinder(Ref<BitMatrix> image, Ref<ResultPointCallback>const&);\n  Ref<FinderPatternInfo> find(DecodeHints const& hints);\n};\n}\n}\n\n#endif // __FINDER_PATTERN_FINDER_H__\n\n// file: zxing/qrcode/detector/QREdgeDetector.h\n\n#ifndef __QREDGEDETECTOR_H__\n// #define __QREDGEDETECTOR_H__\n/*\n *  QREdgeDetector.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n\n// #include <zxing/qrcode/detector/Detector.h>\n// #include <zxing/common/Point.h>\n\nnamespace zxing {\nnamespace qrcode {\n\nclass QREdgeDetector : public Detector {\npublic:\n  QREdgeDetector(Ref<BitMatrix> image);\n\n  virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <\n      ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension);\n\nprivate:\n  Point findCorner(const BitMatrix& image, Point topLeft, Point topRight, Point bottomLeft, int dimension);\n  Line findPatternEdge(const BitMatrix& image, Point pattern, Point opposite, Point direction, bool invert);\n\n  Point endOfReverseBlackWhiteBlackRun(const BitMatrix& image, Point from, Point to);\n\n  Ref<PerspectiveTransform> get1CornerTransform(Point topLeft, Point topRight, Point bottomLeft, Point corner, int dimension);\n};\n\n}\n}\n#endif // QREDGEDETECTOR_H_\n\n// file: zxing/FormatException.h\n\n#ifndef __FORMAT_EXCEPTION_H__\n// #define __FORMAT_EXCEPTION_H__\n\n/*\n *  FormatException.h\n *  zxing\n *\n *  Copyright 2010 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ReaderException.h>\n\nnamespace zxing {\n\nclass FormatException : public ReaderException {\npublic:\n  FormatException();\n  FormatException(const char *msg);\n  ~FormatException() throw();\n};\n\n}\n#endif // __FORMAT_EXCEPTION_H__\n\n// file: zxing/NotFoundException.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n\n#ifndef __NOT_FOUND_EXCEPTION_H__\n// #define __NOT_FOUND_EXCEPTION_H__\n\n/*\n * Copyright 20011 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/ReaderException.h>\n\nnamespace zxing {\n\n  class NotFoundException : public ReaderException {\n  public:\n    NotFoundException(const char *msg);\n    ~NotFoundException() throw();\n  };\n\n}\n#endif // __NOT_FOUND_EXCEPTION_H__\n\n// file: zxing/common/StringUtils.h\n\n// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-\n\n#ifndef __STRING_UTILS__\n#define __STRING_UTILS__\n\n/*\n * Copyright (C) 2010-2011 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <string>\n// #include <map>\n// #include <zxing/DecodeHints.h>\n\nnamespace zxing {\n  namespace common {\n    class StringUtils;\n  }\n}\n\nclass zxing::common::StringUtils {\nprivate:\n  static char const* const PLATFORM_DEFAULT_ENCODING;\n\n  StringUtils() {}\n\npublic:\n  static char const* const ASCII;\n  static char const* const SHIFT_JIS;\n  static char const* const GB2312;\n  static char const* const EUC_JP;\n  static char const* const UTF8;\n  static char const* const ISO88591;\n  static const bool ASSUME_SHIFT_JIS;\n\n  typedef std::map<DecodeHintType, std::string> Hashtable;\n\n  static std::string guessEncoding(unsigned char* bytes, int length, Hashtable const& hints);\n};\n\n#endif\n\n// file: zxing/common/detector/MonochromeRectangleDetector.h\n\n#ifndef __MONOCHROMERECTANGLEDETECTOR_H__\n// #define __MONOCHROMERECTANGLEDETECTOR_H__\n\n/*\n *  MonochromeRectangleDetector.h\n *  y_wmk\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010 y_wmk authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <vector>\n// #include <zxing/NotFoundException.h>\n// #include <zxing/ResultPoint.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/ResultPoint.h>\n\n\nnamespace zxing {\n\nstruct TwoInts: public Counted {\n\tint start;\n\tint end;\n};\n\nclass MonochromeRectangleDetector : public Counted {\nprivate:\n  static const int MAX_MODULES = 32;\n  Ref<BitMatrix> image_;\n\npublic:\n  MonochromeRectangleDetector(Ref<BitMatrix> image) : image_(image) {  };\n\n  std::vector<Ref<ResultPoint> > detect();\n\nprivate:\n  Ref<ResultPoint> findCornerFromCenter(int centerX, int deltaX, int left, int right,\n      int centerY, int deltaY, int top, int bottom, int maxWhiteRun);\n\n  Ref<TwoInts> blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim,\n      bool horizontal);\n\n  int max(int a, float b) { return (float) a > b ? a : (int) b;};\n};\n}\n\n#endif // __MONOCHROMERECTANGLEDETECTOR_H__\n\n// file: zxing/common/detector/WhiteRectangleDetector.h\n\n#ifndef __WHITERECTANGLEDETECTOR_H__\n// #define __WHITERECTANGLEDETECTOR_H__\n\n/*\n *  WhiteRectangleDetector.h\n *\n *\n *  Created by Luiz Silva on 09/02/2010.\n *  Copyright 2010  authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <vector>\n// #include <zxing/ReaderException.h>\n// #include <zxing/ResultPoint.h>\n// #include <zxing/common/BitMatrix.h>\n// #include <zxing/common/Counted.h>\n// #include <zxing/ResultPoint.h>\n\n\nnamespace zxing {\n\nclass WhiteRectangleDetector : public Counted {\n  private:\n    static int INIT_SIZE;\n    static int CORR;\n    Ref<BitMatrix> image_;\n    int width_;\n    int height_;\n\n  public:\n    WhiteRectangleDetector(Ref<BitMatrix> image);\n    std::vector<Ref<ResultPoint> > detect();\n\n  private:\n    int round(float a);\n    Ref<ResultPoint> getBlackPointOnSegment(float aX, float aY, float bX, float bY);\n    int distanceL2(float aX, float aY, float bX, float bY);\n    std::vector<Ref<ResultPoint> > centerEdges(Ref<ResultPoint> y, Ref<ResultPoint> z,\n                                    Ref<ResultPoint> x, Ref<ResultPoint> t);\n    bool containsBlackPoint(int a, int b, int fixed, bool horizontal);\n};\n}\n\n#endif\n\n// file: zxing/datamatrix/detector/DetectorException.h\n\n/*\n * DetectorException.h\n *\n *  Created on: Aug 26, 2011\n *      Author: luiz\n */\n\n#ifndef DETECTOREXCEPTION_H_\n#define DETECTOREXCEPTION_H_\n\n// #include <zxing/Exception.h>\n\nnamespace zxing {\nnamespace datamatrix {\n\nclass DetectorException : public Exception {\n  public:\n    DetectorException(const char *msg);\n    virtual ~DetectorException() throw();\n};\n} /* namespace nexxera */\n} /* namespace zxing */\n#endif /* DETECTOREXCEPTION_H_ */\n\n// file: zxing/multi/ByQuadrantReader.h\n\n#ifndef __BY_QUADRANT_READER_H__\n// #define __BY_QUADRANT_READER_H__\n\n/*\n *  Copyright 2011 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/Reader.h>\n// #include <zxing/BinaryBitmap.h>\n// #include <zxing/Result.h>\n// #include <zxing/DecodeHints.h>\n\nnamespace zxing {\nnamespace multi {\nclass ByQuadrantReader : public Reader {\n  private:\n    Reader& delegate_;\n\n  public:\n    ByQuadrantReader(Reader& delegate);\n    virtual ~ByQuadrantReader();\n    virtual Ref<Result> decode(Ref<BinaryBitmap> image);\n    virtual Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);\n};\n} // End zxing::multi namespace\n} // End zxing namespace\n\n#endif // __BY_QUADRANT_READER_H__\n\n// file: zxing/multi/MultipleBarcodeReader.h\n\n#ifndef __MULTIPLE_BARCODE_READER_H__\n// #define __MULTIPLE_BARCODE_READER_H__\n\n/*\n *  Copyright 2011 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/common/Counted.h>\n// #include <zxing/Result.h>\n// #include <zxing/BinaryBitmap.h>\n// #include <zxing/DecodeHints.h>\n// #include <vector>\n\nnamespace zxing {\nnamespace multi {\nclass MultipleBarcodeReader : public Counted {\n  protected:\n    MultipleBarcodeReader() {}\n  public:\n    virtual std::vector<Ref<Result> > decodeMultiple(Ref<BinaryBitmap> image);\n    virtual std::vector<Ref<Result> > decodeMultiple(Ref<BinaryBitmap> image, DecodeHints hints) = 0;\n    virtual ~MultipleBarcodeReader();\n};\n} // End zxing::multi namespace\n} // End zxing namespace\n\n#endif // __MULTIPLE_BARCODE_READER_H__\n\n// file: zxing/multi/GenericMultipleBarcodeReader.h\n\n#ifndef __GENERIC_MULTIPLE_BARCODE_READER_H__\n// #define __GENERIC_MULTIPLE_BARCODE_READER_H__\n\n/*\n *  Copyright 2011 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/multi/MultipleBarcodeReader.h>\n// #include <zxing/Reader.h>\n\nnamespace zxing {\nnamespace multi {\nclass GenericMultipleBarcodeReader : public MultipleBarcodeReader {\n  private:\n    static Ref<Result> translateResultPoints(Ref<Result> result,\n                                             int xOffset,\n                                             int yOffset);\n    void doDecodeMultiple(Ref<BinaryBitmap> image,\n                          DecodeHints hints,\n                          std::vector<Ref<Result> >& results,\n                          int xOffset,\n                          int yOffset);\n    Reader& delegate_;\n    static const int MIN_DIMENSION_TO_RECUR = 100;\n\n  public:\n    GenericMultipleBarcodeReader(Reader& delegate);\n    virtual ~GenericMultipleBarcodeReader();\n    virtual std::vector<Ref<Result> > decodeMultiple(Ref<BinaryBitmap> image,\n                                                     DecodeHints hints);\n};\n} // End zxing::multi namespace\n} // End zxing namespace\n\n#endif // __GENERIC_MULTIPLE_BARCODE_READER_H__\n\n// file: zxing/multi/qrcode/QRCodeMultiReader.h\n\n#ifndef __QRCODE_MULTI_READER_H__\n// #define __QRCODE_MULTI_READER_H__\n\n/*\n *  Copyright 2011 ZXing authors All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/multi/MultipleBarcodeReader.h>\n// #include <zxing/qrcode/QRCodeReader.h>\n\nnamespace zxing {\nnamespace multi {\nclass QRCodeMultiReader: public zxing::qrcode::QRCodeReader, public MultipleBarcodeReader {\n  public:\n    QRCodeMultiReader();\n    virtual ~QRCodeMultiReader();\n    virtual std::vector<Ref<Result> > decodeMultiple(Ref<BinaryBitmap> image, DecodeHints hints);\n};\n} // End zxing::multi namespace\n} // End zxing namespace\n\n#endif // __QRCODE_MULTI_READER_H__\n\n// file: zxing/multi/qrcode/detector/MultiDetector.h\n\n#ifndef __MULTI_DETECTOR_H__\n// #define __MULTI_DETECTOR_H__\n\n/*\n *  Copyright 2011 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/detector/Detector.h>\n// #include <zxing/common/DetectorResult.h>\n// #include <zxing/DecodeHints.h>\n\nnamespace zxing {\nnamespace multi {\nclass MultiDetector : public zxing::qrcode::Detector {\n  public:\n    MultiDetector(Ref<BitMatrix> image);\n    virtual ~MultiDetector();\n    virtual std::vector<Ref<DetectorResult> > detectMulti(DecodeHints hints);\n};\n} // End zxing::multi namespace\n} // End zxing namespace\n\n#endif // __MULTI_DETECTOR_H__\n\n// file: zxing/multi/qrcode/detector/MultiFinderPatternFinder.h\n\n#ifndef __MULTI_FINDER_PATTERN_FINDER_H__\n// #define __MULTI_FINDER_PATTERN_FINDER_H__\n\n/*\n *  Copyright 2011 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// #include <zxing/qrcode/detector/FinderPattern.h>\n// #include <zxing/qrcode/detector/FinderPatternFinder.h>\n// #include <zxing/qrcode/detector/FinderPatternInfo.h>\n\nnamespace zxing {\nnamespace multi {\nclass MultiFinderPatternFinder : zxing::qrcode::FinderPatternFinder {\n  private:\n    std::vector<std::vector<Ref<zxing::qrcode::FinderPattern> > > selectBestPatterns();\n\n    static const float MAX_MODULE_COUNT_PER_EDGE;\n    static const float MIN_MODULE_COUNT_PER_EDGE;\n    static const float DIFF_MODSIZE_CUTOFF_PERCENT;\n    static const float DIFF_MODSIZE_CUTOFF;\n\n  public:\n    MultiFinderPatternFinder(Ref<BitMatrix> image, Ref<ResultPointCallback> resultPointCallback);\n    virtual ~MultiFinderPatternFinder();\n    virtual std::vector<Ref<zxing::qrcode::FinderPatternInfo> > findMulti(DecodeHints const& hints);\n\n\n};\n}\n}\n\n#endif // __MULTI_FINDER_PATTERN_FINDER_H__\n\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/phonegap-plugin-barcodescanner.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/android\" isTestSource=\"false\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"classes9\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"classes6\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"classes7\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"classes3\" level=\"project\" />\n    <orderEntry type=\"module\" module-name=\"cordova-plugin-compat\" />\n    <orderEntry type=\"module\" module-name=\"android\" />\n    <orderEntry type=\"module\" module-name=\"buildConfig\" />\n    <orderEntry type=\"module\" module-name=\"CordovaLib\" />\n  </component>\n</module>"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/windows/BarcodeScannerProxy.js",
    "content": "/*\n * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.\n *\n * 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\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * 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.\n */\n\nvar urlutil = require('cordova/urlutil');\n\nvar CAMERA_STREAM_STATE_CHECK_RETRY_TIMEOUT = 200; // milliseconds\nvar OPERATION_IS_IN_PROGRESS = -2147024567;\nvar REGDB_E_CLASSNOTREG = -2147221164;\nvar INITIAL_FOCUS_DELAY = 200; // milliseconds\nvar CHECK_PLAYING_TIMEOUT = 100; // milliseconds\n\n/**\n * List of supported barcode formats from ZXing library. Used to return format\n *   name instead of number code as per plugin spec.\n *\n * @enum {String}\n */\nvar BARCODE_FORMAT = {\n    1: 'AZTEC',\n    2: 'CODABAR',\n    4: 'CODE_39',\n    8: 'CODE_93',\n    16: 'CODE_128',\n    32: 'DATA_MATRIX',\n    64: 'EAN_8',\n    128: 'EAN_13',\n    256: 'ITF',\n    512: 'MAXICODE',\n    1024: 'PDF_417',\n    2048: 'QR_CODE',\n    4096: 'RSS_14',\n    8192: 'RSS_EXPANDED',\n    16384: 'UPC_A',\n    32768: 'UPC_E',\n    61918: 'All_1D',\n    65536: 'UPC_EAN_EXTENSION',\n    131072: 'MSI',\n    262144: 'PLESSEY'\n};\n\n/**\n * Detects the first appropriate camera located at the back panel of device. If\n *   there is no back cameras, returns the first available.\n *\n * @returns {Promise<String>} Camera id\n */\nfunction findCamera() {\n    var Devices = Windows.Devices.Enumeration;\n\n    // Enumerate cameras and add them to the list\n    return Devices.DeviceInformation.findAllAsync(Devices.DeviceClass.videoCapture)\n    .then(function (cameras) {\n\n        if (!cameras || cameras.length === 0) {\n            throw new Error(\"No cameras found\");\n        }\n\n        var backCameras = cameras.filter(function (camera) {\n            return camera.enclosureLocation && camera.enclosureLocation.panel === Devices.Panel.back;\n        });\n\n        // If there is back cameras, return the id of the first,\n        // otherwise take the first available device's id\n        return (backCameras[0] || cameras[0]).id;\n    });\n}\n\n/**\n * @param {Windows.Graphics.Display.DisplayOrientations} displayOrientation\n * @return {Number}\n */\nfunction videoPreviewRotationLookup(displayOrientation, isMirrored) {\n    var degreesToRotate;\n\n    switch (displayOrientation) {\n        case Windows.Graphics.Display.DisplayOrientations.landscape:\n            degreesToRotate = 0;\n            break;\n        case Windows.Graphics.Display.DisplayOrientations.portrait:\n            if (isMirrored) {\n                degreesToRotate = 270;\n            } else {\n                degreesToRotate = 90;\n            }\n            break;\n        case Windows.Graphics.Display.DisplayOrientations.landscapeFlipped:\n            degreesToRotate = 180;\n            break;\n        case Windows.Graphics.Display.DisplayOrientations.portraitFlipped:\n            if (isMirrored) {\n                degreesToRotate = 90;\n            } else {\n                degreesToRotate = 270;\n            }\n            break;\n        default:\n            degreesToRotate = 0;\n            break;\n    }\n\n    return degreesToRotate;\n}\n\n/**\n * The pure JS implementation of barcode reader from WinRTBarcodeReader.winmd.\n *   Works only on Windows 10 devices and more efficient than original one.\n *\n * @class {BarcodeReader}\n */\nfunction BarcodeReader () {\n    this._promise = null;\n    this._cancelled = false;\n}\n\n/**\n * Returns an instance of Barcode reader, depending on capabilities of Media\n *   Capture API\n *\n * @static\n * @constructs {BarcodeReader}\n *\n * @param   {MediaCapture}   mediaCaptureInstance  Instance of\n *   Windows.Media.Capture.MediaCapture class\n *\n * @return  {BarcodeReader}  BarcodeReader instance that could be used for\n *   scanning\n */\nBarcodeReader.get = function (mediaCaptureInstance) {\n    if (mediaCaptureInstance.getPreviewFrameAsync && ZXing.BarcodeReader) {\n        return new BarcodeReader();\n    }\n\n    // If there is no corresponding API (Win8/8.1/Phone8.1) use old approach with WinMD library\n    return new WinRTBarcodeReader.Reader();\n\n};\n\n/**\n * Initializes instance of reader.\n *\n * @param   {MediaCapture}  capture  Instance of\n *   Windows.Media.Capture.MediaCapture class, used for acquiring images/ video\n *   stream for barcode scanner.\n * @param   {Number}  width    Video/image frame width\n * @param   {Number}  height   Video/image frame height\n */\nBarcodeReader.prototype.init = function (capture, width, height) {\n    this._capture = capture;\n    this._width = width;\n    this._height = height;\n    this._zxingReader = new ZXing.BarcodeReader();\n    this._zxingReader.tryHarder = true;\n};\n\n/**\n * Starts barcode search routines asyncronously.\n *\n * @return  {Promise<ScanResult>}  barcode scan result or null if search\n *   cancelled.\n */\nBarcodeReader.prototype.readCode = function () {\n\n    /**\n     * Grabs a frame from preview stream uning Win10-only API and tries to\n     *   get a barcode using zxing reader provided. If there is no barcode\n     *   found, returns null.\n     */\n    function scanBarcodeAsync(mediaCapture, zxingReader, frameWidth, frameHeight) {\n        // Shortcuts for namespaces\n        var Imaging = Windows.Graphics.Imaging;\n        var Streams = Windows.Storage.Streams;\n\n        var frame = new Windows.Media.VideoFrame(Imaging.BitmapPixelFormat.bgra8, frameWidth, frameHeight);\n        return mediaCapture.getPreviewFrameAsync(frame)\n        .then(function (capturedFrame) {\n\n            // Copy captured frame to buffer for further deserialization\n            var bitmap = capturedFrame.softwareBitmap;\n            var rawBuffer = new Streams.Buffer(bitmap.pixelWidth * bitmap.pixelHeight * 4);\n            capturedFrame.softwareBitmap.copyToBuffer(rawBuffer);\n            capturedFrame.close();\n\n            // Get raw pixel data from buffer\n            var data = new Uint8Array(rawBuffer.length);\n            var dataReader = Streams.DataReader.fromBuffer(rawBuffer);\n            dataReader.readBytes(data);\n            dataReader.close();\n\n            return zxingReader.decode(data, frameWidth, frameHeight, ZXing.BitmapFormat.bgra32);\n        });\n    }\n\n    var self = this;\n    return scanBarcodeAsync(this._capture, this._zxingReader, this._width, this._height)\n    .then(function (result) {\n        if (self._cancelled)\n            return null;\n\n        return result || (self._promise = self.readCode());\n    });\n};\n\n/**\n * Stops barcode search\n */\nBarcodeReader.prototype.stop = function () {\n    this._cancelled = true;\n};\n\nfunction degreesToRotation(degrees) {\n    switch (degrees) {\n        // portrait\n        case 90:\n            return Windows.Media.Capture.VideoRotation.clockwise90Degrees;\n        // landscape\n        case 0:\n            return Windows.Media.Capture.VideoRotation.none;\n        // portrait-flipped\n        case 270:\n            return Windows.Media.Capture.VideoRotation.clockwise270Degrees;\n        // landscape-flipped\n        case 180:\n            return Windows.Media.Capture.VideoRotation.clockwise180Degrees;\n        default:\n            // Falling back to portrait default\n            return Windows.Media.Capture.VideoRotation.clockwise90Degrees;\n    }\n}\n\nmodule.exports = {\n\n    /**\n     * Scans image via device camera and retieves barcode from it.\n     * @param  {function} success Success callback\n     * @param  {function} fail    Error callback\n     * @param  {array} args       Arguments array\n     */\n    scan: function (success, fail, args) {\n        var capturePreview,\n            capturePreviewAlignmentMark,\n            captureCancelButton,\n            navigationButtonsDiv,\n            previewMirroring,\n            closeButton,\n            capture,\n            reader;\n\n        // Save call state for suspend/resume\n        BarcodeReader.scanCallArgs = {\n            success: success,\n            fail: fail,\n            args: args\n        };\n\n        function updatePreviewForRotation(evt) {\n            if (!capture) {\n                return;\n            }\n\n            var displayInformation = (evt && evt.target) || Windows.Graphics.Display.DisplayInformation.getForCurrentView();\n            var currentOrientation = displayInformation.currentOrientation;\n\n            previewMirroring = capture.getPreviewMirroring();\n\n            // Lookup up the rotation degrees.\n            var rotDegree = videoPreviewRotationLookup(currentOrientation, previewMirroring);\n\n            capture.setPreviewRotation(degreesToRotation(rotDegree));\n            return WinJS.Promise.as();\n        }\n\n        /**\n         * Creates a preview frame and necessary objects\n         */\n        function createPreview() {\n\n            // Create fullscreen preview\n            var capturePreviewFrameStyle = document.createElement('link');\n            capturePreviewFrameStyle.rel = \"stylesheet\";\n            capturePreviewFrameStyle.type = \"text/css\";\n            capturePreviewFrameStyle.href = urlutil.makeAbsolute(\"/www/css/plugin-barcodeScanner.css\");\n\n            document.head.appendChild(capturePreviewFrameStyle);\n\n            capturePreviewFrame = document.createElement('div');\n            capturePreviewFrame.className = \"barcode-scanner-wrap\";\n\n            capturePreview = document.createElement(\"video\");\n            capturePreview.className = \"barcode-scanner-preview\";\n            capturePreview.addEventListener('click', function () {\n                focus();\n            });\n\n            capturePreviewAlignmentMark = document.createElement('div');\n            capturePreviewAlignmentMark.className = \"barcode-scanner-mark\";\n\n            navigationButtonsDiv = document.createElement(\"div\");\n            navigationButtonsDiv.className = \"barcode-scanner-app-bar\";\n            navigationButtonsDiv.onclick = function (e) {\n                e.cancelBubble = true;\n            };\n\n            closeButton = document.createElement(\"div\");\n            closeButton.innerText = \"close\";\n            closeButton.className = \"app-bar-action action-close\";\n            navigationButtonsDiv.appendChild(closeButton);\n\n            BarcodeReader.scanCancelled = false;\n            closeButton.addEventListener(\"click\", cancelPreview, false);\n            document.addEventListener('backbutton', cancelPreview, false);\n\n            [capturePreview, capturePreviewAlignmentMark, navigationButtonsDiv].forEach(function (element) {\n                capturePreviewFrame.appendChild(element);\n            });\n        }\n\n        function focus(controller) {\n\n            var result = WinJS.Promise.wrap();\n\n            if (!capturePreview || capturePreview.paused) {\n                // If the preview is not yet playing, there is no sense in running focus\n                return result;\n            }\n\n            if (!controller) {\n                try {\n                    controller = capture && capture.videoDeviceController;\n                } catch (err) {\n                    console.log('Failed to access focus control for current camera: ' + err);\n                    return result;\n                }\n            }\n\n            if (!controller.focusControl || !controller.focusControl.supported) {\n                console.log('Focus control for current camera is not supported');\n                return result;\n            }\n\n            // Multiple calls to focusAsync leads to internal focusing hang on some Windows Phone 8.1 devices\n            // Also need to wrap in try/catch to avoid crash on Surface 3 - looks like focusState property\n            // somehow is not accessible there. See https://github.com/phonegap/phonegap-plugin-barcodescanner/issues/288\n            try {\n                if (controller.focusControl.focusState === Windows.Media.Devices.MediaCaptureFocusState.searching) {\n                    return result;\n                }\n            } catch (e) {\n                // Nothing to do - just continue w/ focusing\n            }\n\n            // The delay prevents focus hang on slow devices\n            return WinJS.Promise.timeout(INITIAL_FOCUS_DELAY)\n            .then(function () {\n                try {\n                    return controller.focusControl.focusAsync().then(function () {\n                        return result;\n                    }, function (e) {\n                        // This happens on mutliple taps\n                        if (e.number !== OPERATION_IS_IN_PROGRESS) {\n                            console.error('focusAsync failed: ' + e);\n                            return WinJS.Promise.wrapError(e);\n                        }\n                        return result;\n                    });\n                } catch (e) {\n                    // This happens on mutliple taps\n                    if (e.number !== OPERATION_IS_IN_PROGRESS) {\n                        console.error('focusAsync failed: ' + e);\n                        return WinJS.Promise.wrapError(e);\n                    }\n                    return result;\n                }\n            });\n        }\n\n        function setupFocus(focusControl) {\n\n            function supportsFocusMode(mode) {\n                return focusControl.supportedFocusModes.indexOf(mode).returnValue;\n            }\n\n            if (!focusControl || !focusControl.supported || !focusControl.configure) {\n                return WinJS.Promise.wrap();\n            }\n\n            var FocusMode = Windows.Media.Devices.FocusMode;\n            var focusConfig = new Windows.Media.Devices.FocusSettings();\n            focusConfig.autoFocusRange = Windows.Media.Devices.AutoFocusRange.normal;\n\n            // Determine a focus position if the focus search fails:\n            focusConfig.disableDriverFallback = false;\n\n            if (supportsFocusMode(FocusMode.continuous)) {\n                console.log(\"Device supports continuous focus mode\");\n                focusConfig.mode = FocusMode.continuous;\n            } else if (supportsFocusMode(FocusMode.auto)) {\n                console.log(\"Device doesn\\'t support continuous focus mode, switching to autofocus mode\");\n                focusConfig.mode = FocusMode.auto;\n            }\n\n            focusControl.configure(focusConfig);\n\n            // Continuous focus should start only after preview has started. See 'Remarks' at\n            // https://msdn.microsoft.com/en-us/library/windows/apps/windows.media.devices.focuscontrol.configure.aspx\n            function waitForIsPlaying() {\n                var isPlaying = !capturePreview.paused && !capturePreview.ended && capturePreview.readyState > 2;\n\n                if (!isPlaying) {\n                    return WinJS.Promise.timeout(CHECK_PLAYING_TIMEOUT)\n                    .then(function () {\n                        return waitForIsPlaying();\n                    });\n                }\n\n                return focus();\n            }\n\n            return waitForIsPlaying();\n        }\n\n        function disableZoomAndScroll() {\n            document.body.classList.add('no-zoom');\n            document.body.classList.add('no-scroll');\n        }\n\n        function enableZoomAndScroll() {\n            document.body.classList.remove('no-zoom');\n            document.body.classList.remove('no-scroll');\n        }\n\n        /**\n         * Starts stream transmission to preview frame and then run barcode search\n         */\n        function startPreview() {\n            return findCamera()\n            .then(function (id) {\n                var captureSettings;\n\n                try {\n                    captureSettings = new Windows.Media.Capture.MediaCaptureInitializationSettings();\n                } catch (e) {\n                    if (e.number === REGDB_E_CLASSNOTREG) {\n                        throw new Error('Ensure that you have Windows Media Player and Media Feature pack installed.');\n                    }\n\n                    throw e;\n                }\n\n                captureSettings.streamingCaptureMode = Windows.Media.Capture.StreamingCaptureMode.video;\n                captureSettings.photoCaptureSource = Windows.Media.Capture.PhotoCaptureSource.videoPreview;\n                captureSettings.videoDeviceId = id;\n\n                capture = new Windows.Media.Capture.MediaCapture();\n                return capture.initializeAsync(captureSettings);\n            })\n            .then(function () {\n\n                var controller = capture.videoDeviceController;\n                var deviceProps = controller.getAvailableMediaStreamProperties(Windows.Media.Capture.MediaStreamType.videoPreview);\n\n                deviceProps = Array.prototype.slice.call(deviceProps);\n                deviceProps = deviceProps.filter(function (prop) {\n                    // filter out streams with \"unknown\" subtype - causes errors on some devices\n                    return prop.subtype !== \"Unknown\";\n                }).sort(function (propA, propB) {\n                    // sort properties by resolution\n                    return propB.width - propA.width;\n                });\n\n                var preferredProps = deviceProps.filter(function(prop){\n                    // Filter out props where frame size is between 640*480 and 1280*720\n                    return prop.width >= 640 && prop.height >= 480 && prop.width <= 1280 && prop.height <= 720;\n                });\n\n                // prefer video frame size between between 640*480 and 1280*720\n                // use maximum resolution otherwise\n                var maxResProps = preferredProps[0] || deviceProps[0];\n                return controller.setMediaStreamPropertiesAsync(Windows.Media.Capture.MediaStreamType.videoPreview, maxResProps)\n                .then(function () {\n                    return {\n                        capture: capture,\n                        width: maxResProps.width,\n                        height: maxResProps.height\n                    };\n                });\n            })\n            .then(function (captureSettings) {\n\n                capturePreview.msZoom = true;\n                capturePreview.src = URL.createObjectURL(capture);\n                capturePreview.play();\n\n                // Insert preview frame and controls into page\n                document.body.appendChild(capturePreviewFrame);\n\n                disableZoomAndScroll();\n\n                return setupFocus(captureSettings.capture.videoDeviceController.focusControl)\n                .then(function () {\n                    Windows.Graphics.Display.DisplayInformation.getForCurrentView().addEventListener(\"orientationchanged\", updatePreviewForRotation, false);\n                    return updatePreviewForRotation();\n                })\n                .then(function () {\n\n                    if (!Windows.Media.Devices.CameraStreamState) {\n                        // CameraStreamState is available starting with Windows 10 so skip this check for 8.1\n                        // https://msdn.microsoft.com/en-us/library/windows/apps/windows.media.devices.camerastreamstate\n                        return WinJS.Promise.as();\n                    }\n\n                    function checkCameraStreamState() {\n                        if (capture.cameraStreamState !== Windows.Media.Devices.CameraStreamState.streaming) {\n\n                            // Using loop as MediaCapture.CameraStreamStateChanged does not fire with CameraStreamState.streaming state.\n                            return WinJS.Promise.timeout(CAMERA_STREAM_STATE_CHECK_RETRY_TIMEOUT)\n                            .then(function () {\n                                return checkCameraStreamState();\n                            });\n                        }\n\n                        return WinJS.Promise.as();\n                    }\n\n                    // Ensure CameraStreamState is Streaming\n                    return checkCameraStreamState();\n                })\n                .then(function () {\n                    return captureSettings;\n                });\n            });\n        }\n\n        /**\n         * Removes preview frame and corresponding objects from window\n         */\n        function destroyPreview() {\n            var promise = WinJS.Promise.as();\n\n            Windows.Graphics.Display.DisplayInformation.getForCurrentView().removeEventListener(\"orientationchanged\", updatePreviewForRotation, false);\n            document.removeEventListener('backbutton', cancelPreview);\n\n            if (capturePreview) {\n                var isPlaying = !capturePreview.paused && !capturePreview.ended && capturePreview.readyState > 2;\n                if (isPlaying) {\n                    capturePreview.pause();\n                }\n\n                // http://stackoverflow.com/a/28060352/4177762\n                capturePreview.src = \"\";\n                if (capturePreview.load) {\n                    capturePreview.load();\n                }\n            }\n\n            if (capturePreviewFrame) {\n                try {\n                    document.body.removeChild(capturePreviewFrame);\n                } catch (e) {\n                    // Catching NotFoundError\n                    console.error(e);\n                }\n            }\n            capturePreviewFrame = null;\n\n            reader && reader.stop();\n            reader = null;\n\n            if (capture) {\n                try {\n                    promise = capture.stopRecordAsync();\n                } catch (e) {\n                    // Catching NotFoundError\n                    console.error(e);\n                }\n            }\n            capture = null;\n\n            enableZoomAndScroll();\n\n            return promise;\n        }\n\n        /**\n         * Stops preview and then call success callback with cancelled=true\n         * See https://github.com/phonegap-build/BarcodeScanner#using-the-plugin\n         */\n        function cancelPreview() {\n            BarcodeReader.scanCancelled = true;\n            reader && reader.stop();\n        }\n\n        function checkCancelled() {\n            if (BarcodeReader.scanCancelled || BarcodeReader.suspended) {\n                throw new Error('Canceled');\n            }\n        }\n\n        // Timeout is needed so that the .done finalizer below can be attached to the promise.\n        BarcodeReader.scanPromise = WinJS.Promise.timeout()\n        .then(function() {\n            createPreview();\n            checkCancelled();\n            return startPreview();\n        })\n        .then(function (captureSettings) {\n            checkCancelled();\n            reader = BarcodeReader.get(captureSettings.capture);\n            reader.init(captureSettings.capture, captureSettings.width, captureSettings.height);\n\n            // Add a small timeout before capturing first frame otherwise\n            // we would get an 'Invalid state' error from 'getPreviewFrameAsync'\n            return WinJS.Promise.timeout(200)\n            .then(function () {\n                checkCancelled();\n                return reader.readCode();\n            });\n        })\n        .then(function (result) {\n            // Suppress null result (cancel) on suspending\n            if (BarcodeReader.suspended) {\n                return;\n            }\n\n            destroyPreview();\n            success({\n                text: result && result.text,\n                format: result && BARCODE_FORMAT[result.barcodeFormat],\n                cancelled: !result\n            });\n        });\n\n        // Catching any errors here\n        BarcodeReader.scanPromise.done(function () { }, function (error) {\n            // Suppress null result (cancel) on suspending\n            if (BarcodeReader.suspended) {\n                return;\n            }\n\n            destroyPreview();\n            if (error.message == 'Canceled') {\n                success({\n                    cancelled: true\n                });\n            } else {\n                fail(error);\n            }\n        });\n\n        BarcodeReader.videoPreviewIsVisible = function () {\n            return capturePreviewFrame !== null;\n        }\n\n        BarcodeReader.destroyPreview = destroyPreview;\n    },\n\n    /**\n     * Encodes specified data into barcode\n     * @param  {function} success Success callback\n     * @param  {function} fail    Error callback\n     * @param  {array} args       Arguments array\n     */\n    encode: function (success, fail, args) {\n        fail(\"Not implemented yet\");\n    }\n};\n\nvar app = WinJS.Application;\n\nfunction waitForScanEnd() {\n    return BarcodeReader.scanPromise || WinJS.Promise.as();\n}\n\nfunction suspend(args) {\n    BarcodeReader.suspended = true;\n    if (args) {\n        args.setPromise(BarcodeReader.destroyPreview()\n        .then(waitForScanEnd, waitForScanEnd));\n    } else {\n        BarcodeReader.destroyPreview();\n    }\n}\n\nfunction resume() {\n    BarcodeReader.suspended = false;\n    module.exports.scan(BarcodeReader.scanCallArgs.success, BarcodeReader.scanCallArgs.fail, BarcodeReader.scanCallArgs.args);\n}\n\nfunction onVisibilityChanged() {\n    if (document.visibilityState === 'hidden'\n        && BarcodeReader.videoPreviewIsVisible && BarcodeReader.videoPreviewIsVisible() && BarcodeReader.destroyPreview) {\n        suspend();\n    } else if (BarcodeReader.suspended) {\n        resume();\n    }\n}\n\n// Windows 8.1 projects\ndocument.addEventListener('msvisibilitychange', onVisibilityChanged);\n// Windows 10 projects\ndocument.addEventListener('visibilitychange', onVisibilityChanged);\n\n// About to be suspended\napp.addEventListener('checkpoint', function (args) {\n    if (BarcodeReader.videoPreviewIsVisible && BarcodeReader.videoPreviewIsVisible() && BarcodeReader.destroyPreview) {\n        suspend(args);\n    }\n});\n\n// Resuming from a user suspension\nWindows.UI.WebUI.WebUIApplication.addEventListener(\"resuming\", function () {\n    if (BarcodeReader.suspended) {\n        resume();\n    }\n}, false);\n\nrequire(\"cordova/exec/proxy\").add(\"BarcodeScanner\", module.exports);\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/windows/assets/plugin-barcodeScanner.css",
    "content": ".barcode-scanner-wrap {\n    margin: 0;\n    padding: 0;\n    outline: 0;\n    font-size: 100%;\n    vertical-align: baseline;\n    background: 0 0 black;\n    position: fixed;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    z-index: 9999999;\n    -ms-user-select: none;\n}\n\n.barcode-scanner-preview {\n    width: auto;\n    height: calc(100% - 70px);\n    position: absolute;\n    top: calc(50% - 35px);\n    left: 50%;\n    transform: translateX(-50%) translateY(-50%);\n}\n\n.barcode-scanner-mark {\n    position: absolute;\n    left: 0;\n    top: 50%;\n    width: 100%;\n    height: 3px;\n    background: red;\n    z-index: 9999999;\n}\n\n.barcode-scanner-app-bar {\n    height: 70px;\n    width: 100%;\n    padding-top: 10px;\n    z-index: 9999999;\n    text-align: center;\n    user-select: none;\n    position: absolute;\n    bottom: 0px;\n}\n\n.app-bar-action {\n    width: 40px;\n    height: 40px;\n    margin: 0 auto;\n    font-family: \"Segoe UI Symbol\";\n    color: white;\n    font-size: 12px;\n    text-transform: lowercase;\n    text-align: center;\n    cursor: default;\n}\n\n@media all and (orientation: landscape) {\n    .app-bar-action {\n        float: right;\n        margin-right: 20px;\n    }\n}\n\n.app-bar-action::before {\n    font-size: 28px;\n    display: block;\n    height: 36px;\n}\n\n.action-close::before {\n    content: \"\\E0C7\";\n    /* close icon is larger so we re-size it to fit other icons */\n    font-size: 20px;\n    line-height: 40px;\n}\n\n.action-close:hover::before {\n    content: \"\\E0CA\";\n}\n\n.no-zoom {\n    -ms-content-zooming: none;\n}\n\n.no-scroll {\n    overflow: hidden;\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/windows/lib/Properties/AssemblyInfo.cs",
    "content": "﻿/*\n * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.\n *\n * 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\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * 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.\n */\n\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"WinRTBarcodeReader\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"WinRTBarcodeReader\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2014\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n[assembly: ComVisible(false)]"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/windows/lib/Reader.cs",
    "content": "﻿/*\n * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.\n *\n * 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\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * 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.\n */\n\nnamespace WinRTBarcodeReader\n{\n    using System;\n    using System.Threading;\n    using System.Threading.Tasks;\n\n    using Windows.Foundation;\n    using Windows.Graphics.Imaging;\n    using Windows.Media.Capture;\n    using Windows.Media.MediaProperties;\n    using Windows.Storage.Streams;\n\n    using ZXing;\n\n    /// <summary>\n    /// Defines the Reader type, that perform barcode search asynchronously.\n    /// </summary>\n    public sealed class Reader\n    {\n        #region Private fields\n\n        /// <summary>\n        ///     Data reader, used to create bitmap array.\n        /// </summary>\n        private BarcodeReader barcodeReader;\n\n        /// <summary>\n        ///     The cancel search flag.\n        /// </summary>\n        private CancellationTokenSource cancelSearch;\n\n        /// <summary>\n        ///     MediaCapture instance, used for barcode search.\n        /// </summary>\n        private MediaCapture capture;\n\n        /// <summary>\n        ///     Encoding properties for mediaCapture object.\n        /// </summary>\n        private ImageEncodingProperties encodingProps;\n\n        /// <summary>\n        ///     Flag that indicates successful barcode search.\n        /// </summary>\n        private bool barcodeFoundOrCancelled;\n\n        /// <summary>\n        ///     Image stream for MediaCapture content.\n        /// </summary>\n        private InMemoryRandomAccessStream imageStream;\n\n        #endregion\n\n        #region Constructor\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Reader\" /> class.\n        /// </summary>\n        /// <param name=\"capture\">MediaCapture instance.</param>\n        /// <param name=\"width\">Capture frame width.</param>\n        /// <param name=\"height\">Capture frame height.</param>\n        public void Init(MediaCapture capture, uint width, uint height)\n        {\n            this.capture = capture;\n            encodingProps = ImageEncodingProperties.CreateJpeg();\n            encodingProps.Width = width;\n            encodingProps.Height = height;\n\n            barcodeReader = new BarcodeReader {Options = {TryHarder = true}};\n            cancelSearch = new CancellationTokenSource();\n        }\n\n        #endregion\n\n        #region Public methods\n\n        /// <summary>\n        /// Perform async MediaCapture analysis and searches for barcode.\n        /// </summary>\n        /// <returns>IAsyncOperation object</returns>\n        public IAsyncOperation<Result> ReadCode()\n        {\n            return this.Read().AsAsyncOperation();\n        }\n\n        /// <summary>\n        /// Send signal to stop barcode search.\n        /// </summary>\n        public void Stop()\n        {\n            this.cancelSearch.Cancel();\n        }\n\n        #endregion\n\n        #region Private methods\n\n        /// <summary>\n        /// Perform async MediaCapture analysis and searches for barcode.\n        /// </summary>\n        /// <returns>Task object</returns>\n        private async Task<Result> Read()\n        {\n            Result result = null;\n            try\n            {\n                while (result == null)\n                {\n                    result = await GetCameraImage(cancelSearch.Token);\n                }\n            }\n            catch (OperationCanceledException) { }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Perform image capture from mediaCapture object\n        /// </summary>\n        /// <param name=\"cancelToken\">\n        /// The cancel Token.\n        /// </param>\n        /// <returns>\n        /// Decoded barcode string.\n        /// </returns>\n        private async Task<Result> GetCameraImage(CancellationToken cancelToken)\n        {\n            if (cancelToken.IsCancellationRequested)\n            {\n                throw new OperationCanceledException(cancelToken);\n            }\n\n            imageStream = new InMemoryRandomAccessStream();\n\n            await capture.CapturePhotoToStreamAsync(encodingProps, imageStream);\n            await imageStream.FlushAsync();\n\n            var decoder = await BitmapDecoder.CreateAsync(imageStream);\n\n            byte[] pixels =\n                (await\n                    decoder.GetPixelDataAsync(BitmapPixelFormat.Rgba8,\n                        BitmapAlphaMode.Ignore,\n                        new BitmapTransform(),\n                        ExifOrientationMode.IgnoreExifOrientation,\n                        ColorManagementMode.DoNotColorManage)).DetachPixelData();\n\n            const BitmapFormat format = BitmapFormat.RGB32;\n\n            imageStream.Dispose();\n\n            var result =\n                await\n                    Task.Run(\n                        () => barcodeReader.Decode(pixels, (int) decoder.PixelWidth, (int) decoder.PixelHeight, format),\n                        cancelToken);\n\n            return result;\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/windows/lib/WinRTBarcodeReader.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- \n  Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.\n  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\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\n  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.\n-->\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProductVersion>8.0.30703</ProductVersion>\n    <SchemaVersion>2.0</SchemaVersion>\n    <ProjectName>WinRTBarcodeReader</ProjectName>\n    <ProjectGuid>{01412F36-3781-4AF0-903C-ACEA7552C99C}</ProjectGuid>\n    <OutputType>winmdobj</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>WinRTBarcodeReader</RootNamespace>\n    <AssemblyName>WinRTBarcodeReader</AssemblyName>\n    <DefaultLanguage>en-US</DefaultLanguage>\n    <FileAlignment>512</FileAlignment>\n    <ProjectTypeGuids>{BC8A1FFA-BEE3-4634-8014-F334798102B3};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\n    <TargetPlatformVersion>8.1</TargetPlatformVersion>\n    <MinimumVisualStudioVersion>12</MinimumVisualStudioVersion>\n    <TargetFrameworkVersion />\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <DebugSymbols>false</DebugSymbols>\n    <DebugType>None</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|ARM'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\ARM\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>ARM</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|ARM'\">\n    <OutputPath>bin\\ARM\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugSymbols>false</DebugSymbols>\n    <DebugType>None</DebugType>\n    <PlatformTarget>ARM</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x64\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <OutputPath>bin\\x64\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugSymbols>false</DebugSymbols>\n    <DebugType>None</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x86\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\n    <OutputPath>bin\\x86\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugSymbols>false</DebugSymbols>\n    <DebugType>None</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n    <Prefer32Bit>true</Prefer32Bit>\n  </PropertyGroup>\n  <ItemGroup>\n    <Compile Include=\"Reader.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Reference Include=\"ZXing\">\n      <HintPath>ZXing.winmd</HintPath>\n    </Reference>\n  </ItemGroup>\n  <PropertyGroup Condition=\" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '12.0' \">\n    <VisualStudioVersion>12.0</VisualStudioVersion>\n  </PropertyGroup>\n  <Import Project=\"$(MSBuildExtensionsPath)\\Microsoft\\WindowsXaml\\v$(VisualStudioVersion)\\Microsoft.Windows.UI.Xaml.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScanner.cs",
    "content": "﻿﻿/*\n * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.\n *\n * 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\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * 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.\n */\n\n namespace WPCordovaClassLib.Cordova.Commands\n{\n    using System.Runtime.Serialization;\n    using Microsoft.Phone.Tasks;\n    using WPCordovaClassLib.Cordova.JSON;\n    using ZXing;\n\n    /// <summary>\n    /// Class that extends cordova with Barcode scanner functionality.\n    /// </summary>\n    public class BarcodeScanner : BaseCommand\n    {\n        /// <summary>\n        /// Scans the barcode.\n        /// </summary>\n        /// <param name=\"options\">Parameter is ignored.</param>\n        public void scan(string options)\n        {\n            var task = new BarcodeScannerTask();\n            task.Completed += this.TaskCompleted;\n            task.Show();\n        }\n\n        /// <summary>\n        /// Handler for barcode scanner task.\n        /// </summary>\n        /// <param name=\"sender\">The sender.</param>\n        /// <param name=\"e\">The scan result.</param>\n        private void TaskCompleted(object sender, BarcodeScannerTask.ScanResult e)\n        {\n            PluginResult result;\n\n            switch (e.TaskResult)\n            {\n                case TaskResult.OK:\n                    result = new PluginResult(PluginResult.Status.OK);\n                    result.Message = JsonHelper.Serialize(new BarcodeResult(e.Barcode));\n                    break;\n                case TaskResult.Cancel:\n                    // If scan is cancelled we return PluginResult.Status.OK with Message contains cancelled: true\n                    // See plugin docs https://github.com/MSOpenTech/BarcodeScanner#using-the-plugin\n                    result = new PluginResult(PluginResult.Status.OK);\n                    result.Message = JsonHelper.Serialize(new BarcodeResult());\n                    break;\n                default:\n                    result = new PluginResult(PluginResult.Status.ERROR);\n                    break;\n            }\n\n            this.DispatchCommandResult(result);\n        }\n    }\n\n    /// <summary>\n    /// Represents the barcode scan result, that should be serialized and passed to JS layer.\n    /// </summary>\n    [DataContract]\n    public sealed class BarcodeResult\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"BarcodeResult\"/> class.\n        /// </summary>\n        /// <param name=\"canceled\">if set to <c>true</c> [canceled].</param>\n        public BarcodeResult(bool canceled = true)\n        {\n            this.Cancelled = canceled;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"BarcodeResult\"/> class.\n        /// </summary>\n        /// <param name=\"barcode\">The barcode result.</param>\n        public BarcodeResult(Result barcode)\n        {\n            this.Cancelled = false;\n            this.Format = barcode.BarcodeFormat.ToString();\n            this.Text = barcode.Text;\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether barcode scan is cancelled.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if cancelled; otherwise, <c>false</c>.\n        /// </value>\n        [DataMember(Name = \"cancelled\")]\n        public bool Cancelled { get; private set; }\n\n        /// <summary>\n        /// Gets the format of barcode.\n        /// </summary>\n        /// <value>\n        /// The barcode format.\n        /// </value>\n        [DataMember(Name = \"format\")]\n        public string Format { get; private set; }\n\n        /// <summary>\n        /// Gets the barcode text.\n        /// </summary>\n        /// <value>\n        /// The barcode text.\n        /// </value>\n        [DataMember(Name = \"text\")]\n        public string Text { get; private set; }\n    }\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScannerTask.cs",
    "content": "﻿﻿/*\n * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.\n *\n * 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\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * 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.\n */\n\nnamespace WPCordovaClassLib.Cordova.Commands\n{\n    using System;\n    using System.Windows;\n    using System.Windows.Navigation;\n\n    using Microsoft.Phone.Controls;\n    using Microsoft.Phone.Tasks;\n    using ZXing;\n\n    /// <summary>\n    /// Class that represents barcode scanner task that mimics standart WP8 tasks.\n    /// </summary>\n    public class BarcodeScannerTask\n    {\n        /// <summary>\n        /// Occurs when task is [completed].\n        /// </summary>\n        public event EventHandler<ScanResult> Completed;\n\n        /// <summary>\n        /// Shows barcode scanner interface.\n        /// </summary>\n        public void Show()\n        {\n            Deployment.Current.Dispatcher.BeginInvoke(() =>\n            {\n                var root = Application.Current.RootVisual as PhoneApplicationFrame;\n\n                if (root == null)\n                {\n                    return;\n                }\n\n                root.Navigated += this.OnNavigated;\n                root.Navigate(new Uri(\"/Plugins/phonegap-plugin-barcodescanner/BarcodeScannerUI.xaml\", UriKind.Relative));\n            });\n        }\n\n        /// <summary>\n        /// Called when [navigated].\n        /// </summary>\n        /// <param name=\"sender\">The sender.</param>\n        /// <param name=\"e\">The <see cref=\"NavigationEventArgs\"/> instance containing the event data.</param>\n        private void OnNavigated(object sender, NavigationEventArgs e)\n        {\n            if (!(e.Content is BarcodeScannerUI))\n            {\n                return;\n            }\n\n            var phoneApplicationFrame = Application.Current.RootVisual as PhoneApplicationFrame;\n            if (phoneApplicationFrame != null)\n            {\n                phoneApplicationFrame.Navigated -= this.OnNavigated;\n            }\n\n            var barcodeScanner = (BarcodeScannerUI)e.Content;\n\n            if (barcodeScanner != null)\n            {\n                barcodeScanner.Completed += this.Completed;\n            }\n            else if (this.Completed != null)\n            {\n                this.Completed(this, new ScanResult(TaskResult.Cancel));\n            }\n        }\n\n        /// <summary>\n        /// Represents barcode scan result.\n        /// </summary>\n        public class ScanResult : TaskEventArgs\n        {\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"ScanResult\"/> class.\n            /// </summary>\n            /// <param name=\"taskResult\">One of the enumeration values that specifies the status of the task.</param>\n            public ScanResult(TaskResult taskResult)\n                : base(taskResult)\n            {\n            }\n\n            /// <summary>\n            /// Gets the barcode scan result.\n            /// </summary>\n            /// <value>\n            /// The barcode scan result.\n            /// </value>\n            public Result Barcode { get; internal set; }\n        }\n    }\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScannerUI.xaml",
    "content": "﻿<!-- \n  Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.\n  \n    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\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\n  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.\n-->\n<phone:PhoneApplicationPage\n    x:Class=\"WPCordovaClassLib.Cordova.Commands.BarcodeScannerUI\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:phone=\"clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone\"\n    xmlns:shell=\"clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone\"\n    xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n    xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n    FontFamily=\"{StaticResource PhoneFontFamilyNormal}\"\n    FontSize=\"{StaticResource PhoneFontSizeNormal}\"\n    Foreground=\"{StaticResource PhoneForegroundBrush}\"\n    SupportedOrientations=\"Portrait\" Orientation=\"Portrait\"\n    mc:Ignorable=\"d\"\n    shell:SystemTray.IsVisible=\"True\" CacheMode=\"BitmapCache\" >\n    <phone:PhoneApplicationPage.ApplicationBar>\n        <shell:ApplicationBar IsVisible=\"True\" IsMenuEnabled=\"False\" Mode=\"Minimized\">\n            <shell:ApplicationBarIconButton IconUri=\"/www/Images/appbar.cancel.png\" IsEnabled=\"True\" Text=\"Cancel\" Click=\"CancelScan\"/>\n        </shell:ApplicationBar>\n    </phone:PhoneApplicationPage.ApplicationBar>\n\n    <Grid Background=\"Transparent\">\n        <Canvas x:Name=\"CameraCanvas\">\n            <Canvas.Background>\n                <VideoBrush x:Name=\"CameraBrush\">\n                    <VideoBrush.RelativeTransform>\n                        <CompositeTransform\n                            CenterX=\"0.5\"\n                            CenterY=\"0.5\"\n                            Rotation=\"90\"/>\n                    </VideoBrush.RelativeTransform>\n                </VideoBrush>\n            </Canvas.Background>\n        </Canvas>\n        <Rectangle Margin=\"0\" Stroke=\"Red\" Height=\"2\"/>\n    </Grid>\n\n</phone:PhoneApplicationPage>"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/src/wp8/BarcodeScannerUI.xaml.cs",
    "content": "﻿﻿/*\n * Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.\n *\n * 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\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * 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.\n */\n\nnamespace WPCordovaClassLib.Cordova.Commands\n{\n    using System;\n    using System.Windows;\n    using System.Windows.Controls;\n    using System.Windows.Input;\n    using System.Windows.Media.Imaging;\n    using System.Windows.Navigation;\n    using System.Windows.Threading;\n\n    using Microsoft.Devices;\n    using Microsoft.Phone.Tasks;\n\n    using ZXing;\n\n    /// <summary>\n    /// Class that represents UI for barcode scanner.\n    /// </summary>\n    public partial class BarcodeScannerUI\n    {\n        /// <summary>\n        /// The result of scan operation.\n        /// </summary>\n        private BarcodeScannerTask.ScanResult result;\n\n        /// <summary>\n        /// The barcode reader object\n        /// </summary>\n        private BarcodeReader reader;\n\n        /// <summary>\n        /// Device camera object\n        /// </summary>\n        private PhotoCamera camera;\n\n        private DispatcherTimer timer;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"BarcodeScannerUI\"/> class.\n        /// This implementation not use camera autofocus.\n        /// </summary>\n        public BarcodeScannerUI()\n        {\n            this.InitializeComponent();\n\n            // Instantiate objects and start camera preview\n            this.camera = new PhotoCamera();\n            this.reader = new BarcodeReader {Options = {TryHarder = true}};\n            this.CameraBrush.SetSource(this.camera);\n\n            // Bind events\n            this.camera.Initialized += this.CameraInitialized;\n            this.reader.ResultFound += this.ReaderResultFound;\n\n            this.timer = new DispatcherTimer {Interval = TimeSpan.FromMilliseconds(100)};\n            this.timer.Tick += (sender, args) => ScanForBarcode();\n\n            this.BackKeyPress += CancelScan;\n\n            CameraButtons.ShutterKeyHalfPressed += StartCameraFocus;\n            camera.AutoFocusCompleted += StartCameraFocus;\n\n        }\n\n        private void StartCameraFocus(object sender, EventArgs eventArgs)\n        {\n            camera.Focus();\n        }\n\n        /// <summary>\n        /// Occurs when barcode scan is [completed].\n        /// </summary>\n        public event EventHandler<BarcodeScannerTask.ScanResult> Completed;\n\n        /// <summary>\n        /// Called when a page is no longer the active page in a frame.\n        /// </summary>\n        /// <param name=\"e\">An object that contains the event data.</param>\n        protected override void OnNavigatedFrom(NavigationEventArgs e)\n        {\n            // If result is null, user is cancelled scan operation\n            this.result = this.result ?? new BarcodeScannerTask.ScanResult(TaskResult.Cancel);\n            this.Completed(this, this.result);\n            this.CleanUp();\n            base.OnNavigatedFrom(e);\n        }\n\n        /// <summary>\n        /// Called when device camera initialized.\n        /// </summary>\n        /// <param name=\"sender\">The sender.</param>\n        /// <param name=\"e\">The <see cref=\"CameraOperationCompletedEventArgs\"/> instance containing the event data.</param>\n        private void CameraInitialized(object sender, CameraOperationCompletedEventArgs e)\n        {\n            if (e.Succeeded)\n            {\n                if (camera.IsFocusSupported)\n                {\n                    camera.Focus();\n                }\n\n                // Start scan process in separate thread\n                this.Dispatcher.BeginInvoke(() => timer.Start());\n            }\n            else\n            {\n                this.result = new BarcodeScannerTask.ScanResult(TaskResult.None);\n                NavigationService.GoBack();\n            }\n        }\n\n        private void ScanForBarcode()\n        {\n            var cameraBuffer = new WriteableBitmap(\n                                (int)camera.PreviewResolution.Width,\n                                (int)camera.PreviewResolution.Height);\n\n            camera.GetPreviewBufferArgb32(cameraBuffer.Pixels);\n            cameraBuffer.Invalidate();\n\n            reader.Decode(cameraBuffer);\n        }\n\n        /// <summary>\n        /// Called when reader find barcode.\n        /// </summary>\n        /// <param name=\"obj\">Scan result object.</param>\n        private void ReaderResultFound(Result obj)\n        {\n            VibrateController.Default.Start(TimeSpan.FromMilliseconds(100));\n            this.result = new BarcodeScannerTask.ScanResult(TaskResult.OK) { Barcode = obj };\n            NavigationService.GoBack();\n        }\n\n        /// <summary>\n        /// Cleans up resources and removes unnecessary callbacks.\n        /// </summary>\n        private void CleanUp()\n        {\n            CameraButtons.ShutterKeyHalfPressed -= StartCameraFocus;\n            if (this.camera != null)\n            {\n                this.camera.AutoFocusCompleted -= StartCameraFocus;\n                this.camera.Initialized -= this.CameraInitialized;\n                this.camera.Dispose();\n                this.camera = null;\n            }\n\n            if (this.reader != null)\n            {\n                this.reader.ResultFound -= this.ReaderResultFound;\n                this.reader = null;\n            }\n\n            if (this.timer != null)\n            {\n                this.timer.Stop();\n                this.timer = null;\n            }\n        }\n\n        private void ApplicationBarIconButton_Click(object sender, EventArgs e)\n        {\n            NavigationService.GoBack();\n        }\n\n        private void CancelScan(object sender, EventArgs eventArgs)\n        {\n            NavigationService.GoBack();\n        }\n    }\n}"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/tests/plugin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one\n  or more contributor license agreements.  See the NOTICE file\n  distributed with this work for additional information\n  regarding copyright ownership.  The ASF licenses this file\n  to you under the Apache License, Version 2.0 (the\n  \"License\"); you may not use this file except in compliance\n  with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an\n  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n  KIND, either express or implied.  See the License for the\n  specific language governing permissions and limitations\n  under the License.\n-->\n\n<plugin xmlns=\"http://apache.org/cordova/ns/plugins/1.0\"\n    xmlns:rim=\"http://www.blackberry.com/ns/widgets\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    id=\"phonegap-plugin-barcodescanner-tests\"\n    version=\"3.1.0\">\n    <name>PhoneGap BarcodeScanner Plugin Tests</name>\n    <license>Apache 2.0</license>\n\n    <js-module src=\"tests.js\" name=\"tests\">\n    </js-module>\n</plugin>\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/tests/tests.js",
    "content": "/*\n *\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n *\n*/\nexports.defineAutoTests = function() {\n    var scanner;\n    describe('cordova.require object should exist', function () {\n        it(\"should exist\", function() {\n            expect(window.cordova).toBeDefined();\n            expect(typeof cordova.require == 'function').toBe(true);\n        });\n\n        it(\"BarcodeScanner plugin should exist\", function() {\n            scanner = cordova.plugins.barcodeScanner; \n            expect(scanner).toBeDefined();\n            expect(typeof scanner == 'object').toBe(true);\n        });\n\n        it(\"should contain a scan function\", function() {\n            expect(scanner.scan).toBeDefined();\n            expect(typeof scanner.scan == 'function').toBe(true);\n        });\n\n        it(\"should contain an encode function\", function() {\n            expect(scanner.encode).toBeDefined();\n            expect(typeof scanner.encode == 'function').toBe(true);\n        });\n\n        it(\"should contain three DestinationType constants\", function() {\n            expect(scanner.Encode.TEXT_TYPE).toBe(\"TEXT_TYPE\");\n            expect(scanner.Encode.EMAIL_TYPE).toBe(\"EMAIL_TYPE\");\n            expect(scanner.Encode.PHONE_TYPE).toBe(\"PHONE_TYPE\");\n            expect(scanner.Encode.SMS_TYPE).toBe(\"SMS_TYPE\");\n        });\n        /*\n        it(\"should call scan successfully\", function() {\n            scanner.scan(function() {}, function() {});\n        });\n        */\n    });\n}\n"
  },
  {
    "path": "plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js",
    "content": "/**\n * cordova is available under *either* the terms of the modified BSD license *or* the\n * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.\n *\n * Copyright (c) Matt Kane 2010\n * Copyright (c) 2011, IBM Corporation\n */\n\n\n        var exec = cordova.require(\"cordova/exec\");\n\n        var scanInProgress = false;\n\n        /**\n         * Constructor.\n         *\n         * @returns {BarcodeScanner}\n         */\n        function BarcodeScanner() {\n\n            /**\n             * Encoding constants.\n             *\n             * @type Object\n             */\n            this.Encode = {\n                TEXT_TYPE: \"TEXT_TYPE\",\n                EMAIL_TYPE: \"EMAIL_TYPE\",\n                PHONE_TYPE: \"PHONE_TYPE\",\n                SMS_TYPE: \"SMS_TYPE\"\n                //  CONTACT_TYPE: \"CONTACT_TYPE\",  // TODO:  not implemented, requires passing a Bundle class from Javascript to Java\n                //  LOCATION_TYPE: \"LOCATION_TYPE\" // TODO:  not implemented, requires passing a Bundle class from Javascript to Java\n            };\n\n    /**\n     * Barcode format constants, defined in ZXing library.\n     *\n     * @type Object\n     */\n    this.format = {\n        \"all_1D\": 61918,\n        \"aztec\": 1,\n        \"codabar\": 2,\n        \"code_128\": 16,\n        \"code_39\": 4,\n        \"code_93\": 8,\n        \"data_MATRIX\": 32,\n        \"ean_13\": 128,\n        \"ean_8\": 64,\n        \"itf\": 256,\n        \"maxicode\": 512,\n        \"msi\": 131072,\n        \"pdf_417\": 1024,\n        \"plessey\": 262144,\n        \"qr_CODE\": 2048,\n        \"rss_14\": 4096,\n        \"rss_EXPANDED\": 8192,\n        \"upc_A\": 16384,\n        \"upc_E\": 32768,\n        \"upc_EAN_EXTENSION\": 65536\n        };\n  }\n\n/**\n * Read code from scanner.\n *\n * @param {Function} successCallback This function will recieve a result object: {\n         *        text : '12345-mock',    // The code that was scanned.\n         *        format : 'FORMAT_NAME', // Code format.\n         *        cancelled : true/false, // Was canceled.\n         *    }\n * @param {Function} errorCallback\n * @param config\n */\nBarcodeScanner.prototype.scan = function (successCallback, errorCallback, config) {\n\n            if (config instanceof Array) {\n                // do nothing\n            } else {\n                if (typeof(config) === 'object') {\n                    config = [ config ];\n                } else {\n                    config = [];\n                }\n            }\n\n            if (errorCallback == null) {\n                errorCallback = function () {\n                };\n            }\n\n            if (typeof errorCallback != \"function\") {\n                console.log(\"BarcodeScanner.scan failure: failure parameter not a function\");\n                return;\n            }\n\n            if (typeof successCallback != \"function\") {\n                console.log(\"BarcodeScanner.scan failure: success callback parameter must be a function\");\n                return;\n            }\n\n            if (scanInProgress) {\n                errorCallback('Scan is already in progress');\n                return;\n            }\n\n            scanInProgress = true;\n\n            exec(\n                function(result) {\n                    scanInProgress = false;\n                    successCallback(result);\n                },\n                function(error) {\n                    scanInProgress = false;\n                    errorCallback(error);\n                },\n                'BarcodeScanner',\n                'scan',\n                config\n            );\n        };\n\n        //-------------------------------------------------------------------\n        BarcodeScanner.prototype.encode = function (type, data, successCallback, errorCallback, options) {\n            if (errorCallback == null) {\n                errorCallback = function () {\n                };\n            }\n\n            if (typeof errorCallback != \"function\") {\n                console.log(\"BarcodeScanner.encode failure: failure parameter not a function\");\n                return;\n            }\n\n            if (typeof successCallback != \"function\") {\n                console.log(\"BarcodeScanner.encode failure: success callback parameter must be a function\");\n                return;\n            }\n\n            exec(successCallback, errorCallback, 'BarcodeScanner', 'encode', [\n                {\"type\": type, \"data\": data, \"options\": options}\n            ]);\n        };\n\n        var barcodeScanner = new BarcodeScanner();\n        module.exports = barcodeScanner;\n"
  },
  {
    "path": "www/css/responsive.css",
    "content": "/* TABLES */\n@media all and (max-width:500px) {\n    .force-landscape {\n        display: none;\n    }\n}\n@media all and (min-width:500px){\n    .please-rotate {\n        display: none;\n    }\n}\n/* /TABLES */\n\n/* MDL CARD */\n@media all and (min-width:590px) {\n    .pihole-card.pihole-card-floating > .mdl-card__actions > .material-icons{\n        padding-right: 0;\n    }\n\n    .pihole-card.pihole-card-floating > .mdl-card__actions {\n        font-size: 15px;\n    }\n\n    .pihole-card.pihole-card-floating.mdl-card{\n        display: inline-block;\n        width: 46%;\n        margin: 15px 2% 0 0;\n    }\n\n    .pihole-card.pihole-card-floating.mdl-card:nth-child(1),\n    .pihole-card.pihole-card-floating.mdl-card:nth-child(2){\n        margin-top: 0;\n    }\n\n    .pihole-card.pihole-card-floating.mdl-card:nth-of-type(even){\n        margin-right: 0;\n    }\n}\n/* /MDL CARD */"
  },
  {
    "path": "www/css/styles.css",
    "content": "/* GENERAL */\nhtml, body {\n    font-family: 'Roboto', 'Helvetica', sans-serif;\n}\n\n.centered-element {\n    align-items: center;\n    justify-content: center;\n    text-align: center;\n}\n\n#main_content {\n    padding: 25px 0;\n}\n\n.fullwidth {\n    width: 100%;\n}\n\n.mdl-data-table tbody tr:hover {\n    background-color: transparent; \n}\n/* /GENERAL */\n\n/* DRAWER */\n.pihole-drawer {\n    border: none;\n}\n\n.pihole-drawer .mdl-menu .mdl-menu__item {\n    display: -webkit-flex;\n    display: -ms-flexbox;\n    display: flex;\n    -webkit-align-items: center;\n    -ms-flex-align: center;\n    align-items: center;\n}\n\n.pihole-drawer-header {\n    box-sizing: border-box;\n    display: -webkit-flex;\n    display: -ms-flexbox;\n    display: flex;\n    -webkit-flex-direction: column;\n    -ms-flex-direction: column;\n    flex-direction: column;\n    -webkit-justify-content: flex-end;\n    -ms-flex-pack: end;\n    justify-content: flex-end;\n    padding: 16px;\n}\n\n.pihole-avatar-dropdown {\n    display: -webkit-flex;\n    display: -ms-flexbox;\n    display: flex;\n    position: relative;\n    -webkit-flex-direction: row;\n    -ms-flex-direction: row;\n    flex-direction: row;\n    -webkit-align-items: center;\n    -ms-flex-align: center;\n    align-items: center;\n    width: 100%;\n}\n\n.pihole-navigation {\n    -webkit-flex-grow: 1;\n    -ms-flex-positive: 1;\n    flex-grow: 1;\n}\n\n.pihole-layout .pihole-navigation .mdl-navigation__link {\n    display: -webkit-flex !important;\n    display: -ms-flexbox !important;\n    display: flex !important;\n    -webkit-flex-direction: row;\n    -ms-flex-direction: row;\n    flex-direction: row;\n    -webkit-align-items: center;\n    -ms-flex-align: center;\n    align-items: center;\n    font-weight: 500;\n}\n\n.pihole-navigation .mdl-navigation__link .material-icons {\n    margin-right: 32px;\n}\n\n.pihole-drawer .pihole_logo {\n    width: 48px;\n    height: 48px;\n    padding-right: 10px;\n}\n/* /DRAWER */\n\n/* HEADER */\n\n.pihole-header #container-pihole-toggle {\n    padding-right: 10px;\n}\n\n.pihole-header .mdl-switch__thumb {\n    background:#dd4b39;\n}\n\n.pihole-header .mdl-switch.is-checked .mdl-switch__thumb {\n    background: #00a65a;\n}\n\n.pihole-header .mdl-switch.is-checked .mdl-switch__track {\n    background: rgba(0,0,0,.26);\n}\n\n/* /HEADER */\n\n/* CHARTS */\n.pihole-card .ct-chart {\n    margin: 0 auto;\n    width: 100%;\n    text-align: center;\n}\n\n.ct-chart .ct-slice-pie {\n    stroke: white;\n    stroke-width: 2px;\n}\n\n.ct-label {\n    font-size: 15px;\n    fill:#333;\n}\n\n.ct-fill-red {\n    fill:#f56954;\n}\n\n.ct-fill-blue{\n    fill:#3c8dbc;\n}\n\n.ct-fill-light-blue{\n    fill:#00c0ef;\n}\n\n.ct-fill-green{\n    fill:#00a65a;\n}\n\n.ct-fill-orange{\n    fill:#f39c12;\n}\n\n/* /CHARTS */\n\n/* MDL CARD */\n.pihole-card h2 {\n    margin:0;\n}\n\n.material-icons.loading {\n    -webkit-animation:fa-spin 2s infinite linear;\n    animation:fa-spin 2s infinite linear;\n}\n\n@-webkit-keyframes fa-spin {\n    0% {\n        -webkit-transform: rotate(0deg);\n        transform: rotate(0deg);\n    }\n    100% {\n        -webkit-transform: rotate(359deg);\n        transform: rotate(359deg);\n    }\n}\n@keyframes fa-spin {\n    0% {\n        -webkit-transform: rotate(0deg);\n        transform: rotate(0deg);\n    }\n    100% {\n        -webkit-transform: rotate(359deg);\n        transform: rotate(359deg);\n    }\n}\n\n.pihole-card.bg-aqua {     \n    background: #00c0ef;   \n}\n\n.pihole-card.bg-green {     \n    background: #00a65a;   \n}\n\n.pihole-card.bg-yellow {     \n    background: #f39c12;   \n}\n\n.pihole-card.bg-red {     \n    background: #dd4b39;   \n}\n\n.pihole-card.bg-white {\n    background: #fff;        \n}    \n\n.pihole-card.mdl-card {\n    width: 95%;\n    height: auto;\n    margin: 15px auto;\n    min-height: initial;\n}\n\n.pihole-card.mdl-card:first-child{\n    margin-top:0;\n}\n\n.pihole-card > .mdl-card__actions {\n    border-color: rgba(255, 255, 255, 0.2);\n}\n\n.pihole-card > .mdl-card__title {\n    align-items: flex-start;\n}\n\n.pihole-card > .mdl-card__title > h4 {\n    margin-top: 0;\n}\n\n.pihole-card > .mdl-card__actions {\n    display: flex;\n    box-sizing:border-box;\n    align-items: center;\n}\n\n.pihole-card > .mdl-card__actions > .material-icons {\n    padding-right: 10px;\n}\n\n.pihole-card:not(.bg-white) > .mdl-card__title,\n.pihole-card:not(.bg-white) > .mdl-card__actions,\n.pihole-card:not(.bg-white) > .mdl-card__actions > .mdl-button {\n    color: #fff;\n}\n/* /MDL CARD */\n\n/* DATATABLES */\n.dataTables_length,\n.dataTables_filter {\n    margin: 0 15px 15px 15px;\n}\n\ntable.dataTable thead th,\ntable.dataTable thead td,\ntable.dataTable.no-footer{\n    border-bottom: inherit;\n}\n\n@media screen and (max-width: 640px) {\n    .dataTables_wrapper .dataTables_filter {\n        margin-top:0;\n    }\n\n    .dataTables_wrapper .dataTables_length{\n        float:left;\n    }\n\n    .dataTables_wrapper .dataTables_filter {\n        float:right;\n    }\n}\n/* /DATATABLES */\n\n/* SETTINGS */\n.mdl-cell.mdl-card:first-child{\n    margin-top:0;\n}\n\n#form_settings{\n    margin:30px 0 15px 0;\n}\n\n#form_settings .mdl-button {\n    margin: 15px 0 0 0;\n}\n\n.mdl-textfield {\n    width: 100%;\n}\n\n#pihole_token {\n    width:85%;\n    display:inline-block;\n}\n\n#qrcode_scan {\n    float:right;\n    padding-top:5px;\n    opacity:.6;\n}\n/* /SETTINGS */\n\n/* ABOUT&HELP */\nh5 i.material-icons {\n    vertical-align: -4px;\n}\n/* /ABOUT&HELP */\n\n/* QUERYLOG */\n.mdl-chip.mdl-please-wait .material-icons {\n    vertical-align: -6px;\n}\n/* /QUERYLOG */"
  },
  {
    "path": "www/index.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        <title>Pi-hole App</title>\n        <meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">\n        <meta name=\"format-detection\" content=\"telephone=no\">\n        <meta name=\"msapplication-tap-highlight\" content=\"no\">\n        <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width\">\n\n        <!-- styles -->\n        <link rel=\"stylesheet\" href=\"lib/mdl/css/fonts.min.css\">\n        <link rel=\"stylesheet\" href=\"lib/mdl/css/material.icons.min.css\">\n        <link rel=\"stylesheet\" href=\"lib/mdl/css/material.indigo-red.min.css\">\n        <link rel=\"stylesheet\" href=\"lib/chartist/chartist.min.css\">        \n        <link rel=\"stylesheet\" href=\"lib/DataTables/datatables.min.css\"/>\n        <link rel=\"stylesheet\" href=\"css/styles.css\">\n        <link rel=\"stylesheet\" href=\"css/responsive.css\">\n        <!-- /styles -->\n    </head>\n    <body>\n        <div class=\"pihole-layout mdl-layout mdl-js-layout mdl-layout--fixed-drawer mdl-layout--fixed-header\">\n            <header class=\"pihole-header mdl-layout__header\">\n                <div class=\"mdl-layout__header-row\">\n                    <span class=\"mdl-layout-title\"></span>\n                    <div class=\"mdl-layout-spacer\"></div>\n\n                    <!-- Pi-hole toggle -->\n                    <div id=\"container-pihole-toggle\" style=\"display:none\">\n                        <label id=\"label-pihole-toggle\" class=\"mdl-switch mdl-js-switch mdl-js-ripple-effect\" for=\"switch-pihole-toggle\">\n                            <input type=\"checkbox\" id=\"switch-pihole-toggle\" class=\"mdl-switch__input\" checked>\n                            <span class=\"mdl-switch__label\"></span>\n                        </label>\n                    </div>\n                </div>\n            </header>\n\n            <!-- drawer -->\n            <div class=\"pihole-drawer mdl-layout__drawer\">\n                <header id=\"header_loggedin\" style=\"display:none\" class=\"pihole-drawer-header mdl-color--primary-dark mdl-color-text--blue-grey-50\">\n                    <div class=\"pihole-avatar-dropdown\">\n                        <img class=\"pihole_logo\" src=\"img/logo.svg\">\n                        <span>You are logged in</span>\n                        <div class=\"mdl-layout-spacer\"></div>\n                        <button id=\"accbtn\" class=\"mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon\">\n                            <i class=\"material-icons\" role=\"presentation\">arrow_drop_down</i>\n                            <span class=\"visuallyhidden\">Accounts</span>\n                        </button>\n                        <ul class=\"mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect\" for=\"accbtn\">\n                            <li class=\"mdl-menu__item\" id=\"logout\"><i class=\"material-icons\">exit_to_app</i>Logout</li>\n                        </ul>\n                    </div>\n                </header>\n                <header id=\"header_guest\" class=\"pihole-drawer-header mdl-color--primary-dark mdl-color-text--blue-grey-50\">\n                    <div class=\"pihole-avatar-dropdown\">\n                        <img class=\"pihole_logo\" src=\"img/logo.svg\">\n                        <span>You are not logged in</span>\n                        <div class=\"mdl-layout-spacer\"></div>                        \n                    </div>\n                </header>\n                <nav id=\"drawer\" class=\"pihole-navigation mdl-navigation mdl-color--white\">\n                    <a class=\"mdl-navigation__link\" href=\"dashboard\"><i class=\"material-icons\" role=\"presentation\">dashboard</i>Dashboard</a>\n                    <a class=\"mdl-navigation__link\" href=\"query_log\"><i class=\"material-icons\" role=\"presentation\">filter_list</i>Query log</a>\n                    <a class=\"mdl-navigation__link\" href=\"app_settings\"><i class=\"material-icons\" role=\"presentation\">settings</i>App settings</a>\n                    <a class=\"mdl-navigation__link\" href=\"about_help\"><i class=\"material-icons\" role=\"presentation\">help_outline</i>About & Help</a>\n                </nav>\n            </div>\n            <!-- /drawer -->\n\n            <main id=\"main_content\" class=\"mdl-layout__content mdl-color--grey-100\">\n                <!-- the ajax area -->\n            </main>\n        </div>\n\n        <!-- scripts -->\n        <script type=\"text/javascript\" src=\"cordova.js\"></script>   \n        <script type=\"text/javascript\" src=\"lib/jQuery/jquery-3.1.1.min.js\"></script>\n        <script type=\"text/javascript\" src=\"lib/mdl/js/material.min.js\"></script>        \n        <script type=\"text/javascript\" src=\"lib/chartist/chartist.min.js\"></script>\n        <script type=\"text/javascript\" src=\"lib/DataTables/datatables.min.js\"></script>\n        <script type=\"text/javascript\" src=\"lib/hammerjs/hammer.min.js\"></script>\n        <script type=\"text/javascript\" src=\"lib/hammerjs/hammer-time.min.js\"></script>\n        <script type=\"text/javascript\" src=\"js/utilities.js\"></script>\n        <script type=\"text/javascript\" src=\"js/main.js\"></script>        \n        <!-- /scripts -->\n    </body>\n</html>\n"
  },
  {
    "path": "www/js/main.js",
    "content": "/*\n * Check if is a cordova app or browser\n */\n\nvar isCordovaApp = (typeof window.cordova !== \"undefined\");\n\nif (isCordovaApp) {\n    document.addEventListener(\"deviceready\", init, false);\n} else {\n    init();\n}\n\n/*\n * Init app\n */\n\nfunction init() {\n\n    // Bind menu voices\n    $('.pihole-navigation a').click(function (event) {\n        event.preventDefault();\n        mdl_toggleDrawer();\n\n        if ($(this).attr('href') == 'dashboard') {\n            if (getPiholeSuccess()) {\n                pageDashboard();\n                _updateToggleButton();\n            } else {\n                pageAppSettings();\n            }\n        } else if ($(this).attr('href') == 'app_settings') {\n            pageAppSettings();\n        } else if ($(this).attr('href') == 'query_log') {\n            if (getPiholeSuccess()) {\n                pageQueryLog();\n                _updateToggleButton();\n            } else {\n                pageAppSettings();\n            }\n        } else if ($(this).attr('href') == 'about_help') {\n            pageAboutHelp();\n            _updateToggleButton();\n        }\n    });\n\n    // Update current status of toggle button\n    _updateToggleButton();\n\n    // Bind logo click enable/disable\n    $('#label-pihole-toggle input').change(function (evt) {\n        if ($(this).is(':checked')) {\n            if (confirm(\"Do you want to ENABLE Pi-hole's ad blocking?\")) {\n                $.getJSON(getPiholeHost() + \"/admin/api.php?enable&auth=\" + getPiholeToken(), function (response_data) {\n\n                });\n            } else {\n                $('#label-pihole-toggle')[0].MaterialSwitch.off();\n                evt.preventDefault();\n            }\n        } else {\n            if (confirm(\"Do you want to DISABLE Pi-hole's ad blocking?\")) {\n                $.getJSON(getPiholeHost() + \"/admin/api.php?disable&auth=\" + getPiholeToken(), function (response_data) {\n\n                });\n            } else {\n                $('#label-pihole-toggle')[0].MaterialSwitch.on();\n                evt.preventDefault();\n            }\n        }\n    });\n\n    // Bind swipe drawer actions\n    var hammertime_content = new Hammer(document.getElementById('main_content'));\n    hammertime_content.on('swiperight', function () {\n        mdl_toggleDrawer();\n    });\n\n    var hammertime_drawer = new Hammer(document.getElementById('drawer'));\n    hammertime_drawer.on('swipeleft', function () {\n        mdl_toggleDrawer();\n    });\n\n    // Start\n    if (getPiholeHost() && getPiholeToken()) {\n        _manageVisibilityToggle('show');\n        userIsLoggedIn();\n        pageDashboard();\n    } else {\n        pageAppSettings();\n    }\n\n}\n\n/*************************************************************\n * Settings page\n *************************************************************/\n\nfunction pageAppSettings() {\n    $.get(\"partial/app-settings.html\", function (data) {\n        updateAppTitle('<strong>Pi</strong>-hole app settings');\n        $(\"#main_content\").html(data);\n        mdl_upgradeDom();\n\n        // bind go_to_help click\n        $('#go_to_help').click(function () {\n            pageAboutHelp();\n        });\n\n        if (getPiholeHost()) {\n            $('#pihole_host').val(getPiholeHost());\n        }\n\n        if (getPiholeToken()) {\n            $('#pihole_token').val(getPiholeToken());\n        }\n\n        updateFloatLabel();\n\n        document.addEventListener(\"deviceready\", function () {\n            function scanQRCode() {\n                cordova.plugins.barcodeScanner.scan(\n                        function (result) {\n                            if (result.text) {\n                                $('#pihole_token').val(result.text);\n                                updateFloatLabel();\n                            }\n                        },\n                        function (error) {\n                            alert(\"Scanning failed: \" + error);\n                        },\n                        {\n                            preferFrontCamera: false,\n                            showFlipCameraButton: true,\n                            showTorchButton: true,\n                            torchOn: false,\n                            prompt: \"Place Pi-hole QR Code inside the scan area\",\n                            resultDisplayDuration: 0,\n                            formats: \"QR_CODE,PDF_417\",\n                            orientation: \"portrait\"\n                        }\n                );\n            }\n\n            $('#qrcode_scan').click(scanQRCode);\n        });\n\n        $('#form_settings').submit(function (event) {\n            event.preventDefault();\n\n            $(\"#form_settings > button[type='submit']\").html('PLEASE WAIT <i class=\"material-icons loading\">refresh</i>').prop(\"disabled\", true);\n            $(\"#form_settings > button[type='submit'] > .loading\").show();\n\n            var pihole_host = $('#pihole_host').val();\n            var pihole_token = $('#pihole_token').val();\n\n            // check if pihole_host contains http or https, otherwise add http as default\n            // TODO: complete the check\n            if (pihole_host.indexOf(\"http://\") == 0 || pihole_host.indexOf(\"https://\") == 0) {\n\n            }\n\n            _localStorage('save', 'pihole_host', pihole_host);\n            _localStorage('save', 'pihole_token', pihole_token);\n            _localStorage('remove', 'pihole_success');\n\n            $.ajax({\n                type: \"GET\",\n                url: pihole_host + \"/admin/api.php?getQuerySources&auth=\" + pihole_token,\n                success: function (data) {\n                    $.getJSON(pihole_host + \"/admin/api.php?getQuerySources&auth=\" + pihole_token, function (response) {\n                        if (jQuery.isEmptyObject(response)) {\n                            showErrorSettings();\n                        } else {\n                            _localStorage('save', 'pihole_success', 1);\n                            userIsLoggedIn();\n                            _updateToggleButton();\n                            pageDashboard();\n                        }\n                    });\n                },\n                error: function () {\n                    showErrorSettings();\n                }\n            });\n\n        });\n\n    });\n}\n\n/*\n * Show error dialog when settings are wrong\n */\n\nfunction showErrorSettings() {\n    var dialog = document.querySelector('dialog');\n    if (!dialog.showModal) {\n        dialogPolyfill.registerDialog(dialog);\n    }\n    dialog.showModal();\n    dialog.querySelector('.close').addEventListener('click', function () {\n        dialog.close();\n        $(\"#form_settings > button[type='submit']\").html('SAVE').prop(\"disabled\", false);\n    });\n}\n/*************************************************************/\n\n\n/*************************************************************\n * Dashboard page\n *************************************************************/\n\nfunction pageDashboard() {\n    $.get(\"partial/dashboard.html\", function (dataHtml) {\n        updateAppTitle('<strong>Pi</strong>-hole dashboard');\n        $(\"#main_content\").html(dataHtml);\n        mdl_upgradeDom();\n\n        /* summary */\n        var pihole_host = getPiholeHost();\n        var pihole_token = getPiholeToken();\n\n        $.getJSON(pihole_host + \"/admin/api.php?summary&auth=\" + pihole_token, function (response_data) {\n            $('#ads_blocked_today > .mdl-card__title > h2').html(response_data.ads_blocked_today);\n            $('#dns_queries_today > .mdl-card__title > h2').html(response_data.dns_queries_today);\n            $('#ads_percentage_today > .mdl-card__title > h2').html(response_data.ads_percentage_today + '%');\n            $('#domains_being_blocked > .mdl-card__title > h2').html(response_data.domains_being_blocked);\n        });\n\n        /* query types */\n        $.getJSON(pihole_host + \"/admin/api.php?getQueryTypes&auth=\" + pihole_token, function (response_data) {\n\n            var data = {\n                labels: ['A (IPv4)', 'AAAA (IPv6)'],\n                series: [{\n                        value: response_data.querytypes['A (IPv4)'],\n                        className: \"ct-fill-red\"\n                    }, {\n                        value: response_data.querytypes['AAAA (IPv6)'],\n                        className: \"ct-fill-blue\"\n                    }]\n            };\n\n            var options = {\n                height: 300,\n                chartPadding: 50,\n                labelOffset: 85\n            };\n\n            $('.ct-chart-query-types .loading').fadeOut('normal', function () {\n                new Chartist.Pie('.ct-chart-query-types', data, options);\n            });\n        });\n\n\n        /* forward destinations */\n        $.getJSON(pihole_host + \"/admin/api.php?getForwardDestinations&auth=\" + pihole_token, function (response_data) {\n            var labels_array = [];\n            var series_array = [];\n            var colors_array = [\"ct-fill-red\", \"ct-fill-blue\", \"ct-fill-light-blue\", \"ct-fill-orange\", \"ct-fill-green\"];\n\n            $.each(response_data.forward_destinations, function (key, val) {\n\n                // split key for labels\n                var label_array = key.split('|');\n                if (label_array[1]) {\n                    labels_array.push(label_array[1]);\n                } else {\n                    labels_array.push(label_array[0]);\n                }\n\n                serie_value = {value: val, className: colors_array[Math.floor(Math.random() * colors_array.length)]};\n                series_array.push(serie_value);\n            });\n\n            var data = {\n                labels: labels_array,\n                series: series_array\n            };\n\n            var options = {\n                height: 300,\n                chartPadding: 50,\n                labelOffset: 80\n            };\n\n            $('.ct-chart-forward-destinations .loading').fadeOut('normal', function () {\n                new Chartist.Pie('.ct-chart-forward-destinations', data, options);\n            });\n        });\n\n\n        /* top domains + top advertisers */\n        $.getJSON(pihole_host + \"/admin/api.php?topItems&auth=\" + pihole_token, function (response_data) {\n            $.each(response_data, function (key, val) {\n                if (key == 'top_queries') {\n                    if (jQuery.isEmptyObject(val) == false) {\n\n                        // remove loading row and replace it with results\n                        $('#tbody-table-top-queries > tr:first-child').fadeOut(400, function () {\n                            $.each(val, function (domain, domain_hits) {\n                                $('#tbody-table-top-queries:last-child').append('<tr><td class=\"mdl-data-table__cell--non-numeric\">' + domain + '</td><td>' + domain_hits + '</td></tr>');\n                            });\n                        });\n\n                    } else {\n                        // privacy mode enabled, hide the table\n                        $('#tbody-table-top-queries').parents('div.pihole-card').hide();\n                    }\n                } else if (key == 'top_ads') {\n\n                    // remove loading row and replace it with results\n                    $('#tbody-table-top-ads > tr:first-child').fadeOut(400, function () {\n                        $.each(val, function (domain, domain_hits) {\n                            $('#tbody-table-top-ads:last-child').append('<tr><td class=\"mdl-data-table__cell--non-numeric\">' + domain + '</td><td>' + domain_hits + '</td></tr>');\n                        });\n                    });\n\n                }\n            });\n        });\n\n\n        /* top clients */\n        $.getJSON(pihole_host + \"/admin/api.php?getQuerySources&auth=\" + pihole_token, function (response_data) {\n            $.each(response_data, function (key, val) {\n                if (key == 'top_sources') {\n\n                    // remove loading row and replace it with results\n                    $('#tbody-table-top-clients > tr:first-child').fadeOut(400, function () {\n                        $.each(val, function (client, client_hits) {\n                            $('#tbody-table-top-clients:last-child').append('<tr><td class=\"mdl-data-table__cell--non-numeric\">' + client + '</td><td class=\"mdl-data-table__cell--non-numeric\">' + client_hits + '</td></tr>');\n                        });\n                    });\n                }\n            });\n        });\n\n\n        /* recent items */\n        // TODO: forced PHP api version, can't find an alternative on FTL's API\n        $.getJSON(pihole_host + \"/admin/api.php?recentItems=10&PHP&auth=\" + pihole_token, function (response_data) {\n            $.each(response_data, function (key, val) {\n                if (key == 'recent_queries') {\n\n                    // remove loading row and replace it with results\n                    $('#tbody-table-recent-items > tr:first-child').fadeOut(400, function () {\n                        $.each(val, function (key_query, val_query) {\n                            $('#tbody-table-recent-items:last-child').append('<tr><td class=\"mdl-data-table__cell--non-numeric\">' + val_query.time + '</td><td>' + val_query.domain + '</td><td>' + val_query.ip + '</td></tr>');\n                        });\n                    });\n\n                }\n            });\n        });\n    });\n}\n\n/*************************************************************/\n\n\n/*************************************************************\n * Query log page\n *************************************************************/\n\nfunction pageQueryLog() {\n    $.get(\"partial/query-log.html\", function (dataHtml) {\n        updateAppTitle('<strong>Pi</strong>-hole query log');\n        $(\"#main_content\").html(dataHtml);\n        mdl_upgradeDom();\n\n        var pihole_host = getPiholeHost();\n        var pihole_token = getPiholeToken();\n\n        // TODO: add loading to tbody\n        var dataSet = [];\n        $.getJSON(pihole_host + \"/admin/api.php?getAllQueries&auth=\" + pihole_token, function (data) {\n            $.each(data, function (key, val) {\n                $.each(val, function (query) {\n\n                    // replace unnecessary long strings\n                    var client = val[query][3];\n                    var client_short = client.replace('(127.0.0.1)', '');\n\n                    var datetime = val[query][0];\n                    var datetime_short = datetime.replace('T', '<br />');\n\n                    dataSet.push([datetime_short, val[query][1], val[query][2], client_short, val[query][4]]);\n                });\n            });\n\n            $('.mdl-chip.mdl-please-wait').hide();\n\n            $('#query-log-table').DataTable({\n                data: dataSet,\n                order: [[0, \"desc\"]],\n                columns: [\n                    {title: \"Time\", class: \"mdl-data-table__cell--non-numeric fullwidth\"},\n                    {title: \"Type\"},\n                    {title: \"Domain\"},\n                    {title: \"Client\"},\n                    {title: \"Status\"}\n                ]\n            });\n        });\n    });\n}\n\n/*************************************************************/\n\n\n/*************************************************************\n * About&Help page\n *************************************************************/\n\nfunction pageAboutHelp() {\n    $.get(\"partial/about-help.html\", function (data) {\n        updateAppTitle('<strong>Pi</strong>-hole about & help');\n        $(\"#main_content\").html(data);\n        mdl_upgradeDom();\n    });\n}\n\n/*************************************************************/\n\n\n/*************************************************************\n * Helpers\n *************************************************************/\n\n// Get Pi-hole current status\nfunction _updateToggleButton() {\n    var pihole_host = getPiholeHost();\n    var pihole_token = getPiholeToken();\n\n    if (pihole_host && pihole_token) {\n        $.getJSON(pihole_host + \"/admin/api.php?status&auth=\" + pihole_token, function (response_data) {\n            var current_status = response_data.status;\n\n            if (current_status) {\n                _manageVisibilityToggle('show');\n\n                if (current_status == 'disabled') {\n                    $('#label-pihole-toggle')[0].MaterialSwitch.off();\n                } else if (current_status == 'enabled') {\n                    $('#label-pihole-toggle')[0].MaterialSwitch.on();\n                }\n            }\n        });\n    }\n}\n\n/*************************************************************/"
  },
  {
    "path": "www/js/utilities.js",
    "content": "/*\n * Refresh the DOM for MDL dynamic content\n */\n\nfunction mdl_upgradeDom() {\n    componentHandler.upgradeDom();\n}\n\n/*\n * Toggle open/close of Drawer\n */\n\nfunction mdl_toggleDrawer() {\n    var layout = document.querySelector('.mdl-layout');\n    layout.MaterialLayout.toggleDrawer();\n}\n\n/*\n * Handler localStorage\n */\n\nfunction _localStorage(action, key, value) {\n    var storage = window.localStorage;\n\n    if (action == 'get') {\n        return storage.getItem(key);\n    } else if (action == 'save') {\n        if (storage.setItem(key, value)) {\n            return true;\n        }\n    } else if (action == 'remove') {\n        if (storage.removeItem(key)) {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n/*\n * Action to perform when the user is logged in\n */\n\nfunction userIsLoggedIn() {\n    _localStorage('save', 'pihole_success', 1);\n    $('#header_guest').hide();\n    $('#header_loggedin').show();\n\n    $('#logout').click(function (event) {\n        event.preventDefault();\n        _localStorage('remove', 'pihole_success');\n        _localStorage('remove', 'pihole_host');\n        _localStorage('remove', 'pihole_token');\n        userIsGuest();\n        pageAppSettings();\n    });\n}\n\n/*\n * Action to perform when the user is not logged in (guest)\n */\n\nfunction userIsGuest() {\n    $('#header_guest').show();\n    $('#header_loggedin').hide();\n    mdl_toggleDrawer();\n}\n\n/*\n * Get Pihole Hostname\n */\n\nfunction getPiholeHost() {\n    return _localStorage('get', 'pihole_host');\n}\n\n/*\n * Get Pihole Token\n */\n\nfunction getPiholeToken() {\n    return _localStorage('get', 'pihole_token');\n}\n\n/*\n * Get Pihole Success connect flag\n */\n\nfunction getPiholeSuccess() {\n    return _localStorage('get', 'pihole_success');\n}\n\n/*\n * Update MDL float label when there is a value on the input\n */\n\nfunction updateFloatLabel() {\n    var nodeList = document.querySelectorAll('.mdl-textfield');\n\n    Array.prototype.forEach.call(nodeList, function (elem) {\n        elem.MaterialTextfield.checkDirty();\n    });\n}\n\n/*\n * Update the App title according to active page\n */\n\nfunction updateAppTitle(title) {\n    $('.mdl-layout-title').html(title);\n}\n\n/*\n * Manage visibility of toggle button\n */\n\nfunction _manageVisibilityToggle(action) {\n    if(action == 'show') {\n        $('#container-pihole-toggle').show();\n    } else if(action == 'hide') {\n        $('#container-pihole-toggle').hide();\n    }\n}"
  },
  {
    "path": "www/lib/DataTables/DataTables-1.10.13/css/dataTables.bootstrap.css",
    "content": "table.dataTable {\n  clear: both;\n  margin-top: 6px !important;\n  margin-bottom: 6px !important;\n  max-width: none !important;\n  border-collapse: separate !important;\n}\ntable.dataTable td,\ntable.dataTable th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable td.dataTables_empty,\ntable.dataTable th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.nowrap th,\ntable.dataTable.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper div.dataTables_length label {\n  font-weight: normal;\n  text-align: left;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_length select {\n  width: 75px;\n  display: inline-block;\n}\ndiv.dataTables_wrapper div.dataTables_filter {\n  text-align: right;\n}\ndiv.dataTables_wrapper div.dataTables_filter label {\n  font-weight: normal;\n  white-space: nowrap;\n  text-align: left;\n}\ndiv.dataTables_wrapper div.dataTables_filter input {\n  margin-left: 0.5em;\n  display: inline-block;\n  width: auto;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 8px;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_paginate {\n  margin: 0;\n  white-space: nowrap;\n  text-align: right;\n}\ndiv.dataTables_wrapper div.dataTables_paginate ul.pagination {\n  margin: 2px 0;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  margin-top: -26px;\n  text-align: center;\n  padding: 1em 0;\n}\n\ntable.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting,\ntable.dataTable thead > tr > td.sorting_asc,\ntable.dataTable thead > tr > td.sorting_desc,\ntable.dataTable thead > tr > td.sorting {\n  padding-right: 30px;\n}\ntable.dataTable thead > tr > th:active,\ntable.dataTable thead > tr > td:active {\n  outline: none;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  cursor: pointer;\n  position: relative;\n}\ntable.dataTable thead .sorting:after,\ntable.dataTable thead .sorting_asc:after,\ntable.dataTable thead .sorting_desc:after,\ntable.dataTable thead .sorting_asc_disabled:after,\ntable.dataTable thead .sorting_desc_disabled:after {\n  position: absolute;\n  bottom: 8px;\n  right: 8px;\n  display: block;\n  font-family: 'Glyphicons Halflings';\n  opacity: 0.5;\n}\ntable.dataTable thead .sorting:after {\n  opacity: 0.2;\n  content: \"\\e150\";\n  /* sort */\n}\ntable.dataTable thead .sorting_asc:after {\n  content: \"\\e155\";\n  /* sort-by-attributes */\n}\ntable.dataTable thead .sorting_desc:after {\n  content: \"\\e156\";\n  /* sort-by-attributes-alt */\n}\ntable.dataTable thead .sorting_asc_disabled:after,\ntable.dataTable thead .sorting_desc_disabled:after {\n  color: #eee;\n}\n\ndiv.dataTables_scrollHead table.dataTable {\n  margin-bottom: 0 !important;\n}\n\ndiv.dataTables_scrollBody table {\n  border-top: none;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\ndiv.dataTables_scrollBody table thead .sorting:after,\ndiv.dataTables_scrollBody table thead .sorting_asc:after,\ndiv.dataTables_scrollBody table thead .sorting_desc:after {\n  display: none;\n}\ndiv.dataTables_scrollBody table tbody tr:first-child th,\ndiv.dataTables_scrollBody table tbody tr:first-child td {\n  border-top: none;\n}\n\ndiv.dataTables_scrollFoot table {\n  margin-top: 0 !important;\n  border-top: none;\n}\n\n@media screen and (max-width: 767px) {\n  div.dataTables_wrapper div.dataTables_length,\n  div.dataTables_wrapper div.dataTables_filter,\n  div.dataTables_wrapper div.dataTables_info,\n  div.dataTables_wrapper div.dataTables_paginate {\n    text-align: center;\n  }\n}\ntable.dataTable.table-condensed > thead > tr > th {\n  padding-right: 20px;\n}\ntable.dataTable.table-condensed .sorting:after,\ntable.dataTable.table-condensed .sorting_asc:after,\ntable.dataTable.table-condensed .sorting_desc:after {\n  top: 6px;\n  right: 6px;\n}\n\ntable.table-bordered.dataTable th,\ntable.table-bordered.dataTable td {\n  border-left-width: 0;\n}\ntable.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child,\ntable.table-bordered.dataTable td:last-child,\ntable.table-bordered.dataTable td:last-child {\n  border-right-width: 0;\n}\ntable.table-bordered.dataTable tbody th,\ntable.table-bordered.dataTable tbody td {\n  border-bottom-width: 0;\n}\n\ndiv.dataTables_scrollHead table.table-bordered {\n  border-bottom-width: 0;\n}\n\ndiv.table-responsive > div.dataTables_wrapper > div.row {\n  margin: 0;\n}\ndiv.table-responsive > div.dataTables_wrapper > div.row > div[class^=\"col-\"]:first-child {\n  padding-left: 0;\n}\ndiv.table-responsive > div.dataTables_wrapper > div.row > div[class^=\"col-\"]:last-child {\n  padding-right: 0;\n}\n"
  },
  {
    "path": "www/lib/DataTables/DataTables-1.10.13/css/dataTables.foundation.css",
    "content": "table.dataTable {\n  clear: both;\n  margin: 0.5em 0 !important;\n  max-width: none !important;\n  width: 100%;\n}\ntable.dataTable td,\ntable.dataTable th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable td.dataTables_empty,\ntable.dataTable th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper {\n  position: relative;\n}\ndiv.dataTables_wrapper div.dataTables_length label {\n  float: left;\n  text-align: left;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_length select {\n  width: 75px;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter label {\n  float: right;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter input {\n  display: inline-block !important;\n  width: auto !important;\n  margin-bottom: 0;\n  margin-left: 0.5em;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 2px;\n}\ndiv.dataTables_wrapper div.dataTables_paginate {\n  float: right;\n  margin: 0;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  margin-top: -26px;\n  text-align: center;\n  padding: 1rem 0;\n}\n\ntable.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting,\ntable.dataTable thead > tr > td.sorting_asc,\ntable.dataTable thead > tr > td.sorting_desc,\ntable.dataTable thead > tr > td.sorting {\n  padding-right: 1.5rem;\n}\ntable.dataTable thead > tr > th:active,\ntable.dataTable thead > tr > td:active {\n  outline: none;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc {\n  cursor: pointer;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"../images/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"../images/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"../images/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"../images/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"../images/sort_desc_disabled.png\");\n}\n\ndiv.dataTables_scrollHead table {\n  margin-bottom: 0 !important;\n}\n\ndiv.dataTables_scrollBody table {\n  border-top: none;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\ndiv.dataTables_scrollBody table tbody tr:first-child th,\ndiv.dataTables_scrollBody table tbody tr:first-child td {\n  border-top: none;\n}\n\ndiv.dataTables_scrollFoot table {\n  margin-top: 0 !important;\n  border-top: none;\n}\n"
  },
  {
    "path": "www/lib/DataTables/DataTables-1.10.13/css/dataTables.jqueryui.css",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: #f6f6f6;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #fafafa;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #fafafa;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fcfcfc;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fefefe;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ececec;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #efefef;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em 1em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #979797;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  color: white !important;\n  border: 1px solid #111;\n  background-color: #585858;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #585858 0%, #111 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #585858 0%, #111 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #585858 0%, #111 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #585858 0%, #111 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  background-color: #2b2b2b;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);\n  /* W3C */\n  box-shadow: inset 0 0 3px #111;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td {\n  vertical-align: middle;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}\ntable.dataTable thead th div.DataTables_sort_wrapper {\n  position: relative;\n}\ntable.dataTable thead th div.DataTables_sort_wrapper span {\n  position: absolute;\n  top: 50%;\n  margin-top: -8px;\n  right: -18px;\n}\ntable.dataTable thead th.ui-state-default,\ntable.dataTable tfoot th.ui-state-default {\n  border-left-width: 0;\n}\ntable.dataTable thead th.ui-state-default:first-child,\ntable.dataTable tfoot th.ui-state-default:first-child {\n  border-left-width: 1px;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper .dataTables_paginate .fg-button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  border: 1px solid transparent;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:active {\n  outline: none;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:first-child {\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:last-child {\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.dataTables_wrapper .ui-widget-header {\n  font-weight: normal;\n}\n.dataTables_wrapper .ui-toolbar {\n  padding: 8px;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: none;\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: inherit;\n}\n"
  },
  {
    "path": "www/lib/DataTables/DataTables-1.10.13/css/dataTables.semanticui.css",
    "content": "/*\n * Styling for DataTables with Semantic UI\n */\ntable.dataTable.table {\n  margin: 0;\n}\ntable.dataTable.table thead th,\ntable.dataTable.table thead td {\n  position: relative;\n}\ntable.dataTable.table thead th.sorting, table.dataTable.table thead th.sorting_asc, table.dataTable.table thead th.sorting_desc,\ntable.dataTable.table thead td.sorting,\ntable.dataTable.table thead td.sorting_asc,\ntable.dataTable.table thead td.sorting_desc {\n  padding-right: 20px;\n}\ntable.dataTable.table thead th.sorting:after, table.dataTable.table thead th.sorting_asc:after, table.dataTable.table thead th.sorting_desc:after,\ntable.dataTable.table thead td.sorting:after,\ntable.dataTable.table thead td.sorting_asc:after,\ntable.dataTable.table thead td.sorting_desc:after {\n  position: absolute;\n  top: 12px;\n  right: 8px;\n  display: block;\n  font-family: Icons;\n}\ntable.dataTable.table thead th.sorting:after,\ntable.dataTable.table thead td.sorting:after {\n  content: \"\\f0dc\";\n  color: #ddd;\n  font-size: 0.8em;\n}\ntable.dataTable.table thead th.sorting_asc:after,\ntable.dataTable.table thead td.sorting_asc:after {\n  content: \"\\f0de\";\n}\ntable.dataTable.table thead th.sorting_desc:after,\ntable.dataTable.table thead td.sorting_desc:after {\n  content: \"\\f0dd\";\n}\ntable.dataTable.table td,\ntable.dataTable.table th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable.table td.dataTables_empty,\ntable.dataTable.table th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.table.nowrap th,\ntable.dataTable.table.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper div.dataTables_length select {\n  vertical-align: middle;\n  min-height: 2.7142em;\n}\ndiv.dataTables_wrapper div.dataTables_length .ui.selection.dropdown {\n  min-width: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter input {\n  margin-left: 0.5em;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 13px;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  text-align: center;\n}\ndiv.dataTables_wrapper div.row.dt-table {\n  padding: 0;\n}\ndiv.dataTables_wrapper div.dataTables_scrollHead table.dataTable {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n  border-bottom: none;\n}\ndiv.dataTables_wrapper div.dataTables_scrollBody thead .sorting:after,\ndiv.dataTables_wrapper div.dataTables_scrollBody thead .sorting_asc:after,\ndiv.dataTables_wrapper div.dataTables_scrollBody thead .sorting_desc:after {\n  display: none;\n}\ndiv.dataTables_wrapper div.dataTables_scrollBody table.dataTable {\n  border-radius: 0;\n  border-top: none;\n  border-bottom-width: 0;\n}\ndiv.dataTables_wrapper div.dataTables_scrollBody table.dataTable.no-footer {\n  border-bottom-width: 1px;\n}\ndiv.dataTables_wrapper div.dataTables_scrollFoot table.dataTable {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n  border-top: none;\n}\n"
  },
  {
    "path": "www/lib/DataTables/DataTables-1.10.13/css/jquery.dataTables.css",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px;\n  border-bottom: 1px solid #111;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n  border-top: 1px solid #111;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc {\n  cursor: pointer;\n  *cursor: hand;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"../images/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"../images/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"../images/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"../images/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"../images/sort_desc_disabled.png\");\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: #f6f6f6;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #fafafa;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #fafafa;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fcfcfc;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fefefe;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ececec;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #efefef;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em 1em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #979797;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  color: white !important;\n  border: 1px solid #111;\n  background-color: #585858;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #585858 0%, #111 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #585858 0%, #111 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #585858 0%, #111 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #585858 0%, #111 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  background-color: #2b2b2b;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);\n  /* W3C */\n  box-shadow: inset 0 0 3px #111;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td {\n  vertical-align: middle;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}\n"
  },
  {
    "path": "www/lib/DataTables/DataTables-1.10.13/css/jquery.dataTables_themeroller.css",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable thead td,\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 4px 10px;\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting {\n  cursor: pointer;\n  *cursor: hand;\n}\ntable.dataTable thead th div.DataTables_sort_wrapper {\n  position: relative;\n  padding-right: 10px;\n}\ntable.dataTable thead th div.DataTables_sort_wrapper span {\n  position: absolute;\n  top: 50%;\n  margin-top: -8px;\n  right: -5px;\n}\ntable.dataTable thead th.ui-state-default {\n  border-right-width: 0;\n}\ntable.dataTable thead th.ui-state-default:last-child {\n  border-right-width: 1px;\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable th.center,\ntable.dataTable td.center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.right,\ntable.dataTable td.right {\n  text-align: right;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #abb9d3;\n}\ntable.dataTable.hover tbody tr:hover,\ntable.dataTable.hover tbody tr.odd:hover,\ntable.dataTable.hover tbody tr.even:hover, table.dataTable.display tbody tr:hover,\ntable.dataTable.display tbody tr.odd:hover,\ntable.dataTable.display tbody tr.even:hover {\n  background-color: whitesmoke;\n}\ntable.dataTable.hover tbody tr:hover.selected,\ntable.dataTable.hover tbody tr.odd:hover.selected,\ntable.dataTable.hover tbody tr.even:hover.selected, table.dataTable.display tbody tr:hover.selected,\ntable.dataTable.display tbody tr.odd:hover.selected,\ntable.dataTable.display tbody tr.even:hover.selected {\n  background-color: #a9b7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #f9f9f9;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad4;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b3cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a7b5ce;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b6d0;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #f9f9f9;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fbfbfb;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fdfdfd;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad4;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #adbbd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1,\ntable.dataTable.display tbody tr.odd:hover > .sorting_1,\ntable.dataTable.display tbody tr.even:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1,\ntable.dataTable.order-column.hover tbody tr.odd:hover > .sorting_1,\ntable.dataTable.order-column.hover tbody tr.even:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2,\ntable.dataTable.display tbody tr.odd:hover > .sorting_2,\ntable.dataTable.display tbody tr.even:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2,\ntable.dataTable.order-column.hover tbody tr.odd:hover > .sorting_2,\ntable.dataTable.order-column.hover tbody tr.even:hover > .sorting_2 {\n  background-color: #ebebeb;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3,\ntable.dataTable.display tbody tr.odd:hover > .sorting_3,\ntable.dataTable.display tbody tr.even:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3,\ntable.dataTable.order-column.hover tbody tr.odd:hover > .sorting_3,\ntable.dataTable.order-column.hover tbody tr.even:hover > .sorting_3 {\n  background-color: #eeeeee;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1,\ntable.dataTable.display tbody tr.odd:hover.selected > .sorting_1,\ntable.dataTable.display tbody tr.even:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1,\ntable.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_1,\ntable.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_1 {\n  background-color: #a1aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2,\ntable.dataTable.display tbody tr.odd:hover.selected > .sorting_2,\ntable.dataTable.display tbody tr.even:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2,\ntable.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_2,\ntable.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_2 {\n  background-color: #a2afc8;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3,\ntable.dataTable.display tbody tr.odd:hover.selected > .sorting_3,\ntable.dataTable.display tbody tr.even:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3,\ntable.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_3,\ntable.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_3 {\n  background-color: #a4b2cb;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 5px 9px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 5px 9px 3px 9px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px 5px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.55em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:active {\n  outline: none;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:first-child {\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:last-child {\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .ui-widget-header {\n  font-weight: normal;\n}\n.dataTables_wrapper .ui-toolbar {\n  padding: 8px;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter,\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter,\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n"
  },
  {
    "path": "www/lib/DataTables/DataTables-1.10.13/js/dataTables.bootstrap.js",
    "content": "/*! DataTables Bootstrap 3 integration\n * ©2011-2015 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Bootstrap 3. This requires Bootstrap 3 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t// Require DataTables, which attaches to jQuery, including\n\t\t\t\t// jQuery if needed and have a $ property so we can access the\n\t\t\t\t// jQuery object that is used\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'row'<'col-sm-6'l><'col-sm-6'f>>\" +\n\t\t\"<'row'<'col-sm-12'tr>>\" +\n\t\t\"<'row'<'col-sm-5'i><'col-sm-7'p>>\",\n\trenderer: 'bootstrap'\n} );\n\n\n/* Default class modification */\n$.extend( DataTable.ext.classes, {\n\tsWrapper:      \"dataTables_wrapper form-inline dt-bootstrap\",\n\tsFilterInput:  \"form-control input-sm\",\n\tsLengthSelect: \"form-control input-sm\",\n\tsProcessing:   \"dataTables_processing panel panel-default\"\n} );\n\n\n/* Bootstrap paging button renderer */\nDataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api     = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang    = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass, counter=0;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'disabled';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'active' : '';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<li>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append( $('<a>', {\n\t\t\t\t\t\t\t\t'href': '#',\n\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\n\t\t\t\t\tcounter++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t// inside an iframe or frame. \n\tvar activeEl;\n\n\ttry {\n\t\t// Because this approach is destroying and recreating the paging\n\t\t// elements, focus is lost on the select button which is bad for\n\t\t// accessibility. So we want to restore focus once the draw has\n\t\t// completed\n\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t}\n\tcatch (e) {}\n\n\tattach(\n\t\t$(host).empty().html('<ul class=\"pagination\"/>').children('ul'),\n\t\tbuttons\n\t);\n\n\tif ( activeEl !== undefined ) {\n\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t}\n};\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "www/lib/DataTables/DataTables-1.10.13/js/dataTables.foundation.js",
    "content": "/*! DataTables Foundation integration\n * ©2011-2015 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Foundation. This requires Foundation 5 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Foundation. See http://datatables.net/manual/styling/foundation\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n// Detect Foundation 5 / 6 as they have different element and class requirements\nvar meta = $('<meta class=\"foundation-mq\"/>').appendTo('head');\nDataTable.ext.foundationVersion = meta.css('font-family').match(/small|medium|large/) ? 6 : 5;\nmeta.remove();\n\n\n$.extend( DataTable.ext.classes, {\n\tsWrapper:    \"dataTables_wrapper dt-foundation\",\n\tsProcessing: \"dataTables_processing panel callout\"\n} );\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'row'<'small-6 columns'l><'small-6 columns'f>r>\"+\n\t\t\"t\"+\n\t\t\"<'row'<'small-6 columns'i><'small-6 columns'p>>\",\n\trenderer: 'foundation'\n} );\n\n\n/* Page button renderer */\nDataTable.ext.renderer.pageButton.foundation = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass;\n\tvar tag;\n\tvar v5 = DataTable.ext.foundationVersion === 5;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('unavailable') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\t\t\t\ttag = null;\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'unavailable disabled';\n\t\t\t\t\t\ttag = null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page > 0 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page > 0 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page < pages-1 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page < pages-1 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'current' : '';\n\t\t\t\t\t\ttag = page === button ?\n\t\t\t\t\t\t\tnull : 'a';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( v5 ) {\n\t\t\t\t\ttag = 'a';\n\t\t\t\t}\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<li>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append( tag ?\n\t\t\t\t\t\t\t$('<'+tag+'/>', {'href': '#'} ).html( btnDisplay ) :\n\t\t\t\t\t\t\tbtnDisplay\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tattach(\n\t\t$(host).empty().html('<ul class=\"pagination\"/>').children('ul'),\n\t\tbuttons\n\t);\n};\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "www/lib/DataTables/DataTables-1.10.13/js/dataTables.jqueryui.js",
    "content": "/*! DataTables jQuery UI integration\n * ©2011-2014 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for jQuery UI. This requires jQuery UI and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using jQuery UI. See http://datatables.net/manual/styling/jqueryui\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar sort_prefix = 'css_right ui-icon ui-icon-';\nvar toolbar_prefix = 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix ui-corner-';\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t'<\"'+toolbar_prefix+'tl ui-corner-tr\"lfr>'+\n\t\t't'+\n\t\t'<\"'+toolbar_prefix+'bl ui-corner-br\"ip>',\n\trenderer: 'jqueryui'\n} );\n\n\n$.extend( DataTable.ext.classes, {\n\t\"sWrapper\":            \"dataTables_wrapper dt-jqueryui\",\n\n\t/* Full numbers paging buttons */\n\t\"sPageButton\":         \"fg-button ui-button ui-state-default\",\n\t\"sPageButtonActive\":   \"ui-state-disabled\",\n\t\"sPageButtonDisabled\": \"ui-state-disabled\",\n\n\t/* Features */\n\t\"sPaging\": \"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi \"+\n\t\t\"ui-buttonset-multi paging_\", /* Note that the type is postfixed */\n\n\t/* Sorting */\n\t\"sSortAsc\":            \"ui-state-default sorting_asc\",\n\t\"sSortDesc\":           \"ui-state-default sorting_desc\",\n\t\"sSortable\":           \"ui-state-default sorting\",\n\t\"sSortableAsc\":        \"ui-state-default sorting_asc_disabled\",\n\t\"sSortableDesc\":       \"ui-state-default sorting_desc_disabled\",\n\t\"sSortableNone\":       \"ui-state-default sorting_disabled\",\n\t\"sSortIcon\":           \"DataTables_sort_icon\",\n\n\t/* Scrolling */\n\t\"sScrollHead\": \"dataTables_scrollHead \"+\"ui-state-default\",\n\t\"sScrollFoot\": \"dataTables_scrollFoot \"+\"ui-state-default\",\n\n\t/* Misc */\n\t\"sHeaderTH\":  \"ui-state-default\",\n\t\"sFooterTH\":  \"ui-state-default\"\n} );\n\n\nDataTable.ext.renderer.header.jqueryui = function ( settings, cell, column, classes ) {\n\t// Calculate what the unsorted class should be\n\tvar noSortAppliedClass = sort_prefix+'carat-2-n-s';\n\tvar asc = $.inArray('asc', column.asSorting) !== -1;\n\tvar desc = $.inArray('desc', column.asSorting) !== -1;\n\n\tif ( !column.bSortable || (!asc && !desc) ) {\n\t\tnoSortAppliedClass = '';\n\t}\n\telse if ( asc && !desc ) {\n\t\tnoSortAppliedClass = sort_prefix+'carat-1-n';\n\t}\n\telse if ( !asc && desc ) {\n\t\tnoSortAppliedClass = sort_prefix+'carat-1-s';\n\t}\n\n\t// Setup the DOM structure\n\t$('<div/>')\n\t\t.addClass( 'DataTables_sort_wrapper' )\n\t\t.append( cell.contents() )\n\t\t.append( $('<span/>')\n\t\t\t.addClass( classes.sSortIcon+' '+noSortAppliedClass )\n\t\t)\n\t\t.appendTo( cell );\n\n\t// Attach a sort listener to update on sort\n\t$(settings.nTable).on( 'order.dt', function ( e, ctx, sorting, columns ) {\n\t\tif ( settings !== ctx ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar colIdx = column.idx;\n\n\t\tcell\n\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\tcolumn.sSortingClass\n\t\t\t);\n\n\t\tcell\n\t\t\t.find( 'span.'+classes.sSortIcon )\n\t\t\t.removeClass(\n\t\t\t\tsort_prefix+'triangle-1-n' +\" \"+\n\t\t\t\tsort_prefix+'triangle-1-s' +\" \"+\n\t\t\t\tsort_prefix+'carat-2-n-s' +\" \"+\n\t\t\t\tsort_prefix+'carat-1-n' +\" \"+\n\t\t\t\tsort_prefix+'carat-1-s'\n\t\t\t)\n\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\tsort_prefix+'triangle-1-n' : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\tsort_prefix+'triangle-1-s' :\n\t\t\t\t\tnoSortAppliedClass\n\t\t\t);\n\t} );\n};\n\n\n/*\n * TableTools jQuery UI compatibility\n * Required TableTools 2.1+\n */\nif ( DataTable.TableTools ) {\n\t$.extend( true, DataTable.TableTools.classes, {\n\t\t\"container\": \"DTTT_container ui-buttonset ui-buttonset-multi\",\n\t\t\"buttons\": {\n\t\t\t\"normal\": \"DTTT_button ui-button ui-state-default\"\n\t\t},\n\t\t\"collection\": {\n\t\t\t\"container\": \"DTTT_collection ui-buttonset ui-buttonset-multi\"\n\t\t}\n\t} );\n}\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "www/lib/DataTables/DataTables-1.10.13/js/dataTables.semanticui.js",
    "content": "/*! DataTables Bootstrap 3 integration\n * ©2011-2015 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Bootstrap 3. This requires Bootstrap 3 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t// Require DataTables, which attaches to jQuery, including\n\t\t\t\t// jQuery if needed and have a $ property so we can access the\n\t\t\t\t// jQuery object that is used\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'ui grid'\"+\n\t\t\t\"<'row'\"+\n\t\t\t\t\"<'eight wide column'l>\"+\n\t\t\t\t\"<'right aligned eight wide column'f>\"+\n\t\t\t\">\"+\n\t\t\t\"<'row dt-table'\"+\n\t\t\t\t\"<'sixteen wide column'tr>\"+\n\t\t\t\">\"+\n\t\t\t\"<'row'\"+\n\t\t\t\t\"<'seven wide column'i>\"+\n\t\t\t\t\"<'right aligned nine wide column'p>\"+\n\t\t\t\">\"+\n\t\t\">\",\n\trenderer: 'semanticUI'\n} );\n\n\n/* Default class modification */\n$.extend( DataTable.ext.classes, {\n\tsWrapper:      \"dataTables_wrapper dt-semanticUI\",\n\tsFilter:       \"dataTables_filter ui input\",\n\tsProcessing:   \"dataTables_processing ui segment\",\n\tsPageButton:   \"paginate_button item\"\n} );\n\n\n/* Bootstrap paging button renderer */\nDataTable.ext.renderer.pageButton.semanticUI = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api     = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang    = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass, counter=0;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'disabled';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'active' : '';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tvar tag = btnClass.indexOf( 'disabled' ) === -1 ?\n\t\t\t\t\t'a' :\n\t\t\t\t\t'div';\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<'+tag+'>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t'href': '#',\n\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t'tabindex': settings.iTabIndex\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\n\t\t\t\t\tcounter++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t// inside an iframe or frame. \n\tvar activeEl;\n\n\ttry {\n\t\t// Because this approach is destroying and recreating the paging\n\t\t// elements, focus is lost on the select button which is bad for\n\t\t// accessibility. So we want to restore focus once the draw has\n\t\t// completed\n\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t}\n\tcatch (e) {}\n\n\tattach(\n\t\t$(host).empty().html('<div class=\"ui pagination menu\"/>').children(),\n\t\tbuttons\n\t);\n\n\tif ( activeEl !== undefined ) {\n\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t}\n};\n\n\n// Javascript enhancements on table initialisation\n$(document).on( 'init.dt', function (e, ctx) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\t// Length menu drop down\n\tif ( $.fn.dropdown ) {\n\t\tvar api = new $.fn.dataTable.Api( ctx );\n\n\t\t$( 'div.dataTables_length select', api.table().container() ).dropdown();\n\t}\n} );\n\n\nreturn DataTable;\n}));"
  },
  {
    "path": "www/lib/DataTables/DataTables-1.10.13/js/jquery.dataTables.js",
    "content": "/*! DataTables 1.10.13\n * ©2008-2016 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     DataTables\n * @description Paginate, search and order HTML tables\n * @version     1.10.13\n * @file        jquery.dataTables.js\n * @author      SpryMedia Ltd\n * @contact     www.datatables.net\n * @copyright   Copyright 2008-2016 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n/*jslint evil: true, undef: true, browser: true */\n/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/\n\n(function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\t// CommonJS environments without a window global must pass a\n\t\t\t\t// root. This will give an error otherwise\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ ) {\n\t\t\t\t$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window\n\t\t\t\t\trequire('jquery') :\n\t\t\t\t\trequire('jquery')( root );\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}\n(function( $, window, document, undefined ) {\n\t\"use strict\";\n\n\t/**\n\t * DataTables is a plug-in for the jQuery Javascript library. It is a highly\n\t * flexible tool, based upon the foundations of progressive enhancement,\n\t * which will add advanced interaction controls to any HTML table. For a\n\t * full list of features please refer to\n\t * [DataTables.net](href=\"http://datatables.net).\n\t *\n\t * Note that the `DataTable` object is not a global variable but is aliased\n\t * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may\n\t * be  accessed.\n\t *\n\t *  @class\n\t *  @param {object} [init={}] Configuration object for DataTables. Options\n\t *    are defined by {@link DataTable.defaults}\n\t *  @requires jQuery 1.7+\n\t *\n\t *  @example\n\t *    // Basic initialisation\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable();\n\t *    } );\n\t *\n\t *  @example\n\t *    // Initialisation with configuration options - in this case, disable\n\t *    // pagination and sorting.\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable( {\n\t *        \"paginate\": false,\n\t *        \"sort\": false\n\t *      } );\n\t *    } );\n\t */\n\tvar DataTable = function ( options )\n\t{\n\t\t/**\n\t\t * Perform a jQuery selector action on the table's TR elements (from the tbody) and\n\t\t * return the resulting jQuery object.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter\n\t\t *    criterion (\"applied\") or all TR elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {object} jQuery object, filtered by the given selector.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Highlight every second row\n\t\t *      oTable.$('tr:odd').css('backgroundColor', 'blue');\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to rows with 'Webkit' in them, add a background colour and then\n\t\t *      // remove the filter, thus highlighting the 'Webkit' rows only.\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      oTable.$('tr', {\"search\": \"applied\"}).css('backgroundColor', 'blue');\n\t\t *      oTable.fnFilter('');\n\t\t *    } );\n\t\t */\n\t\tthis.$ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).$( sSelector, oOpts );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Almost identical to $ in operation, but in this case returns the data for the matched\n\t\t * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes\n\t\t * rather than any descendants, so the data can be obtained for the row/cell. If matching\n\t\t * rows are found, the data returned is the original data array/object that was used to\n\t\t * create the row (or a generated array if from a DOM source).\n\t\t *\n\t\t * This method is often useful in-combination with $ where both functions are given the\n\t\t * same parameters and the array indexes will match identically.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select elements that meet the current filter\n\t\t *    criterion (\"applied\") or all elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the data in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {array} Data for the matched elements. If any elements, as a result of the\n\t\t *    selector, were not TR, TD or TH elements in the DataTable, they will have a null\n\t\t *    entry in the array.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the data from the first row in the table\n\t\t *      var data = oTable._('tr:first');\n\t\t *\n\t\t *      // Do something useful with the data\n\t\t *      alert( \"First cell is: \"+data[0] );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to 'Webkit' and get all data for\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      var data = oTable._('tr', {\"search\": \"applied\"});\n\t\t *\n\t\t *      // Do something with the data\n\t\t *      alert( data.length+\" rows matched the search\" );\n\t\t *    } );\n\t\t */\n\t\tthis._ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).rows( sSelector, oOpts ).data();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Create a DataTables Api instance, with the currently selected tables for\n\t\t * the Api's context.\n\t\t * @param {boolean} [traditional=false] Set the API instance's context to be\n\t\t *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was\n\t\t *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),\n\t\t *   or if all tables captured in the jQuery object should be used.\n\t\t * @return {DataTables.Api}\n\t\t */\n\t\tthis.api = function ( traditional )\n\t\t{\n\t\t\treturn traditional ?\n\t\t\t\tnew _Api(\n\t\t\t\t\t_fnSettingsFromNode( this[ _ext.iApiIndex ] )\n\t\t\t\t) :\n\t\t\t\tnew _Api( this );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Add a single new row or multiple rows of data to the table. Please note\n\t\t * that this is suitable for client-side processing only - if you are using\n\t\t * server-side processing (i.e. \"bServerSide\": true), then to add data, you\n\t\t * must add it to the data source, i.e. the server-side, through an Ajax call.\n\t\t *  @param {array|object} data The data to be added to the table. This can be:\n\t\t *    <ul>\n\t\t *      <li>1D array of data - add a single row with the data provided</li>\n\t\t *      <li>2D array of arrays - add multiple rows in a single call</li>\n\t\t *      <li>object - data object when using <i>mData</i></li>\n\t\t *      <li>array of objects - multiple data objects when using <i>mData</i></li>\n\t\t *    </ul>\n\t\t *  @param {bool} [redraw=true] redraw the table or not\n\t\t *  @returns {array} An array of integers, representing the list of indexes in\n\t\t *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to\n\t\t *    the table.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Global var for counter\n\t\t *    var giCount = 2;\n\t\t *\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example').dataTable();\n\t\t *    } );\n\t\t *\n\t\t *    function fnClickAddRow() {\n\t\t *      $('#example').dataTable().fnAddData( [\n\t\t *        giCount+\".1\",\n\t\t *        giCount+\".2\",\n\t\t *        giCount+\".3\",\n\t\t *        giCount+\".4\" ]\n\t\t *      );\n\t\t *\n\t\t *      giCount++;\n\t\t *    }\n\t\t */\n\t\tthis.fnAddData = function( data, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\t/* Check if we want to add multiple rows or not */\n\t\t\tvar rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?\n\t\t\t\tapi.rows.add( data ) :\n\t\t\t\tapi.row.add( data );\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn rows.flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will make DataTables recalculate the column sizes, based on the data\n\t\t * contained in the table and the sizes applied to the columns (in the DOM, CSS or\n\t\t * through the sWidth parameter). This can be useful when the width of the table's\n\t\t * parent element changes (for example a window resize).\n\t\t *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable( {\n\t\t *        \"sScrollY\": \"200px\",\n\t\t *        \"bPaginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      $(window).on('resize', function () {\n\t\t *        oTable.fnAdjustColumnSizing();\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnAdjustColumnSizing = function ( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).columns.adjust();\n\t\t\tvar settings = api.settings()[0];\n\t\t\tvar scroll = settings.oScroll;\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw( false );\n\t\t\t}\n\t\t\telse if ( scroll.sX !== \"\" || scroll.sY !== \"\" ) {\n\t\t\t\t/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */\n\t\t\t\t_fnScrollDraw( settings );\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Quickly and simply clear a table\n\t\t *  @param {bool} [bRedraw=true] redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)\n\t\t *      oTable.fnClearTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClearTable = function( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).clear();\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * The exact opposite of 'opening' a row, this function will close any rows which\n\t\t * are currently 'open'.\n\t\t *  @param {node} nTr the table row to 'close'\n\t\t *  @returns {int} 0 on success, or 1 if failed (can't find the row)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClose = function( nTr )\n\t\t{\n\t\t\tthis.api( true ).row( nTr ).child.hide();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Remove a row for the table\n\t\t *  @param {mixed} target The index of the row from aoData to be deleted, or\n\t\t *    the TR element you want to delete\n\t\t *  @param {function|null} [callBack] Callback function\n\t\t *  @param {bool} [redraw=true] Redraw the table or not\n\t\t *  @returns {array} The row that was deleted\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately remove the first row\n\t\t *      oTable.fnDeleteRow( 0 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnDeleteRow = function( target, callback, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar rows = api.rows( target );\n\t\t\tvar settings = rows.settings()[0];\n\t\t\tvar data = settings.aoData[ rows[0][0] ];\n\t\t\n\t\t\trows.remove();\n\t\t\n\t\t\tif ( callback ) {\n\t\t\t\tcallback.call( this, settings, data );\n\t\t\t}\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn data;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Restore the table to it's original state in the DOM by removing all of DataTables\n\t\t * enhancements, alterations to the DOM structure of the table and event listeners.\n\t\t *  @param {boolean} [remove=false] Completely remove the table from the DOM\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      // This example is fairly pointless in reality, but shows how fnDestroy can be used\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnDestroy();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDestroy = function ( remove )\n\t\t{\n\t\t\tthis.api( true ).destroy( remove );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Redraw the table\n\t\t *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)\n\t\t *      oTable.fnDraw();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDraw = function( complete )\n\t\t{\n\t\t\t// Note that this isn't an exact match to the old call to _fnDraw - it takes\n\t\t\t// into account the new data, but can hold position.\n\t\t\tthis.api( true ).draw( complete );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Filter the input based on data\n\t\t *  @param {string} sInput String to filter the table on\n\t\t *  @param {int|null} [iColumn] Column to limit filtering to\n\t\t *  @param {bool} [bRegex=false] Treat as regular expression or not\n\t\t *  @param {bool} [bSmart=true] Perform smart filtering or not\n\t\t *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)\n\t\t *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sometime later - filter...\n\t\t *      oTable.fnFilter( 'test string' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === null || iColumn === undefined ) {\n\t\t\t\tapi.search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\n\t\t\tapi.draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the data for the whole table, an individual row or an individual cell based on the\n\t\t * provided parameters.\n\t\t *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as\n\t\t *    a TR node then the data source for the whole row will be returned. If given as a\n\t\t *    TD/TH cell node then iCol will be automatically calculated and the data for the\n\t\t *    cell returned. If given as an integer, then this is treated as the aoData internal\n\t\t *    data index for the row (see fnGetPosition) and the data for that row used.\n\t\t *  @param {int} [col] Optional column index that you want the data of.\n\t\t *  @returns {array|object|string} If mRow is undefined, then the data for all rows is\n\t\t *    returned. If mRow is defined, just data for that row, and is iCol is\n\t\t *    defined, only data for the designated cell is returned.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Row data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('tr').click( function () {\n\t\t *        var data = oTable.fnGetData( this );\n\t\t *        // ... do something with the array / object of data for the row\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Individual cell data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('td').click( function () {\n\t\t *        var sData = oTable.fnGetData( this );\n\t\t *        alert( 'The cell clicked on had the value of '+sData );\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetData = function( src, col )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( src !== undefined ) {\n\t\t\t\tvar type = src.nodeName ? src.nodeName.toLowerCase() : '';\n\t\t\n\t\t\t\treturn col !== undefined || type == 'td' || type == 'th' ?\n\t\t\t\t\tapi.cell( src, col ).data() :\n\t\t\t\t\tapi.row( src ).data() || null;\n\t\t\t}\n\t\t\n\t\t\treturn api.data().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get an array of the TR nodes that are used in the table's body. Note that you will\n\t\t * typically want to use the '$' API method in preference to this as it is more\n\t\t * flexible.\n\t\t *  @param {int} [iRow] Optional row index for the TR element you want\n\t\t *  @returns {array|node} If iRow is undefined, returns an array of all TR elements\n\t\t *    in the table's body, or iRow is defined, just the TR element requested.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the nodes from the table\n\t\t *      var nNodes = oTable.fnGetNodes( );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetNodes = function( iRow )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\treturn iRow !== undefined ?\n\t\t\t\tapi.row( iRow ).node() :\n\t\t\t\tapi.rows().nodes().flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the array indexes of a particular cell from it's DOM element\n\t\t * and column index including hidden columns\n\t\t *  @param {node} node this can either be a TR, TD or TH in the table's body\n\t\t *  @returns {int} If nNode is given as a TR, then a single index is returned, or\n\t\t *    if given as a cell, an array of [row index, column index (visible),\n\t\t *    column index (all)] is given.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example tbody td').click( function () {\n\t\t *        // Get the position of the current data from the node\n\t\t *        var aPos = oTable.fnGetPosition( this );\n\t\t *\n\t\t *        // Get the data array for this row\n\t\t *        var aData = oTable.fnGetData( aPos[0] );\n\t\t *\n\t\t *        // Update the data array and return the value\n\t\t *        aData[ aPos[1] ] = 'clicked';\n\t\t *        this.innerHTML = 'clicked';\n\t\t *      } );\n\t\t *\n\t\t *      // Init DataTables\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetPosition = function( node )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar nodeName = node.nodeName.toUpperCase();\n\t\t\n\t\t\tif ( nodeName == 'TR' ) {\n\t\t\t\treturn api.row( node ).index();\n\t\t\t}\n\t\t\telse if ( nodeName == 'TD' || nodeName == 'TH' ) {\n\t\t\t\tvar cell = api.cell( node ).index();\n\t\t\n\t\t\t\treturn [\n\t\t\t\t\tcell.row,\n\t\t\t\t\tcell.columnVisible,\n\t\t\t\t\tcell.column\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Check to see if a row is 'open' or not.\n\t\t *  @param {node} nTr the table row to check\n\t\t *  @returns {boolean} true if the row is currently open, false otherwise\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnIsOpen = function( nTr )\n\t\t{\n\t\t\treturn this.api( true ).row( nTr ).child.isShown();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will place a new row directly after a row which is currently\n\t\t * on display on the page, with the HTML contents that is passed into the\n\t\t * function. This can be used, for example, to ask for confirmation that a\n\t\t * particular record should be deleted.\n\t\t *  @param {node} nTr The table row to 'open'\n\t\t *  @param {string|node|jQuery} mHtml The HTML to put into the row\n\t\t *  @param {string} sClass Class to give the new TD cell\n\t\t *  @returns {node} The row opened. Note that if the table row passed in as the\n\t\t *    first parameter, is not found in the table, this method will silently\n\t\t *    return.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnOpen = function( nTr, mHtml, sClass )\n\t\t{\n\t\t\treturn this.api( true )\n\t\t\t\t.row( nTr )\n\t\t\t\t.child( mHtml, sClass )\n\t\t\t\t.show()\n\t\t\t\t.child()[0];\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Change the pagination - provides the internal logic for pagination in a simple API\n\t\t * function. With this function you can have a DataTables table go to the next,\n\t\t * previous, first or last pages.\n\t\t *  @param {string|int} mAction Paging action to take: \"first\", \"previous\", \"next\" or \"last\"\n\t\t *    or page number to jump to (integer), note that page 0 is the first page.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnPageChange( 'next' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnPageChange = function ( mAction, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).page( mAction );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw(false);\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Show a particular column\n\t\t *  @param {int} iCol The column whose display should be changed\n\t\t *  @param {bool} bShow Show (true) or hide (false) the column\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Hide the second column after initialisation\n\t\t *      oTable.fnSetColumnVis( 1, false );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSetColumnVis = function ( iCol, bShow, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).column( iCol ).visible( bShow );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.columns.adjust().draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the settings for a particular table for external manipulation\n\t\t *  @returns {object} DataTables settings object. See\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      var oSettings = oTable.fnSettings();\n\t\t *\n\t\t *      // Show an example parameter from the settings\n\t\t *      alert( oSettings._iDisplayStart );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSettings = function()\n\t\t{\n\t\t\treturn _fnSettingsFromNode( this[_ext.iApiIndex] );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Sort the table by a particular column\n\t\t *  @param {int} iCol the data index to sort on. Note that this will not match the\n\t\t *    'display index' if you have hidden data entries\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort immediately with columns 0 and 1\n\t\t *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSort = function( aaSort )\n\t\t{\n\t\t\tthis.api( true ).order( aaSort ).draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Attach a sort listener to an element for a given column\n\t\t *  @param {node} nNode the element to attach the sort listener to\n\t\t *  @param {int} iColumn the column that a click on this node will sort on\n\t\t *  @param {function} [fnCallback] callback function when sort is run\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort on column 1, when 'sorter' is clicked on\n\t\t *      oTable.fnSortListener( document.getElementById('sorter'), 1 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSortListener = function( nNode, iColumn, fnCallback )\n\t\t{\n\t\t\tthis.api( true ).order.listener( nNode, iColumn, fnCallback );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Update a table cell or row - this method will accept either a single value to\n\t\t * update the cell with, an array of values with one element for each column or\n\t\t * an object in the same format as the original data source. The function is\n\t\t * self-referencing in order to make the multi column updates easier.\n\t\t *  @param {object|array|string} mData Data to update the cell/row with\n\t\t *  @param {node|int} mRow TR element you want to update or the aoData index\n\t\t *  @param {int} [iColumn] The column to update, give as null or undefined to\n\t\t *    update a whole row.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @param {bool} [bAction=true] Perform pre-draw actions or not\n\t\t *  @returns {int} 0 on success, 1 on error\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell\n\t\t *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row\n\t\t *    } );\n\t\t */\n\t\tthis.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === undefined || iColumn === null ) {\n\t\t\t\tapi.row( mRow ).data( mData );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.cell( mRow, iColumn ).data( mData );\n\t\t\t}\n\t\t\n\t\t\tif ( bAction === undefined || bAction ) {\n\t\t\t\tapi.columns.adjust();\n\t\t\t}\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Provide a common method for plug-ins to check the version of DataTables being used, in order\n\t\t * to ensure compatibility.\n\t\t *  @param {string} sVersion Version string to check for, in the format \"X.Y.Z\". Note that the\n\t\t *    formats \"X\" and \"X.Y\" are also acceptable.\n\t\t *  @returns {boolean} true if this version of DataTables is greater or equal to the required\n\t\t *    version, or false if this version of DataTales is not suitable\n\t\t *  @method\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      alert( oTable.fnVersionCheck( '1.9.0' ) );\n\t\t *    } );\n\t\t */\n\t\tthis.fnVersionCheck = _ext.fnVersionCheck;\n\t\t\n\n\t\tvar _that = this;\n\t\tvar emptyInit = options === undefined;\n\t\tvar len = this.length;\n\n\t\tif ( emptyInit ) {\n\t\t\toptions = {};\n\t\t}\n\n\t\tthis.oApi = this.internal = _ext.internal;\n\n\t\t// Extend with old style plug-in API methods\n\t\tfor ( var fn in DataTable.ext.internal ) {\n\t\t\tif ( fn ) {\n\t\t\t\tthis[fn] = _fnExternApiFunc(fn);\n\t\t\t}\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\t// For each initialisation we want to give it a clean initialisation\n\t\t\t// object that can be bashed around\n\t\t\tvar o = {};\n\t\t\tvar oInit = len > 1 ? // optimisation for single table case\n\t\t\t\t_fnExtend( o, options, true ) :\n\t\t\t\toptions;\n\n\t\t\t/*global oInit,_that,emptyInit*/\n\t\t\tvar i=0, iLen, j, jLen, k, kLen;\n\t\t\tvar sId = this.getAttribute( 'id' );\n\t\t\tvar bInitHandedOff = false;\n\t\t\tvar defaults = DataTable.defaults;\n\t\t\tvar $this = $(this);\n\t\t\t\n\t\t\t\n\t\t\t/* Sanity check */\n\t\t\tif ( this.nodeName.toLowerCase() != 'table' )\n\t\t\t{\n\t\t\t\t_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/* Backwards compatibility for the defaults */\n\t\t\t_fnCompatOpts( defaults );\n\t\t\t_fnCompatCols( defaults.column );\n\t\t\t\n\t\t\t/* Convert the camel-case defaults to Hungarian */\n\t\t\t_fnCamelToHungarian( defaults, defaults, true );\n\t\t\t_fnCamelToHungarian( defaults.column, defaults.column, true );\n\t\t\t\n\t\t\t/* Setting up the initialisation object */\n\t\t\t_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/* Check to see if we are re-initialising a table */\n\t\t\tvar allSettings = DataTable.settings;\n\t\t\tfor ( i=0, iLen=allSettings.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tvar s = allSettings[i];\n\t\t\t\n\t\t\t\t/* Base check on table node */\n\t\t\t\tif ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )\n\t\t\t\t{\n\t\t\t\t\tvar bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;\n\t\t\t\t\tvar bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;\n\t\t\t\n\t\t\t\t\tif ( emptyInit || bRetrieve )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn s.oInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( bDestroy )\n\t\t\t\t\t{\n\t\t\t\t\t\ts.oInstance.fnDestroy();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* If the element we are initialising has the same ID as a table which was previously\n\t\t\t\t * initialised, but the table nodes don't match (from before) then we destroy the old\n\t\t\t\t * instance by simply deleting it. This is under the assumption that the table has been\n\t\t\t\t * destroyed by other methods. Anyone using non-id selectors will need to do this manually\n\t\t\t\t */\n\t\t\t\tif ( s.sTableId == this.id )\n\t\t\t\t{\n\t\t\t\t\tallSettings.splice( i, 1 );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Ensure the table has an ID - required for accessibility */\n\t\t\tif ( sId === null || sId === \"\" )\n\t\t\t{\n\t\t\t\tsId = \"DataTables_Table_\"+(DataTable.ext._unique++);\n\t\t\t\tthis.id = sId;\n\t\t\t}\n\t\t\t\n\t\t\t/* Create the settings object for this table and set some of the default parameters */\n\t\t\tvar oSettings = $.extend( true, {}, DataTable.models.oSettings, {\n\t\t\t\t\"sDestroyWidth\": $this[0].style.width,\n\t\t\t\t\"sInstance\":     sId,\n\t\t\t\t\"sTableId\":      sId\n\t\t\t} );\n\t\t\toSettings.nTable = this;\n\t\t\toSettings.oApi   = _that.internal;\n\t\t\toSettings.oInit  = oInit;\n\t\t\t\n\t\t\tallSettings.push( oSettings );\n\t\t\t\n\t\t\t// Need to add the instance after the instance after the settings object has been added\n\t\t\t// to the settings array, so we can self reference the table instance if more than one\n\t\t\toSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();\n\t\t\t\n\t\t\t// Backwards compatibility, before we apply all the defaults\n\t\t\t_fnCompatOpts( oInit );\n\t\t\t\n\t\t\tif ( oInit.oLanguage )\n\t\t\t{\n\t\t\t\t_fnLanguageCompat( oInit.oLanguage );\n\t\t\t}\n\t\t\t\n\t\t\t// If the length menu is given, but the init display length is not, use the length menu\n\t\t\tif ( oInit.aLengthMenu && ! oInit.iDisplayLength )\n\t\t\t{\n\t\t\t\toInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?\n\t\t\t\t\toInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];\n\t\t\t}\n\t\t\t\n\t\t\t// Apply the defaults and init options to make a single init object will all\n\t\t\t// options defined from defaults and instance options.\n\t\t\toInit = _fnExtend( $.extend( true, {}, defaults ), oInit );\n\t\t\t\n\t\t\t\n\t\t\t// Map the initialisation options onto the settings object\n\t\t\t_fnMap( oSettings.oFeatures, oInit, [\n\t\t\t\t\"bPaginate\",\n\t\t\t\t\"bLengthChange\",\n\t\t\t\t\"bFilter\",\n\t\t\t\t\"bSort\",\n\t\t\t\t\"bSortMulti\",\n\t\t\t\t\"bInfo\",\n\t\t\t\t\"bProcessing\",\n\t\t\t\t\"bAutoWidth\",\n\t\t\t\t\"bSortClasses\",\n\t\t\t\t\"bServerSide\",\n\t\t\t\t\"bDeferRender\"\n\t\t\t] );\n\t\t\t_fnMap( oSettings, oInit, [\n\t\t\t\t\"asStripeClasses\",\n\t\t\t\t\"ajax\",\n\t\t\t\t\"fnServerData\",\n\t\t\t\t\"fnFormatNumber\",\n\t\t\t\t\"sServerMethod\",\n\t\t\t\t\"aaSorting\",\n\t\t\t\t\"aaSortingFixed\",\n\t\t\t\t\"aLengthMenu\",\n\t\t\t\t\"sPaginationType\",\n\t\t\t\t\"sAjaxSource\",\n\t\t\t\t\"sAjaxDataProp\",\n\t\t\t\t\"iStateDuration\",\n\t\t\t\t\"sDom\",\n\t\t\t\t\"bSortCellsTop\",\n\t\t\t\t\"iTabIndex\",\n\t\t\t\t\"fnStateLoadCallback\",\n\t\t\t\t\"fnStateSaveCallback\",\n\t\t\t\t\"renderer\",\n\t\t\t\t\"searchDelay\",\n\t\t\t\t\"rowId\",\n\t\t\t\t[ \"iCookieDuration\", \"iStateDuration\" ], // backwards compat\n\t\t\t\t[ \"oSearch\", \"oPreviousSearch\" ],\n\t\t\t\t[ \"aoSearchCols\", \"aoPreSearchCols\" ],\n\t\t\t\t[ \"iDisplayLength\", \"_iDisplayLength\" ],\n\t\t\t\t[ \"bJQueryUI\", \"bJUI\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oScroll, oInit, [\n\t\t\t\t[ \"sScrollX\", \"sX\" ],\n\t\t\t\t[ \"sScrollXInner\", \"sXInner\" ],\n\t\t\t\t[ \"sScrollY\", \"sY\" ],\n\t\t\t\t[ \"bScrollCollapse\", \"bCollapse\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oLanguage, oInit, \"fnInfoCallback\" );\n\t\t\t\n\t\t\t/* Callback functions which are array driven */\n\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );\n\t\t\t\n\t\t\toSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );\n\t\t\t\n\t\t\t/* Browser support detection */\n\t\t\t_fnBrowserDetect( oSettings );\n\t\t\t\n\t\t\tvar oClasses = oSettings.oClasses;\n\t\t\t\n\t\t\t// @todo Remove in 1.11\n\t\t\tif ( oInit.bJQueryUI )\n\t\t\t{\n\t\t\t\t/* Use the JUI classes object for display. You could clone the oStdClasses object if\n\t\t\t\t * you want to have multiple tables with multiple independent classes\n\t\t\t\t */\n\t\t\t\t$.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );\n\t\t\t\n\t\t\t\tif ( oInit.sDom === defaults.sDom && defaults.sDom === \"lfrtip\" )\n\t\t\t\t{\n\t\t\t\t\t/* Set the DOM to use a layout suitable for jQuery UI's theming */\n\t\t\t\t\toSettings.sDom = '<\"H\"lfr>t<\"F\"ip>';\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( ! oSettings.renderer ) {\n\t\t\t\t\toSettings.renderer = 'jqueryui';\n\t\t\t\t}\n\t\t\t\telse if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {\n\t\t\t\t\toSettings.renderer.header = 'jqueryui';\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );\n\t\t\t}\n\t\t\t$this.addClass( oClasses.sTable );\n\t\t\t\n\t\t\t\n\t\t\tif ( oSettings.iInitDisplayStart === undefined )\n\t\t\t{\n\t\t\t\t/* Display start point, taking into account the save saving */\n\t\t\t\toSettings.iInitDisplayStart = oInit.iDisplayStart;\n\t\t\t\toSettings._iDisplayStart = oInit.iDisplayStart;\n\t\t\t}\n\t\t\t\n\t\t\tif ( oInit.iDeferLoading !== null )\n\t\t\t{\n\t\t\t\toSettings.bDeferLoading = true;\n\t\t\t\tvar tmp = $.isArray( oInit.iDeferLoading );\n\t\t\t\toSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;\n\t\t\t\toSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;\n\t\t\t}\n\t\t\t\n\t\t\t/* Language definitions */\n\t\t\tvar oLanguage = oSettings.oLanguage;\n\t\t\t$.extend( true, oLanguage, oInit.oLanguage );\n\t\t\t\n\t\t\tif ( oLanguage.sUrl )\n\t\t\t{\n\t\t\t\t/* Get the language definitions from a file - because this Ajax call makes the language\n\t\t\t\t * get async to the remainder of this function we use bInitHandedOff to indicate that\n\t\t\t\t * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor\n\t\t\t\t */\n\t\t\t\t$.ajax( {\n\t\t\t\t\tdataType: 'json',\n\t\t\t\t\turl: oLanguage.sUrl,\n\t\t\t\t\tsuccess: function ( json ) {\n\t\t\t\t\t\t_fnLanguageCompat( json );\n\t\t\t\t\t\t_fnCamelToHungarian( defaults.oLanguage, json );\n\t\t\t\t\t\t$.extend( true, oLanguage, json );\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t},\n\t\t\t\t\terror: function () {\n\t\t\t\t\t\t// Error occurred loading language file, continue on as best we can\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tbInitHandedOff = true;\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Stripes\n\t\t\t */\n\t\t\tif ( oInit.asStripeClasses === null )\n\t\t\t{\n\t\t\t\toSettings.asStripeClasses =[\n\t\t\t\t\toClasses.sStripeOdd,\n\t\t\t\t\toClasses.sStripeEven\n\t\t\t\t];\n\t\t\t}\n\t\t\t\n\t\t\t/* Remove row stripe classes if they are already on the table row */\n\t\t\tvar stripeClasses = oSettings.asStripeClasses;\n\t\t\tvar rowOne = $this.children('tbody').find('tr').eq(0);\n\t\t\tif ( $.inArray( true, $.map( stripeClasses, function(el, i) {\n\t\t\t\treturn rowOne.hasClass(el);\n\t\t\t} ) ) !== -1 ) {\n\t\t\t\t$('tbody tr', this).removeClass( stripeClasses.join(' ') );\n\t\t\t\toSettings.asDestroyStripes = stripeClasses.slice();\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Columns\n\t\t\t * See if we should load columns automatically or use defined ones\n\t\t\t */\n\t\t\tvar anThs = [];\n\t\t\tvar aoColumnsInit;\n\t\t\tvar nThead = this.getElementsByTagName('thead');\n\t\t\tif ( nThead.length !== 0 )\n\t\t\t{\n\t\t\t\t_fnDetectHeader( oSettings.aoHeader, nThead[0] );\n\t\t\t\tanThs = _fnGetUniqueThs( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* If not given a column array, generate one with nulls */\n\t\t\tif ( oInit.aoColumns === null )\n\t\t\t{\n\t\t\t\taoColumnsInit = [];\n\t\t\t\tfor ( i=0, iLen=anThs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\taoColumnsInit.push( null );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoColumnsInit = oInit.aoColumns;\n\t\t\t}\n\t\t\t\n\t\t\t/* Add the columns */\n\t\t\tfor ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t_fnAddColumn( oSettings, anThs ? anThs[i] : null );\n\t\t\t}\n\t\t\t\n\t\t\t/* Apply the column definitions */\n\t\t\t_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {\n\t\t\t\t_fnColumnOptions( oSettings, iCol, oDef );\n\t\t\t} );\n\t\t\t\n\t\t\t/* HTML5 attribute detection - build an mData object automatically if the\n\t\t\t * attributes are found\n\t\t\t */\n\t\t\tif ( rowOne.length ) {\n\t\t\t\tvar a = function ( cell, name ) {\n\t\t\t\t\treturn cell.getAttribute( 'data-'+name ) !== null ? name : null;\n\t\t\t\t};\n\t\t\t\n\t\t\t\t$( rowOne[0] ).children('th, td').each( function (i, cell) {\n\t\t\t\t\tvar col = oSettings.aoColumns[i];\n\t\t\t\n\t\t\t\t\tif ( col.mData === i ) {\n\t\t\t\t\t\tvar sort = a( cell, 'sort' ) || a( cell, 'order' );\n\t\t\t\t\t\tvar filter = a( cell, 'filter' ) || a( cell, 'search' );\n\t\t\t\n\t\t\t\t\t\tif ( sort !== null || filter !== null ) {\n\t\t\t\t\t\t\tcol.mData = {\n\t\t\t\t\t\t\t\t_:      i+'.display',\n\t\t\t\t\t\t\t\tsort:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\ttype:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\tfilter: filter !== null ? i+'.@data-'+filter : undefined\n\t\t\t\t\t\t\t};\n\t\t\t\n\t\t\t\t\t\t\t_fnColumnOptions( oSettings, i );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\t\n\t\t\tvar features = oSettings.oFeatures;\n\t\t\tvar loadedInit = function () {\n\t\t\t\t/*\n\t\t\t\t * Sorting\n\t\t\t\t * @todo For modularisation (1.11) this needs to do into a sort start up handler\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// If aaSorting is not defined, then we use the first indicator in asSorting\n\t\t\t\t// in case that has been altered, so the default sort reflects that option\n\t\t\t\tif ( oInit.aaSorting === undefined ) {\n\t\t\t\t\tvar sorting = oSettings.aaSorting;\n\t\t\t\t\tfor ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {\n\t\t\t\t\t\tsorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Do a first pass on the sorting classes (allows any size changes to be taken into\n\t\t\t\t * account, and also will apply sorting disabled classes if disabled\n\t\t\t\t */\n\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\n\t\t\t\tif ( features.bSort ) {\n\t\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\t\tif ( oSettings.bSorted ) {\n\t\t\t\t\t\t\tvar aSort = _fnSortFlatten( oSettings );\n\t\t\t\t\t\t\tvar sortedColumns = {};\n\t\t\t\n\t\t\t\t\t\t\t$.each( aSort, function (i, val) {\n\t\t\t\t\t\t\t\tsortedColumns[ val.src ] = val.dir;\n\t\t\t\t\t\t\t} );\n\t\t\t\n\t\t\t\t\t\t\t_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );\n\t\t\t\t\t\t\t_fnSortAria( oSettings );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\tif ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {\n\t\t\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\t\t}\n\t\t\t\t}, 'sc' );\n\t\t\t\n\t\t\t\n\t\t\t\t/*\n\t\t\t\t * Final init\n\t\t\t\t * Cache the header, body and footer as required, creating them if needed\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// Work around for Webkit bug 83867 - store the caption-side before removing from doc\n\t\t\t\tvar captions = $this.children('caption').each( function () {\n\t\t\t\t\tthis._captionSide = $(this).css('caption-side');\n\t\t\t\t} );\n\t\t\t\n\t\t\t\tvar thead = $this.children('thead');\n\t\t\t\tif ( thead.length === 0 ) {\n\t\t\t\t\tthead = $('<thead/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTHead = thead[0];\n\t\t\t\n\t\t\t\tvar tbody = $this.children('tbody');\n\t\t\t\tif ( tbody.length === 0 ) {\n\t\t\t\t\ttbody = $('<tbody/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTBody = tbody[0];\n\t\t\t\n\t\t\t\tvar tfoot = $this.children('tfoot');\n\t\t\t\tif ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\") ) {\n\t\t\t\t\t// If we are a scrolling table, and no footer has been given, then we need to create\n\t\t\t\t\t// a tfoot element for the caption element to be appended to\n\t\t\t\t\ttfoot = $('<tfoot/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( tfoot.length === 0 || tfoot.children().length === 0 ) {\n\t\t\t\t\t$this.addClass( oClasses.sNoFooter );\n\t\t\t\t}\n\t\t\t\telse if ( tfoot.length > 0 ) {\n\t\t\t\t\toSettings.nTFoot = tfoot[0];\n\t\t\t\t\t_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Check if there is data passing into the constructor */\n\t\t\t\tif ( oInit.aaData ) {\n\t\t\t\t\tfor ( i=0 ; i<oInit.aaData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( oSettings, oInit.aaData[ i ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {\n\t\t\t\t\t/* Grab the data from the page - only do this when deferred loading or no Ajax\n\t\t\t\t\t * source since there is no point in reading the DOM data if we are then going\n\t\t\t\t\t * to replace it with Ajax data\n\t\t\t\t\t */\n\t\t\t\t\t_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Copy the data index array */\n\t\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\n\t\t\t\t/* Initialisation complete - table can be drawn */\n\t\t\t\toSettings.bInitialised = true;\n\t\t\t\n\t\t\t\t/* Check if we need to initialise the table (it might not have been handed off to the\n\t\t\t\t * language processor)\n\t\t\t\t */\n\t\t\t\tif ( bInitHandedOff === false ) {\n\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\t/* Must be done after everything which can be overridden by the state saving! */\n\t\t\tif ( oInit.bStateSave )\n\t\t\t{\n\t\t\t\tfeatures.bStateSave = true;\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );\n\t\t\t\t_fnLoadState( oSettings, oInit, loadedInit );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadedInit();\n\t\t\t}\n\t\t\t\n\t\t} );\n\t\t_that = null;\n\t\treturn this;\n\t};\n\n\t\n\t/*\n\t * It is useful to have variables which are scoped locally so only the\n\t * DataTables functions can access them and they don't leak into global space.\n\t * At the same time these functions are often useful over multiple files in the\n\t * core and API, so we list, or at least document, all variables which are used\n\t * by DataTables as private variables here. This also ensures that there is no\n\t * clashing of variable names and that they can easily referenced for reuse.\n\t */\n\t\n\t\n\t// Defined else where\n\t//  _selector_run\n\t//  _selector_opts\n\t//  _selector_first\n\t//  _selector_row_indexes\n\t\n\tvar _ext; // DataTable.ext\n\tvar _Api; // DataTable.Api\n\tvar _api_register; // DataTable.Api.register\n\tvar _api_registerPlural; // DataTable.Api.registerPlural\n\t\n\tvar _re_dic = {};\n\tvar _re_new_lines = /[\\r\\n]/g;\n\tvar _re_html = /<.*?>/g;\n\t\n\t// This is not strict ISO8601 - Date.parse() is quite lax, although\n\t// implementations differ between browsers.\n\tvar _re_date = /^\\d{2,4}[\\.\\/\\-]\\d{1,2}[\\.\\/\\-]\\d{1,2}([T ]{1}\\d{1,2}[:\\.]\\d{2}([\\.:]\\d{2})?)?$/;\n\t\n\t// Escape regular expression special characters\n\tvar _re_escape_regex = new RegExp( '(\\\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\\\', '$', '^', '-' ].join('|\\\\') + ')', 'g' );\n\t\n\t// http://en.wikipedia.org/wiki/Foreign_exchange_market\n\t// - \\u20BD - Russian ruble.\n\t// - \\u20a9 - South Korean Won\n\t// - \\u20BA - Turkish Lira\n\t// - \\u20B9 - Indian Rupee\n\t// - R - Brazil (R$) and South Africa\n\t// - fr - Swiss Franc\n\t// - kr - Swedish krona, Norwegian krone and Danish krone\n\t// - \\u2009 is thin space and \\u202F is narrow no-break space, both used in many\n\t//   standards as thousands separators.\n\tvar _re_formatted_numeric = /[',$£€¥%\\u2009\\u202F\\u20BD\\u20a9\\u20BArfk]/gi;\n\t\n\t\n\tvar _empty = function ( d ) {\n\t\treturn !d || d === true || d === '-' ? true : false;\n\t};\n\t\n\t\n\tvar _intVal = function ( s ) {\n\t\tvar integer = parseInt( s, 10 );\n\t\treturn !isNaN(integer) && isFinite(s) ? integer : null;\n\t};\n\t\n\t// Convert from a formatted number with characters other than `.` as the\n\t// decimal place, to a Javascript number\n\tvar _numToDecimal = function ( num, decimalPoint ) {\n\t\t// Cache created regular expressions for speed as this function is called often\n\t\tif ( ! _re_dic[ decimalPoint ] ) {\n\t\t\t_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );\n\t\t}\n\t\treturn typeof num === 'string' && decimalPoint !== '.' ?\n\t\t\tnum.replace( /\\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :\n\t\t\tnum;\n\t};\n\t\n\t\n\tvar _isNumber = function ( d, decimalPoint, formatted ) {\n\t\tvar strType = typeof d === 'string';\n\t\n\t\t// If empty return immediately so there must be a number if it is a\n\t\t// formatted string (this stops the string \"k\", or \"kr\", etc being detected\n\t\t// as a formatted number for currency\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tif ( decimalPoint && strType ) {\n\t\t\td = _numToDecimal( d, decimalPoint );\n\t\t}\n\t\n\t\tif ( formatted && strType ) {\n\t\t\td = d.replace( _re_formatted_numeric, '' );\n\t\t}\n\t\n\t\treturn !isNaN( parseFloat(d) ) && isFinite( d );\n\t};\n\t\n\t\n\t// A string without HTML in it can be considered to be HTML still\n\tvar _isHtml = function ( d ) {\n\t\treturn _empty( d ) || typeof d === 'string';\n\t};\n\t\n\t\n\tvar _htmlNumeric = function ( d, decimalPoint, formatted ) {\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tvar html = _isHtml( d );\n\t\treturn ! html ?\n\t\t\tnull :\n\t\t\t_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?\n\t\t\t\ttrue :\n\t\t\t\tnull;\n\t};\n\t\n\t\n\tvar _pluck = function ( a, prop, prop2 ) {\n\t\tvar out = [];\n\t\tvar i=0, ien=a.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] && a[i][ prop ] ) {\n\t\t\t\t\tout.push( a[i][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] ) {\n\t\t\t\t\tout.push( a[i][ prop ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t// Basically the same as _pluck, but rather than looping over `a` we use `order`\n\t// as the indexes to pick from `a`\n\tvar _pluck_order = function ( a, order, prop, prop2 )\n\t{\n\t\tvar out = [];\n\t\tvar i=0, ien=order.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[ order[i] ][ prop ] ) {\n\t\t\t\t\tout.push( a[ order[i] ][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tout.push( a[ order[i] ][ prop ] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _range = function ( len, start )\n\t{\n\t\tvar out = [];\n\t\tvar end;\n\t\n\t\tif ( start === undefined ) {\n\t\t\tstart = 0;\n\t\t\tend = len;\n\t\t}\n\t\telse {\n\t\t\tend = start;\n\t\t\tstart = len;\n\t\t}\n\t\n\t\tfor ( var i=start ; i<end ; i++ ) {\n\t\t\tout.push( i );\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _removeEmpty = function ( a )\n\t{\n\t\tvar out = [];\n\t\n\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\tif ( a[i] ) { // careful - will remove all falsy values!\n\t\t\t\tout.push( a[i] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _stripHtml = function ( d ) {\n\t\treturn d.replace( _re_html, '' );\n\t};\n\t\n\t\n\t/**\n\t * Find the unique elements in a source array.\n\t *\n\t * @param  {array} src Source array\n\t * @return {array} Array of unique items\n\t * @ignore\n\t */\n\tvar _unique = function ( src )\n\t{\n\t\t// A faster unique method is to use object keys to identify used values,\n\t\t// but this doesn't work with arrays or objects, which we must also\n\t\t// consider. See jsperf.com/compare-array-unique-versions/4 for more\n\t\t// information.\n\t\tvar\n\t\t\tout = [],\n\t\t\tval,\n\t\t\ti, ien=src.length,\n\t\t\tj, k=0;\n\t\n\t\tagain: for ( i=0 ; i<ien ; i++ ) {\n\t\t\tval = src[i];\n\t\n\t\t\tfor ( j=0 ; j<k ; j++ ) {\n\t\t\t\tif ( out[j] === val ) {\n\t\t\t\t\tcontinue again;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tout.push( val );\n\t\t\tk++;\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t/**\n\t * DataTables utility methods\n\t * \n\t * This namespace provides helper methods that DataTables uses internally to\n\t * create a DataTable, but which are not exclusively used only for DataTables.\n\t * These methods can be used by extension authors to save the duplication of\n\t * code.\n\t *\n\t *  @namespace\n\t */\n\tDataTable.util = {\n\t\t/**\n\t\t * Throttle the calls to a function. Arguments and context are maintained\n\t\t * for the throttled function.\n\t\t *\n\t\t * @param {function} fn Function to be called\n\t\t * @param {integer} freq Call frequency in mS\n\t\t * @return {function} Wrapped function\n\t\t */\n\t\tthrottle: function ( fn, freq ) {\n\t\t\tvar\n\t\t\t\tfrequency = freq !== undefined ? freq : 200,\n\t\t\t\tlast,\n\t\t\t\ttimer;\n\t\n\t\t\treturn function () {\n\t\t\t\tvar\n\t\t\t\t\tthat = this,\n\t\t\t\t\tnow  = +new Date(),\n\t\t\t\t\targs = arguments;\n\t\n\t\t\t\tif ( last && now < last + frequency ) {\n\t\t\t\t\tclearTimeout( timer );\n\t\n\t\t\t\t\ttimer = setTimeout( function () {\n\t\t\t\t\t\tlast = undefined;\n\t\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t\t}, frequency );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlast = now;\n\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Escape a string such that it can be used in a regular expression\n\t\t *\n\t\t *  @param {string} val string to escape\n\t\t *  @returns {string} escaped string\n\t\t */\n\t\tescapeRegex: function ( val ) {\n\t\t\treturn val.replace( _re_escape_regex, '\\\\$1' );\n\t\t}\n\t};\n\t\n\t\n\t\n\t/**\n\t * Create a mapping object that allows camel case parameters to be looked up\n\t * for their Hungarian counterparts. The mapping is stored in a private\n\t * parameter called `_hungarianMap` which can be accessed on the source object.\n\t *  @param {object} o\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnHungarianMap ( o )\n\t{\n\t\tvar\n\t\t\thungarian = 'a aa ai ao as b fn i m o s ',\n\t\t\tmatch,\n\t\t\tnewKey,\n\t\t\tmap = {};\n\t\n\t\t$.each( o, function (key, val) {\n\t\t\tmatch = key.match(/^([^A-Z]+?)([A-Z])/);\n\t\n\t\t\tif ( match && hungarian.indexOf(match[1]+' ') !== -1 )\n\t\t\t{\n\t\t\t\tnewKey = key.replace( match[0], match[2].toLowerCase() );\n\t\t\t\tmap[ newKey ] = key;\n\t\n\t\t\t\tif ( match[1] === 'o' )\n\t\t\t\t{\n\t\t\t\t\t_fnHungarianMap( o[key] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\n\t\to._hungarianMap = map;\n\t}\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian, based on a Hungarian map\n\t * created by _fnHungarianMap.\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCamelToHungarian ( src, user, force )\n\t{\n\t\tif ( ! src._hungarianMap ) {\n\t\t\t_fnHungarianMap( src );\n\t\t}\n\t\n\t\tvar hungarianKey;\n\t\n\t\t$.each( user, function (key, val) {\n\t\t\thungarianKey = src._hungarianMap[ key ];\n\t\n\t\t\tif ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )\n\t\t\t{\n\t\t\t\t// For objects, we need to buzz down into the object to copy parameters\n\t\t\t\tif ( hungarianKey.charAt(0) === 'o' )\n\t\t\t\t{\n\t\t\t\t\t// Copy the camelCase options over to the hungarian\n\t\t\t\t\tif ( ! user[ hungarianKey ] ) {\n\t\t\t\t\t\tuser[ hungarianKey ] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, user[hungarianKey], user[key] );\n\t\n\t\t\t\t\t_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tuser[hungarianKey] = user[ key ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Language compatibility - when certain options are given, and others aren't, we\n\t * need to duplicate the values over, in order to provide backwards compatibility\n\t * with older language files.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLanguageCompat( lang )\n\t{\n\t\tvar defaults = DataTable.defaults.oLanguage;\n\t\tvar zeroRecords = lang.sZeroRecords;\n\t\n\t\t/* Backwards compatibility - if there is no sEmptyTable given, then use the same as\n\t\t * sZeroRecords - assuming that is given.\n\t\t */\n\t\tif ( ! lang.sEmptyTable && zeroRecords &&\n\t\t\tdefaults.sEmptyTable === \"No data available in table\" )\n\t\t{\n\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );\n\t\t}\n\t\n\t\t/* Likewise with loading records */\n\t\tif ( ! lang.sLoadingRecords && zeroRecords &&\n\t\t\tdefaults.sLoadingRecords === \"Loading...\" )\n\t\t{\n\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );\n\t\t}\n\t\n\t\t// Old parameter name of the thousands separator mapped onto the new\n\t\tif ( lang.sInfoThousands ) {\n\t\t\tlang.sThousands = lang.sInfoThousands;\n\t\t}\n\t\n\t\tvar decimal = lang.sDecimal;\n\t\tif ( decimal ) {\n\t\t\t_addNumericSort( decimal );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Map one parameter onto another\n\t *  @param {object} o Object to map\n\t *  @param {*} knew The new parameter name\n\t *  @param {*} old The old parameter name\n\t */\n\tvar _fnCompatMap = function ( o, knew, old ) {\n\t\tif ( o[ knew ] !== undefined ) {\n\t\t\to[ old ] = o[ knew ];\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for the main DT options. Note that the new\n\t * options are mapped onto the old parameters, so this is an external interface\n\t * change only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatOpts ( init )\n\t{\n\t\t_fnCompatMap( init, 'ordering',      'bSort' );\n\t\t_fnCompatMap( init, 'orderMulti',    'bSortMulti' );\n\t\t_fnCompatMap( init, 'orderClasses',  'bSortClasses' );\n\t\t_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );\n\t\t_fnCompatMap( init, 'order',         'aaSorting' );\n\t\t_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );\n\t\t_fnCompatMap( init, 'paging',        'bPaginate' );\n\t\t_fnCompatMap( init, 'pagingType',    'sPaginationType' );\n\t\t_fnCompatMap( init, 'pageLength',    'iDisplayLength' );\n\t\t_fnCompatMap( init, 'searching',     'bFilter' );\n\t\n\t\t// Boolean initialisation of x-scrolling\n\t\tif ( typeof init.sScrollX === 'boolean' ) {\n\t\t\tinit.sScrollX = init.sScrollX ? '100%' : '';\n\t\t}\n\t\tif ( typeof init.scrollX === 'boolean' ) {\n\t\t\tinit.scrollX = init.scrollX ? '100%' : '';\n\t\t}\n\t\n\t\t// Column search objects are in an array, so it needs to be converted\n\t\t// element by element\n\t\tvar searchCols = init.aoSearchCols;\n\t\n\t\tif ( searchCols ) {\n\t\t\tfor ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {\n\t\t\t\tif ( searchCols[i] ) {\n\t\t\t\t\t_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for column options. Note that the new options\n\t * are mapped onto the old parameters, so this is an external interface change\n\t * only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatCols ( init )\n\t{\n\t\t_fnCompatMap( init, 'orderable',     'bSortable' );\n\t\t_fnCompatMap( init, 'orderData',     'aDataSort' );\n\t\t_fnCompatMap( init, 'orderSequence', 'asSorting' );\n\t\t_fnCompatMap( init, 'orderDataType', 'sortDataType' );\n\t\n\t\t// orderData can be given as an integer\n\t\tvar dataSort = init.aDataSort;\n\t\tif ( dataSort && ! $.isArray( dataSort ) ) {\n\t\t\tinit.aDataSort = [ dataSort ];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Browser feature detection for capabilities, quirks\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBrowserDetect( settings )\n\t{\n\t\t// We don't need to do this every time DataTables is constructed, the values\n\t\t// calculated are specific to the browser and OS configuration which we\n\t\t// don't expect to change between initialisations\n\t\tif ( ! DataTable.__browser ) {\n\t\t\tvar browser = {};\n\t\t\tDataTable.__browser = browser;\n\t\n\t\t\t// Scrolling feature / quirks detection\n\t\t\tvar n = $('<div/>')\n\t\t\t\t.css( {\n\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: $(window).scrollLeft()*-1, // allow for scrolling\n\t\t\t\t\theight: 1,\n\t\t\t\t\twidth: 1,\n\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t} )\n\t\t\t\t.append(\n\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\ttop: 1,\n\t\t\t\t\t\t\tleft: 1,\n\t\t\t\t\t\t\twidth: 100,\n\t\t\t\t\t\t\toverflow: 'scroll'\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t\t\t\theight: 10\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t.appendTo( 'body' );\n\t\n\t\t\tvar outer = n.children();\n\t\t\tvar inner = outer.children();\n\t\n\t\t\t// Numbers below, in order, are:\n\t\t\t// inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth\n\t\t\t//\n\t\t\t// IE6 XP:                           100 100 100  83\n\t\t\t// IE7 Vista:                        100 100 100  83\n\t\t\t// IE 8+ Windows:                     83  83 100  83\n\t\t\t// Evergreen Windows:                 83  83 100  83\n\t\t\t// Evergreen Mac with scrollbars:     85  85 100  85\n\t\t\t// Evergreen Mac without scrollbars: 100 100 100 100\n\t\n\t\t\t// Get scrollbar width\n\t\t\tbrowser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;\n\t\n\t\t\t// IE6/7 will oversize a width 100% element inside a scrolling element, to\n\t\t\t// include the width of the scrollbar, while other browsers ensure the inner\n\t\t\t// element is contained without forcing scrolling\n\t\t\tbrowser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;\n\t\n\t\t\t// In rtl text layout, some browsers (most, but not all) will place the\n\t\t\t// scrollbar on the left, rather than the right.\n\t\t\tbrowser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;\n\t\n\t\t\t// IE8- don't provide height and width for getBoundingClientRect\n\t\t\tbrowser.bBounding = n[0].getBoundingClientRect().width ? true : false;\n\t\n\t\t\tn.remove();\n\t\t}\n\t\n\t\t$.extend( settings.oBrowser, DataTable.__browser );\n\t\tsettings.oScroll.iBarWidth = DataTable.__browser.barWidth;\n\t}\n\t\n\t\n\t/**\n\t * Array.prototype reduce[Right] method, used for browsers which don't support\n\t * JS 1.6. Done this way to reduce code size, since we iterate either way\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReduce ( that, fn, init, start, end, inc )\n\t{\n\t\tvar\n\t\t\ti = start,\n\t\t\tvalue,\n\t\t\tisSet = false;\n\t\n\t\tif ( init !== undefined ) {\n\t\t\tvalue = init;\n\t\t\tisSet = true;\n\t\t}\n\t\n\t\twhile ( i !== end ) {\n\t\t\tif ( ! that.hasOwnProperty(i) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\tvalue = isSet ?\n\t\t\t\tfn( value, that[i], i, that ) :\n\t\t\t\tthat[i];\n\t\n\t\t\tisSet = true;\n\t\t\ti += inc;\n\t\t}\n\t\n\t\treturn value;\n\t}\n\t\n\t/**\n\t * Add a column to the list used for the table with default values\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nTh The th element for this column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddColumn( oSettings, nTh )\n\t{\n\t\t// Add column to aoColumns array\n\t\tvar oDefaults = DataTable.defaults.column;\n\t\tvar iCol = oSettings.aoColumns.length;\n\t\tvar oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {\n\t\t\t\"nTh\": nTh ? nTh : document.createElement('th'),\n\t\t\t\"sTitle\":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',\n\t\t\t\"aDataSort\": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],\n\t\t\t\"mData\": oDefaults.mData ? oDefaults.mData : iCol,\n\t\t\tidx: iCol\n\t\t} );\n\t\toSettings.aoColumns.push( oCol );\n\t\n\t\t// Add search object for column specific search. Note that the `searchCols[ iCol ]`\n\t\t// passed into extend can be undefined. This allows the user to give a default\n\t\t// with only some of the parameters defined, and also not give a default\n\t\tvar searchCols = oSettings.aoPreSearchCols;\n\t\tsearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );\n\t\n\t\t// Use the default column options function to initialise classes etc\n\t\t_fnColumnOptions( oSettings, iCol, $(nTh).data() );\n\t}\n\t\n\t\n\t/**\n\t * Apply options for a column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iCol column index to consider\n\t *  @param {object} oOptions object with sType, bVisible and bSearchable etc\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnOptions( oSettings, iCol, oOptions )\n\t{\n\t\tvar oCol = oSettings.aoColumns[ iCol ];\n\t\tvar oClasses = oSettings.oClasses;\n\t\tvar th = $(oCol.nTh);\n\t\n\t\t// Try to get width information from the DOM. We can't get it from CSS\n\t\t// as we'd need to parse the CSS stylesheet. `width` option can override\n\t\tif ( ! oCol.sWidthOrig ) {\n\t\t\t// Width attribute\n\t\t\toCol.sWidthOrig = th.attr('width') || null;\n\t\n\t\t\t// Style attribute\n\t\t\tvar t = (th.attr('style') || '').match(/width:\\s*(\\d+[pxem%]+)/);\n\t\t\tif ( t ) {\n\t\t\t\toCol.sWidthOrig = t[1];\n\t\t\t}\n\t\t}\n\t\n\t\t/* User specified column options */\n\t\tif ( oOptions !== undefined && oOptions !== null )\n\t\t{\n\t\t\t// Backwards compatibility\n\t\t\t_fnCompatCols( oOptions );\n\t\n\t\t\t// Map camel case parameters to their Hungarian counterparts\n\t\t\t_fnCamelToHungarian( DataTable.defaults.column, oOptions );\n\t\n\t\t\t/* Backwards compatibility for mDataProp */\n\t\t\tif ( oOptions.mDataProp !== undefined && !oOptions.mData )\n\t\t\t{\n\t\t\t\toOptions.mData = oOptions.mDataProp;\n\t\t\t}\n\t\n\t\t\tif ( oOptions.sType )\n\t\t\t{\n\t\t\t\toCol._sManualType = oOptions.sType;\n\t\t\t}\n\t\n\t\t\t// `class` is a reserved word in Javascript, so we need to provide\n\t\t\t// the ability to use a valid name for the camel case input\n\t\t\tif ( oOptions.className && ! oOptions.sClass )\n\t\t\t{\n\t\t\t\toOptions.sClass = oOptions.className;\n\t\t\t}\n\t\n\t\t\t$.extend( oCol, oOptions );\n\t\t\t_fnMap( oCol, oOptions, \"sWidth\", \"sWidthOrig\" );\n\t\n\t\t\t/* iDataSort to be applied (backwards compatibility), but aDataSort will take\n\t\t\t * priority if defined\n\t\t\t */\n\t\t\tif ( oOptions.iDataSort !== undefined )\n\t\t\t{\n\t\t\t\toCol.aDataSort = [ oOptions.iDataSort ];\n\t\t\t}\n\t\t\t_fnMap( oCol, oOptions, \"aDataSort\" );\n\t\t}\n\t\n\t\t/* Cache the data get and set functions for speed */\n\t\tvar mDataSrc = oCol.mData;\n\t\tvar mData = _fnGetObjectDataFn( mDataSrc );\n\t\tvar mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;\n\t\n\t\tvar attrTest = function( src ) {\n\t\t\treturn typeof src === 'string' && src.indexOf('@') !== -1;\n\t\t};\n\t\toCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (\n\t\t\tattrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)\n\t\t);\n\t\toCol._setter = null;\n\t\n\t\toCol.fnGetData = function (rowData, type, meta) {\n\t\t\tvar innerData = mData( rowData, type, undefined, meta );\n\t\n\t\t\treturn mRender && type ?\n\t\t\t\tmRender( innerData, type, rowData, meta ) :\n\t\t\t\tinnerData;\n\t\t};\n\t\toCol.fnSetData = function ( rowData, val, meta ) {\n\t\t\treturn _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );\n\t\t};\n\t\n\t\t// Indicate if DataTables should read DOM data as an object or array\n\t\t// Used in _fnGetRowElements\n\t\tif ( typeof mDataSrc !== 'number' ) {\n\t\t\toSettings._rowReadObject = true;\n\t\t}\n\t\n\t\t/* Feature sorting overrides column specific when off */\n\t\tif ( !oSettings.oFeatures.bSort )\n\t\t{\n\t\t\toCol.bSortable = false;\n\t\t\tth.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called\n\t\t}\n\t\n\t\t/* Check that the class assignment is correct for sorting */\n\t\tvar bAsc = $.inArray('asc', oCol.asSorting) !== -1;\n\t\tvar bDesc = $.inArray('desc', oCol.asSorting) !== -1;\n\t\tif ( !oCol.bSortable || (!bAsc && !bDesc) )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableNone;\n\t\t\toCol.sSortingClassJUI = \"\";\n\t\t}\n\t\telse if ( bAsc && !bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableAsc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;\n\t\t}\n\t\telse if ( !bAsc && bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableDesc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;\n\t\t}\n\t\telse\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortable;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUI;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Adjust the table column widths for new data. Note: you would probably want to\n\t * do a redraw after calling this function!\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAdjustColumnSizing ( settings )\n\t{\n\t\t/* Not interested in doing column width calculation if auto-width is disabled */\n\t\tif ( settings.oFeatures.bAutoWidth !== false )\n\t\t{\n\t\t\tvar columns = settings.aoColumns;\n\t\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t\tfor ( var i=0 , iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tcolumns[i].nTh.style.width = columns[i].sWidth;\n\t\t\t}\n\t\t}\n\t\n\t\tvar scroll = settings.oScroll;\n\t\tif ( scroll.sY !== '' || scroll.sX !== '')\n\t\t{\n\t\t\t_fnScrollDraw( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'column-sizing', [settings] );\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of a visible column to the index in the data array (take account\n\t * of hidden columns)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iMatch Visible column index to lookup\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisibleToColumnIndex( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\n\t\treturn typeof aiVis[iMatch] === 'number' ?\n\t\t\taiVis[iMatch] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of an index in the data array and convert it to the visible\n\t *   column index (take account of hidden columns)\n\t *  @param {int} iMatch Column index to lookup\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnIndexToVisible( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\tvar iPos = $.inArray( iMatch, aiVis );\n\t\n\t\treturn iPos !== -1 ? iPos : null;\n\t}\n\t\n\t\n\t/**\n\t * Get the number of visible columns\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the number of visible columns\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisbleColumns( oSettings )\n\t{\n\t\tvar vis = 0;\n\t\n\t\t// No reduce in IE8, use a loop for now\n\t\t$.each( oSettings.aoColumns, function ( i, col ) {\n\t\t\tif ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {\n\t\t\t\tvis++;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn vis;\n\t}\n\t\n\t\n\t/**\n\t * Get an array of column indexes that match a given property\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sParam Parameter in aoColumns to look for - typically\n\t *    bVisible or bSearchable\n\t *  @returns {array} Array of indexes with matched properties\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetColumns( oSettings, sParam )\n\t{\n\t\tvar a = [];\n\t\n\t\t$.map( oSettings.aoColumns, function(val, i) {\n\t\t\tif ( val[sParam] ) {\n\t\t\t\ta.push( i );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn a;\n\t}\n\t\n\t\n\t/**\n\t * Calculate the 'type' of a column\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnTypes ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar data = settings.aoData;\n\t\tvar types = DataTable.ext.type.detect;\n\t\tvar i, ien, j, jen, k, ken;\n\t\tvar col, cell, detectedType, cache;\n\t\n\t\t// For each column, spin over the \n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcol = columns[i];\n\t\t\tcache = [];\n\t\n\t\t\tif ( ! col.sType && col._sManualType ) {\n\t\t\t\tcol.sType = col._sManualType;\n\t\t\t}\n\t\t\telse if ( ! col.sType ) {\n\t\t\t\tfor ( j=0, jen=types.length ; j<jen ; j++ ) {\n\t\t\t\t\tfor ( k=0, ken=data.length ; k<ken ; k++ ) {\n\t\t\t\t\t\t// Use a cache array so we only need to get the type data\n\t\t\t\t\t\t// from the formatter once (when using multiple detectors)\n\t\t\t\t\t\tif ( cache[k] === undefined ) {\n\t\t\t\t\t\t\tcache[k] = _fnGetCellData( settings, k, i, 'type' );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tdetectedType = types[j]( cache[k], settings );\n\t\n\t\t\t\t\t\t// If null, then this type can't apply to this column, so\n\t\t\t\t\t\t// rather than testing all cells, break out. There is an\n\t\t\t\t\t\t// exception for the last type which is `html`. We need to\n\t\t\t\t\t\t// scan all rows since it is possible to mix string and HTML\n\t\t\t\t\t\t// types\n\t\t\t\t\t\tif ( ! detectedType && j !== types.length-1 ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Only a single match is needed for html type since it is\n\t\t\t\t\t\t// bottom of the pile and very similar to string\n\t\t\t\t\t\tif ( detectedType === 'html' ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Type is valid for all data points in the column - use this\n\t\t\t\t\t// type\n\t\t\t\t\tif ( detectedType ) {\n\t\t\t\t\t\tcol.sType = detectedType;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Fall back - if no type was detected, always use string\n\t\t\t\tif ( ! col.sType ) {\n\t\t\t\t\tcol.sType = 'string';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Take the column definitions and static columns arrays and calculate how\n\t * they relate to column indexes. The callback function will then apply the\n\t * definition found for a column to a suitable configuration object.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aoColDefs The aoColumnDefs array that is to be applied\n\t *  @param {array} aoCols The aoColumns array that defines columns individually\n\t *  @param {function} fn Callback function - takes two parameters, the calculated\n\t *    column index and the definition for that column.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, def;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Column definitions with aTargets\n\t\tif ( aoColDefs )\n\t\t{\n\t\t\t/* Loop over the definitions array - loop in reverse so first instance has priority */\n\t\t\tfor ( i=aoColDefs.length-1 ; i>=0 ; i-- )\n\t\t\t{\n\t\t\t\tdef = aoColDefs[i];\n\t\n\t\t\t\t/* Each definition can target multiple columns, as it is an array */\n\t\t\t\tvar aTargets = def.targets !== undefined ?\n\t\t\t\t\tdef.targets :\n\t\t\t\t\tdef.aTargets;\n\t\n\t\t\t\tif ( ! $.isArray( aTargets ) )\n\t\t\t\t{\n\t\t\t\t\taTargets = [ aTargets ];\n\t\t\t\t}\n\t\n\t\t\t\tfor ( j=0, jLen=aTargets.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Add columns that we don't yet know about */\n\t\t\t\t\t\twhile( columns.length <= aTargets[j] )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_fnAddColumn( oSettings );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t/* Integer, basic index */\n\t\t\t\t\t\tfn( aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Negative integer, right to left column counting */\n\t\t\t\t\t\tfn( columns.length+aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'string' )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Class name matching on TH element */\n\t\t\t\t\t\tfor ( k=0, kLen=columns.length ; k<kLen ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( aTargets[j] == \"_all\" ||\n\t\t\t\t\t\t\t     $(columns[k].nTh).hasClass( aTargets[j] ) )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfn( k, def );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// Statically defined columns array\n\t\tif ( aoCols )\n\t\t{\n\t\t\tfor ( i=0, iLen=aoCols.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfn( i, aoCols[i] );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * Add a data array to the table, creating DOM node etc. This is the parallel to\n\t * _fnGatherData, but for adding rows from a Javascript source, rather than a\n\t * DOM source.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aData data array to be added\n\t *  @param {node} [nTr] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddData ( oSettings, aDataIn, nTr, anTds )\n\t{\n\t\t/* Create the object for storing information about this new row */\n\t\tvar iRow = oSettings.aoData.length;\n\t\tvar oData = $.extend( true, {}, DataTable.models.oRow, {\n\t\t\tsrc: nTr ? 'dom' : 'data',\n\t\t\tidx: iRow\n\t\t} );\n\t\n\t\toData._aData = aDataIn;\n\t\toSettings.aoData.push( oData );\n\t\n\t\t/* Create the cells */\n\t\tvar nTd, sThisType;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Invalidate the column types as the new data needs to be revalidated\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tcolumns[i].sType = null;\n\t\t}\n\t\n\t\t/* Add to the display array */\n\t\toSettings.aiDisplayMaster.push( iRow );\n\t\n\t\tvar id = oSettings.rowIdFn( aDataIn );\n\t\tif ( id !== undefined ) {\n\t\t\toSettings.aIds[ id ] = oData;\n\t\t}\n\t\n\t\t/* Create the DOM information, or register it if already present */\n\t\tif ( nTr || ! oSettings.oFeatures.bDeferRender )\n\t\t{\n\t\t\t_fnCreateTr( oSettings, iRow, nTr, anTds );\n\t\t}\n\t\n\t\treturn iRow;\n\t}\n\t\n\t\n\t/**\n\t * Add one or more TR elements to the table. Generally we'd expect to\n\t * use this for reading data from a DOM sourced table, but it could be\n\t * used for an TR element. Note that if a TR is given, it is used (i.e.\n\t * it is not cloned).\n\t *  @param {object} settings dataTables settings object\n\t *  @param {array|node|jQuery} trs The TR element(s) to add to the table\n\t *  @returns {array} Array of indexes for the added rows\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddTr( settings, trs )\n\t{\n\t\tvar row;\n\t\n\t\t// Allow an individual node to be passed in\n\t\tif ( ! (trs instanceof $) ) {\n\t\t\ttrs = $(trs);\n\t\t}\n\t\n\t\treturn trs.map( function (i, el) {\n\t\t\trow = _fnGetRowElements( settings, el );\n\t\t\treturn _fnAddData( settings, row.data, el, row.cells );\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Take a TR element and convert it to an index in aoData\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} n the TR element to find\n\t *  @returns {int} index if the node is found, null if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToDataIndex( oSettings, n )\n\t{\n\t\treturn (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;\n\t}\n\t\n\t\n\t/**\n\t * Take a TD element and convert it into a column data index (not the visible index)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow The row number the TD/TH can be found in\n\t *  @param {node} n The TD/TH element to find\n\t *  @returns {int} index if the node is found, -1 if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToColumnIndex( oSettings, iRow, n )\n\t{\n\t\treturn $.inArray( n, oSettings.aoData[ iRow ].anCells );\n\t}\n\t\n\t\n\t/**\n\t * Get the data for a given cell from the internal cache, taking into account data mapping\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {string} type data get type ('display', 'type' 'filter' 'sort')\n\t *  @returns {*} Cell data\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetCellData( settings, rowIdx, colIdx, type )\n\t{\n\t\tvar draw           = settings.iDraw;\n\t\tvar col            = settings.aoColumns[colIdx];\n\t\tvar rowData        = settings.aoData[rowIdx]._aData;\n\t\tvar defaultContent = col.sDefaultContent;\n\t\tvar cellData       = col.fnGetData( rowData, type, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t} );\n\t\n\t\tif ( cellData === undefined ) {\n\t\t\tif ( settings.iDrawError != draw && defaultContent === null ) {\n\t\t\t\t_fnLog( settings, 0, \"Requested unknown parameter \"+\n\t\t\t\t\t(typeof col.mData=='function' ? '{function}' : \"'\"+col.mData+\"'\")+\n\t\t\t\t\t\" for row \"+rowIdx+\", column \"+colIdx, 4 );\n\t\t\t\tsettings.iDrawError = draw;\n\t\t\t}\n\t\t\treturn defaultContent;\n\t\t}\n\t\n\t\t// When the data source is null and a specific data type is requested (i.e.\n\t\t// not the original data), we can use default column data\n\t\tif ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {\n\t\t\tcellData = defaultContent;\n\t\t}\n\t\telse if ( typeof cellData === 'function' ) {\n\t\t\t// If the data source is a function, then we run it and use the return,\n\t\t\t// executing in the scope of the data object (for instances)\n\t\t\treturn cellData.call( rowData );\n\t\t}\n\t\n\t\tif ( cellData === null && type == 'display' ) {\n\t\t\treturn '';\n\t\t}\n\t\treturn cellData;\n\t}\n\t\n\t\n\t/**\n\t * Set the value for a specific cell, into the internal data cache\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {*} val Value to set\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetCellData( settings, rowIdx, colIdx, val )\n\t{\n\t\tvar col     = settings.aoColumns[colIdx];\n\t\tvar rowData = settings.aoData[rowIdx]._aData;\n\t\n\t\tcol.fnSetData( rowData, val, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t}  );\n\t}\n\t\n\t\n\t// Private variable that is used to match action syntax in the data property object\n\tvar __reArray = /\\[.*?\\]$/;\n\tvar __reFn = /\\(\\)$/;\n\t\n\t/**\n\t * Split string on periods, taking into account escaped periods\n\t * @param  {string} str String to split\n\t * @return {array} Split string\n\t */\n\tfunction _fnSplitObjNotation( str )\n\t{\n\t\treturn $.map( str.match(/(\\\\.|[^\\.])+/g) || [''], function ( s ) {\n\t\t\treturn s.replace(/\\\\\\./g, '.');\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to get data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data get function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Build an object of get functions, and wrap them in a single call */\n\t\t\tvar o = {};\n\t\t\t$.each( mSource, function (key, val) {\n\t\t\t\tif ( val ) {\n\t\t\t\t\to[key] = _fnGetObjectDataFn( val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\tvar t = o[type] || o._;\n\t\t\t\treturn t !== undefined ?\n\t\t\t\t\tt(data, type, row, meta) :\n\t\t\t\t\tdata;\n\t\t\t};\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Give an empty string for rendering / sorting etc */\n\t\t\treturn function (data) { // type, row and meta also passed, but not used\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\treturn mSource( data, type, row, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* If there is a . in the source string then the data source is in a\n\t\t\t * nested object so we loop over the data for each level to get the next\n\t\t\t * level down. On each loop we test for undefined, and if found immediately\n\t\t\t * return. This allows entire objects to be missing and sDefaultContent to\n\t\t\t * be used if defined, rather than throwing an error\n\t\t\t */\n\t\t\tvar fetchData = function (data, type, src) {\n\t\t\t\tvar arrayNotation, funcNotation, out, innerSrc;\n\t\n\t\t\t\tif ( src !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tvar a = _fnSplitObjNotation( src );\n\t\n\t\t\t\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if we are dealing with special notation\n\t\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Array notation\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\n\t\t\t\t\t\t\t// Condition allows simply [] to be passed in\n\t\t\t\t\t\t\tif ( a[i] !== \"\" ) {\n\t\t\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tout = [];\n\t\n\t\t\t\t\t\t\t// Get the remainder of the nested object to get\n\t\t\t\t\t\t\ta.splice( 0, i+1 );\n\t\t\t\t\t\t\tinnerSrc = a.join('.');\n\t\n\t\t\t\t\t\t\t// Traverse each entry in the array getting the properties requested\n\t\t\t\t\t\t\tif ( $.isArray( data ) ) {\n\t\t\t\t\t\t\t\tfor ( var j=0, jLen=data.length ; j<jLen ; j++ ) {\n\t\t\t\t\t\t\t\t\tout.push( fetchData( data[j], type, innerSrc ) );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\t// If a string is given in between the array notation indicators, that\n\t\t\t\t\t\t\t// is used to join the strings together, otherwise an array is returned\n\t\t\t\t\t\t\tvar join = arrayNotation[0].substring(1, arrayNotation[0].length-1);\n\t\t\t\t\t\t\tdata = (join===\"\") ? out : out.join(join);\n\t\n\t\t\t\t\t\t\t// The inner call to fetchData has already traversed through the remainder\n\t\t\t\t\t\t\t// of the source requested, so we exit from the loop\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Function call\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\t\tdata = data[ a[i] ]();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( data === null || data[ a[i] ] === undefined )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn data;\n\t\t\t};\n\t\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn fetchData( data, type, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn data[mSource];\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to set data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data set function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Unlike get, only the underscore (global) option is used for for\n\t\t\t * setting data since we don't know the type here. This is why an object\n\t\t\t * option is not documented for `mData` (which is read/write), but it is\n\t\t\t * for `mRender` which is read only.\n\t\t\t */\n\t\t\treturn _fnSetObjectDataFn( mSource._ );\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Nothing to do when the data source is null */\n\t\t\treturn function () {};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, val, meta) {\n\t\t\t\tmSource( data, 'set', val, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* Like the get, we need to get data from a nested object */\n\t\t\tvar setData = function (data, val, src) {\n\t\t\t\tvar a = _fnSplitObjNotation( src ), b;\n\t\t\t\tvar aLast = a[a.length-1];\n\t\t\t\tvar arrayNotation, funcNotation, o, innerSrc;\n\t\n\t\t\t\tfor ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\t// Check if we are dealing with an array notation request\n\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\t\t\t\t\tdata[ a[i] ] = [];\n\t\n\t\t\t\t\t\t// Get the remainder of the nested object to set so we can recurse\n\t\t\t\t\t\tb = a.slice();\n\t\t\t\t\t\tb.splice( 0, i+1 );\n\t\t\t\t\t\tinnerSrc = b.join('.');\n\t\n\t\t\t\t\t\t// Traverse each entry in the array setting the properties requested\n\t\t\t\t\t\tif ( $.isArray( val ) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor ( var j=0, jLen=val.length ; j<jLen ; j++ )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\to = {};\n\t\t\t\t\t\t\t\tsetData( o, val[j], innerSrc );\n\t\t\t\t\t\t\t\tdata[ a[i] ].push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We've been asked to save data to an array, but it\n\t\t\t\t\t\t\t// isn't array data to be saved. Best that can be done\n\t\t\t\t\t\t\t// is to just save the value.\n\t\t\t\t\t\t\tdata[ a[i] ] = val;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// The inner call to setData has already traversed through the remainder\n\t\t\t\t\t\t// of the source and has set the data, thus we can exit here\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Function call\n\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\tdata = data[ a[i] ]( val );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If the nested object doesn't currently exist - since we are\n\t\t\t\t\t// trying to set the value - create it\n\t\t\t\t\tif ( data[ a[i] ] === null || data[ a[i] ] === undefined )\n\t\t\t\t\t{\n\t\t\t\t\t\tdata[ a[i] ] = {};\n\t\t\t\t\t}\n\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t}\n\t\n\t\t\t\t// Last item in the input - i.e, the actual set\n\t\t\t\tif ( aLast.match(__reFn ) )\n\t\t\t\t{\n\t\t\t\t\t// Function call\n\t\t\t\t\tdata = data[ aLast.replace(__reFn, '') ]( val );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// If array notation is used, we just want to strip it and use the property name\n\t\t\t\t\t// and assign the value. If it isn't used, then we get the result we want anyway\n\t\t\t\t\tdata[ aLast.replace(__reArray, '') ] = val;\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\treturn setData( data, val, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\tdata[mSource] = val;\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return an array with the full table data\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns array {array} aData Master data array\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetDataMaster ( settings )\n\t{\n\t\treturn _pluck( settings.aoData, '_aData' );\n\t}\n\t\n\t\n\t/**\n\t * Nuke the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnClearTable( settings )\n\t{\n\t\tsettings.aoData.length = 0;\n\t\tsettings.aiDisplayMaster.length = 0;\n\t\tsettings.aiDisplay.length = 0;\n\t\tsettings.aIds = {};\n\t}\n\t\n\t\n\t /**\n\t * Take an array of integers (index array) and remove a target integer (value - not\n\t * the key!)\n\t *  @param {array} a Index array to target\n\t *  @param {int} iTarget value to find\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDeleteIndex( a, iTarget, splice )\n\t{\n\t\tvar iTargetIndex = -1;\n\t\n\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( a[i] == iTarget )\n\t\t\t{\n\t\t\t\tiTargetIndex = i;\n\t\t\t}\n\t\t\telse if ( a[i] > iTarget )\n\t\t\t{\n\t\t\t\ta[i]--;\n\t\t\t}\n\t\t}\n\t\n\t\tif ( iTargetIndex != -1 && splice === undefined )\n\t\t{\n\t\t\ta.splice( iTargetIndex, 1 );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Mark cached data as invalid such that a re-read of the data will occur when\n\t * the cached data is next requested. Also update from the data source object.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {int}    rowIdx   Row index to invalidate\n\t * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'\n\t *     or 'data'\n\t * @param {int}    [colIdx] Column index to invalidate. If undefined the whole\n\t *     row will be invalidated\n\t * @memberof DataTable#oApi\n\t *\n\t * @todo For the modularisation of v1.11 this will need to become a callback, so\n\t *   the sort and filter methods can subscribe to it. That will required\n\t *   initialisation options for sorting, which is why it is not already baked in\n\t */\n\tfunction _fnInvalidate( settings, rowIdx, src, colIdx )\n\t{\n\t\tvar row = settings.aoData[ rowIdx ];\n\t\tvar i, ien;\n\t\tvar cellWrite = function ( cell, col ) {\n\t\t\t// This is very frustrating, but in IE if you just write directly\n\t\t\t// to innerHTML, and elements that are overwritten are GC'ed,\n\t\t\t// even if there is a reference to them elsewhere\n\t\t\twhile ( cell.childNodes.length ) {\n\t\t\t\tcell.removeChild( cell.firstChild );\n\t\t\t}\n\t\n\t\t\tcell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );\n\t\t};\n\t\n\t\t// Are we reading last data from DOM or the data object?\n\t\tif ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {\n\t\t\t// Read the data from the DOM\n\t\t\trow._aData = _fnGetRowElements(\n\t\t\t\t\tsettings, row, colIdx, colIdx === undefined ? undefined : row._aData\n\t\t\t\t)\n\t\t\t\t.data;\n\t\t}\n\t\telse {\n\t\t\t// Reading from data object, update the DOM\n\t\t\tvar cells = row.anCells;\n\t\n\t\t\tif ( cells ) {\n\t\t\t\tif ( colIdx !== undefined ) {\n\t\t\t\t\tcellWrite( cells[colIdx], colIdx );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tcellWrite( cells[i], i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// For both row and cell invalidation, the cached data for sorting and\n\t\t// filtering is nulled out\n\t\trow._aSortData = null;\n\t\trow._aFilterData = null;\n\t\n\t\t// Invalidate the type for a specific column (if given) or all columns since\n\t\t// the data might have changed\n\t\tvar cols = settings.aoColumns;\n\t\tif ( colIdx !== undefined ) {\n\t\t\tcols[ colIdx ].sType = null;\n\t\t}\n\t\telse {\n\t\t\tfor ( i=0, ien=cols.length ; i<ien ; i++ ) {\n\t\t\t\tcols[i].sType = null;\n\t\t\t}\n\t\n\t\t\t// Update DataTables special `DT_*` attributes for the row\n\t\t\t_fnRowAttributes( settings, row );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a data source object from an HTML row, reading the contents of the\n\t * cells that are in the row.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {node|object} TR element from which to read data or existing row\n\t *   object from which to re-read the data from the cells\n\t * @param {int} [colIdx] Optional column index\n\t * @param {array|object} [d] Data source object. If `colIdx` is given then this\n\t *   parameter should also be given and will be used to write the data into.\n\t *   Only the column in question will be written\n\t * @returns {object} Object with two parameters: `data` the data read, in\n\t *   document order, and `cells` and array of nodes (they can be useful to the\n\t *   caller, so rather than needing a second traversal to get them, just return\n\t *   them from here).\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetRowElements( settings, row, colIdx, d )\n\t{\n\t\tvar\n\t\t\ttds = [],\n\t\t\ttd = row.firstChild,\n\t\t\tname, col, o, i=0, contents,\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tobjectRead = settings._rowReadObject;\n\t\n\t\t// Allow the data object to be passed in, or construct\n\t\td = d !== undefined ?\n\t\t\td :\n\t\t\tobjectRead ?\n\t\t\t\t{} :\n\t\t\t\t[];\n\t\n\t\tvar attr = function ( str, td  ) {\n\t\t\tif ( typeof str === 'string' ) {\n\t\t\t\tvar idx = str.indexOf('@');\n\t\n\t\t\t\tif ( idx !== -1 ) {\n\t\t\t\t\tvar attr = str.substring( idx+1 );\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( str );\n\t\t\t\t\tsetter( d, td.getAttribute( attr ) );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\n\t\t// Read data from a cell and store into the data object\n\t\tvar cellProcess = function ( cell ) {\n\t\t\tif ( colIdx === undefined || colIdx === i ) {\n\t\t\t\tcol = columns[i];\n\t\t\t\tcontents = $.trim(cell.innerHTML);\n\t\n\t\t\t\tif ( col && col._bAttrSrc ) {\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( col.mData._ );\n\t\t\t\t\tsetter( d, contents );\n\t\n\t\t\t\t\tattr( col.mData.sort, cell );\n\t\t\t\t\tattr( col.mData.type, cell );\n\t\t\t\t\tattr( col.mData.filter, cell );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Depending on the `data` option for the columns the data can\n\t\t\t\t\t// be read to either an object or an array.\n\t\t\t\t\tif ( objectRead ) {\n\t\t\t\t\t\tif ( ! col._setter ) {\n\t\t\t\t\t\t\t// Cache the setter function\n\t\t\t\t\t\t\tcol._setter = _fnSetObjectDataFn( col.mData );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcol._setter( d, contents );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\td[i] = contents;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t};\n\t\n\t\tif ( td ) {\n\t\t\t// `tr` element was passed in\n\t\t\twhile ( td ) {\n\t\t\t\tname = td.nodeName.toUpperCase();\n\t\n\t\t\t\tif ( name == \"TD\" || name == \"TH\" ) {\n\t\t\t\t\tcellProcess( td );\n\t\t\t\t\ttds.push( td );\n\t\t\t\t}\n\t\n\t\t\t\ttd = td.nextSibling;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Existing row object passed in\n\t\t\ttds = row.anCells;\n\t\n\t\t\tfor ( var j=0, jen=tds.length ; j<jen ; j++ ) {\n\t\t\t\tcellProcess( tds[j] );\n\t\t\t}\n\t\t}\n\t\n\t\t// Read the ID from the DOM if present\n\t\tvar rowNode = row.firstChild ? row : row.nTr;\n\t\n\t\tif ( rowNode ) {\n\t\t\tvar id = rowNode.getAttribute( 'id' );\n\t\n\t\t\tif ( id ) {\n\t\t\t\t_fnSetObjectDataFn( settings.rowId )( d, id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn {\n\t\t\tdata: d,\n\t\t\tcells: tds\n\t\t};\n\t}\n\t/**\n\t * Create a new TR element (and it's TD children) for a row\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow Row to consider\n\t *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCreateTr ( oSettings, iRow, nTrIn, anTds )\n\t{\n\t\tvar\n\t\t\trow = oSettings.aoData[iRow],\n\t\t\trowData = row._aData,\n\t\t\tcells = [],\n\t\t\tnTr, nTd, oCol,\n\t\t\ti, iLen;\n\t\n\t\tif ( row.nTr === null )\n\t\t{\n\t\t\tnTr = nTrIn || document.createElement('tr');\n\t\n\t\t\trow.nTr = nTr;\n\t\t\trow.anCells = cells;\n\t\n\t\t\t/* Use a private property on the node to allow reserve mapping from the node\n\t\t\t * to the aoData array for fast look up\n\t\t\t */\n\t\t\tnTr._DT_RowIndex = iRow;\n\t\n\t\t\t/* Special parameters can be given by the data source to be used on the row */\n\t\t\t_fnRowAttributes( oSettings, row );\n\t\n\t\t\t/* Process each column */\n\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toCol = oSettings.aoColumns[i];\n\t\n\t\t\t\tnTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );\n\t\t\t\tnTd._DT_CellIndex = {\n\t\t\t\t\trow: iRow,\n\t\t\t\t\tcolumn: i\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tcells.push( nTd );\n\t\n\t\t\t\t// Need to create the HTML if new, or if a rendering function is defined\n\t\t\t\tif ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&\n\t\t\t\t\t (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')\n\t\t\t\t) {\n\t\t\t\t\tnTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );\n\t\t\t\t}\n\t\n\t\t\t\t/* Add user defined class */\n\t\t\t\tif ( oCol.sClass )\n\t\t\t\t{\n\t\t\t\t\tnTd.className += ' '+oCol.sClass;\n\t\t\t\t}\n\t\n\t\t\t\t// Visibility - add or remove as required\n\t\t\t\tif ( oCol.bVisible && ! nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTr.appendChild( nTd );\n\t\t\t\t}\n\t\t\t\telse if ( ! oCol.bVisible && nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTd.parentNode.removeChild( nTd );\n\t\t\t\t}\n\t\n\t\t\t\tif ( oCol.fnCreatedCell )\n\t\t\t\t{\n\t\t\t\t\toCol.fnCreatedCell.call( oSettings.oInstance,\n\t\t\t\t\t\tnTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );\n\t\t}\n\t\n\t\t// Remove once webkit bug 131819 and Chromium bug 365619 have been resolved\n\t\t// and deployed\n\t\trow.nTr.setAttribute( 'role', 'row' );\n\t}\n\t\n\t\n\t/**\n\t * Add attributes to a row based on the special `DT_*` parameters in a data\n\t * source object.\n\t *  @param {object} settings DataTables settings object\n\t *  @param {object} DataTables row object for the row to be modified\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnRowAttributes( settings, row )\n\t{\n\t\tvar tr = row.nTr;\n\t\tvar data = row._aData;\n\t\n\t\tif ( tr ) {\n\t\t\tvar id = settings.rowIdFn( data );\n\t\n\t\t\tif ( id ) {\n\t\t\t\ttr.id = id;\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowClass ) {\n\t\t\t\t// Remove any classes added by DT_RowClass before\n\t\t\t\tvar a = data.DT_RowClass.split(' ');\n\t\t\t\trow.__rowc = row.__rowc ?\n\t\t\t\t\t_unique( row.__rowc.concat( a ) ) :\n\t\t\t\t\ta;\n\t\n\t\t\t\t$(tr)\n\t\t\t\t\t.removeClass( row.__rowc.join(' ') )\n\t\t\t\t\t.addClass( data.DT_RowClass );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowAttr ) {\n\t\t\t\t$(tr).attr( data.DT_RowAttr );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowData ) {\n\t\t\t\t$(tr).data( data.DT_RowData );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Create the HTML header for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBuildHead( oSettings )\n\t{\n\t\tvar i, ien, cell, row, column;\n\t\tvar thead = oSettings.nTHead;\n\t\tvar tfoot = oSettings.nTFoot;\n\t\tvar createHeader = $('th, td', thead).length === 0;\n\t\tvar classes = oSettings.oClasses;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\tif ( createHeader ) {\n\t\t\trow = $('<tr/>').appendTo( thead );\n\t\t}\n\t\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcell = $( column.nTh ).addClass( column.sClass );\n\t\n\t\t\tif ( createHeader ) {\n\t\t\t\tcell.appendTo( row );\n\t\t\t}\n\t\n\t\t\t// 1.11 move into sorting\n\t\t\tif ( oSettings.oFeatures.bSort ) {\n\t\t\t\tcell.addClass( column.sSortingClass );\n\t\n\t\t\t\tif ( column.bSortable !== false ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.attr( 'tabindex', oSettings.iTabIndex )\n\t\t\t\t\t\t.attr( 'aria-controls', oSettings.sTableId );\n\t\n\t\t\t\t\t_fnSortAttachListener( oSettings, column.nTh, i );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( column.sTitle != cell[0].innerHTML ) {\n\t\t\t\tcell.html( column.sTitle );\n\t\t\t}\n\t\n\t\t\t_fnRenderer( oSettings, 'header' )(\n\t\t\t\toSettings, cell, column, classes\n\t\t\t);\n\t\t}\n\t\n\t\tif ( createHeader ) {\n\t\t\t_fnDetectHeader( oSettings.aoHeader, thead );\n\t\t}\n\t\t\n\t\t/* ARIA role for the rows */\n\t \t$(thead).find('>tr').attr('role', 'row');\n\t\n\t\t/* Deal with the footer - add classes if required */\n\t\t$(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );\n\t\t$(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );\n\t\n\t\t// Cache the footer cells. Note that we only take the cells from the first\n\t\t// row in the footer. If there is more than one row the user wants to\n\t\t// interact with, they need to use the table().foot() method. Note also this\n\t\t// allows cells to be used for multiple columns using colspan\n\t\tif ( tfoot !== null ) {\n\t\t\tvar cells = oSettings.aoFooter[0];\n\t\n\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tcolumn = columns[i];\n\t\t\t\tcolumn.nTf = cells[i].cell;\n\t\n\t\t\t\tif ( column.sClass ) {\n\t\t\t\t\t$(column.nTf).addClass( column.sClass );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the header (or footer) element based on the column visibility states. The\n\t * methodology here is to use the layout array from _fnDetectHeader, modified for\n\t * the instantaneous column visibility, to construct the new layout. The grid is\n\t * traversed over cell at a time in a rows x columns grid fashion, although each\n\t * cell insert can cover multiple elements in the grid - which is tracks using the\n\t * aApplied array. Cell inserts in the grid will only occur where there isn't\n\t * already a cell in that position.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param array {objects} aoSource Layout array from _fnDetectHeader\n\t *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDrawHead( oSettings, aoSource, bIncludeHidden )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, n, nLocalTr;\n\t\tvar aoLocal = [];\n\t\tvar aApplied = [];\n\t\tvar iColumns = oSettings.aoColumns.length;\n\t\tvar iRowspan, iColspan;\n\t\n\t\tif ( ! aoSource )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif (  bIncludeHidden === undefined )\n\t\t{\n\t\t\tbIncludeHidden = false;\n\t\t}\n\t\n\t\t/* Make a copy of the master layout array, but without the visible columns in it */\n\t\tfor ( i=0, iLen=aoSource.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taoLocal[i] = aoSource[i].slice();\n\t\t\taoLocal[i].nTr = aoSource[i].nTr;\n\t\n\t\t\t/* Remove any columns which are currently hidden */\n\t\t\tfor ( j=iColumns-1 ; j>=0 ; j-- )\n\t\t\t{\n\t\t\t\tif ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )\n\t\t\t\t{\n\t\t\t\t\taoLocal[i].splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Prep the applied array - it needs an element for each row */\n\t\t\taApplied.push( [] );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnLocalTr = aoLocal[i].nTr;\n\t\n\t\t\t/* All cells are going to be replaced, so empty out the row */\n\t\t\tif ( nLocalTr )\n\t\t\t{\n\t\t\t\twhile( (n = nLocalTr.firstChild) )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.removeChild( n );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tfor ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tiRowspan = 1;\n\t\t\t\tiColspan = 1;\n\t\n\t\t\t\t/* Check to see if there is already a cell (row/colspan) covering our target\n\t\t\t\t * insert point. If there is, then there is nothing to do.\n\t\t\t\t */\n\t\t\t\tif ( aApplied[i][j] === undefined )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.appendChild( aoLocal[i][j].cell );\n\t\t\t\t\taApplied[i][j] = 1;\n\t\n\t\t\t\t\t/* Expand the cell to cover as many rows as needed */\n\t\t\t\t\twhile ( aoLocal[i+iRowspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\taApplied[i+iRowspan][j] = 1;\n\t\t\t\t\t\tiRowspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Expand the cell to cover as many columns as needed */\n\t\t\t\t\twhile ( aoLocal[i][j+iColspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Must update the applied array over the rows for the columns */\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taApplied[i+k][j+iColspan] = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiColspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Do the actual expansion in the DOM */\n\t\t\t\t\t$(aoLocal[i][j].cell)\n\t\t\t\t\t\t.attr('rowspan', iRowspan)\n\t\t\t\t\t\t.attr('colspan', iColspan);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Insert the required TR nodes into the table for display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDraw( oSettings )\n\t{\n\t\t/* Provide a pre-callback function which can be used to cancel the draw is false is returned */\n\t\tvar aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );\n\t\tif ( $.inArray( false, aPreDraw ) !== -1 )\n\t\t{\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar i, iLen, n;\n\t\tvar anRows = [];\n\t\tvar iRowCount = 0;\n\t\tvar asStripeClasses = oSettings.asStripeClasses;\n\t\tvar iStripes = asStripeClasses.length;\n\t\tvar iOpenRows = oSettings.aoOpenRows.length;\n\t\tvar oLang = oSettings.oLanguage;\n\t\tvar iInitDisplayStart = oSettings.iInitDisplayStart;\n\t\tvar bServerSide = _fnDataSource( oSettings ) == 'ssp';\n\t\tvar aiDisplay = oSettings.aiDisplay;\n\t\n\t\toSettings.bDrawing = true;\n\t\n\t\t/* Check and see if we have an initial draw position from state saving */\n\t\tif ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )\n\t\t{\n\t\t\toSettings._iDisplayStart = bServerSide ?\n\t\t\t\tiInitDisplayStart :\n\t\t\t\tiInitDisplayStart >= oSettings.fnRecordsDisplay() ?\n\t\t\t\t\t0 :\n\t\t\t\t\tiInitDisplayStart;\n\t\n\t\t\toSettings.iInitDisplayStart = -1;\n\t\t}\n\t\n\t\tvar iDisplayStart = oSettings._iDisplayStart;\n\t\tvar iDisplayEnd = oSettings.fnDisplayEnd();\n\t\n\t\t/* Server-side processing draw intercept */\n\t\tif ( oSettings.bDeferLoading )\n\t\t{\n\t\t\toSettings.bDeferLoading = false;\n\t\t\toSettings.iDraw++;\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t}\n\t\telse if ( !bServerSide )\n\t\t{\n\t\t\toSettings.iDraw++;\n\t\t}\n\t\telse if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( aiDisplay.length !== 0 )\n\t\t{\n\t\t\tvar iStart = bServerSide ? 0 : iDisplayStart;\n\t\t\tvar iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;\n\t\n\t\t\tfor ( var j=iStart ; j<iEnd ; j++ )\n\t\t\t{\n\t\t\t\tvar iDataIndex = aiDisplay[j];\n\t\t\t\tvar aoData = oSettings.aoData[ iDataIndex ];\n\t\t\t\tif ( aoData.nTr === null )\n\t\t\t\t{\n\t\t\t\t\t_fnCreateTr( oSettings, iDataIndex );\n\t\t\t\t}\n\t\n\t\t\t\tvar nRow = aoData.nTr;\n\t\n\t\t\t\t/* Remove the old striping classes and then add the new one */\n\t\t\t\tif ( iStripes !== 0 )\n\t\t\t\t{\n\t\t\t\t\tvar sStripe = asStripeClasses[ iRowCount % iStripes ];\n\t\t\t\t\tif ( aoData._sRowStripe != sStripe )\n\t\t\t\t\t{\n\t\t\t\t\t\t$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );\n\t\t\t\t\t\taoData._sRowStripe = sStripe;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Row callback functions - might want to manipulate the row\n\t\t\t\t// iRowCount and j are not currently documented. Are they at all\n\t\t\t\t// useful?\n\t\t\t\t_fnCallbackFire( oSettings, 'aoRowCallback', null,\n\t\t\t\t\t[nRow, aoData._aData, iRowCount, j] );\n\t\n\t\t\t\tanRows.push( nRow );\n\t\t\t\tiRowCount++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Table is empty - create a row with an empty message in it */\n\t\t\tvar sZero = oLang.sZeroRecords;\n\t\t\tif ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )\n\t\t\t{\n\t\t\t\tsZero = oLang.sLoadingRecords;\n\t\t\t}\n\t\t\telse if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )\n\t\t\t{\n\t\t\t\tsZero = oLang.sEmptyTable;\n\t\t\t}\n\t\n\t\t\tanRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )\n\t\t\t\t.append( $('<td />', {\n\t\t\t\t\t'valign':  'top',\n\t\t\t\t\t'colSpan': _fnVisbleColumns( oSettings ),\n\t\t\t\t\t'class':   oSettings.oClasses.sRowEmpty\n\t\t\t\t} ).html( sZero ) )[0];\n\t\t}\n\t\n\t\t/* Header and footer callbacks */\n\t\t_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\t_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\tvar body = $(oSettings.nTBody);\n\t\n\t\tbody.children().detach();\n\t\tbody.append( $(anRows) );\n\t\n\t\t/* Call all required callback functions for the end of a draw */\n\t\t_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );\n\t\n\t\t/* Draw is complete, sorting and filtering must be as well */\n\t\toSettings.bSorted = false;\n\t\toSettings.bFiltered = false;\n\t\toSettings.bDrawing = false;\n\t}\n\t\n\t\n\t/**\n\t * Redraw the table - taking account of the various features which are enabled\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {boolean} [holdPosition] Keep the current paging position. By default\n\t *    the paging is reset to the first page\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReDraw( settings, holdPosition )\n\t{\n\t\tvar\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tsort     = features.bSort,\n\t\t\tfilter   = features.bFilter;\n\t\n\t\tif ( sort ) {\n\t\t\t_fnSort( settings );\n\t\t}\n\t\n\t\tif ( filter ) {\n\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch );\n\t\t}\n\t\telse {\n\t\t\t// No filtering, so we want to just use the display master\n\t\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\t}\n\t\n\t\tif ( holdPosition !== true ) {\n\t\t\tsettings._iDisplayStart = 0;\n\t\t}\n\t\n\t\t// Let any modules know about the draw hold position state (used by\n\t\t// scrolling internally)\n\t\tsettings._drawHold = holdPosition;\n\t\n\t\t_fnDraw( settings );\n\t\n\t\tsettings._drawHold = false;\n\t}\n\t\n\t\n\t/**\n\t * Add the options to the page HTML for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddOptionsHtml ( oSettings )\n\t{\n\t\tvar classes = oSettings.oClasses;\n\t\tvar table = $(oSettings.nTable);\n\t\tvar holding = $('<div/>').insertBefore( table ); // Holding element for speed\n\t\tvar features = oSettings.oFeatures;\n\t\n\t\t// All DataTables are wrapped in a div\n\t\tvar insert = $('<div/>', {\n\t\t\tid:      oSettings.sTableId+'_wrapper',\n\t\t\t'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)\n\t\t} );\n\t\n\t\toSettings.nHolding = holding[0];\n\t\toSettings.nTableWrapper = insert[0];\n\t\toSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;\n\t\n\t\t/* Loop over the user set positioning and place the elements as needed */\n\t\tvar aDom = oSettings.sDom.split('');\n\t\tvar featureNode, cOption, nNewNode, cNext, sAttr, j;\n\t\tfor ( var i=0 ; i<aDom.length ; i++ )\n\t\t{\n\t\t\tfeatureNode = null;\n\t\t\tcOption = aDom[i];\n\t\n\t\t\tif ( cOption == '<' )\n\t\t\t{\n\t\t\t\t/* New container div */\n\t\t\t\tnNewNode = $('<div/>')[0];\n\t\n\t\t\t\t/* Check to see if we should append an id and/or a class name to the container */\n\t\t\t\tcNext = aDom[i+1];\n\t\t\t\tif ( cNext == \"'\" || cNext == '\"' )\n\t\t\t\t{\n\t\t\t\t\tsAttr = \"\";\n\t\t\t\t\tj = 2;\n\t\t\t\t\twhile ( aDom[i+j] != cNext )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr += aDom[i+j];\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Replace jQuery UI constants @todo depreciated */\n\t\t\t\t\tif ( sAttr == \"H\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIHeader;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr == \"F\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIFooter;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* The attribute can be in the format of \"#id.class\", \"#id\" or \"class\" This logic\n\t\t\t\t\t * breaks the string into parts and applies them as needed\n\t\t\t\t\t */\n\t\t\t\t\tif ( sAttr.indexOf('.') != -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar aSplit = sAttr.split('.');\n\t\t\t\t\t\tnNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);\n\t\t\t\t\t\tnNewNode.className = aSplit[1];\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr.charAt(0) == \"#\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.id = sAttr.substr(1, sAttr.length-1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.className = sAttr;\n\t\t\t\t\t}\n\t\n\t\t\t\t\ti += j; /* Move along the position array */\n\t\t\t\t}\n\t\n\t\t\t\tinsert.append( nNewNode );\n\t\t\t\tinsert = $(nNewNode);\n\t\t\t}\n\t\t\telse if ( cOption == '>' )\n\t\t\t{\n\t\t\t\t/* End container div */\n\t\t\t\tinsert = insert.parent();\n\t\t\t}\n\t\t\t// @todo Move options into their own plugins?\n\t\t\telse if ( cOption == 'l' && features.bPaginate && features.bLengthChange )\n\t\t\t{\n\t\t\t\t/* Length */\n\t\t\t\tfeatureNode = _fnFeatureHtmlLength( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'f' && features.bFilter )\n\t\t\t{\n\t\t\t\t/* Filter */\n\t\t\t\tfeatureNode = _fnFeatureHtmlFilter( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'r' && features.bProcessing )\n\t\t\t{\n\t\t\t\t/* pRocessing */\n\t\t\t\tfeatureNode = _fnFeatureHtmlProcessing( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 't' )\n\t\t\t{\n\t\t\t\t/* Table */\n\t\t\t\tfeatureNode = _fnFeatureHtmlTable( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption ==  'i' && features.bInfo )\n\t\t\t{\n\t\t\t\t/* Info */\n\t\t\t\tfeatureNode = _fnFeatureHtmlInfo( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'p' && features.bPaginate )\n\t\t\t{\n\t\t\t\t/* Pagination */\n\t\t\t\tfeatureNode = _fnFeatureHtmlPaginate( oSettings );\n\t\t\t}\n\t\t\telse if ( DataTable.ext.feature.length !== 0 )\n\t\t\t{\n\t\t\t\t/* Plug-in features */\n\t\t\t\tvar aoFeatures = DataTable.ext.feature;\n\t\t\t\tfor ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )\n\t\t\t\t{\n\t\t\t\t\tif ( cOption == aoFeatures[k].cFeature )\n\t\t\t\t\t{\n\t\t\t\t\t\tfeatureNode = aoFeatures[k].fnInit( oSettings );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Add to the 2D features array */\n\t\t\tif ( featureNode )\n\t\t\t{\n\t\t\t\tvar aanFeatures = oSettings.aanFeatures;\n\t\n\t\t\t\tif ( ! aanFeatures[cOption] )\n\t\t\t\t{\n\t\t\t\t\taanFeatures[cOption] = [];\n\t\t\t\t}\n\t\n\t\t\t\taanFeatures[cOption].push( featureNode );\n\t\t\t\tinsert.append( featureNode );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Built our DOM structure - replace the holding div with what we want */\n\t\tholding.replaceWith( insert );\n\t\toSettings.nHolding = null;\n\t}\n\t\n\t\n\t/**\n\t * Use the DOM source to create up an array of header cells. The idea here is to\n\t * create a layout grid (array) of rows x columns, which contains a reference\n\t * to the cell that that point in the grid (regardless of col/rowspan), such that\n\t * any column / row could be removed and the new grid constructed\n\t *  @param array {object} aLayout Array to store the calculated layout in\n\t *  @param {node} nThead The header/footer element for the table\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDetectHeader ( aLayout, nThead )\n\t{\n\t\tvar nTrs = $(nThead).children('tr');\n\t\tvar nTr, nCell;\n\t\tvar i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;\n\t\tvar bUnique;\n\t\tvar fnShiftCol = function ( a, i, j ) {\n\t\t\tvar k = a[i];\n\t                while ( k[j] ) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\treturn j;\n\t\t};\n\t\n\t\taLayout.splice( 0, aLayout.length );\n\t\n\t\t/* We know how many rows there are in the layout - so prep it */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taLayout.push( [] );\n\t\t}\n\t\n\t\t/* Calculate a layout array */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnTr = nTrs[i];\n\t\t\tiColumn = 0;\n\t\n\t\t\t/* For every cell in the row... */\n\t\t\tnCell = nTr.firstChild;\n\t\t\twhile ( nCell ) {\n\t\t\t\tif ( nCell.nodeName.toUpperCase() == \"TD\" ||\n\t\t\t\t     nCell.nodeName.toUpperCase() == \"TH\" )\n\t\t\t\t{\n\t\t\t\t\t/* Get the col and rowspan attributes from the DOM and sanitise them */\n\t\t\t\t\tiColspan = nCell.getAttribute('colspan') * 1;\n\t\t\t\t\tiRowspan = nCell.getAttribute('rowspan') * 1;\n\t\t\t\t\tiColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;\n\t\t\t\t\tiRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;\n\t\n\t\t\t\t\t/* There might be colspan cells already in this row, so shift our target\n\t\t\t\t\t * accordingly\n\t\t\t\t\t */\n\t\t\t\t\tiColShifted = fnShiftCol( aLayout, i, iColumn );\n\t\n\t\t\t\t\t/* Cache calculation for unique columns */\n\t\t\t\t\tbUnique = iColspan === 1 ? true : false;\n\t\n\t\t\t\t\t/* If there is col / rowspan, copy the information into the layout grid */\n\t\t\t\t\tfor ( l=0 ; l<iColspan ; l++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taLayout[i+k][iColShifted+l] = {\n\t\t\t\t\t\t\t\t\"cell\": nCell,\n\t\t\t\t\t\t\t\t\"unique\": bUnique\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\taLayout[i+k].nTr = nTr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnCell = nCell.nextSibling;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Get an array of unique th elements, one for each column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nHeader automatically detect the layout from this node - optional\n\t *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional\n\t *  @returns array {node} aReturn list of unique th's\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetUniqueThs ( oSettings, nHeader, aLayout )\n\t{\n\t\tvar aReturn = [];\n\t\tif ( !aLayout )\n\t\t{\n\t\t\taLayout = oSettings.aoHeader;\n\t\t\tif ( nHeader )\n\t\t\t{\n\t\t\t\taLayout = [];\n\t\t\t\t_fnDetectHeader( aLayout, nHeader );\n\t\t\t}\n\t\t}\n\t\n\t\tfor ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfor ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( aLayout[i][j].unique &&\n\t\t\t\t\t (!aReturn[j] || !oSettings.bSortCellsTop) )\n\t\t\t\t{\n\t\t\t\t\taReturn[j] = aLayout[i][j].cell;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn aReturn;\n\t}\n\t\n\t/**\n\t * Create an Ajax call based on the table's settings, taking into account that\n\t * parameters can have multiple forms, and backwards compatibility.\n\t *\n\t * @param {object} oSettings dataTables settings object\n\t * @param {array} data Data to send to the server, required by\n\t *     DataTables - may be augmented by developer callbacks\n\t * @param {function} fn Callback function to run when data is obtained\n\t */\n\tfunction _fnBuildAjax( oSettings, data, fn )\n\t{\n\t\t// Compatibility with 1.9-, allow fnServerData and event to manipulate\n\t\t_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );\n\t\n\t\t// Convert to object based for 1.10+ if using the old array scheme which can\n\t\t// come from server-side processing or serverParams\n\t\tif ( data && $.isArray(data) ) {\n\t\t\tvar tmp = {};\n\t\t\tvar rbracket = /(.*?)\\[\\]$/;\n\t\n\t\t\t$.each( data, function (key, val) {\n\t\t\t\tvar match = val.name.match(rbracket);\n\t\n\t\t\t\tif ( match ) {\n\t\t\t\t\t// Support for arrays\n\t\t\t\t\tvar name = match[0];\n\t\n\t\t\t\t\tif ( ! tmp[ name ] ) {\n\t\t\t\t\t\ttmp[ name ] = [];\n\t\t\t\t\t}\n\t\t\t\t\ttmp[ name ].push( val.value );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttmp[val.name] = val.value;\n\t\t\t\t}\n\t\t\t} );\n\t\t\tdata = tmp;\n\t\t}\n\t\n\t\tvar ajaxData;\n\t\tvar ajax = oSettings.ajax;\n\t\tvar instance = oSettings.oInstance;\n\t\tvar callback = function ( json ) {\n\t\t\t_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );\n\t\t\tfn( json );\n\t\t};\n\t\n\t\tif ( $.isPlainObject( ajax ) && ajax.data )\n\t\t{\n\t\t\tajaxData = ajax.data;\n\t\n\t\t\tvar newData = $.isFunction( ajaxData ) ?\n\t\t\t\tajaxData( data, oSettings ) :  // fn can manipulate data or return\n\t\t\t\tajaxData;                      // an object object or array to merge\n\t\n\t\t\t// If the function returned something, use that alone\n\t\t\tdata = $.isFunction( ajaxData ) && newData ?\n\t\t\t\tnewData :\n\t\t\t\t$.extend( true, data, newData );\n\t\n\t\t\t// Remove the data property as we've resolved it already and don't want\n\t\t\t// jQuery to do it again (it is restored at the end of the function)\n\t\t\tdelete ajax.data;\n\t\t}\n\t\n\t\tvar baseAjax = {\n\t\t\t\"data\": data,\n\t\t\t\"success\": function (json) {\n\t\t\t\tvar error = json.error || json.sError;\n\t\t\t\tif ( error ) {\n\t\t\t\t\t_fnLog( oSettings, 0, error );\n\t\t\t\t}\n\t\n\t\t\t\toSettings.json = json;\n\t\t\t\tcallback( json );\n\t\t\t},\n\t\t\t\"dataType\": \"json\",\n\t\t\t\"cache\": false,\n\t\t\t\"type\": oSettings.sServerMethod,\n\t\t\t\"error\": function (xhr, error, thrown) {\n\t\t\t\tvar ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );\n\t\n\t\t\t\tif ( $.inArray( true, ret ) === -1 ) {\n\t\t\t\t\tif ( error == \"parsererror\" ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Invalid JSON response', 1 );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( xhr.readyState === 4 ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Ajax error', 7 );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\t}\n\t\t};\n\t\n\t\t// Store the data submitted for the API\n\t\toSettings.oAjaxData = data;\n\t\n\t\t// Allow plug-ins and external processes to modify the data\n\t\t_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );\n\t\n\t\tif ( oSettings.fnServerData )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.fnServerData.call( instance,\n\t\t\t\toSettings.sAjaxSource,\n\t\t\t\t$.map( data, function (val, key) { // Need to convert back to 1.9 trad format\n\t\t\t\t\treturn { name: key, value: val };\n\t\t\t\t} ),\n\t\t\t\tcallback,\n\t\t\t\toSettings\n\t\t\t);\n\t\t}\n\t\telse if ( oSettings.sAjaxSource || typeof ajax === 'string' )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, {\n\t\t\t\turl: ajax || oSettings.sAjaxSource\n\t\t\t} ) );\n\t\t}\n\t\telse if ( $.isFunction( ajax ) )\n\t\t{\n\t\t\t// Is a function - let the caller define what needs to be done\n\t\t\toSettings.jqXHR = ajax.call( instance, data, callback, oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Object to extend the base settings\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );\n\t\n\t\t\t// Restore for next time around\n\t\t\tajax.data = ajaxData;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Update the table using an Ajax call\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {boolean} Block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdate( settings )\n\t{\n\t\tif ( settings.bAjaxDataGet ) {\n\t\t\tsettings.iDraw++;\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t_fnBuildAjax(\n\t\t\t\tsettings,\n\t\t\t\t_fnAjaxParameters( settings ),\n\t\t\t\tfunction(json) {\n\t\t\t\t\t_fnAjaxUpdateDraw( settings, json );\n\t\t\t\t}\n\t\t\t);\n\t\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\t\n\t/**\n\t * Build up the parameters in an object needed for a server-side processing\n\t * request. Note that this is basically done twice, is different ways - a modern\n\t * method which is used by default in DataTables 1.10 which uses objects and\n\t * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if\n\t * the sAjaxSource option is used in the initialisation, or the legacyAjax\n\t * option is set.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {bool} block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxParameters( settings )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tcolumnCount = columns.length,\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tpreSearch = settings.oPreviousSearch,\n\t\t\tpreColSearch = settings.aoPreSearchCols,\n\t\t\ti, data = [], dataProp, column, columnSearch,\n\t\t\tsort = _fnSortFlatten( settings ),\n\t\t\tdisplayStart = settings._iDisplayStart,\n\t\t\tdisplayLength = features.bPaginate !== false ?\n\t\t\t\tsettings._iDisplayLength :\n\t\t\t\t-1;\n\t\n\t\tvar param = function ( name, value ) {\n\t\t\tdata.push( { 'name': name, 'value': value } );\n\t\t};\n\t\n\t\t// DataTables 1.9- compatible method\n\t\tparam( 'sEcho',          settings.iDraw );\n\t\tparam( 'iColumns',       columnCount );\n\t\tparam( 'sColumns',       _pluck( columns, 'sName' ).join(',') );\n\t\tparam( 'iDisplayStart',  displayStart );\n\t\tparam( 'iDisplayLength', displayLength );\n\t\n\t\t// DataTables 1.10+ method\n\t\tvar d = {\n\t\t\tdraw:    settings.iDraw,\n\t\t\tcolumns: [],\n\t\t\torder:   [],\n\t\t\tstart:   displayStart,\n\t\t\tlength:  displayLength,\n\t\t\tsearch:  {\n\t\t\t\tvalue: preSearch.sSearch,\n\t\t\t\tregex: preSearch.bRegex\n\t\t\t}\n\t\t};\n\t\n\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcolumnSearch = preColSearch[i];\n\t\t\tdataProp = typeof column.mData==\"function\" ? 'function' : column.mData ;\n\t\n\t\t\td.columns.push( {\n\t\t\t\tdata:       dataProp,\n\t\t\t\tname:       column.sName,\n\t\t\t\tsearchable: column.bSearchable,\n\t\t\t\torderable:  column.bSortable,\n\t\t\t\tsearch:     {\n\t\t\t\t\tvalue: columnSearch.sSearch,\n\t\t\t\t\tregex: columnSearch.bRegex\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\tparam( \"mDataProp_\"+i, dataProp );\n\t\n\t\t\tif ( features.bFilter ) {\n\t\t\t\tparam( 'sSearch_'+i,     columnSearch.sSearch );\n\t\t\t\tparam( 'bRegex_'+i,      columnSearch.bRegex );\n\t\t\t\tparam( 'bSearchable_'+i, column.bSearchable );\n\t\t\t}\n\t\n\t\t\tif ( features.bSort ) {\n\t\t\t\tparam( 'bSortable_'+i, column.bSortable );\n\t\t\t}\n\t\t}\n\t\n\t\tif ( features.bFilter ) {\n\t\t\tparam( 'sSearch', preSearch.sSearch );\n\t\t\tparam( 'bRegex', preSearch.bRegex );\n\t\t}\n\t\n\t\tif ( features.bSort ) {\n\t\t\t$.each( sort, function ( i, val ) {\n\t\t\t\td.order.push( { column: val.col, dir: val.dir } );\n\t\n\t\t\t\tparam( 'iSortCol_'+i, val.col );\n\t\t\t\tparam( 'sSortDir_'+i, val.dir );\n\t\t\t} );\n\t\n\t\t\tparam( 'iSortingCols', sort.length );\n\t\t}\n\t\n\t\t// If the legacy.ajax parameter is null, then we automatically decide which\n\t\t// form to use, based on sAjaxSource\n\t\tvar legacy = DataTable.ext.legacy.ajax;\n\t\tif ( legacy === null ) {\n\t\t\treturn settings.sAjaxSource ? data : d;\n\t\t}\n\t\n\t\t// Otherwise, if legacy has been specified then we use that to decide on the\n\t\t// form\n\t\treturn legacy ? data : d;\n\t}\n\t\n\t\n\t/**\n\t * Data the data from the server (nuking the old) and redraw the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} json json data return from the server.\n\t *  @param {string} json.sEcho Tracking flag for DataTables to match requests\n\t *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering\n\t *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering\n\t *  @param {array} json.aaData The data to display on this page\n\t *  @param {string} [json.sColumns] Column ordering (sName, comma separated)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdateDraw ( settings, json )\n\t{\n\t\t// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.\n\t\t// Support both\n\t\tvar compat = function ( old, modern ) {\n\t\t\treturn json[old] !== undefined ? json[old] : json[modern];\n\t\t};\n\t\n\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\tvar draw            = compat( 'sEcho',                'draw' );\n\t\tvar recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );\n\t\tvar recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );\n\t\n\t\tif ( draw ) {\n\t\t\t// Protect against out of sequence returns\n\t\t\tif ( draw*1 < settings.iDraw ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettings.iDraw = draw * 1;\n\t\t}\n\t\n\t\t_fnClearTable( settings );\n\t\tsettings._iRecordsTotal   = parseInt(recordsTotal, 10);\n\t\tsettings._iRecordsDisplay = parseInt(recordsFiltered, 10);\n\t\n\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t_fnAddData( settings, data[i] );\n\t\t}\n\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\n\t\tsettings.bAjaxDataGet = false;\n\t\t_fnDraw( settings );\n\t\n\t\tif ( ! settings._bInitComplete ) {\n\t\t\t_fnInitComplete( settings, json );\n\t\t}\n\t\n\t\tsettings.bAjaxDataGet = true;\n\t\t_fnProcessingDisplay( settings, false );\n\t}\n\t\n\t\n\t/**\n\t * Get the data from the JSON data source to use for drawing a table. Using\n\t * `_fnGetObjectDataFn` allows the data to be sourced from a property of the\n\t * source object, or from a processing function.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param  {object} json Data source object / array from the server\n\t *  @return {array} Array of data to use\n\t */\n\tfunction _fnAjaxDataSrc ( oSettings, json )\n\t{\n\t\tvar dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?\n\t\t\toSettings.ajax.dataSrc :\n\t\t\toSettings.sAjaxDataProp; // Compatibility with 1.9-.\n\t\n\t\t// Compatibility with 1.9-. In order to read from aaData, check if the\n\t\t// default has been changed, if not, check for aaData\n\t\tif ( dataSrc === 'data' ) {\n\t\t\treturn json.aaData || json[dataSrc];\n\t\t}\n\t\n\t\treturn dataSrc !== \"\" ?\n\t\t\t_fnGetObjectDataFn( dataSrc )( json ) :\n\t\t\tjson;\n\t}\n\t\n\t/**\n\t * Generate the node required for filtering text\n\t *  @returns {node} Filter control element\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlFilter ( settings )\n\t{\n\t\tvar classes = settings.oClasses;\n\t\tvar tableId = settings.sTableId;\n\t\tvar language = settings.oLanguage;\n\t\tvar previousSearch = settings.oPreviousSearch;\n\t\tvar features = settings.aanFeatures;\n\t\tvar input = '<input type=\"search\" class=\"'+classes.sFilterInput+'\"/>';\n\t\n\t\tvar str = language.sSearch;\n\t\tstr = str.match(/_INPUT_/) ?\n\t\t\tstr.replace('_INPUT_', input) :\n\t\t\tstr+input;\n\t\n\t\tvar filter = $('<div/>', {\n\t\t\t\t'id': ! features.f ? tableId+'_filter' : null,\n\t\t\t\t'class': classes.sFilter\n\t\t\t} )\n\t\t\t.append( $('<label/>' ).append( str ) );\n\t\n\t\tvar searchFn = function() {\n\t\t\t/* Update all other filter input elements for the new display */\n\t\t\tvar n = features.f;\n\t\t\tvar val = !this.value ? \"\" : this.value; // mental IE8 fix :-(\n\t\n\t\t\t/* Now do the filter */\n\t\t\tif ( val != previousSearch.sSearch ) {\n\t\t\t\t_fnFilterComplete( settings, {\n\t\t\t\t\t\"sSearch\": val,\n\t\t\t\t\t\"bRegex\": previousSearch.bRegex,\n\t\t\t\t\t\"bSmart\": previousSearch.bSmart ,\n\t\t\t\t\t\"bCaseInsensitive\": previousSearch.bCaseInsensitive\n\t\t\t\t} );\n\t\n\t\t\t\t// Need to redraw, without resorting\n\t\t\t\tsettings._iDisplayStart = 0;\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t};\n\t\n\t\tvar searchDelay = settings.searchDelay !== null ?\n\t\t\tsettings.searchDelay :\n\t\t\t_fnDataSource( settings ) === 'ssp' ?\n\t\t\t\t400 :\n\t\t\t\t0;\n\t\n\t\tvar jqFilter = $('input', filter)\n\t\t\t.val( previousSearch.sSearch )\n\t\t\t.attr( 'placeholder', language.sSearchPlaceholder )\n\t\t\t.on(\n\t\t\t\t'keyup.DT search.DT input.DT paste.DT cut.DT',\n\t\t\t\tsearchDelay ?\n\t\t\t\t\t_fnThrottle( searchFn, searchDelay ) :\n\t\t\t\t\tsearchFn\n\t\t\t)\n\t\t\t.on( 'keypress.DT', function(e) {\n\t\t\t\t/* Prevent form submission */\n\t\t\t\tif ( e.keyCode == 13 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.attr('aria-controls', tableId);\n\t\n\t\t// Update the input elements whenever the table is filtered\n\t\t$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame...\n\t\t\t\ttry {\n\t\t\t\t\tif ( jqFilter[0] !== document.activeElement ) {\n\t\t\t\t\t\tjqFilter.val( previousSearch.sSearch );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch ( e ) {}\n\t\t\t}\n\t\t} );\n\t\n\t\treturn filter[0];\n\t}\n\t\n\t\n\t/**\n\t * Filter the table using both the global filter and column based filtering\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oSearch search information\n\t *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterComplete ( oSettings, oInput, iForce )\n\t{\n\t\tvar oPrevSearch = oSettings.oPreviousSearch;\n\t\tvar aoPrevSearch = oSettings.aoPreSearchCols;\n\t\tvar fnSaveFilter = function ( oFilter ) {\n\t\t\t/* Save the filtering values */\n\t\t\toPrevSearch.sSearch = oFilter.sSearch;\n\t\t\toPrevSearch.bRegex = oFilter.bRegex;\n\t\t\toPrevSearch.bSmart = oFilter.bSmart;\n\t\t\toPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;\n\t\t};\n\t\tvar fnRegex = function ( o ) {\n\t\t\t// Backwards compatibility with the bEscapeRegex option\n\t\t\treturn o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;\n\t\t};\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo As per sort - can this be moved into an event handler?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\t/* In server-side processing all filtering is done by the server, so no point hanging around here */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' )\n\t\t{\n\t\t\t/* Global filter */\n\t\t\t_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );\n\t\t\tfnSaveFilter( oInput );\n\t\n\t\t\t/* Now do the individual column filter */\n\t\t\tfor ( var i=0 ; i<aoPrevSearch.length ; i++ )\n\t\t\t{\n\t\t\t\t_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),\n\t\t\t\t\taoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );\n\t\t\t}\n\t\n\t\t\t/* Custom filtering */\n\t\t\t_fnFilterCustom( oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfnSaveFilter( oInput );\n\t\t}\n\t\n\t\t/* Tell the draw function we have been filtering */\n\t\toSettings.bFiltered = true;\n\t\t_fnCallbackFire( oSettings, null, 'search', [oSettings] );\n\t}\n\t\n\t\n\t/**\n\t * Apply custom filtering functions\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCustom( settings )\n\t{\n\t\tvar filters = DataTable.ext.search;\n\t\tvar displayRows = settings.aiDisplay;\n\t\tvar row, rowIdx;\n\t\n\t\tfor ( var i=0, ien=filters.length ; i<ien ; i++ ) {\n\t\t\tvar rows = [];\n\t\n\t\t\t// Loop over each row and see if it should be included\n\t\t\tfor ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {\n\t\t\t\trowIdx = displayRows[ j ];\n\t\t\t\trow = settings.aoData[ rowIdx ];\n\t\n\t\t\t\tif ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {\n\t\t\t\t\trows.push( rowIdx );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// So the array reference doesn't break set the results into the\n\t\t\t// existing array\n\t\t\tdisplayRows.length = 0;\n\t\t\t$.merge( displayRows, rows );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Filter the table on a per-column basis\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sInput string to filter on\n\t *  @param {int} iColumn column to filter\n\t *  @param {bool} bRegex treat search string as a regular expression or not\n\t *  @param {bool} bSmart use smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )\n\t{\n\t\tif ( searchStr === '' ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar data;\n\t\tvar out = [];\n\t\tvar display = settings.aiDisplay;\n\t\tvar rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );\n\t\n\t\tfor ( var i=0 ; i<display.length ; i++ ) {\n\t\t\tdata = settings.aoData[ display[i] ]._aFilterData[ colIdx ];\n\t\n\t\t\tif ( rpSearch.test( data ) ) {\n\t\t\t\tout.push( display[i] );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aiDisplay = out;\n\t}\n\t\n\t\n\t/**\n\t * Filter the data table based on user input and draw the table\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} input string to filter on\n\t *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)\n\t *  @param {bool} regex treat as a regular expression or not\n\t *  @param {bool} smart perform smart filtering or not\n\t *  @param {bool} caseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilter( settings, input, force, regex, smart, caseInsensitive )\n\t{\n\t\tvar rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );\n\t\tvar prevSearch = settings.oPreviousSearch.sSearch;\n\t\tvar displayMaster = settings.aiDisplayMaster;\n\t\tvar display, invalidated, i;\n\t\tvar filtered = [];\n\t\n\t\t// Need to take account of custom filtering functions - always filter\n\t\tif ( DataTable.ext.search.length !== 0 ) {\n\t\t\tforce = true;\n\t\t}\n\t\n\t\t// Check if any of the rows were invalidated\n\t\tinvalidated = _fnFilterData( settings );\n\t\n\t\t// If the input is blank - we just want the full data set\n\t\tif ( input.length <= 0 ) {\n\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t}\n\t\telse {\n\t\t\t// New search - start from the master array\n\t\t\tif ( invalidated ||\n\t\t\t\t force ||\n\t\t\t\t prevSearch.length > input.length ||\n\t\t\t\t input.indexOf(prevSearch) !== 0 ||\n\t\t\t\t settings.bSorted // On resort, the display master needs to be\n\t\t\t\t                  // re-filtered since indexes will have changed\n\t\t\t) {\n\t\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t\t}\n\t\n\t\t\t// Search the display array\n\t\t\tdisplay = settings.aiDisplay;\n\t\n\t\t\tfor ( i=0 ; i<display.length ; i++ ) {\n\t\t\t\tif ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {\n\t\t\t\t\tfiltered.push( display[i] );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tsettings.aiDisplay = filtered;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a regular expression object suitable for searching a table\n\t *  @param {string} sSearch string to search for\n\t *  @param {bool} bRegex treat as a regular expression or not\n\t *  @param {bool} bSmart perform smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insensitive matching or not\n\t *  @returns {RegExp} constructed object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCreateSearch( search, regex, smart, caseInsensitive )\n\t{\n\t\tsearch = regex ?\n\t\t\tsearch :\n\t\t\t_fnEscapeRegex( search );\n\t\t\n\t\tif ( smart ) {\n\t\t\t/* For smart filtering we want to allow the search to work regardless of\n\t\t\t * word order. We also want double quoted text to be preserved, so word\n\t\t\t * order is important - a la google. So this is what we want to\n\t\t\t * generate:\n\t\t\t * \n\t\t\t * ^(?=.*?\\bone\\b)(?=.*?\\btwo three\\b)(?=.*?\\bfour\\b).*$\n\t\t\t */\n\t\t\tvar a = $.map( search.match( /\"[^\"]+\"|[^ ]+/g ) || [''], function ( word ) {\n\t\t\t\tif ( word.charAt(0) === '\"' ) {\n\t\t\t\t\tvar m = word.match( /^\"(.*)\"$/ );\n\t\t\t\t\tword = m ? m[1] : word;\n\t\t\t\t}\n\t\n\t\t\t\treturn word.replace('\"', '');\n\t\t\t} );\n\t\n\t\t\tsearch = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';\n\t\t}\n\t\n\t\treturn new RegExp( search, caseInsensitive ? 'i' : '' );\n\t}\n\t\n\t\n\t/**\n\t * Escape a string such that it can be used in a regular expression\n\t *  @param {string} sVal string to escape\n\t *  @returns {string} escaped string\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnEscapeRegex = DataTable.util.escapeRegex;\n\t\n\tvar __filter_div = $('<div>')[0];\n\tvar __filter_div_textContent = __filter_div.textContent !== undefined;\n\t\n\t// Update the filtering data for each row if needed (by invalidation or first run)\n\tfunction _fnFilterData ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar column;\n\t\tvar i, j, ien, jen, filterData, cellData, row;\n\t\tvar fomatters = DataTable.ext.type.search;\n\t\tvar wasInvalidated = false;\n\t\n\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aFilterData ) {\n\t\t\t\tfilterData = [];\n\t\n\t\t\t\tfor ( j=0, jen=columns.length ; j<jen ; j++ ) {\n\t\t\t\t\tcolumn = columns[j];\n\t\n\t\t\t\t\tif ( column.bSearchable ) {\n\t\t\t\t\t\tcellData = _fnGetCellData( settings, i, j, 'filter' );\n\t\n\t\t\t\t\t\tif ( fomatters[ column.sType ] ) {\n\t\t\t\t\t\t\tcellData = fomatters[ column.sType ]( cellData );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Search in DataTables 1.10 is string based. In 1.11 this\n\t\t\t\t\t\t// should be altered to also allow strict type checking.\n\t\t\t\t\t\tif ( cellData === null ) {\n\t\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( typeof cellData !== 'string' && cellData.toString ) {\n\t\t\t\t\t\t\tcellData = cellData.toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If it looks like there is an HTML entity in the string,\n\t\t\t\t\t// attempt to decode it so sorting works as expected. Note that\n\t\t\t\t\t// we could use a single line of jQuery to do this, but the DOM\n\t\t\t\t\t// method used here is much faster http://jsperf.com/html-decode\n\t\t\t\t\tif ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {\n\t\t\t\t\t\t__filter_div.innerHTML = cellData;\n\t\t\t\t\t\tcellData = __filter_div_textContent ?\n\t\t\t\t\t\t\t__filter_div.textContent :\n\t\t\t\t\t\t\t__filter_div.innerText;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tif ( cellData.replace ) {\n\t\t\t\t\t\tcellData = cellData.replace(/[\\r\\n]/g, '');\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfilterData.push( cellData );\n\t\t\t\t}\n\t\n\t\t\t\trow._aFilterData = filterData;\n\t\t\t\trow._sFilterRow = filterData.join('  ');\n\t\t\t\twasInvalidated = true;\n\t\t\t}\n\t\t}\n\t\n\t\treturn wasInvalidated;\n\t}\n\t\n\t\n\t/**\n\t * Convert from the internal Hungarian notation to camelCase for external\n\t * interaction\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToCamel ( obj )\n\t{\n\t\treturn {\n\t\t\tsearch:          obj.sSearch,\n\t\t\tsmart:           obj.bSmart,\n\t\t\tregex:           obj.bRegex,\n\t\t\tcaseInsensitive: obj.bCaseInsensitive\n\t\t};\n\t}\n\t\n\t\n\t\n\t/**\n\t * Convert from camelCase notation to the internal Hungarian. We could use the\n\t * Hungarian convert function here, but this is cleaner\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToHung ( obj )\n\t{\n\t\treturn {\n\t\t\tsSearch:          obj.search,\n\t\t\tbSmart:           obj.smart,\n\t\t\tbRegex:           obj.regex,\n\t\t\tbCaseInsensitive: obj.caseInsensitive\n\t\t};\n\t}\n\t\n\t/**\n\t * Generate the node required for the info display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Information element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlInfo ( settings )\n\t{\n\t\tvar\n\t\t\ttid = settings.sTableId,\n\t\t\tnodes = settings.aanFeatures.i,\n\t\t\tn = $('<div/>', {\n\t\t\t\t'class': settings.oClasses.sInfo,\n\t\t\t\t'id': ! nodes ? tid+'_info' : null\n\t\t\t} );\n\t\n\t\tif ( ! nodes ) {\n\t\t\t// Update display on each draw\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": _fnUpdateInfo,\n\t\t\t\t\"sName\": \"information\"\n\t\t\t} );\n\t\n\t\t\tn\n\t\t\t\t.attr( 'role', 'status' )\n\t\t\t\t.attr( 'aria-live', 'polite' );\n\t\n\t\t\t// Table is described by our info div\n\t\t\t$(settings.nTable).attr( 'aria-describedby', tid+'_info' );\n\t\t}\n\t\n\t\treturn n[0];\n\t}\n\t\n\t\n\t/**\n\t * Update the information elements in the display\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnUpdateInfo ( settings )\n\t{\n\t\t/* Show information about the table */\n\t\tvar nodes = settings.aanFeatures.i;\n\t\tif ( nodes.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\tlang  = settings.oLanguage,\n\t\t\tstart = settings._iDisplayStart+1,\n\t\t\tend   = settings.fnDisplayEnd(),\n\t\t\tmax   = settings.fnRecordsTotal(),\n\t\t\ttotal = settings.fnRecordsDisplay(),\n\t\t\tout   = total ?\n\t\t\t\tlang.sInfo :\n\t\t\t\tlang.sInfoEmpty;\n\t\n\t\tif ( total !== max ) {\n\t\t\t/* Record set after filtering */\n\t\t\tout += ' ' + lang.sInfoFiltered;\n\t\t}\n\t\n\t\t// Convert the macros\n\t\tout += lang.sInfoPostFix;\n\t\tout = _fnInfoMacros( settings, out );\n\t\n\t\tvar callback = lang.fnInfoCallback;\n\t\tif ( callback !== null ) {\n\t\t\tout = callback.call( settings.oInstance,\n\t\t\t\tsettings, start, end, max, total, out\n\t\t\t);\n\t\t}\n\t\n\t\t$(nodes).html( out );\n\t}\n\t\n\t\n\tfunction _fnInfoMacros ( settings, str )\n\t{\n\t\t// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only\n\t\t// internally\n\t\tvar\n\t\t\tformatter  = settings.fnFormatNumber,\n\t\t\tstart      = settings._iDisplayStart+1,\n\t\t\tlen        = settings._iDisplayLength,\n\t\t\tvis        = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn str.\n\t\t\treplace(/_START_/g, formatter.call( settings, start ) ).\n\t\t\treplace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).\n\t\t\treplace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).\n\t\t\treplace(/_TOTAL_/g, formatter.call( settings, vis ) ).\n\t\t\treplace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).\n\t\t\treplace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );\n\t}\n\t\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitialise ( settings )\n\t{\n\t\tvar i, iLen, iAjaxStart=settings.iInitDisplayStart;\n\t\tvar columns = settings.aoColumns, column;\n\t\tvar features = settings.oFeatures;\n\t\tvar deferLoading = settings.bDeferLoading; // value modified by the draw\n\t\n\t\t/* Ensure that the table data is fully initialised */\n\t\tif ( ! settings.bInitialised ) {\n\t\t\tsetTimeout( function(){ _fnInitialise( settings ); }, 200 );\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Show the display HTML options */\n\t\t_fnAddOptionsHtml( settings );\n\t\n\t\t/* Build and draw the header / footer for the table */\n\t\t_fnBuildHead( settings );\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t/* Okay to show that something is going on now */\n\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t/* Calculate sizes for columns */\n\t\tif ( features.bAutoWidth ) {\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\n\t\t\tif ( column.sWidth ) {\n\t\t\t\tcolumn.nTh.style.width = _fnStringToCss( column.sWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'preInit', [settings] );\n\t\n\t\t// If there is default sorting required - let's do it. The sort function\n\t\t// will do the drawing for us. Otherwise we draw the table regardless of the\n\t\t// Ajax source - this allows the table to look initialised for Ajax sourcing\n\t\t// data (show 'loading' message possibly)\n\t\t_fnReDraw( settings );\n\t\n\t\t// Server-side processing init complete is done by _fnAjaxUpdateDraw\n\t\tvar dataSrc = _fnDataSource( settings );\n\t\tif ( dataSrc != 'ssp' || deferLoading ) {\n\t\t\t// if there is an ajax source load the data\n\t\t\tif ( dataSrc == 'ajax' ) {\n\t\t\t\t_fnBuildAjax( settings, [], function(json) {\n\t\t\t\t\tvar aData = _fnAjaxDataSrc( settings, json );\n\t\n\t\t\t\t\t// Got the data - add it to the table\n\t\t\t\t\tfor ( i=0 ; i<aData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( settings, aData[i] );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Reset the init display for cookie saving. We've already done\n\t\t\t\t\t// a filter, and therefore cleared it before. So we need to make\n\t\t\t\t\t// it appear 'fresh'\n\t\t\t\t\tsettings.iInitDisplayStart = iAjaxStart;\n\t\n\t\t\t\t\t_fnReDraw( settings );\n\t\n\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t_fnInitComplete( settings, json );\n\t\t\t\t}, settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t_fnInitComplete( settings );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} [json] JSON from the server that completed the table, if using Ajax source\n\t *    with client-side processing (optional)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitComplete ( settings, json )\n\t{\n\t\tsettings._bInitComplete = true;\n\t\n\t\t// When data was added after the initialisation (data or Ajax) we need to\n\t\t// calculate the column sizing\n\t\tif ( json || settings.oInit.aaData ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'plugin-init', [settings, json] );\n\t\t_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );\n\t}\n\t\n\t\n\tfunction _fnLengthChange ( settings, val )\n\t{\n\t\tvar len = parseInt( val, 10 );\n\t\tsettings._iDisplayLength = len;\n\t\n\t\t_fnLengthOverflow( settings );\n\t\n\t\t// Fire length change event\n\t\t_fnCallbackFire( settings, null, 'length', [settings, len] );\n\t}\n\t\n\t\n\t/**\n\t * Generate the node required for user display length changing\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Display length feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlLength ( settings )\n\t{\n\t\tvar\n\t\t\tclasses  = settings.oClasses,\n\t\t\ttableId  = settings.sTableId,\n\t\t\tmenu     = settings.aLengthMenu,\n\t\t\td2       = $.isArray( menu[0] ),\n\t\t\tlengths  = d2 ? menu[0] : menu,\n\t\t\tlanguage = d2 ? menu[1] : menu;\n\t\n\t\tvar select = $('<select/>', {\n\t\t\t'name':          tableId+'_length',\n\t\t\t'aria-controls': tableId,\n\t\t\t'class':         classes.sLengthSelect\n\t\t} );\n\t\n\t\tfor ( var i=0, ien=lengths.length ; i<ien ; i++ ) {\n\t\t\tselect[0][ i ] = new Option( language[i], lengths[i] );\n\t\t}\n\t\n\t\tvar div = $('<div><label/></div>').addClass( classes.sLength );\n\t\tif ( ! settings.aanFeatures.l ) {\n\t\t\tdiv[0].id = tableId+'_length';\n\t\t}\n\t\n\t\tdiv.children().append(\n\t\t\tsettings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )\n\t\t);\n\t\n\t\t// Can't use `select` variable as user might provide their own and the\n\t\t// reference is broken by the use of outerHTML\n\t\t$('select', div)\n\t\t\t.val( settings._iDisplayLength )\n\t\t\t.on( 'change.DT', function(e) {\n\t\t\t\t_fnLengthChange( settings, $(this).val() );\n\t\t\t\t_fnDraw( settings );\n\t\t\t} );\n\t\n\t\t// Update node value whenever anything changes the table's length\n\t\t$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t$('select', div).val( len );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn div[0];\n\t}\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Note that most of the paging logic is done in\n\t * DataTable.ext.pager\n\t */\n\t\n\t/**\n\t * Generate the node required for default pagination\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Pagination feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlPaginate ( settings )\n\t{\n\t\tvar\n\t\t\ttype   = settings.sPaginationType,\n\t\t\tplugin = DataTable.ext.pager[ type ],\n\t\t\tmodern = typeof plugin === 'function',\n\t\t\tredraw = function( settings ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t},\n\t\t\tnode = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],\n\t\t\tfeatures = settings.aanFeatures;\n\t\n\t\tif ( ! modern ) {\n\t\t\tplugin.fnInit( settings, node, redraw );\n\t\t}\n\t\n\t\t/* Add a draw callback for the pagination on first instance, to update the paging display */\n\t\tif ( ! features.p )\n\t\t{\n\t\t\tnode.id = settings.sTableId+'_paginate';\n\t\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": function( settings ) {\n\t\t\t\t\tif ( modern ) {\n\t\t\t\t\t\tvar\n\t\t\t\t\t\t\tstart      = settings._iDisplayStart,\n\t\t\t\t\t\t\tlen        = settings._iDisplayLength,\n\t\t\t\t\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\t\t\t\t\tall        = len === -1,\n\t\t\t\t\t\t\tpage = all ? 0 : Math.ceil( start / len ),\n\t\t\t\t\t\t\tpages = all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\t\t\t\tbuttons = plugin(page, pages),\n\t\t\t\t\t\t\ti, ien;\n\t\n\t\t\t\t\t\tfor ( i=0, ien=features.p.length ; i<ien ; i++ ) {\n\t\t\t\t\t\t\t_fnRenderer( settings, 'pageButton' )(\n\t\t\t\t\t\t\t\tsettings, features.p[i], i, buttons, page, pages\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tplugin.fnUpdate( settings, redraw );\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"sName\": \"pagination\"\n\t\t\t} );\n\t\t}\n\t\n\t\treturn node;\n\t}\n\t\n\t\n\t/**\n\t * Alter the display settings to change the page\n\t *  @param {object} settings DataTables settings object\n\t *  @param {string|int} action Paging action to take: \"first\", \"previous\",\n\t *    \"next\" or \"last\" or page number to jump to (integer)\n\t *  @param [bool] redraw Automatically draw the update or not\n\t *  @returns {bool} true page has changed, false - no change\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnPageChange ( settings, action, redraw )\n\t{\n\t\tvar\n\t\t\tstart     = settings._iDisplayStart,\n\t\t\tlen       = settings._iDisplayLength,\n\t\t\trecords   = settings.fnRecordsDisplay();\n\t\n\t\tif ( records === 0 || len === -1 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( typeof action === \"number\" )\n\t\t{\n\t\t\tstart = action * len;\n\t\n\t\t\tif ( start > records )\n\t\t\t{\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"first\" )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( action == \"previous\" )\n\t\t{\n\t\t\tstart = len >= 0 ?\n\t\t\t\tstart - len :\n\t\t\t\t0;\n\t\n\t\t\tif ( start < 0 )\n\t\t\t{\n\t\t\t  start = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"next\" )\n\t\t{\n\t\t\tif ( start + len < records )\n\t\t\t{\n\t\t\t\tstart += len;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"last\" )\n\t\t{\n\t\t\tstart = Math.floor( (records-1) / len) * len;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_fnLog( settings, 0, \"Unknown paging action: \"+action, 5 );\n\t\t}\n\t\n\t\tvar changed = settings._iDisplayStart !== start;\n\t\tsettings._iDisplayStart = start;\n\t\n\t\tif ( changed ) {\n\t\t\t_fnCallbackFire( settings, null, 'page', [settings] );\n\t\n\t\t\tif ( redraw ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t}\n\t\n\t\treturn changed;\n\t}\n\t\n\t\n\t\n\t/**\n\t * Generate the node required for the processing node\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Processing element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlProcessing ( settings )\n\t{\n\t\treturn $('<div/>', {\n\t\t\t\t'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,\n\t\t\t\t'class': settings.oClasses.sProcessing\n\t\t\t} )\n\t\t\t.html( settings.oLanguage.sProcessing )\n\t\t\t.insertBefore( settings.nTable )[0];\n\t}\n\t\n\t\n\t/**\n\t * Display or hide the processing indicator\n\t *  @param {object} settings dataTables settings object\n\t *  @param {bool} show Show the processing indicator (true) or not (false)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnProcessingDisplay ( settings, show )\n\t{\n\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t$(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'processing', [settings, show] );\n\t}\n\t\n\t/**\n\t * Add any control elements for the table - specifically scrolling\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Node to add to the DOM\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlTable ( settings )\n\t{\n\t\tvar table = $(settings.nTable);\n\t\n\t\t// Add the ARIA grid role to the table\n\t\ttable.attr( 'role', 'grid' );\n\t\n\t\t// Scrolling from here on in\n\t\tvar scroll = settings.oScroll;\n\t\n\t\tif ( scroll.sX === '' && scroll.sY === '' ) {\n\t\t\treturn settings.nTable;\n\t\t}\n\t\n\t\tvar scrollX = scroll.sX;\n\t\tvar scrollY = scroll.sY;\n\t\tvar classes = settings.oClasses;\n\t\tvar caption = table.children('caption');\n\t\tvar captionSide = caption.length ? caption[0]._captionSide : null;\n\t\tvar headerClone = $( table[0].cloneNode(false) );\n\t\tvar footerClone = $( table[0].cloneNode(false) );\n\t\tvar footer = table.children('tfoot');\n\t\tvar _div = '<div/>';\n\t\tvar size = function ( s ) {\n\t\t\treturn !s ? null : _fnStringToCss( s );\n\t\t};\n\t\n\t\tif ( ! footer.length ) {\n\t\t\tfooter = null;\n\t\t}\n\t\n\t\t/*\n\t\t * The HTML structure that we want to generate in this function is:\n\t\t *  div - scroller\n\t\t *    div - scroll head\n\t\t *      div - scroll head inner\n\t\t *        table - scroll head table\n\t\t *          thead - thead\n\t\t *    div - scroll body\n\t\t *      table - table (master table)\n\t\t *        thead - thead clone for sizing\n\t\t *        tbody - tbody\n\t\t *    div - scroll foot\n\t\t *      div - scroll foot inner\n\t\t *        table - scroll foot table\n\t\t *          tfoot - tfoot\n\t\t */\n\t\tvar scroller = $( _div, { 'class': classes.sScrollWrapper } )\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollHead } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollHeadInner } )\n\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t'box-sizing': 'content-box',\n\t\t\t\t\t\t\t\twidth: scroll.sXInner || '100%'\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\theaderClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'top' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('thead')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t)\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollBody } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\toverflow: 'auto',\n\t\t\t\t\t\twidth: size( scrollX )\n\t\t\t\t\t} )\n\t\t\t\t\t.append( table )\n\t\t\t);\n\t\n\t\tif ( footer ) {\n\t\t\tscroller.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollFoot } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollFootInner } )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\tfooterClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'bottom' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('tfoot')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\n\t\tvar children = scroller.children();\n\t\tvar scrollHead = children[0];\n\t\tvar scrollBody = children[1];\n\t\tvar scrollFoot = footer ? children[2] : null;\n\t\n\t\t// When the body is scrolled, then we also want to scroll the headers\n\t\tif ( scrollX ) {\n\t\t\t$(scrollBody).on( 'scroll.DT', function (e) {\n\t\t\t\tvar scrollLeft = this.scrollLeft;\n\t\n\t\t\t\tscrollHead.scrollLeft = scrollLeft;\n\t\n\t\t\t\tif ( footer ) {\n\t\t\t\t\tscrollFoot.scrollLeft = scrollLeft;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\n\t\t$(scrollBody).css(\n\t\t\tscrollY && scroll.bCollapse ? 'max-height' : 'height', \n\t\t\tscrollY\n\t\t);\n\t\n\t\tsettings.nScrollHead = scrollHead;\n\t\tsettings.nScrollBody = scrollBody;\n\t\tsettings.nScrollFoot = scrollFoot;\n\t\n\t\t// On redraw - align columns\n\t\tsettings.aoDrawCallback.push( {\n\t\t\t\"fn\": _fnScrollDraw,\n\t\t\t\"sName\": \"scrolling\"\n\t\t} );\n\t\n\t\treturn scroller[0];\n\t}\n\t\n\t\n\t\n\t/**\n\t * Update the header, footer and body tables for resizing - i.e. column\n\t * alignment.\n\t *\n\t * Welcome to the most horrible function DataTables. The process that this\n\t * function follows is basically:\n\t *   1. Re-create the table inside the scrolling div\n\t *   2. Take live measurements from the DOM\n\t *   3. Apply the measurements to align the columns\n\t *   4. Clean up\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnScrollDraw ( settings )\n\t{\n\t\t// Given that this is such a monster function, a lot of variables are use\n\t\t// to try and keep the minimised size as small as possible\n\t\tvar\n\t\t\tscroll         = settings.oScroll,\n\t\t\tscrollX        = scroll.sX,\n\t\t\tscrollXInner   = scroll.sXInner,\n\t\t\tscrollY        = scroll.sY,\n\t\t\tbarWidth       = scroll.iBarWidth,\n\t\t\tdivHeader      = $(settings.nScrollHead),\n\t\t\tdivHeaderStyle = divHeader[0].style,\n\t\t\tdivHeaderInner = divHeader.children('div'),\n\t\t\tdivHeaderInnerStyle = divHeaderInner[0].style,\n\t\t\tdivHeaderTable = divHeaderInner.children('table'),\n\t\t\tdivBodyEl      = settings.nScrollBody,\n\t\t\tdivBody        = $(divBodyEl),\n\t\t\tdivBodyStyle   = divBodyEl.style,\n\t\t\tdivFooter      = $(settings.nScrollFoot),\n\t\t\tdivFooterInner = divFooter.children('div'),\n\t\t\tdivFooterTable = divFooterInner.children('table'),\n\t\t\theader         = $(settings.nTHead),\n\t\t\ttable          = $(settings.nTable),\n\t\t\ttableEl        = table[0],\n\t\t\ttableStyle     = tableEl.style,\n\t\t\tfooter         = settings.nTFoot ? $(settings.nTFoot) : null,\n\t\t\tbrowser        = settings.oBrowser,\n\t\t\tie67           = browser.bScrollOversize,\n\t\t\tdtHeaderCells  = _pluck( settings.aoColumns, 'nTh' ),\n\t\t\theaderTrgEls, footerTrgEls,\n\t\t\theaderSrcEls, footerSrcEls,\n\t\t\theaderCopy, footerCopy,\n\t\t\theaderWidths=[], footerWidths=[],\n\t\t\theaderContent=[], footerContent=[],\n\t\t\tidx, correction, sanityWidth,\n\t\t\tzeroOut = function(nSizer) {\n\t\t\t\tvar style = nSizer.style;\n\t\t\t\tstyle.paddingTop = \"0\";\n\t\t\t\tstyle.paddingBottom = \"0\";\n\t\t\t\tstyle.borderTopWidth = \"0\";\n\t\t\t\tstyle.borderBottomWidth = \"0\";\n\t\t\t\tstyle.height = 0;\n\t\t\t};\n\t\n\t\t// If the scrollbar visibility has changed from the last draw, we need to\n\t\t// adjust the column sizes as the table width will have changed to account\n\t\t// for the scrollbar\n\t\tvar scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;\n\t\t\n\t\tif ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t\treturn; // adjust column sizing will call this function again\n\t\t}\n\t\telse {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t}\n\t\n\t\t/*\n\t\t * 1. Re-create the table inside the scrolling div\n\t\t */\n\t\n\t\t// Remove the old minimised thead and tfoot elements in the inner table\n\t\ttable.children('thead, tfoot').remove();\n\t\n\t\tif ( footer ) {\n\t\t\tfooterCopy = footer.clone().prependTo( table );\n\t\t\tfooterTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized\n\t\t\tfooterSrcEls = footerCopy.find('tr');\n\t\t}\n\t\n\t\t// Clone the current header and footer elements and then place it into the inner table\n\t\theaderCopy = header.clone().prependTo( table );\n\t\theaderTrgEls = header.find('tr'); // original header is in its own table\n\t\theaderSrcEls = headerCopy.find('tr');\n\t\theaderCopy.find('th, td').removeAttr('tabindex');\n\t\n\t\n\t\t/*\n\t\t * 2. Take live measurements from the DOM - do not alter the DOM itself!\n\t\t */\n\t\n\t\t// Remove old sizing and apply the calculated column widths\n\t\t// Get the unique column headers in the newly created (cloned) header. We want to apply the\n\t\t// calculated sizes to this header\n\t\tif ( ! scrollX )\n\t\t{\n\t\t\tdivBodyStyle.width = '100%';\n\t\t\tdivHeader[0].style.width = '100%';\n\t\t}\n\t\n\t\t$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {\n\t\t\tidx = _fnVisibleToColumnIndex( settings, i );\n\t\t\tel.style.width = settings.aoColumns[idx].sWidth;\n\t\t} );\n\t\n\t\tif ( footer ) {\n\t\t\t_fnApplyToChildren( function(n) {\n\t\t\t\tn.style.width = \"\";\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Size the table as a whole\n\t\tsanityWidth = table.outerWidth();\n\t\tif ( scrollX === \"\" ) {\n\t\t\t// No x scrolling\n\t\t\ttableStyle.width = \"100%\";\n\t\n\t\t\t// IE7 will make the width of the table when 100% include the scrollbar\n\t\t\t// - which is shouldn't. When there is a scrollbar we need to take this\n\t\t\t// into account.\n\t\t\tif ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);\n\t\t\t}\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\telse if ( scrollXInner !== \"\" ) {\n\t\t\t// legacy x scroll inner has been given - use it\n\t\t\ttableStyle.width = _fnStringToCss(scrollXInner);\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\n\t\t// Hidden header should have zero height, so remove padding and borders. Then\n\t\t// set the width based on the real headers\n\t\n\t\t// Apply all styles in one pass\n\t\t_fnApplyToChildren( zeroOut, headerSrcEls );\n\t\n\t\t// Read all widths in next pass\n\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\theaderContent.push( nSizer.innerHTML );\n\t\t\theaderWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t}, headerSrcEls );\n\t\n\t\t// Apply all widths in final pass\n\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t// Only apply widths to the DataTables detected header cells - this\n\t\t\t// prevents complex headers from having contradictory sizes applied\n\t\t\tif ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {\n\t\t\t\tnToSize.style.width = headerWidths[i];\n\t\t\t}\n\t\t}, headerTrgEls );\n\t\n\t\t$(headerSrcEls).height(0);\n\t\n\t\t/* Same again with the footer if we have one */\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( zeroOut, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\t\tfooterContent.push( nSizer.innerHTML );\n\t\t\t\tfooterWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t\t}, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t\tnToSize.style.width = footerWidths[i];\n\t\t\t}, footerTrgEls );\n\t\n\t\t\t$(footerSrcEls).height(0);\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 3. Apply the measurements\n\t\t */\n\t\n\t\t// \"Hide\" the header and footer that we used for the sizing. We need to keep\n\t\t// the content of the cell so that the width applied to the header and body\n\t\t// both match, but we want to hide it completely. We want to also fix their\n\t\t// width to what they currently are\n\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\" style=\"height:0;overflow:hidden;\">'+headerContent[i]+'</div>';\n\t\t\tnSizer.style.width = headerWidths[i];\n\t\t}, headerSrcEls );\n\t\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\" style=\"height:0;overflow:hidden;\">'+footerContent[i]+'</div>';\n\t\t\t\tnSizer.style.width = footerWidths[i];\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Sanity check that the table is of a sensible width. If not then we are going to get\n\t\t// misalignment - try to prevent this by not allowing the table to shrink below its min width\n\t\tif ( table.outerWidth() < sanityWidth )\n\t\t{\n\t\t\t// The min width depends upon if we have a vertical scrollbar visible or not */\n\t\t\tcorrection = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")) ?\n\t\t\t\t\tsanityWidth+barWidth :\n\t\t\t\t\tsanityWidth;\n\t\n\t\t\t// IE6/7 are a law unto themselves...\n\t\t\tif ( ie67 && (divBodyEl.scrollHeight >\n\t\t\t\tdivBodyEl.offsetHeight || divBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( correction-barWidth );\n\t\t\t}\n\t\n\t\t\t// And give the user a warning that we've stopped the table getting too small\n\t\t\tif ( scrollX === \"\" || scrollXInner !== \"\" ) {\n\t\t\t\t_fnLog( settings, 1, 'Possible column misalignment', 6 );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcorrection = '100%';\n\t\t}\n\t\n\t\t// Apply to the container elements\n\t\tdivBodyStyle.width = _fnStringToCss( correction );\n\t\tdivHeaderStyle.width = _fnStringToCss( correction );\n\t\n\t\tif ( footer ) {\n\t\t\tsettings.nScrollFoot.style.width = _fnStringToCss( correction );\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 4. Clean up\n\t\t */\n\t\tif ( ! scrollY ) {\n\t\t\t/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting\n\t\t\t * the scrollbar height from the visible display, rather than adding it on. We need to\n\t\t\t * set the height in order to sort this. Don't want to do it in any other browsers.\n\t\t\t */\n\t\t\tif ( ie67 ) {\n\t\t\t\tdivBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Finally set the width's of the header and footer tables */\n\t\tvar iOuterWidth = table.outerWidth();\n\t\tdivHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\tdivHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );\n\t\n\t\t// Figure out if there are scrollbar present - if so then we need a the header and footer to\n\t\t// provide a bit more space to allow \"overflow\" scrolling (i.e. past the scrollbar)\n\t\tvar bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == \"scroll\";\n\t\tvar padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );\n\t\tdivHeaderInnerStyle[ padding ] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\n\t\tif ( footer ) {\n\t\t\tdivFooterTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style[padding] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\t}\n\t\n\t\t// Correct DOM ordering for colgroup - comes before the thead\n\t\ttable.children('colgroup').insertBefore( table.children('thead') );\n\t\n\t\t/* Adjust the position of the header in case we loose the y-scrollbar */\n\t\tdivBody.scroll();\n\t\n\t\t// If sorting or filtering has occurred, jump the scrolling back to the top\n\t\t// only if we aren't holding the position\n\t\tif ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {\n\t\t\tdivBodyEl.scrollTop = 0;\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Apply a given function to the display child nodes of an element array (typically\n\t * TD children of TR rows\n\t *  @param {function} fn Method to apply to the objects\n\t *  @param array {nodes} an1 List of elements to look through for display children\n\t *  @param array {nodes} an2 Another list (identical structure to the first) - optional\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyToChildren( fn, an1, an2 )\n\t{\n\t\tvar index=0, i=0, iLen=an1.length;\n\t\tvar nNode1, nNode2;\n\t\n\t\twhile ( i < iLen ) {\n\t\t\tnNode1 = an1[i].firstChild;\n\t\t\tnNode2 = an2 ? an2[i].firstChild : null;\n\t\n\t\t\twhile ( nNode1 ) {\n\t\t\t\tif ( nNode1.nodeType === 1 ) {\n\t\t\t\t\tif ( an2 ) {\n\t\t\t\t\t\tfn( nNode1, nNode2, index );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfn( nNode1, index );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\n\t\t\t\tnNode1 = nNode1.nextSibling;\n\t\t\t\tnNode2 = an2 ? nNode2.nextSibling : null;\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t}\n\t}\n\t\n\t\n\t\n\tvar __re_html_remove = /<.*?>/g;\n\t\n\t\n\t/**\n\t * Calculate the width of columns for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCalculateColumnWidths ( oSettings )\n\t{\n\t\tvar\n\t\t\ttable = oSettings.nTable,\n\t\t\tcolumns = oSettings.aoColumns,\n\t\t\tscroll = oSettings.oScroll,\n\t\t\tscrollY = scroll.sY,\n\t\t\tscrollX = scroll.sX,\n\t\t\tscrollXInner = scroll.sXInner,\n\t\t\tcolumnCount = columns.length,\n\t\t\tvisibleColumns = _fnGetColumns( oSettings, 'bVisible' ),\n\t\t\theaderCells = $('th', oSettings.nTHead),\n\t\t\ttableWidthAttr = table.getAttribute('width'), // from DOM element\n\t\t\ttableContainer = table.parentNode,\n\t\t\tuserInputs = false,\n\t\t\ti, column, columnIdx, width, outerWidth,\n\t\t\tbrowser = oSettings.oBrowser,\n\t\t\tie67 = browser.bScrollOversize;\n\t\n\t\tvar styleWidth = table.style.width;\n\t\tif ( styleWidth && styleWidth.indexOf('%') !== -1 ) {\n\t\t\ttableWidthAttr = styleWidth;\n\t\t}\n\t\n\t\t/* Convert any user input sizes into pixel sizes */\n\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\tif ( column.sWidth !== null ) {\n\t\t\t\tcolumn.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );\n\t\n\t\t\t\tuserInputs = true;\n\t\t\t}\n\t\t}\n\t\n\t\t/* If the number of columns in the DOM equals the number that we have to\n\t\t * process in DataTables, then we can use the offsets that are created by\n\t\t * the web- browser. No custom sizes can be set in order for this to happen,\n\t\t * nor scrolling used\n\t\t */\n\t\tif ( ie67 || ! userInputs && ! scrollX && ! scrollY &&\n\t\t     columnCount == _fnVisbleColumns( oSettings ) &&\n\t\t     columnCount == headerCells.length\n\t\t) {\n\t\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\t\tvar colIdx = _fnVisibleToColumnIndex( oSettings, i );\n\t\n\t\t\t\tif ( colIdx !== null ) {\n\t\t\t\t\tcolumns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise construct a single row, worst case, table with the widest\n\t\t\t// node in the data, assign any user defined widths, then insert it into\n\t\t\t// the DOM and allow the browser to do all the hard work of calculating\n\t\t\t// table widths\n\t\t\tvar tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table\n\t\t\t\t.css( 'visibility', 'hidden' )\n\t\t\t\t.removeAttr( 'id' );\n\t\n\t\t\t// Clean up the table body\n\t\t\ttmpTable.find('tbody tr').remove();\n\t\t\tvar tr = $('<tr/>').appendTo( tmpTable.find('tbody') );\n\t\n\t\t\t// Clone the table header and footer - we can't use the header / footer\n\t\t\t// from the cloned table, since if scrolling is active, the table's\n\t\t\t// real header and footer are contained in different table tags\n\t\t\ttmpTable.find('thead, tfoot').remove();\n\t\t\ttmpTable\n\t\t\t\t.append( $(oSettings.nTHead).clone() )\n\t\t\t\t.append( $(oSettings.nTFoot).clone() );\n\t\n\t\t\t// Remove any assigned widths from the footer (from scrolling)\n\t\t\ttmpTable.find('tfoot th, tfoot td').css('width', '');\n\t\n\t\t\t// Apply custom sizing to the cloned header\n\t\t\theaderCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );\n\t\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\t\theaderCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?\n\t\t\t\t\t_fnStringToCss( column.sWidthOrig ) :\n\t\t\t\t\t'';\n\t\n\t\t\t\t// For scrollX we need to force the column width otherwise the\n\t\t\t\t// browser will collapse it. If this width is smaller than the\n\t\t\t\t// width the column requires, then it will have no effect\n\t\t\t\tif ( column.sWidthOrig && scrollX ) {\n\t\t\t\t\t$( headerCells[i] ).append( $('<div/>').css( {\n\t\t\t\t\t\twidth: column.sWidthOrig,\n\t\t\t\t\t\tmargin: 0,\n\t\t\t\t\t\tpadding: 0,\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\theight: 1\n\t\t\t\t\t} ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Find the widest cell for each column and put it into the table\n\t\t\tif ( oSettings.aoData.length ) {\n\t\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\t\tcolumnIdx = visibleColumns[i];\n\t\t\t\t\tcolumn = columns[ columnIdx ];\n\t\n\t\t\t\t\t$( _fnGetWidestNode( oSettings, columnIdx ) )\n\t\t\t\t\t\t.clone( false )\n\t\t\t\t\t\t.append( column.sContentPadding )\n\t\t\t\t\t\t.appendTo( tr );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Tidy the temporary table - remove name attributes so there aren't\n\t\t\t// duplicated in the dom (radio elements for example)\n\t\t\t$('[name]', tmpTable).removeAttr('name');\n\t\n\t\t\t// Table has been built, attach to the document so we can work with it.\n\t\t\t// A holding element is used, positioned at the top of the container\n\t\t\t// with minimal height, so it has no effect on if the container scrolls\n\t\t\t// or not. Otherwise it might trigger scrolling when it actually isn't\n\t\t\t// needed\n\t\t\tvar holder = $('<div/>').css( scrollX || scrollY ?\n\t\t\t\t\t{\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\theight: 1,\n\t\t\t\t\t\tright: 0,\n\t\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t\t} :\n\t\t\t\t\t{}\n\t\t\t\t)\n\t\t\t\t.append( tmpTable )\n\t\t\t\t.appendTo( tableContainer );\n\t\n\t\t\t// When scrolling (X or Y) we want to set the width of the table as \n\t\t\t// appropriate. However, when not scrolling leave the table width as it\n\t\t\t// is. This results in slightly different, but I think correct behaviour\n\t\t\tif ( scrollX && scrollXInner ) {\n\t\t\t\ttmpTable.width( scrollXInner );\n\t\t\t}\n\t\t\telse if ( scrollX ) {\n\t\t\t\ttmpTable.css( 'width', 'auto' );\n\t\t\t\ttmpTable.removeAttr('width');\n\t\n\t\t\t\t// If there is no width attribute or style, then allow the table to\n\t\t\t\t// collapse\n\t\t\t\tif ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {\n\t\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( scrollY ) {\n\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t}\n\t\t\telse if ( tableWidthAttr ) {\n\t\t\t\ttmpTable.width( tableWidthAttr );\n\t\t\t}\n\t\n\t\t\t// Get the width of each column in the constructed table - we need to\n\t\t\t// know the inner width (so it can be assigned to the other table's\n\t\t\t// cells) and the outer width so we can calculate the full width of the\n\t\t\t// table. This is safe since DataTables requires a unique cell for each\n\t\t\t// column, but if ever a header can span multiple columns, this will\n\t\t\t// need to be modified.\n\t\t\tvar total = 0;\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tvar cell = $(headerCells[i]);\n\t\t\t\tvar border = cell.outerWidth() - cell.width();\n\t\n\t\t\t\t// Use getBounding... where possible (not IE8-) because it can give\n\t\t\t\t// sub-pixel accuracy, which we then want to round up!\n\t\t\t\tvar bounding = browser.bBounding ?\n\t\t\t\t\tMath.ceil( headerCells[i].getBoundingClientRect().width ) :\n\t\t\t\t\tcell.outerWidth();\n\t\n\t\t\t\t// Total is tracked to remove any sub-pixel errors as the outerWidth\n\t\t\t\t// of the table might not equal the total given here (IE!).\n\t\t\t\ttotal += bounding;\n\t\n\t\t\t\t// Width for each column to use\n\t\t\t\tcolumns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );\n\t\t\t}\n\t\n\t\t\ttable.style.width = _fnStringToCss( total );\n\t\n\t\t\t// Finished with the table - ditch it\n\t\t\tholder.remove();\n\t\t}\n\t\n\t\t// If there is a width attr, we want to attach an event listener which\n\t\t// allows the table sizing to automatically adjust when the window is\n\t\t// resized. Use the width attr rather than CSS, since we can't know if the\n\t\t// CSS is a relative value or absolute - DOM read is always px.\n\t\tif ( tableWidthAttr ) {\n\t\t\ttable.style.width = _fnStringToCss( tableWidthAttr );\n\t\t}\n\t\n\t\tif ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {\n\t\t\tvar bindResize = function () {\n\t\t\t\t$(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {\n\t\t\t\t\t_fnAdjustColumnSizing( oSettings );\n\t\t\t\t} ) );\n\t\t\t};\n\t\n\t\t\t// IE6/7 will crash if we bind a resize event handler on page load.\n\t\t\t// To be removed in 1.11 which drops IE6/7 support\n\t\t\tif ( ie67 ) {\n\t\t\t\tsetTimeout( bindResize, 1000 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbindResize();\n\t\t\t}\n\t\n\t\t\toSettings._reszEvt = true;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Throttle the calls to a function. Arguments and context are maintained for\n\t * the throttled function\n\t *  @param {function} fn Function to be called\n\t *  @param {int} [freq=200] call frequency in mS\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnThrottle = DataTable.util.throttle;\n\t\n\t\n\t/**\n\t * Convert a CSS unit width to pixels (e.g. 2em)\n\t *  @param {string} width width to be converted\n\t *  @param {node} parent parent to get the with for (required for relative widths) - optional\n\t *  @returns {int} width in pixels\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnConvertToWidth ( width, parent )\n\t{\n\t\tif ( ! width ) {\n\t\t\treturn 0;\n\t\t}\n\t\n\t\tvar n = $('<div/>')\n\t\t\t.css( 'width', _fnStringToCss( width ) )\n\t\t\t.appendTo( parent || document.body );\n\t\n\t\tvar val = n[0].offsetWidth;\n\t\tn.remove();\n\t\n\t\treturn val;\n\t}\n\t\n\t\n\t/**\n\t * Get the widest node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {node} widest table node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetWidestNode( settings, colIdx )\n\t{\n\t\tvar idx = _fnGetMaxLenString( settings, colIdx );\n\t\tif ( idx < 0 ) {\n\t\t\treturn null;\n\t\t}\n\t\n\t\tvar data = settings.aoData[ idx ];\n\t\treturn ! data.nTr ? // Might not have been created when deferred rendering\n\t\t\t$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :\n\t\t\tdata.anCells[ colIdx ];\n\t}\n\t\n\t\n\t/**\n\t * Get the maximum strlen for each data column\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {string} max string length for each column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetMaxLenString( settings, colIdx )\n\t{\n\t\tvar s, max=-1, maxIdx = -1;\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\ts = _fnGetCellData( settings, i, colIdx, 'display' )+'';\n\t\t\ts = s.replace( __re_html_remove, '' );\n\t\t\ts = s.replace( /&nbsp;/g, ' ' );\n\t\n\t\t\tif ( s.length > max ) {\n\t\t\t\tmax = s.length;\n\t\t\t\tmaxIdx = i;\n\t\t\t}\n\t\t}\n\t\n\t\treturn maxIdx;\n\t}\n\t\n\t\n\t/**\n\t * Append a CSS unit (only if required) to a string\n\t *  @param {string} value to css-ify\n\t *  @returns {string} value with css unit\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnStringToCss( s )\n\t{\n\t\tif ( s === null ) {\n\t\t\treturn '0px';\n\t\t}\n\t\n\t\tif ( typeof s == 'number' ) {\n\t\t\treturn s < 0 ?\n\t\t\t\t'0px' :\n\t\t\t\ts+'px';\n\t\t}\n\t\n\t\t// Check it has a unit character already\n\t\treturn s.match(/\\d$/) ?\n\t\t\ts+'px' :\n\t\t\ts;\n\t}\n\t\n\t\n\t\n\tfunction _fnSortFlatten ( settings )\n\t{\n\t\tvar\n\t\t\ti, iLen, k, kLen,\n\t\t\taSort = [],\n\t\t\taiOrig = [],\n\t\t\taoColumns = settings.aoColumns,\n\t\t\taDataSort, iCol, sType, srcCol,\n\t\t\tfixed = settings.aaSortingFixed,\n\t\t\tfixedObj = $.isPlainObject( fixed ),\n\t\t\tnestedSort = [],\n\t\t\tadd = function ( a ) {\n\t\t\t\tif ( a.length && ! $.isArray( a[0] ) ) {\n\t\t\t\t\t// 1D array\n\t\t\t\t\tnestedSort.push( a );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// 2D array\n\t\t\t\t\t$.merge( nestedSort, a );\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t// Build the sort array, with pre-fix and post-fix options if they have been\n\t\t// specified\n\t\tif ( $.isArray( fixed ) ) {\n\t\t\tadd( fixed );\n\t\t}\n\t\n\t\tif ( fixedObj && fixed.pre ) {\n\t\t\tadd( fixed.pre );\n\t\t}\n\t\n\t\tadd( settings.aaSorting );\n\t\n\t\tif (fixedObj && fixed.post ) {\n\t\t\tadd( fixed.post );\n\t\t}\n\t\n\t\tfor ( i=0 ; i<nestedSort.length ; i++ )\n\t\t{\n\t\t\tsrcCol = nestedSort[i][0];\n\t\t\taDataSort = aoColumns[ srcCol ].aDataSort;\n\t\n\t\t\tfor ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )\n\t\t\t{\n\t\t\t\tiCol = aDataSort[k];\n\t\t\t\tsType = aoColumns[ iCol ].sType || 'string';\n\t\n\t\t\t\tif ( nestedSort[i]._idx === undefined ) {\n\t\t\t\t\tnestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );\n\t\t\t\t}\n\t\n\t\t\t\taSort.push( {\n\t\t\t\t\tsrc:       srcCol,\n\t\t\t\t\tcol:       iCol,\n\t\t\t\t\tdir:       nestedSort[i][1],\n\t\t\t\t\tindex:     nestedSort[i]._idx,\n\t\t\t\t\ttype:      sType,\n\t\t\t\t\tformatter: DataTable.ext.type.order[ sType+\"-pre\" ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\treturn aSort;\n\t}\n\t\n\t/**\n\t * Change the order of the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t *  @todo This really needs split up!\n\t */\n\tfunction _fnSort ( oSettings )\n\t{\n\t\tvar\n\t\t\ti, ien, iLen, j, jLen, k, kLen,\n\t\t\tsDataType, nTh,\n\t\t\taiOrig = [],\n\t\t\toExtSort = DataTable.ext.type.order,\n\t\t\taoData = oSettings.aoData,\n\t\t\taoColumns = oSettings.aoColumns,\n\t\t\taDataSort, data, iCol, sType, oSort,\n\t\t\tformatters = 0,\n\t\t\tsortCol,\n\t\t\tdisplayMaster = oSettings.aiDisplayMaster,\n\t\t\taSort;\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo Can this be moved into a 'data-ready' handler which is called when\n\t\t//   data is going to be used in the table?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\taSort = _fnSortFlatten( oSettings );\n\t\n\t\tfor ( i=0, ien=aSort.length ; i<ien ; i++ ) {\n\t\t\tsortCol = aSort[i];\n\t\n\t\t\t// Track if we can use the fast sort algorithm\n\t\t\tif ( sortCol.formatter ) {\n\t\t\t\tformatters++;\n\t\t\t}\n\t\n\t\t\t// Load the data needed for the sort, for each cell\n\t\t\t_fnSortData( oSettings, sortCol.col );\n\t\t}\n\t\n\t\t/* No sorting required if server-side or no sorting array */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )\n\t\t{\n\t\t\t// Create a value - key array of the current row positions such that we can use their\n\t\t\t// current position during the sort, if values match, in order to perform stable sorting\n\t\t\tfor ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {\n\t\t\t\taiOrig[ displayMaster[i] ] = i;\n\t\t\t}\n\t\n\t\t\t/* Do the sort - here we want multi-column sorting based on a given data source (column)\n\t\t\t * and sorting function (from oSort) in a certain direction. It's reasonably complex to\n\t\t\t * follow on it's own, but this is what we want (example two column sorting):\n\t\t\t *  fnLocalSorting = function(a,b){\n\t\t\t *    var iTest;\n\t\t\t *    iTest = oSort['string-asc']('data11', 'data12');\n\t\t\t *      if (iTest !== 0)\n\t\t\t *        return iTest;\n\t\t\t *    iTest = oSort['numeric-desc']('data21', 'data22');\n\t\t\t *    if (iTest !== 0)\n\t\t\t *      return iTest;\n\t\t\t *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );\n\t\t\t *  }\n\t\t\t * Basically we have a test for each sorting column, if the data in that column is equal,\n\t\t\t * test the next column. If all columns match, then we use a numeric sort on the row\n\t\t\t * positions in the original data array to provide a stable sort.\n\t\t\t *\n\t\t\t * Note - I know it seems excessive to have two sorting methods, but the first is around\n\t\t\t * 15% faster, so the second is only maintained for backwards compatibility with sorting\n\t\t\t * methods which do not have a pre-sort formatting function.\n\t\t\t */\n\t\t\tif ( formatters === aSort.length ) {\n\t\t\t\t// All sort types have formatting functions\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, test, sort,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\ttest = x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn sort.dir === 'asc' ? test : -test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Depreciated - remove in 1.11 (providing a plug-in option)\n\t\t\t\t// Not all sort types have formatting methods, so we have to call their sorting\n\t\t\t\t// methods.\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, l, test, sort, fn,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\tfn = oExtSort[ sort.type+\"-\"+sort.dir ] || oExtSort[ \"string-\"+sort.dir ];\n\t\t\t\t\t\ttest = fn( x, y );\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Tell the draw function that we have sorted the data */\n\t\toSettings.bSorted = true;\n\t}\n\t\n\t\n\tfunction _fnSortAria ( settings )\n\t{\n\t\tvar label;\n\t\tvar nextSort;\n\t\tvar columns = settings.aoColumns;\n\t\tvar aSort = _fnSortFlatten( settings );\n\t\tvar oAria = settings.oLanguage.oAria;\n\t\n\t\t// ARIA attributes - need to loop all columns, to update all (removing old\n\t\t// attributes as needed)\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar col = columns[i];\n\t\t\tvar asSorting = col.asSorting;\n\t\t\tvar sTitle = col.sTitle.replace( /<.*?>/g, \"\" );\n\t\t\tvar th = col.nTh;\n\t\n\t\t\t// IE7 is throwing an error when setting these properties with jQuery's\n\t\t\t// attr() and removeAttr() methods...\n\t\t\tth.removeAttribute('aria-sort');\n\t\n\t\t\t/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */\n\t\t\tif ( col.bSortable ) {\n\t\t\t\tif ( aSort.length > 0 && aSort[0].col == i ) {\n\t\t\t\t\tth.setAttribute('aria-sort', aSort[0].dir==\"asc\" ? \"ascending\" : \"descending\" );\n\t\t\t\t\tnextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnextSort = asSorting[0];\n\t\t\t\t}\n\t\n\t\t\t\tlabel = sTitle + ( nextSort === \"asc\" ?\n\t\t\t\t\toAria.sSortAscending :\n\t\t\t\t\toAria.sSortDescending\n\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlabel = sTitle;\n\t\t\t}\n\t\n\t\t\tth.setAttribute('aria-label', label);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Function to run on user sort request\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {boolean} [append=false] Append the requested sort to the existing\n\t *    sort if true (i.e. multi-column sort)\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortListener ( settings, colIdx, append, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\tvar sorting = settings.aaSorting;\n\t\tvar asSorting = col.asSorting;\n\t\tvar nextSortIdx;\n\t\tvar next = function ( a, overflow ) {\n\t\t\tvar idx = a._idx;\n\t\t\tif ( idx === undefined ) {\n\t\t\t\tidx = $.inArray( a[1], asSorting );\n\t\t\t}\n\t\n\t\t\treturn idx+1 < asSorting.length ?\n\t\t\t\tidx+1 :\n\t\t\t\toverflow ?\n\t\t\t\t\tnull :\n\t\t\t\t\t0;\n\t\t};\n\t\n\t\t// Convert to 2D array if needed\n\t\tif ( typeof sorting[0] === 'number' ) {\n\t\t\tsorting = settings.aaSorting = [ sorting ];\n\t\t}\n\t\n\t\t// If appending the sort then we are multi-column sorting\n\t\tif ( append && settings.oFeatures.bSortMulti ) {\n\t\t\t// Are we already doing some kind of sort on this column?\n\t\t\tvar sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );\n\t\n\t\t\tif ( sortIdx !== -1 ) {\n\t\t\t\t// Yes, modify the sort\n\t\t\t\tnextSortIdx = next( sorting[sortIdx], true );\n\t\n\t\t\t\tif ( nextSortIdx === null && sorting.length === 1 ) {\n\t\t\t\t\tnextSortIdx = 0; // can't remove sorting completely\n\t\t\t\t}\n\t\n\t\t\t\tif ( nextSortIdx === null ) {\n\t\t\t\t\tsorting.splice( sortIdx, 1 );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tsorting[sortIdx][1] = asSorting[ nextSortIdx ];\n\t\t\t\t\tsorting[sortIdx]._idx = nextSortIdx;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// No sort on this column yet\n\t\t\t\tsorting.push( [ colIdx, asSorting[0], 0 ] );\n\t\t\t\tsorting[sorting.length-1]._idx = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( sorting.length && sorting[0][0] == colIdx ) {\n\t\t\t// Single column - already sorting on this column, modify the sort\n\t\t\tnextSortIdx = next( sorting[0] );\n\t\n\t\t\tsorting.length = 1;\n\t\t\tsorting[0][1] = asSorting[ nextSortIdx ];\n\t\t\tsorting[0]._idx = nextSortIdx;\n\t\t}\n\t\telse {\n\t\t\t// Single column - sort only on this column\n\t\t\tsorting.length = 0;\n\t\t\tsorting.push( [ colIdx, asSorting[0] ] );\n\t\t\tsorting[0]._idx = 0;\n\t\t}\n\t\n\t\t// Run the sort by calling a full redraw\n\t\t_fnReDraw( settings );\n\t\n\t\t// callback used for async user interaction\n\t\tif ( typeof callback == 'function' ) {\n\t\t\tcallback( settings );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Attach a sort handler (click) to a node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortAttachListener ( settings, attachTo, colIdx, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\n\t\t_fnBindAction( attachTo, {}, function (e) {\n\t\t\t/* If the column is not sortable - don't to anything */\n\t\t\tif ( col.bSortable === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If processing is enabled use a timeout to allow the processing\n\t\t\t// display to be shown - otherwise to it synchronously\n\t\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t\tsetTimeout( function() {\n\t\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\n\t\t\t\t\t// In server-side processing, the draw callback will remove the\n\t\t\t\t\t// processing display\n\t\t\t\t\tif ( _fnDataSource( settings ) !== 'ssp' ) {\n\t\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t}\n\t\t\t\t}, 0 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Set the sorting classes on table's body, Note: it is safe to call this function\n\t * when bSort and bSortClasses are false\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortingClasses( settings )\n\t{\n\t\tvar oldSort = settings.aLastSort;\n\t\tvar sortClass = settings.oClasses.sSortColumn;\n\t\tvar sort = _fnSortFlatten( settings );\n\t\tvar features = settings.oFeatures;\n\t\tvar i, ien, colIdx;\n\t\n\t\tif ( features.bSort && features.bSortClasses ) {\n\t\t\t// Remove old sorting classes\n\t\t\tfor ( i=0, ien=oldSort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = oldSort[i].src;\n\t\n\t\t\t\t// Remove column sorting\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.removeClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\n\t\t\t// Add new column sorting\n\t\t\tfor ( i=0, ien=sort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = sort[i].src;\n\t\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.addClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aLastSort = sort;\n\t}\n\t\n\t\n\t// Get the data to sort a column, be it from cache, fresh (populating the\n\t// cache), or from a sort formatter\n\tfunction _fnSortData( settings, idx )\n\t{\n\t\t// Custom sorting function - provided by the sort data type\n\t\tvar column = settings.aoColumns[ idx ];\n\t\tvar customSort = DataTable.ext.order[ column.sSortDataType ];\n\t\tvar customData;\n\t\n\t\tif ( customSort ) {\n\t\t\tcustomData = customSort.call( settings.oInstance, settings, idx,\n\t\t\t\t_fnColumnIndexToVisible( settings, idx )\n\t\t\t);\n\t\t}\n\t\n\t\t// Use / populate cache\n\t\tvar row, cellData;\n\t\tvar formatter = DataTable.ext.type.order[ column.sType+\"-pre\" ];\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aSortData ) {\n\t\t\t\trow._aSortData = [];\n\t\t\t}\n\t\n\t\t\tif ( ! row._aSortData[idx] || customSort ) {\n\t\t\t\tcellData = customSort ?\n\t\t\t\t\tcustomData[i] : // If there was a custom sort function, use data from there\n\t\t\t\t\t_fnGetCellData( settings, i, idx, 'sort' );\n\t\n\t\t\t\trow._aSortData[ idx ] = formatter ?\n\t\t\t\t\tformatter( cellData ) :\n\t\t\t\t\tcellData;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Save the state of a table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSaveState ( settings )\n\t{\n\t\tif ( !settings.oFeatures.bStateSave || settings.bDestroying )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Store the interesting variables */\n\t\tvar state = {\n\t\t\ttime:    +new Date(),\n\t\t\tstart:   settings._iDisplayStart,\n\t\t\tlength:  settings._iDisplayLength,\n\t\t\torder:   $.extend( true, [], settings.aaSorting ),\n\t\t\tsearch:  _fnSearchToCamel( settings.oPreviousSearch ),\n\t\t\tcolumns: $.map( settings.aoColumns, function ( col, i ) {\n\t\t\t\treturn {\n\t\t\t\t\tvisible: col.bVisible,\n\t\t\t\t\tsearch: _fnSearchToCamel( settings.aoPreSearchCols[i] )\n\t\t\t\t};\n\t\t\t} )\n\t\t};\n\t\n\t\t_fnCallbackFire( settings, \"aoStateSaveParams\", 'stateSaveParams', [settings, state] );\n\t\n\t\tsettings.oSavedState = state;\n\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, state );\n\t}\n\t\n\t\n\t/**\n\t * Attempt to load a saved table state\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oInit DataTables init object so we can override settings\n\t *  @param {function} callback Callback to execute when the state has been loaded\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLoadState ( settings, oInit, callback )\n\t{\n\t\tvar i, ien;\n\t\tvar columns = settings.aoColumns;\n\t\tvar loaded = function ( s ) {\n\t\t\tif ( ! s || ! s.time ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Allow custom and plug-in manipulation functions to alter the saved data set and\n\t\t\t// cancelling of loading by returning false\n\t\t\tvar abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );\n\t\t\tif ( $.inArray( false, abStateLoad ) !== -1 ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Reject old data\n\t\t\tvar duration = settings.iStateDuration;\n\t\t\tif ( duration > 0 && s.time < +new Date() - (duration*1000) ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Number of columns have changed - all bets are off, no restore of settings\n\t\t\tif ( s.columns && columns.length !== s.columns.length ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Store the saved state so it might be accessed at any time\n\t\t\tsettings.oLoadedState = $.extend( true, {}, state );\n\t\n\t\t\t// Restore key features - todo - for 1.11 this needs to be done by\n\t\t\t// subscribed events\n\t\t\tif ( s.start !== undefined ) {\n\t\t\t\tsettings._iDisplayStart    = s.start;\n\t\t\t\tsettings.iInitDisplayStart = s.start;\n\t\t\t}\n\t\t\tif ( s.length !== undefined ) {\n\t\t\t\tsettings._iDisplayLength   = s.length;\n\t\t\t}\n\t\n\t\t\t// Order\n\t\t\tif ( s.order !== undefined ) {\n\t\t\t\tsettings.aaSorting = [];\n\t\t\t\t$.each( s.order, function ( i, col ) {\n\t\t\t\t\tsettings.aaSorting.push( col[0] >= columns.length ?\n\t\t\t\t\t\t[ 0, col[1] ] :\n\t\t\t\t\t\tcol\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Search\n\t\t\tif ( s.search !== undefined ) {\n\t\t\t\t$.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );\n\t\t\t}\n\t\n\t\t\t// Columns\n\t\t\t// \n\t\t\tif ( s.columns ) {\n\t\t\t\tfor ( i=0, ien=s.columns.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar col = s.columns[i];\n\t\n\t\t\t\t\t// Visibility\n\t\t\t\t\tif ( col.visible !== undefined ) {\n\t\t\t\t\t\tcolumns[i].bVisible = col.visible;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Search\n\t\t\t\t\tif ( col.search !== undefined ) {\n\t\t\t\t\t\t$.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );\n\t\t\tcallback();\n\t\t}\n\t\n\t\tif ( ! settings.oFeatures.bStateSave ) {\n\t\t\tcallback();\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );\n\t\n\t\tif ( state !== undefined ) {\n\t\t\tloaded( state );\n\t\t}\n\t\t// otherwise, wait for the loaded callback to be executed\n\t}\n\t\n\t\n\t/**\n\t * Return the settings object for a particular table\n\t *  @param {node} table table we are using as a dataTable\n\t *  @returns {object} Settings object - or null if not found\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSettingsFromNode ( table )\n\t{\n\t\tvar settings = DataTable.settings;\n\t\tvar idx = $.inArray( table, _pluck( settings, 'nTable' ) );\n\t\n\t\treturn idx !== -1 ?\n\t\t\tsettings[ idx ] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Log an error message\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} level log error messages, or display them to the user\n\t *  @param {string} msg error message\n\t *  @param {int} tn Technical note id to get more information about the error.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLog( settings, level, msg, tn )\n\t{\n\t\tmsg = 'DataTables warning: '+\n\t\t\t(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;\n\t\n\t\tif ( tn ) {\n\t\t\tmsg += '. For more information about this error, please see '+\n\t\t\t'http://datatables.net/tn/'+tn;\n\t\t}\n\t\n\t\tif ( ! level  ) {\n\t\t\t// Backwards compatibility pre 1.10\n\t\t\tvar ext = DataTable.ext;\n\t\t\tvar type = ext.sErrMode || ext.errMode;\n\t\n\t\t\tif ( settings ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );\n\t\t\t}\n\t\n\t\t\tif ( type == 'alert' ) {\n\t\t\t\talert( msg );\n\t\t\t}\n\t\t\telse if ( type == 'throw' ) {\n\t\t\t\tthrow new Error(msg);\n\t\t\t}\n\t\t\telse if ( typeof type == 'function' ) {\n\t\t\t\ttype( settings, tn, msg );\n\t\t\t}\n\t\t}\n\t\telse if ( window.console && console.log ) {\n\t\t\tconsole.log( msg );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * See if a property is defined on one object, if so assign it to the other object\n\t *  @param {object} ret target object\n\t *  @param {object} src source object\n\t *  @param {string} name property\n\t *  @param {string} [mappedName] name to map too - optional, name used if not given\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnMap( ret, src, name, mappedName )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\t$.each( name, function (i, val) {\n\t\t\t\tif ( $.isArray( val ) ) {\n\t\t\t\t\t_fnMap( ret, src, val[0], val[1] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_fnMap( ret, src, val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( mappedName === undefined ) {\n\t\t\tmappedName = name;\n\t\t}\n\t\n\t\tif ( src[name] !== undefined ) {\n\t\t\tret[mappedName] = src[name];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Extend objects - very similar to jQuery.extend, but deep copy objects, and\n\t * shallow copy arrays. The reason we need to do this, is that we don't want to\n\t * deep copy array init values (such as aaSorting) since the dev wouldn't be\n\t * able to override them, but we do want to deep copy arrays.\n\t *  @param {object} out Object to extend\n\t *  @param {object} extender Object from which the properties will be applied to\n\t *      out\n\t *  @param {boolean} breakRefs If true, then arrays will be sliced to take an\n\t *      independent copy with the exception of the `data` or `aaData` parameters\n\t *      if they are present. This is so you can pass in a collection to\n\t *      DataTables and have that used as your data source without breaking the\n\t *      references\n\t *  @returns {object} out Reference, just for convenience - out === the return.\n\t *  @memberof DataTable#oApi\n\t *  @todo This doesn't take account of arrays inside the deep copied objects.\n\t */\n\tfunction _fnExtend( out, extender, breakRefs )\n\t{\n\t\tvar val;\n\t\n\t\tfor ( var prop in extender ) {\n\t\t\tif ( extender.hasOwnProperty(prop) ) {\n\t\t\t\tval = extender[prop];\n\t\n\t\t\t\tif ( $.isPlainObject( val ) ) {\n\t\t\t\t\tif ( ! $.isPlainObject( out[prop] ) ) {\n\t\t\t\t\t\tout[prop] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, out[prop], val );\n\t\t\t\t}\n\t\t\t\telse if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {\n\t\t\t\t\tout[prop] = val.slice();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tout[prop] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t}\n\t\n\t\n\t/**\n\t * Bind an event handers to allow a click or return key to activate the callback.\n\t * This is good for accessibility since a return on the keyboard will have the\n\t * same effect as a click, if the element has focus.\n\t *  @param {element} n Element to bind the action to\n\t *  @param {object} oData Data object to pass to the triggered function\n\t *  @param {function} fn Callback function for when the event is triggered\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBindAction( n, oData, fn )\n\t{\n\t\t$(n)\n\t\t\t.on( 'click.DT', oData, function (e) {\n\t\t\t\t\tn.blur(); // Remove focus outline for mouse users\n\t\t\t\t\tfn(e);\n\t\t\t\t} )\n\t\t\t.on( 'keypress.DT', oData, function (e){\n\t\t\t\t\tif ( e.which === 13 ) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tfn(e);\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t.on( 'selectstart.DT', function () {\n\t\t\t\t\t/* Take the brutal approach to cancelling text selection */\n\t\t\t\t\treturn false;\n\t\t\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Register a callback function. Easily allows a callback function to be added to\n\t * an array store of callback functions that can then all be called together.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sStore Name of the array storage for the callbacks in oSettings\n\t *  @param {function} fn Function to be called back\n\t *  @param {string} sName Identifying name for the callback (i.e. a label)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackReg( oSettings, sStore, fn, sName )\n\t{\n\t\tif ( fn )\n\t\t{\n\t\t\toSettings[sStore].push( {\n\t\t\t\t\"fn\": fn,\n\t\t\t\t\"sName\": sName\n\t\t\t} );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Fire callback functions and trigger events. Note that the loop over the\n\t * callback array store is done backwards! Further note that you do not want to\n\t * fire off triggers in time sensitive applications (for example cell creation)\n\t * as its slow.\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} callbackArr Name of the array storage for the callbacks in\n\t *      oSettings\n\t *  @param {string} eventName Name of the jQuery custom event to trigger. If\n\t *      null no trigger is fired\n\t *  @param {array} args Array of arguments to pass to the callback function /\n\t *      trigger\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackFire( settings, callbackArr, eventName, args )\n\t{\n\t\tvar ret = [];\n\t\n\t\tif ( callbackArr ) {\n\t\t\tret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {\n\t\t\t\treturn val.fn.apply( settings.oInstance, args );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( eventName !== null ) {\n\t\t\tvar e = $.Event( eventName+'.dt' );\n\t\n\t\t\t$(settings.nTable).trigger( e, args );\n\t\n\t\t\tret.push( e.result );\n\t\t}\n\t\n\t\treturn ret;\n\t}\n\t\n\t\n\tfunction _fnLengthOverflow ( settings )\n\t{\n\t\tvar\n\t\t\tstart = settings._iDisplayStart,\n\t\t\tend = settings.fnDisplayEnd(),\n\t\t\tlen = settings._iDisplayLength;\n\t\n\t\t/* If we have space to show extra rows (backing up from the end point - then do so */\n\t\tif ( start >= end )\n\t\t{\n\t\t\tstart = end - len;\n\t\t}\n\t\n\t\t// Keep the start record on the current page\n\t\tstart -= (start % len);\n\t\n\t\tif ( len === -1 || start < 0 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\n\t\tsettings._iDisplayStart = start;\n\t}\n\t\n\t\n\tfunction _fnRenderer( settings, type )\n\t{\n\t\tvar renderer = settings.renderer;\n\t\tvar host = DataTable.ext.renderer[type];\n\t\n\t\tif ( $.isPlainObject( renderer ) && renderer[type] ) {\n\t\t\t// Specific renderer for this type. If available use it, otherwise use\n\t\t\t// the default.\n\t\t\treturn host[renderer[type]] || host._;\n\t\t}\n\t\telse if ( typeof renderer === 'string' ) {\n\t\t\t// Common renderer - if there is one available for this type use it,\n\t\t\t// otherwise use the default\n\t\t\treturn host[renderer] || host._;\n\t\t}\n\t\n\t\t// Use the default\n\t\treturn host._;\n\t}\n\t\n\t\n\t/**\n\t * Detect the data source being used for the table. Used to simplify the code\n\t * a little (ajax) and to make it compress a little smaller.\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {string} Data source\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDataSource ( settings )\n\t{\n\t\tif ( settings.oFeatures.bServerSide ) {\n\t\t\treturn 'ssp';\n\t\t}\n\t\telse if ( settings.ajax || settings.sAjaxSource ) {\n\t\t\treturn 'ajax';\n\t\t}\n\t\treturn 'dom';\n\t}\n\t\n\n\t\n\t\n\t/**\n\t * Computed structure of the DataTables API, defined by the options passed to\n\t * `DataTable.Api.register()` when building the API.\n\t *\n\t * The structure is built in order to speed creation and extension of the Api\n\t * objects since the extensions are effectively pre-parsed.\n\t *\n\t * The array is an array of objects with the following structure, where this\n\t * base array represents the Api prototype base:\n\t *\n\t *     [\n\t *       {\n\t *         name:      'data'                -- string   - Property name\n\t *         val:       function () {},       -- function - Api method (or undefined if just an object\n\t *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t *       },\n\t *       {\n\t *         name:     'row'\n\t *         val:       {},\n\t *         methodExt: [ ... ],\n\t *         propExt:   [\n\t *           {\n\t *             name:      'data'\n\t *             val:       function () {},\n\t *             methodExt: [ ... ],\n\t *             propExt:   [ ... ]\n\t *           },\n\t *           ...\n\t *         ]\n\t *       }\n\t *     ]\n\t *\n\t * @type {Array}\n\t * @ignore\n\t */\n\tvar __apiStruct = [];\n\t\n\t\n\t/**\n\t * `Array.prototype` reference.\n\t *\n\t * @type object\n\t * @ignore\n\t */\n\tvar __arrayProto = Array.prototype;\n\t\n\t\n\t/**\n\t * Abstraction for `context` parameter of the `Api` constructor to allow it to\n\t * take several different forms for ease of use.\n\t *\n\t * Each of the input parameter types will be converted to a DataTables settings\n\t * object where possible.\n\t *\n\t * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one\n\t *   of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t *   * `DataTables.Api` - API instance\n\t * @return {array|null} Matching DataTables settings objects. `null` or\n\t *   `undefined` is returned if no matching DataTable is found.\n\t * @ignore\n\t */\n\tvar _toSettings = function ( mixed )\n\t{\n\t\tvar idx, jq;\n\t\tvar settings = DataTable.settings;\n\t\tvar tables = $.map( settings, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\tif ( ! mixed ) {\n\t\t\treturn [];\n\t\t}\n\t\telse if ( mixed.nTable && mixed.oApi ) {\n\t\t\t// DataTables settings object\n\t\t\treturn [ mixed ];\n\t\t}\n\t\telse if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {\n\t\t\t// Table node\n\t\t\tidx = $.inArray( mixed, tables );\n\t\t\treturn idx !== -1 ? [ settings[idx] ] : null;\n\t\t}\n\t\telse if ( mixed && typeof mixed.settings === 'function' ) {\n\t\t\treturn mixed.settings().toArray();\n\t\t}\n\t\telse if ( typeof mixed === 'string' ) {\n\t\t\t// jQuery selector\n\t\t\tjq = $(mixed);\n\t\t}\n\t\telse if ( mixed instanceof $ ) {\n\t\t\t// jQuery object (also DataTables instance)\n\t\t\tjq = mixed;\n\t\t}\n\t\n\t\tif ( jq ) {\n\t\t\treturn jq.map( function(i) {\n\t\t\t\tidx = $.inArray( this, tables );\n\t\t\t\treturn idx !== -1 ? settings[idx] : null;\n\t\t\t} ).toArray();\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * DataTables API class - used to control and interface with  one or more\n\t * DataTables enhanced tables.\n\t *\n\t * The API class is heavily based on jQuery, presenting a chainable interface\n\t * that you can use to interact with tables. Each instance of the API class has\n\t * a \"context\" - i.e. the tables that it will operate on. This could be a single\n\t * table, all tables on a page or a sub-set thereof.\n\t *\n\t * Additionally the API is designed to allow you to easily work with the data in\n\t * the tables, retrieving and manipulating it as required. This is done by\n\t * presenting the API class as an array like interface. The contents of the\n\t * array depend upon the actions requested by each method (for example\n\t * `rows().nodes()` will return an array of nodes, while `rows().data()` will\n\t * return an array of objects or arrays depending upon your table's\n\t * configuration). The API object has a number of array like methods (`push`,\n\t * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,\n\t * `unique` etc) to assist your working with the data held in a table.\n\t *\n\t * Most methods (those which return an Api instance) are chainable, which means\n\t * the return from a method call also has all of the methods available that the\n\t * top level object had. For example, these two calls are equivalent:\n\t *\n\t *     // Not chained\n\t *     api.row.add( {...} );\n\t *     api.draw();\n\t *\n\t *     // Chained\n\t *     api.row.add( {...} ).draw();\n\t *\n\t * @class DataTable.Api\n\t * @param {array|object|string|jQuery} context DataTable identifier. This is\n\t *   used to define which DataTables enhanced tables this API will operate on.\n\t *   Can be one of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t * @param {array} [data] Data to initialise the Api instance with.\n\t *\n\t * @example\n\t *   // Direct initialisation during DataTables construction\n\t *   var api = $('#example').DataTable();\n\t *\n\t * @example\n\t *   // Initialisation using a DataTables jQuery object\n\t *   var api = $('#example').dataTable().api();\n\t *\n\t * @example\n\t *   // Initialisation as a constructor\n\t *   var api = new $.fn.DataTable.Api( 'table.dataTable' );\n\t */\n\t_Api = function ( context, data )\n\t{\n\t\tif ( ! (this instanceof _Api) ) {\n\t\t\treturn new _Api( context, data );\n\t\t}\n\t\n\t\tvar settings = [];\n\t\tvar ctxSettings = function ( o ) {\n\t\t\tvar a = _toSettings( o );\n\t\t\tif ( a ) {\n\t\t\t\tsettings = settings.concat( a );\n\t\t\t}\n\t\t};\n\t\n\t\tif ( $.isArray( context ) ) {\n\t\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tctxSettings( context[i] );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tctxSettings( context );\n\t\t}\n\t\n\t\t// Remove duplicates\n\t\tthis.context = _unique( settings );\n\t\n\t\t// Initial data\n\t\tif ( data ) {\n\t\t\t$.merge( this, data );\n\t\t}\n\t\n\t\t// selector\n\t\tthis.selector = {\n\t\t\trows: null,\n\t\t\tcols: null,\n\t\t\topts: null\n\t\t};\n\t\n\t\t_Api.extend( this, this, __apiStruct );\n\t};\n\t\n\tDataTable.Api = _Api;\n\t\n\t// Don't destroy the existing prototype, just extend it. Required for jQuery 2's\n\t// isPlainObject.\n\t$.extend( _Api.prototype, {\n\t\tany: function ()\n\t\t{\n\t\t\treturn this.count() !== 0;\n\t\t},\n\t\n\t\n\t\tconcat:  __arrayProto.concat,\n\t\n\t\n\t\tcontext: [], // array of table settings objects\n\t\n\t\n\t\tcount: function ()\n\t\t{\n\t\t\treturn this.flatten().length;\n\t\t},\n\t\n\t\n\t\teach: function ( fn )\n\t\t{\n\t\t\tfor ( var i=0, ien=this.length ; i<ien; i++ ) {\n\t\t\t\tfn.call( this, this[i], i, this );\n\t\t\t}\n\t\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\teq: function ( idx )\n\t\t{\n\t\t\tvar ctx = this.context;\n\t\n\t\t\treturn ctx.length > idx ?\n\t\t\t\tnew _Api( ctx[idx], this[idx] ) :\n\t\t\t\tnull;\n\t\t},\n\t\n\t\n\t\tfilter: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.filter ) {\n\t\t\t\ta = __arrayProto.filter.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( fn.call( this, this[i], i, this ) ) {\n\t\t\t\t\t\ta.push( this[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tflatten: function ()\n\t\t{\n\t\t\tvar a = [];\n\t\t\treturn new _Api( this.context, a.concat.apply( a, this.toArray() ) );\n\t\t},\n\t\n\t\n\t\tjoin:    __arrayProto.join,\n\t\n\t\n\t\tindexOf: __arrayProto.indexOf || function (obj, start)\n\t\t{\n\t\t\tfor ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {\n\t\t\t\tif ( this[i] === obj ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1;\n\t\t},\n\t\n\t\titerator: function ( flatten, type, fn, alwaysNew ) {\n\t\t\tvar\n\t\t\t\ta = [], ret,\n\t\t\t\ti, ien, j, jen,\n\t\t\t\tcontext = this.context,\n\t\t\t\trows, items, item,\n\t\t\t\tselector = this.selector;\n\t\n\t\t\t// Argument shifting\n\t\t\tif ( typeof flatten === 'string' ) {\n\t\t\t\talwaysNew = fn;\n\t\t\t\tfn = type;\n\t\t\t\ttype = flatten;\n\t\t\t\tflatten = false;\n\t\t\t}\n\t\n\t\t\tfor ( i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tvar apiInst = new _Api( context[i] );\n\t\n\t\t\t\tif ( type === 'table' ) {\n\t\t\t\t\tret = fn.call( apiInst, context[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'columns' || type === 'rows' ) {\n\t\t\t\t\t// this has same length as context - one entry for each table\n\t\t\t\t\tret = fn.call( apiInst, context[i], this[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {\n\t\t\t\t\t// columns and rows share the same structure.\n\t\t\t\t\t// 'this' is an array of column indexes for each context\n\t\t\t\t\titems = this[i];\n\t\n\t\t\t\t\tif ( type === 'column-rows' ) {\n\t\t\t\t\t\trows = _selector_row_indexes( context[i], selector.opts );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfor ( j=0, jen=items.length ; j<jen ; j++ ) {\n\t\t\t\t\t\titem = items[j];\n\t\n\t\t\t\t\t\tif ( type === 'cell' ) {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item.row, item.column, i, j );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item, i, j, rows );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( a.length || alwaysNew ) {\n\t\t\t\tvar api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );\n\t\t\t\tvar apiSelector = api.selector;\n\t\t\t\tapiSelector.rows = selector.rows;\n\t\t\t\tapiSelector.cols = selector.cols;\n\t\t\t\tapiSelector.opts = selector.opts;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\tlastIndexOf: __arrayProto.lastIndexOf || function (obj, start)\n\t\t{\n\t\t\t// Bit cheeky...\n\t\t\treturn this.indexOf.apply( this.toArray.reverse(), arguments );\n\t\t},\n\t\n\t\n\t\tlength:  0,\n\t\n\t\n\t\tmap: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.map ) {\n\t\t\t\ta = __arrayProto.map.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\ta.push( fn.call( this, this[i], i ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tpluck: function ( prop )\n\t\t{\n\t\t\treturn this.map( function ( el ) {\n\t\t\t\treturn el[ prop ];\n\t\t\t} );\n\t\t},\n\t\n\t\tpop:     __arrayProto.pop,\n\t\n\t\n\t\tpush:    __arrayProto.push,\n\t\n\t\n\t\t// Does not return an API instance\n\t\treduce: __arrayProto.reduce || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, 0, this.length, 1 );\n\t\t},\n\t\n\t\n\t\treduceRight: __arrayProto.reduceRight || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, this.length-1, -1, -1 );\n\t\t},\n\t\n\t\n\t\treverse: __arrayProto.reverse,\n\t\n\t\n\t\t// Object with rows, columns and opts\n\t\tselector: null,\n\t\n\t\n\t\tshift:   __arrayProto.shift,\n\t\n\t\n\t\tsort:    __arrayProto.sort, // ? name - order?\n\t\n\t\n\t\tsplice:  __arrayProto.splice,\n\t\n\t\n\t\ttoArray: function ()\n\t\t{\n\t\t\treturn __arrayProto.slice.call( this );\n\t\t},\n\t\n\t\n\t\tto$: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\ttoJQuery: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\tunique: function ()\n\t\t{\n\t\t\treturn new _Api( this.context, _unique(this) );\n\t\t},\n\t\n\t\n\t\tunshift: __arrayProto.unshift\n\t} );\n\t\n\t\n\t_Api.extend = function ( scope, obj, ext )\n\t{\n\t\t// Only extend API instances and static properties of the API\n\t\tif ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\tj, jen,\n\t\t\tstruct, inner,\n\t\t\tmethodScoping = function ( scope, fn, struc ) {\n\t\t\t\treturn function () {\n\t\t\t\t\tvar ret = fn.apply( scope, arguments );\n\t\n\t\t\t\t\t// Method extension\n\t\t\t\t\t_Api.extend( ret, ret, struc.methodExt );\n\t\t\t\t\treturn ret;\n\t\t\t\t};\n\t\t\t};\n\t\n\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\tstruct = ext[i];\n\t\n\t\t\t// Value\n\t\t\tobj[ struct.name ] = typeof struct.val === 'function' ?\n\t\t\t\tmethodScoping( scope, struct.val, struct ) :\n\t\t\t\t$.isPlainObject( struct.val ) ?\n\t\t\t\t\t{} :\n\t\t\t\t\tstruct.val;\n\t\n\t\t\tobj[ struct.name ].__dt_wrapper = true;\n\t\n\t\t\t// Property extension\n\t\t\t_Api.extend( scope, obj[ struct.name ], struct.propExt );\n\t\t}\n\t};\n\t\n\t\n\t// @todo - Is there need for an augment function?\n\t// _Api.augment = function ( inst, name )\n\t// {\n\t// \t// Find src object in the structure from the name\n\t// \tvar parts = name.split('.');\n\t\n\t// \t_Api.extend( inst, obj );\n\t// };\n\t\n\t\n\t//     [\n\t//       {\n\t//         name:      'data'                -- string   - Property name\n\t//         val:       function () {},       -- function - Api method (or undefined if just an object\n\t//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t//       },\n\t//       {\n\t//         name:     'row'\n\t//         val:       {},\n\t//         methodExt: [ ... ],\n\t//         propExt:   [\n\t//           {\n\t//             name:      'data'\n\t//             val:       function () {},\n\t//             methodExt: [ ... ],\n\t//             propExt:   [ ... ]\n\t//           },\n\t//           ...\n\t//         ]\n\t//       }\n\t//     ]\n\t\n\t_Api.register = _api_register = function ( name, val )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\tfor ( var j=0, jen=name.length ; j<jen ; j++ ) {\n\t\t\t\t_Api.register( name[j], val );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\their = name.split('.'),\n\t\t\tstruct = __apiStruct,\n\t\t\tkey, method;\n\t\n\t\tvar find = function ( src, name ) {\n\t\t\tfor ( var i=0, ien=src.length ; i<ien ; i++ ) {\n\t\t\t\tif ( src[i].name === name ) {\n\t\t\t\t\treturn src[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\n\t\tfor ( i=0, ien=heir.length ; i<ien ; i++ ) {\n\t\t\tmethod = heir[i].indexOf('()') !== -1;\n\t\t\tkey = method ?\n\t\t\t\their[i].replace('()', '') :\n\t\t\t\their[i];\n\t\n\t\t\tvar src = find( struct, key );\n\t\t\tif ( ! src ) {\n\t\t\t\tsrc = {\n\t\t\t\t\tname:      key,\n\t\t\t\t\tval:       {},\n\t\t\t\t\tmethodExt: [],\n\t\t\t\t\tpropExt:   []\n\t\t\t\t};\n\t\t\t\tstruct.push( src );\n\t\t\t}\n\t\n\t\t\tif ( i === ien-1 ) {\n\t\t\t\tsrc.val = val;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstruct = method ?\n\t\t\t\t\tsrc.methodExt :\n\t\t\t\t\tsrc.propExt;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\t_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {\n\t\t_Api.register( pluralName, val );\n\t\n\t\t_Api.register( singularName, function () {\n\t\t\tvar ret = val.apply( this, arguments );\n\t\n\t\t\tif ( ret === this ) {\n\t\t\t\t// Returned item is the API instance that was passed in, return it\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\telse if ( ret instanceof _Api ) {\n\t\t\t\t// New API instance returned, want the value from the first item\n\t\t\t\t// in the returned array for the singular result.\n\t\t\t\treturn ret.length ?\n\t\t\t\t\t$.isArray( ret[0] ) ?\n\t\t\t\t\t\tnew _Api( ret.context, ret[0] ) : // Array results are 'enhanced'\n\t\t\t\t\t\tret[0] :\n\t\t\t\t\tundefined;\n\t\t\t}\n\t\n\t\t\t// Non-API return - just fire it back\n\t\t\treturn ret;\n\t\t} );\n\t};\n\t\n\t\n\t/**\n\t * Selector for HTML tables. Apply the given selector to the give array of\n\t * DataTables settings objects.\n\t *\n\t * @param {string|integer} [selector] jQuery selector string or integer\n\t * @param  {array} Array of DataTables settings objects to be filtered\n\t * @return {array}\n\t * @ignore\n\t */\n\tvar __table_selector = function ( selector, a )\n\t{\n\t\t// Integer is used to pick out a table by index\n\t\tif ( typeof selector === 'number' ) {\n\t\t\treturn [ a[ selector ] ];\n\t\t}\n\t\n\t\t// Perform a jQuery selector on the table nodes\n\t\tvar nodes = $.map( a, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\treturn $(nodes)\n\t\t\t.filter( selector )\n\t\t\t.map( function (i) {\n\t\t\t\t// Need to translate back from the table node to the settings\n\t\t\t\tvar idx = $.inArray( this, nodes );\n\t\t\t\treturn a[ idx ];\n\t\t\t} )\n\t\t\t.toArray();\n\t};\n\t\n\t\n\t\n\t/**\n\t * Context selector for the API's context (i.e. the tables the API instance\n\t * refers to.\n\t *\n\t * @name    DataTable.Api#tables\n\t * @param {string|integer} [selector] Selector to pick which tables the iterator\n\t *   should operate on. If not given, all tables in the current context are\n\t *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to\n\t *   select multiple tables or as an integer to select a single table.\n\t * @returns {DataTable.Api} Returns a new API instance if a selector is given.\n\t */\n\t_api_register( 'tables()', function ( selector ) {\n\t\t// A new instance is created if there was a selector specified\n\t\treturn selector ?\n\t\t\tnew _Api( __table_selector( selector, this.context ) ) :\n\t\t\tthis;\n\t} );\n\t\n\t\n\t_api_register( 'table()', function ( selector ) {\n\t\tvar tables = this.tables( selector );\n\t\tvar ctx = tables.context;\n\t\n\t\t// Truncate to the first matched table\n\t\treturn ctx.length ?\n\t\t\tnew _Api( ctx[0] ) :\n\t\t\ttables;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTable;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().body()', 'table().body()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTBody;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().header()', 'table().header()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTHead;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTFoot;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().containers()', 'table().container()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTableWrapper;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Redraw the tables in the current context.\n\t */\n\t_api_register( 'draw()', function ( paging ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( paging === 'page' ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ( typeof paging === 'string' ) {\n\t\t\t\t\tpaging = paging === 'full-hold' ?\n\t\t\t\t\t\tfalse :\n\t\t\t\t\t\ttrue;\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, paging===false );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get the current page index.\n\t *\n\t * @return {integer} Current page index (zero based)\n\t *//**\n\t * Set the current page.\n\t *\n\t * Note that if you attempt to show a page which does not exist, DataTables will\n\t * not throw an error, but rather reset the paging.\n\t *\n\t * @param {integer|string} action The paging action to take. This can be one of:\n\t *  * `integer` - The page index to jump to\n\t *  * `string` - An action to take:\n\t *    * `first` - Jump to first page.\n\t *    * `next` - Jump to the next page\n\t *    * `previous` - Jump to previous page\n\t *    * `last` - Jump to the last page.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page()', function ( action ) {\n\t\tif ( action === undefined ) {\n\t\t\treturn this.page.info().page; // not an expensive call\n\t\t}\n\t\n\t\t// else, have an action to take on all tables\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnPageChange( settings, action );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Paging information for the first table in the current context.\n\t *\n\t * If you require paging information for another table, use the `table()` method\n\t * with a suitable selector.\n\t *\n\t * @return {object} Object with the following properties set:\n\t *  * `page` - Current page index (zero based - i.e. the first page is `0`)\n\t *  * `pages` - Total number of pages\n\t *  * `start` - Display index for the first record shown on the current page\n\t *  * `end` - Display index for the last record shown on the current page\n\t *  * `length` - Display length (number of records). Note that generally `start\n\t *    + length = end`, but this is not always true, for example if there are\n\t *    only 2 records to show on the final page, with a length of 10.\n\t *  * `recordsTotal` - Full data set length\n\t *  * `recordsDisplay` - Data set length once the current filtering criterion\n\t *    are applied.\n\t */\n\t_api_register( 'page.info()', function ( action ) {\n\t\tif ( this.context.length === 0 ) {\n\t\t\treturn undefined;\n\t\t}\n\t\n\t\tvar\n\t\t\tsettings   = this.context[0],\n\t\t\tstart      = settings._iDisplayStart,\n\t\t\tlen        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,\n\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn {\n\t\t\t\"page\":           all ? 0 : Math.floor( start / len ),\n\t\t\t\"pages\":          all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\"start\":          start,\n\t\t\t\"end\":            settings.fnDisplayEnd(),\n\t\t\t\"length\":         len,\n\t\t\t\"recordsTotal\":   settings.fnRecordsTotal(),\n\t\t\t\"recordsDisplay\": visRecords,\n\t\t\t\"serverSide\":     _fnDataSource( settings ) === 'ssp'\n\t\t};\n\t} );\n\t\n\t\n\t/**\n\t * Get the current page length.\n\t *\n\t * @return {integer} Current page length. Note `-1` indicates that all records\n\t *   are to be shown.\n\t *//**\n\t * Set the current page length.\n\t *\n\t * @param {integer} Page length to set. Use `-1` to show all records.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page.len()', function ( len ) {\n\t\t// Note that we can't call this function 'length()' because `length`\n\t\t// is a Javascript property of functions which defines how many arguments\n\t\t// the function expects.\n\t\tif ( len === undefined ) {\n\t\t\treturn this.context.length !== 0 ?\n\t\t\t\tthis.context[0]._iDisplayLength :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// else, set the page length\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnLengthChange( settings, len );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\tvar __reload = function ( settings, holdPosition, callback ) {\n\t\t// Use the draw event to trigger a callback\n\t\tif ( callback ) {\n\t\t\tvar api = new _Api( settings );\n\t\n\t\t\tapi.one( 'draw', function () {\n\t\t\t\tcallback( api.ajax.json() );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t_fnReDraw( settings, holdPosition );\n\t\t}\n\t\telse {\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t// Cancel an existing request\n\t\t\tvar xhr = settings.jqXHR;\n\t\t\tif ( xhr && xhr.readyState !== 4 ) {\n\t\t\t\txhr.abort();\n\t\t\t}\n\t\n\t\t\t// Trigger xhr\n\t\t\t_fnBuildAjax( settings, [], function( json ) {\n\t\t\t\t_fnClearTable( settings );\n\t\n\t\t\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\t_fnAddData( settings, data[i] );\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, holdPosition );\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Get the JSON response from the last Ajax request that DataTables made to the\n\t * server. Note that this returns the JSON from the first table in the current\n\t * context.\n\t *\n\t * @return {object} JSON received from the server.\n\t */\n\t_api_register( 'ajax.json()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].json;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Get the data submitted in the last Ajax request\n\t */\n\t_api_register( 'ajax.params()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].oAjaxData;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Reload tables from the Ajax data source. Note that this function will\n\t * automatically re-draw the table when the remote data has been loaded.\n\t *\n\t * @param {boolean} [reset=true] Reset (default) or hold the current paging\n\t *   position. A full re-sort and re-filter is performed when this method is\n\t *   called, which is why the pagination reset is the default action.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.reload()', function ( callback, resetPaging ) {\n\t\treturn this.iterator( 'table', function (settings) {\n\t\t\t__reload( settings, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Get the current Ajax URL. Note that this returns the URL from the first\n\t * table in the current context.\n\t *\n\t * @return {string} Current Ajax source URL\n\t *//**\n\t * Set the Ajax URL. Note that this will set the URL for all tables in the\n\t * current context.\n\t *\n\t * @param {string} url URL to set.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url()', function ( url ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( url === undefined ) {\n\t\t\t// get\n\t\t\tif ( ctx.length === 0 ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tctx = ctx[0];\n\t\n\t\t\treturn ctx.ajax ?\n\t\t\t\t$.isPlainObject( ctx.ajax ) ?\n\t\t\t\t\tctx.ajax.url :\n\t\t\t\t\tctx.ajax :\n\t\t\t\tctx.sAjaxSource;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( $.isPlainObject( settings.ajax ) ) {\n\t\t\t\tsettings.ajax.url = url;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsettings.ajax = url;\n\t\t\t}\n\t\t\t// No need to consider sAjaxSource here since DataTables gives priority\n\t\t\t// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any\n\t\t\t// value of `sAjaxSource` redundant.\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Load data from the newly set Ajax URL. Note that this method is only\n\t * available when `ajax.url()` is used to set a URL. Additionally, this method\n\t * has the same effect as calling `ajax.reload()` but is provided for\n\t * convenience when setting a new URL. Like `ajax.reload()` it will\n\t * automatically redraw the table once the remote data has been loaded.\n\t *\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {\n\t\t// Same as a reload, but makes sense to present it for easy access after a\n\t\t// url change\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\t__reload( ctx, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t\n\tvar _selector_run = function ( type, selector, selectFn, settings, opts )\n\t{\n\t\tvar\n\t\t\tout = [], res,\n\t\t\ta, i, ien, j, jen,\n\t\t\tselectorType = typeof selector;\n\t\n\t\t// Can't just check for isArray here, as an API or jQuery instance might be\n\t\t// given with their array like look\n\t\tif ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {\n\t\t\tselector = [ selector ];\n\t\t}\n\t\n\t\tfor ( i=0, ien=selector.length ; i<ien ; i++ ) {\n\t\t\t// Only split on simple strings - complex expressions will be jQuery selectors\n\t\t\ta = selector[i] && selector[i].split && ! selector[i].match(/[\\[\\(:]/) ?\n\t\t\t\tselector[i].split(',') :\n\t\t\t\t[ selector[i] ];\n\t\n\t\t\tfor ( j=0, jen=a.length ; j<jen ; j++ ) {\n\t\t\t\tres = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );\n\t\n\t\t\t\tif ( res && res.length ) {\n\t\t\t\t\tout = out.concat( res );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// selector extensions\n\t\tvar ext = _ext.selector[ type ];\n\t\tif ( ext.length ) {\n\t\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\t\tout = ext[i]( settings, opts, out );\n\t\t\t}\n\t\t}\n\t\n\t\treturn _unique( out );\n\t};\n\t\n\t\n\tvar _selector_opts = function ( opts )\n\t{\n\t\tif ( ! opts ) {\n\t\t\topts = {};\n\t\t}\n\t\n\t\t// Backwards compatibility for 1.9- which used the terminology filter rather\n\t\t// than search\n\t\tif ( opts.filter && opts.search === undefined ) {\n\t\t\topts.search = opts.filter;\n\t\t}\n\t\n\t\treturn $.extend( {\n\t\t\tsearch: 'none',\n\t\t\torder: 'current',\n\t\t\tpage: 'all'\n\t\t}, opts );\n\t};\n\t\n\t\n\tvar _selector_first = function ( inst )\n\t{\n\t\t// Reduce the API instance to the first item found\n\t\tfor ( var i=0, ien=inst.length ; i<ien ; i++ ) {\n\t\t\tif ( inst[i].length > 0 ) {\n\t\t\t\t// Assign the first element to the first item in the instance\n\t\t\t\t// and truncate the instance and context\n\t\t\t\tinst[0] = inst[i];\n\t\t\t\tinst[0].length = 1;\n\t\t\t\tinst.length = 1;\n\t\t\t\tinst.context = [ inst.context[i] ];\n\t\n\t\t\t\treturn inst;\n\t\t\t}\n\t\t}\n\t\n\t\t// Not found - return an empty instance\n\t\tinst.length = 0;\n\t\treturn inst;\n\t};\n\t\n\t\n\tvar _selector_row_indexes = function ( settings, opts )\n\t{\n\t\tvar\n\t\t\ti, ien, tmp, a=[],\n\t\t\tdisplayFiltered = settings.aiDisplay,\n\t\t\tdisplayMaster = settings.aiDisplayMaster;\n\t\n\t\tvar\n\t\t\tsearch = opts.search,  // none, applied, removed\n\t\t\torder  = opts.order,   // applied, current, index (original - compatibility with 1.9)\n\t\t\tpage   = opts.page;    // all, current\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t// In server-side processing mode, most options are irrelevant since\n\t\t\t// rows not shown don't exist and the index order is the applied order\n\t\t\t// Removed is a special case - for consistency just return an empty\n\t\t\t// array\n\t\t\treturn search === 'removed' ?\n\t\t\t\t[] :\n\t\t\t\t_range( 0, displayMaster.length );\n\t\t}\n\t\telse if ( page == 'current' ) {\n\t\t\t// Current page implies that order=current and fitler=applied, since it is\n\t\t\t// fairly senseless otherwise, regardless of what order and search actually\n\t\t\t// are\n\t\t\tfor ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {\n\t\t\t\ta.push( displayFiltered[i] );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'current' || order == 'applied' ) {\n\t\t\ta = search == 'none' ?\n\t\t\t\tdisplayMaster.slice() :                      // no search\n\t\t\t\tsearch == 'applied' ?\n\t\t\t\t\tdisplayFiltered.slice() :                // applied search\n\t\t\t\t\t$.map( displayMaster, function (el, i) { // removed search\n\t\t\t\t\t\treturn $.inArray( el, displayFiltered ) === -1 ? el : null;\n\t\t\t\t\t} );\n\t\t}\n\t\telse if ( order == 'index' || order == 'original' ) {\n\t\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tif ( search == 'none' ) {\n\t\t\t\t\ta.push( i );\n\t\t\t\t}\n\t\t\t\telse { // applied | removed\n\t\t\t\t\ttmp = $.inArray( i, displayFiltered );\n\t\n\t\t\t\t\tif ((tmp === -1 && search == 'removed') ||\n\t\t\t\t\t\t(tmp >= 0   && search == 'applied') )\n\t\t\t\t\t{\n\t\t\t\t\t\ta.push( i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn a;\n\t};\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Rows\n\t *\n\t * {}          - no selector - use all available rows\n\t * {integer}   - row aoData index\n\t * {node}      - TR node\n\t * {string}    - jQuery selector to apply to the TR elements\n\t * {array}     - jQuery array of nodes, or simply an array of TR nodes\n\t *\n\t */\n\t\n\t\n\tvar __row_selector = function ( settings, selector, opts )\n\t{\n\t\tvar rows;\n\t\tvar run = function ( sel ) {\n\t\t\tvar selInt = _intVal( sel );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Short cut - selector is a number and no options provided (default is\n\t\t\t// all records, so no need to check if the index is in there, since it\n\t\t\t// must be - dev error if the index doesn't exist).\n\t\t\tif ( selInt !== null && ! opts ) {\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\n\t\t\tif ( ! rows ) {\n\t\t\t\trows = _selector_row_indexes( settings, opts );\n\t\t\t}\n\t\n\t\t\tif ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {\n\t\t\t\t// Selector - integer\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\t\telse if ( sel === null || sel === undefined || sel === '' ) {\n\t\t\t\t// Selector - none\n\t\t\t\treturn rows;\n\t\t\t}\n\t\n\t\t\t// Selector - function\n\t\t\tif ( typeof sel === 'function' ) {\n\t\t\t\treturn $.map( rows, function (idx) {\n\t\t\t\t\tvar row = settings.aoData[ idx ];\n\t\t\t\t\treturn sel( idx, row._aData, row.nTr ) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Get nodes in the order from the `rows` array with null values removed\n\t\t\tvar nodes = _removeEmpty(\n\t\t\t\t_pluck_order( settings.aoData, rows, 'nTr' )\n\t\t\t);\n\t\n\t\t\t// Selector - node\n\t\t\tif ( sel.nodeName ) {\n\t\t\t\tif ( sel._DT_RowIndex !== undefined ) {\n\t\t\t\t\treturn [ sel._DT_RowIndex ]; // Property added by DT for fast lookup\n\t\t\t\t}\n\t\t\t\telse if ( sel._DT_CellIndex ) {\n\t\t\t\t\treturn [ sel._DT_CellIndex.row ];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tvar host = $(sel).closest('*[data-dt-row]');\n\t\t\t\t\treturn host.length ?\n\t\t\t\t\t\t[ host.data('dt-row') ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// ID selector. Want to always be able to select rows by id, regardless\n\t\t\t// of if the tr element has been created or not, so can't rely upon\n\t\t\t// jQuery here - hence a custom implementation. This does not match\n\t\t\t// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,\n\t\t\t// but to select it using a CSS selector engine (like Sizzle or\n\t\t\t// querySelect) it would need to need to be escaped for some characters.\n\t\t\t// DataTables simplifies this for row selectors since you can select\n\t\t\t// only a row. A # indicates an id any anything that follows is the id -\n\t\t\t// unescaped.\n\t\t\tif ( typeof sel === 'string' && sel.charAt(0) === '#' ) {\n\t\t\t\t// get row index from id\n\t\t\t\tvar rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];\n\t\t\t\tif ( rowObj !== undefined ) {\n\t\t\t\t\treturn [ rowObj.idx ];\n\t\t\t\t}\n\t\n\t\t\t\t// need to fall through to jQuery in case there is DOM id that\n\t\t\t\t// matches\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery selector string, array of nodes or jQuery object/\n\t\t\t// As jQuery's .filter() allows jQuery objects to be passed in filter,\n\t\t\t// it also allows arrays, so this will cope with all three options\n\t\t\treturn $(nodes)\n\t\t\t\t.filter( sel )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn this._DT_RowIndex;\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\t};\n\t\n\t\treturn _selector_run( 'row', selector, run, settings, opts );\n\t};\n\t\n\t\n\t_api_register( 'rows()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __row_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in __row_selector?\n\t\tinst.selector.rows = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_register( 'rows().nodes()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn settings.aoData[ row ].nTr || undefined;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'rows().data()', function () {\n\t\treturn this.iterator( true, 'rows', function ( settings, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, '_aData' );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\tvar r = settings.aoData[ row ];\n\t\t\treturn type === 'search' ? r._aFilterData : r._aSortData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\t_fnInvalidate( settings, row, src );\n\t\t} );\n\t} );\n\t\n\t_api_registerPlural( 'rows().indexes()', 'row().index()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn row;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {\n\t\tvar a = [];\n\t\tvar context = this.context;\n\t\n\t\t// `iterator` will drop undefined values, but in this case we want them\n\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\tfor ( var j=0, jen=this[i].length ; j<jen ; j++ ) {\n\t\t\t\tvar id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );\n\t\t\t\ta.push( (hash === true ? '#' : '' )+ id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn new _Api( context, a );\n\t} );\n\t\n\t_api_registerPlural( 'rows().remove()', 'row().remove()', function () {\n\t\tvar that = this;\n\t\n\t\tthis.iterator( 'row', function ( settings, row, thatIdx ) {\n\t\t\tvar data = settings.aoData;\n\t\t\tvar rowData = data[ row ];\n\t\t\tvar i, ien, j, jen;\n\t\t\tvar loopRow, loopCells;\n\t\n\t\t\tdata.splice( row, 1 );\n\t\n\t\t\t// Update the cached indexes\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\tloopRow = data[i];\n\t\t\t\tloopCells = loopRow.anCells;\n\t\n\t\t\t\t// Rows\n\t\t\t\tif ( loopRow.nTr !== null ) {\n\t\t\t\t\tloopRow.nTr._DT_RowIndex = i;\n\t\t\t\t}\n\t\n\t\t\t\t// Cells\n\t\t\t\tif ( loopCells !== null ) {\n\t\t\t\t\tfor ( j=0, jen=loopCells.length ; j<jen ; j++ ) {\n\t\t\t\t\t\tloopCells[j]._DT_CellIndex.row = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Delete from the display arrays\n\t\t\t_fnDeleteIndex( settings.aiDisplayMaster, row );\n\t\t\t_fnDeleteIndex( settings.aiDisplay, row );\n\t\t\t_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes\n\t\n\t\t\t// Check for an 'overflow' they case for displaying the table\n\t\t\t_fnLengthOverflow( settings );\n\t\n\t\t\t// Remove the row's ID reference if there is one\n\t\t\tvar id = settings.rowIdFn( rowData._aData );\n\t\t\tif ( id !== undefined ) {\n\t\t\t\tdelete settings.aIds[ id ];\n\t\t\t}\n\t\t} );\n\t\n\t\tthis.iterator( 'table', function ( settings ) {\n\t\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tsettings.aoData[i].idx = i;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'rows.add()', function ( rows ) {\n\t\tvar newRows = this.iterator( 'table', function ( settings ) {\n\t\t\t\tvar row, i, ien;\n\t\t\t\tvar out = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\t\t\tout.push( _fnAddTr( settings, row )[0] );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tout.push( _fnAddData( settings, row ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn out;\n\t\t\t}, 1 );\n\t\n\t\t// Return an Api.rows() extended instance, so rows().nodes() etc can be used\n\t\tvar modRows = this.rows( -1 );\n\t\tmodRows.pop();\n\t\t$.merge( modRows, newRows );\n\t\n\t\treturn modRows;\n\t} );\n\t\n\t\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( 'row()', function ( selector, opts ) {\n\t\treturn _selector_first( this.rows( selector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'row().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._aData :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\tctx[0].aoData[ this[0] ]._aData = data;\n\t\n\t\t// Automatically invalidate\n\t\t_fnInvalidate( ctx[0], this[0], 'data' );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'row().node()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\treturn ctx.length && this.length ?\n\t\t\tctx[0].aoData[ this[0] ].nTr || null :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'row.add()', function ( row ) {\n\t\t// Allow a jQuery object to be passed in - only a single row is added from\n\t\t// it though - the first element in the set\n\t\tif ( row instanceof $ && row.length ) {\n\t\t\trow = row[0];\n\t\t}\n\t\n\t\tvar rows = this.iterator( 'table', function ( settings ) {\n\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\treturn _fnAddTr( settings, row )[0];\n\t\t\t}\n\t\t\treturn _fnAddData( settings, row );\n\t\t} );\n\t\n\t\t// Return an Api.rows() extended instance, with the newly added row selected\n\t\treturn this.row( rows[0] );\n\t} );\n\t\n\t\n\t\n\tvar __details_add = function ( ctx, row, data, klass )\n\t{\n\t\t// Convert to array of TR elements\n\t\tvar rows = [];\n\t\tvar addRow = function ( r, k ) {\n\t\t\t// Recursion to allow for arrays of jQuery objects\n\t\t\tif ( $.isArray( r ) || r instanceof $ ) {\n\t\t\t\tfor ( var i=0, ien=r.length ; i<ien ; i++ ) {\n\t\t\t\t\taddRow( r[i], k );\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If we get a TR element, then just add it directly - up to the dev\n\t\t\t// to add the correct number of columns etc\n\t\t\tif ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {\n\t\t\t\trows.push( r );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Otherwise create a row with a wrapper\n\t\t\t\tvar created = $('<tr><td/></tr>').addClass( k );\n\t\t\t\t$('td', created)\n\t\t\t\t\t.addClass( k )\n\t\t\t\t\t.html( r )\n\t\t\t\t\t[0].colSpan = _fnVisbleColumns( ctx );\n\t\n\t\t\t\trows.push( created[0] );\n\t\t\t}\n\t\t};\n\t\n\t\taddRow( data, klass );\n\t\n\t\tif ( row._details ) {\n\t\t\trow._details.detach();\n\t\t}\n\t\n\t\trow._details = $(rows);\n\t\n\t\t// If the children were already shown, that state should be retained\n\t\tif ( row._detailsShow ) {\n\t\t\trow._details.insertAfter( row.nTr );\n\t\t}\n\t};\n\t\n\t\n\tvar __details_remove = function ( api, idx )\n\t{\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length ) {\n\t\t\tvar row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];\n\t\n\t\t\tif ( row && row._details ) {\n\t\t\t\trow._details.remove();\n\t\n\t\t\t\trow._detailsShow = undefined;\n\t\t\t\trow._details = undefined;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_display = function ( api, show ) {\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length && api.length ) {\n\t\t\tvar row = ctx[0].aoData[ api[0] ];\n\t\n\t\t\tif ( row._details ) {\n\t\t\t\trow._detailsShow = show;\n\t\n\t\t\t\tif ( show ) {\n\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\trow._details.detach();\n\t\t\t\t}\n\t\n\t\t\t\t__details_events( ctx[0] );\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_events = function ( settings )\n\t{\n\t\tvar api = new _Api( settings );\n\t\tvar namespace = '.dt.DT_details';\n\t\tvar drawEvent = 'draw'+namespace;\n\t\tvar colvisEvent = 'column-visibility'+namespace;\n\t\tvar destroyEvent = 'destroy'+namespace;\n\t\tvar data = settings.aoData;\n\t\n\t\tapi.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );\n\t\n\t\tif ( _pluck( data, '_details' ).length > 0 ) {\n\t\t\t// On each draw, insert the required elements into the document\n\t\t\tapi.on( drawEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tapi.rows( {page:'current'} ).eq(0).each( function (idx) {\n\t\t\t\t\t// Internal data grab\n\t\t\t\t\tvar row = data[ idx ];\n\t\n\t\t\t\t\tif ( row._detailsShow ) {\n\t\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\n\t\t\t// Column visibility change - update the colspan\n\t\t\tapi.on( colvisEvent, function ( e, ctx, idx, vis ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t// Update the colspan for the details rows (note, only if it already has\n\t\t\t\t// a colspan)\n\t\t\t\tvar row, visible = _fnVisbleColumns( ctx );\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = data[i];\n\t\n\t\t\t\t\tif ( row._details ) {\n\t\t\t\t\t\trow._details.children('td[colspan]').attr('colspan', visible );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\t// Table destroyed - nuke any child rows\n\t\t\tapi.on( destroyEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( data[i]._details ) {\n\t\t\t\t\t\t__details_remove( api, i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t// Strings for the method names to help minification\n\tvar _emp = '';\n\tvar _child_obj = _emp+'row().child';\n\tvar _child_mth = _child_obj+'()';\n\t\n\t// data can be:\n\t//  tr\n\t//  string\n\t//  jQuery or array of any of the above\n\t_api_register( _child_mth, function ( data, klass ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._details :\n\t\t\t\tundefined;\n\t\t}\n\t\telse if ( data === true ) {\n\t\t\t// show\n\t\t\tthis.child.show();\n\t\t}\n\t\telse if ( data === false ) {\n\t\t\t// remove\n\t\t\t__details_remove( this );\n\t\t}\n\t\telse if ( ctx.length && this.length ) {\n\t\t\t// set\n\t\t\t__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );\n\t\t}\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.show()',\n\t\t_child_mth+'.show()' // only when `child()` was called with parameters (without\n\t], function ( show ) {   // it returns an object and this method is not executed)\n\t\t__details_display( this, true );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.hide()',\n\t\t_child_mth+'.hide()' // only when `child()` was called with parameters (without\n\t], function () {         // it returns an object and this method is not executed)\n\t\t__details_display( this, false );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.remove()',\n\t\t_child_mth+'.remove()' // only when `child()` was called with parameters (without\n\t], function () {           // it returns an object and this method is not executed)\n\t\t__details_remove( this );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( _child_obj+'.isShown()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length && this.length ) {\n\t\t\t// _detailsShown as false or undefined will fall through to return false\n\t\t\treturn ctx[0].aoData[ this[0] ]._detailsShow || false;\n\t\t}\n\t\treturn false;\n\t} );\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Columns\n\t *\n\t * {integer}           - column index (>=0 count from left, <0 count from right)\n\t * \"{integer}:visIdx\"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)\n\t * \"{integer}:visible\" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)\n\t * \"{string}:name\"     - column name\n\t * \"{string}\"          - jQuery selector on column header nodes\n\t *\n\t */\n\t\n\t// can be an array of these items, comma separated list, or an array of comma\n\t// separated lists\n\t\n\tvar __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;\n\t\n\t\n\t// r1 and r2 are redundant - but it means that the parameters match for the\n\t// iterator callback in columns().data()\n\tvar __columnData = function ( settings, column, r1, r2, rows ) {\n\t\tvar a = [];\n\t\tfor ( var row=0, ien=rows.length ; row<ien ; row++ ) {\n\t\t\ta.push( _fnGetCellData( settings, rows[row], column ) );\n\t\t}\n\t\treturn a;\n\t};\n\t\n\t\n\tvar __column_selector = function ( settings, selector, opts )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tnames = _pluck( columns, 'sName' ),\n\t\t\tnodes = _pluck( columns, 'nTh' );\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar selInt = _intVal( s );\n\t\n\t\t\t// Selector - all\n\t\t\tif ( s === '' ) {\n\t\t\t\treturn _range( columns.length );\n\t\t\t}\n\t\n\t\t\t// Selector - index\n\t\t\tif ( selInt !== null ) {\n\t\t\t\treturn [ selInt >= 0 ?\n\t\t\t\t\tselInt : // Count from left\n\t\t\t\t\tcolumns.length + selInt // Count from right (+ because its a negative value)\n\t\t\t\t];\n\t\t\t}\n\t\n\t\t\t// Selector = function\n\t\t\tif ( typeof s === 'function' ) {\n\t\t\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\n\t\t\t\treturn $.map( columns, function (col, idx) {\n\t\t\t\t\treturn s(\n\t\t\t\t\t\t\tidx,\n\t\t\t\t\t\t\t__columnData( settings, idx, 0, 0, rows ),\n\t\t\t\t\t\t\tnodes[ idx ]\n\t\t\t\t\t\t) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// jQuery or string selector\n\t\t\tvar match = typeof s === 'string' ?\n\t\t\t\ts.match( __re_column_selector ) :\n\t\t\t\t'';\n\t\n\t\t\tif ( match ) {\n\t\t\t\tswitch( match[2] ) {\n\t\t\t\t\tcase 'visIdx':\n\t\t\t\t\tcase 'visible':\n\t\t\t\t\t\tvar idx = parseInt( match[1], 10 );\n\t\t\t\t\t\t// Visible index given, convert to column index\n\t\t\t\t\t\tif ( idx < 0 ) {\n\t\t\t\t\t\t\t// Counting from the right\n\t\t\t\t\t\t\tvar visColumns = $.map( columns, function (col,i) {\n\t\t\t\t\t\t\t\treturn col.bVisible ? i : null;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\treturn [ visColumns[ visColumns.length + idx ] ];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Counting from the left\n\t\t\t\t\t\treturn [ _fnVisibleToColumnIndex( settings, idx ) ];\n\t\n\t\t\t\t\tcase 'name':\n\t\t\t\t\t\t// match by name. `names` is column index complete and in order\n\t\t\t\t\t\treturn $.map( names, function (name, i) {\n\t\t\t\t\t\t\treturn name === match[1] ? i : null;\n\t\t\t\t\t\t} );\n\t\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Cell in the table body\n\t\t\tif ( s.nodeName && s._DT_CellIndex ) {\n\t\t\t\treturn [ s._DT_CellIndex.column ];\n\t\t\t}\n\t\n\t\t\t// jQuery selector on the TH elements for the columns\n\t\t\tvar jqResult = $( nodes )\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn $.inArray( this, nodes ); // `nodes` is column index complete and in order\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise a node which might have a `dt-column` data attribute, or be\n\t\t\t// a child or such an element\n\t\t\tvar host = $(s).closest('*[data-dt-column]');\n\t\t\treturn host.length ?\n\t\t\t\t[ host.data('dt-column') ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'column', selector, run, settings, opts );\n\t};\n\t\n\t\n\tvar __setColumnVis = function ( settings, column, vis ) {\n\t\tvar\n\t\t\tcols = settings.aoColumns,\n\t\t\tcol  = cols[ column ],\n\t\t\tdata = settings.aoData,\n\t\t\trow, cells, i, ien, tr;\n\t\n\t\t// Get\n\t\tif ( vis === undefined ) {\n\t\t\treturn col.bVisible;\n\t\t}\n\t\n\t\t// Set\n\t\t// No change\n\t\tif ( col.bVisible === vis ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( vis ) {\n\t\t\t// Insert column\n\t\t\t// Need to decide if we should use appendChild or insertBefore\n\t\t\tvar insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );\n\t\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\ttr = data[i].nTr;\n\t\t\t\tcells = data[i].anCells;\n\t\n\t\t\t\tif ( tr ) {\n\t\t\t\t\t// insertBefore can act like appendChild if 2nd arg is null\n\t\t\t\t\ttr.insertBefore( cells[ column ], cells[ insertBefore ] || null );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Remove column\n\t\t\t$( _pluck( settings.aoData, 'anCells', column ) ).detach();\n\t\t}\n\t\n\t\t// Common actions\n\t\tcol.bVisible = vis;\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t_fnSaveState( settings );\n\t};\n\t\n\t\n\t_api_register( 'columns()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __column_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in _row_selector?\n\t\tinst.selector.cols = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTh;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTf;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().data()', 'column().data()', function () {\n\t\treturn this.iterator( 'column-rows', __columnData, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].mData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows,\n\t\t\t\ttype === 'search' ? '_aFilterData' : '_aSortData', column\n\t\t\t);\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, 'anCells', column ) ;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {\n\t\tvar ret = this.iterator( 'column', function ( settings, column ) {\n\t\t\tif ( vis === undefined ) {\n\t\t\t\treturn settings.aoColumns[ column ].bVisible;\n\t\t\t} // else\n\t\t\t__setColumnVis( settings, column, vis );\n\t\t} );\n\t\n\t\t// Group the column visibility changes\n\t\tif ( vis !== undefined ) {\n\t\t\t// Second loop once the first is done for events\n\t\t\tthis.iterator( 'column', function ( settings, column ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );\n\t\t\t} );\n\t\n\t\t\tif ( calc === undefined || calc ) {\n\t\t\t\tthis.columns.adjust();\n\t\t\t}\n\t\t}\n\t\n\t\treturn ret;\n\t} );\n\t\n\t_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn type === 'visible' ?\n\t\t\t\t_fnColumnIndexToVisible( settings, column ) :\n\t\t\t\tcolumn;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'columns.adjust()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'column.index()', function ( type, idx ) {\n\t\tif ( this.context.length !== 0 ) {\n\t\t\tvar ctx = this.context[0];\n\t\n\t\t\tif ( type === 'fromVisible' || type === 'toData' ) {\n\t\t\t\treturn _fnVisibleToColumnIndex( ctx, idx );\n\t\t\t}\n\t\t\telse if ( type === 'fromData' || type === 'toVisible' ) {\n\t\t\t\treturn _fnColumnIndexToVisible( ctx, idx );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t_api_register( 'column()', function ( selector, opts ) {\n\t\treturn _selector_first( this.columns( selector, opts ) );\n\t} );\n\t\n\t\n\t\n\tvar __cell_selector = function ( settings, selector, opts )\n\t{\n\t\tvar data = settings.aoData;\n\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\tvar cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );\n\t\tvar allCells = $( [].concat.apply([], cells) );\n\t\tvar row;\n\t\tvar columns = settings.aoColumns.length;\n\t\tvar a, i, ien, j, o, host;\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar fnSelector = typeof s === 'function';\n\t\n\t\t\tif ( s === null || s === undefined || fnSelector ) {\n\t\t\t\t// All cells and function selectors\n\t\t\t\ta = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tfor ( j=0 ; j<columns ; j++ ) {\n\t\t\t\t\t\to = {\n\t\t\t\t\t\t\trow: row,\n\t\t\t\t\t\t\tcolumn: j\n\t\t\t\t\t\t};\n\t\n\t\t\t\t\t\tif ( fnSelector ) {\n\t\t\t\t\t\t\t// Selector - function\n\t\t\t\t\t\t\thost = data[ row ];\n\t\n\t\t\t\t\t\t\tif ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {\n\t\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Selector - all\n\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn a;\n\t\t\t}\n\t\t\t\n\t\t\t// Selector - index\n\t\t\tif ( $.isPlainObject( s ) ) {\n\t\t\t\treturn [s];\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery filtered cells\n\t\t\tvar jqResult = allCells\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function (i, el) {\n\t\t\t\t\treturn { // use a new object, in case someone changes the values\n\t\t\t\t\t\trow:    el._DT_CellIndex.row,\n\t\t\t\t\t\tcolumn: el._DT_CellIndex.column\n\t \t\t\t\t};\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise the selector is a node, and there is one last option - the\n\t\t\t// element might be a child of an element which has dt-row and dt-column\n\t\t\t// data attributes\n\t\t\thost = $(s).closest('*[data-dt-row]');\n\t\t\treturn host.length ?\n\t\t\t\t[ {\n\t\t\t\t\trow: host.data('dt-row'),\n\t\t\t\t\tcolumn: host.data('dt-column')\n\t\t\t\t} ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'cell', selector, run, settings, opts );\n\t};\n\t\n\t\n\t\n\t\n\t_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {\n\t\t// Argument shifting\n\t\tif ( $.isPlainObject( rowSelector ) ) {\n\t\t\t// Indexes\n\t\t\tif ( rowSelector.row === undefined ) {\n\t\t\t\t// Selector options in first parameter\n\t\t\t\topts = rowSelector;\n\t\t\t\trowSelector = null;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Cell index objects in first parameter\n\t\t\t\topts = columnSelector;\n\t\t\t\tcolumnSelector = null;\n\t\t\t}\n\t\t}\n\t\tif ( $.isPlainObject( columnSelector ) ) {\n\t\t\topts = columnSelector;\n\t\t\tcolumnSelector = null;\n\t\t}\n\t\n\t\t// Cell selector\n\t\tif ( columnSelector === null || columnSelector === undefined ) {\n\t\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t\treturn __cell_selector( settings, rowSelector, _selector_opts( opts ) );\n\t\t\t} );\n\t\t}\n\t\n\t\t// Row + column selector\n\t\tvar columns = this.columns( columnSelector, opts );\n\t\tvar rows = this.rows( rowSelector, opts );\n\t\tvar a, i, ien, j, jen;\n\t\n\t\tvar cells = this.iterator( 'table', function ( settings, idx ) {\n\t\t\ta = [];\n\t\n\t\t\tfor ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {\n\t\t\t\tfor ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {\n\t\t\t\t\ta.push( {\n\t\t\t\t\t\trow:    rows[idx][i],\n\t\t\t\t\t\tcolumn: columns[idx][j]\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn a;\n\t\t}, 1 );\n\t\n\t\t$.extend( cells.selector, {\n\t\t\tcols: columnSelector,\n\t\t\trows: rowSelector,\n\t\t\topts: opts\n\t\t} );\n\t\n\t\treturn cells;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\tvar data = settings.aoData[ row ];\n\t\n\t\t\treturn data && data.anCells ?\n\t\t\t\tdata.anCells[ column ] :\n\t\t\t\tundefined;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_register( 'cells().data()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {\n\t\ttype = type === 'search' ? '_aFilterData' : '_aSortData';\n\t\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn settings.aoData[ row ][ type ][ column ];\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column, type );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn {\n\t\t\t\trow: row,\n\t\t\t\tcolumn: column,\n\t\t\t\tcolumnVisible: _fnColumnIndexToVisible( settings, column )\n\t\t\t};\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\t_fnInvalidate( settings, row, src, column );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {\n\t\treturn _selector_first( this.cells( rowSelector, columnSelector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'cell().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\tvar cell = this[0];\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && cell.length ?\n\t\t\t\t_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\t_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );\n\t\t_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get current ordering (sorting) that has been applied to the table.\n\t *\n\t * @returns {array} 2D array containing the sorting information for the first\n\t *   table in the current context. Each element in the parent array represents\n\t *   a column being sorted upon (i.e. multi-sorting with two columns would have\n\t *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is\n\t *   the column index that the sorting condition applies to, the second is the\n\t *   direction of the sort (`desc` or `asc`) and, optionally, the third is the\n\t *   index of the sorting order from the `column.sorting` initialisation array.\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {integer} order Column index to sort upon.\n\t * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 1D array of sorting information to be applied.\n\t * @param {array} [...] Optional additional sorting conditions\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 2D array of sorting information to be applied.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order()', function ( order, dir ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( order === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].aaSorting :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\tif ( typeof order === 'number' ) {\n\t\t\t// Simple column / direction passed in\n\t\t\torder = [ [ order, dir ] ];\n\t\t}\n\t\telse if ( order.length && ! $.isArray( order[0] ) ) {\n\t\t\t// Arguments passed in (list of 1D arrays)\n\t\t\torder = Array.prototype.slice.call( arguments );\n\t\t}\n\t\t// otherwise a 2D array was passed in\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSorting = order.slice();\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Attach a sort listener to an element for a given column\n\t *\n\t * @param {node|jQuery|string} node Identifier for the element(s) to attach the\n\t *   listener to. This can take the form of a single DOM node, a jQuery\n\t *   collection of nodes or a jQuery selector which will identify the node(s).\n\t * @param {integer} column the column that a click on this node will sort on\n\t * @param {function} [callback] callback function when sort is run\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order.listener()', function ( node, column, callback ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSortAttachListener( settings, node, column, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'order.fixed()', function ( set ) {\n\t\tif ( ! set ) {\n\t\t\tvar ctx = this.context;\n\t\t\tvar fixed = ctx.length ?\n\t\t\t\tctx[0].aaSortingFixed :\n\t\t\t\tundefined;\n\t\n\t\t\treturn $.isArray( fixed ) ?\n\t\t\t\t{ pre: fixed } :\n\t\t\t\tfixed;\n\t\t}\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSortingFixed = $.extend( true, {}, set );\n\t\t} );\n\t} );\n\t\n\t\n\t// Order by the selected column(s)\n\t_api_register( [\n\t\t'columns().order()',\n\t\t'column().order()'\n\t], function ( dir ) {\n\t\tvar that = this;\n\t\n\t\treturn this.iterator( 'table', function ( settings, i ) {\n\t\t\tvar sort = [];\n\t\n\t\t\t$.each( that[i], function (j, col) {\n\t\t\t\tsort.push( [ col, dir ] );\n\t\t\t} );\n\t\n\t\t\tsettings.aaSorting = sort;\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'search()', function ( input, regex, smart, caseInsen ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( input === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].oPreviousSearch.sSearch :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {\n\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t} ), 1 );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural(\n\t\t'columns().search()',\n\t\t'column().search()',\n\t\tfunction ( input, regex, smart, caseInsen ) {\n\t\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\t\tvar preSearch = settings.aoPreSearchCols;\n\t\n\t\t\t\tif ( input === undefined ) {\n\t\t\t\t\t// get\n\t\t\t\t\treturn preSearch[ column ].sSearch;\n\t\t\t\t}\n\t\n\t\t\t\t// set\n\t\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t$.extend( preSearch[ column ], {\n\t\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t\t} );\n\t\n\t\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch, 1 );\n\t\t\t} );\n\t\t}\n\t);\n\t\n\t/*\n\t * State API methods\n\t */\n\t\n\t_api_register( 'state()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oSavedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t// Save an empty object\n\t\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, {} );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'state.loaded()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oLoadedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.save()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSaveState( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Provide a common method for plug-ins to check the version of DataTables being\n\t * used, in order to ensure compatibility.\n\t *\n\t *  @param {string} version Version string to check for, in the format \"X.Y.Z\".\n\t *    Note that the formats \"X\" and \"X.Y\" are also acceptable.\n\t *  @returns {boolean} true if this version of DataTables is greater or equal to\n\t *    the required version, or false if this version of DataTales is not\n\t *    suitable\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );\n\t */\n\tDataTable.versionCheck = DataTable.fnVersionCheck = function( version )\n\t{\n\t\tvar aThis = DataTable.version.split('.');\n\t\tvar aThat = version.split('.');\n\t\tvar iThis, iThat;\n\t\n\t\tfor ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {\n\t\t\tiThis = parseInt( aThis[i], 10 ) || 0;\n\t\t\tiThat = parseInt( aThat[i], 10 ) || 0;\n\t\n\t\t\t// Parts are the same, keep comparing\n\t\t\tif (iThis === iThat) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\t// Parts are different, return immediately\n\t\t\treturn iThis > iThat;\n\t\t}\n\t\n\t\treturn true;\n\t};\n\t\n\t\n\t/**\n\t * Check if a `<table>` node is a DataTable table already or not.\n\t *\n\t *  @param {node|jquery|string} table Table node, jQuery object or jQuery\n\t *      selector for the table to test. Note that if more than more than one\n\t *      table is passed on, only the first will be checked\n\t *  @returns {boolean} true the table given is a DataTable, or false otherwise\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {\n\t *      $('#example').dataTable();\n\t *    }\n\t */\n\tDataTable.isDataTable = DataTable.fnIsDataTable = function ( table )\n\t{\n\t\tvar t = $(table).get(0);\n\t\tvar is = false;\n\t\n\t\tif ( table instanceof DataTable.Api ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\t$.each( DataTable.settings, function (i, o) {\n\t\t\tvar head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;\n\t\t\tvar foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;\n\t\n\t\t\tif ( o.nTable === t || head === t || foot === t ) {\n\t\t\t\tis = true;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn is;\n\t};\n\t\n\t\n\t/**\n\t * Get all DataTable tables that have been initialised - optionally you can\n\t * select to get only currently visible tables.\n\t *\n\t *  @param {boolean} [visible=false] Flag to indicate if you want all (default)\n\t *    or visible tables only.\n\t *  @returns {array} Array of `table` nodes (not DataTable instances) which are\n\t *    DataTables\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    $.each( $.fn.dataTable.tables(true), function () {\n\t *      $(table).DataTable().columns.adjust();\n\t *    } );\n\t */\n\tDataTable.tables = DataTable.fnTables = function ( visible )\n\t{\n\t\tvar api = false;\n\t\n\t\tif ( $.isPlainObject( visible ) ) {\n\t\t\tapi = visible.api;\n\t\t\tvisible = visible.visible;\n\t\t}\n\t\n\t\tvar a = $.map( DataTable.settings, function (o) {\n\t\t\tif ( !visible || (visible && $(o.nTable).is(':visible')) ) {\n\t\t\t\treturn o.nTable;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn api ?\n\t\t\tnew _Api( a ) :\n\t\t\ta;\n\t};\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian notation. This is made public\n\t * for the extensions to provide the same ability as DataTables core to accept\n\t * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase\n\t * parameters.\n\t *\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t */\n\tDataTable.camelToHungarian = _fnCamelToHungarian;\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( '$()', function ( selector, opts ) {\n\t\tvar\n\t\t\trows   = this.rows( opts ).nodes(), // Get all rows\n\t\t\tjqRows = $(rows);\n\t\n\t\treturn $( [].concat(\n\t\t\tjqRows.filter( selector ).toArray(),\n\t\t\tjqRows.find( selector ).toArray()\n\t\t) );\n\t} );\n\t\n\t\n\t// jQuery functions to operate on the tables\n\t$.each( [ 'on', 'one', 'off' ], function (i, key) {\n\t\t_api_register( key+'()', function ( /* event, handler */ ) {\n\t\t\tvar args = Array.prototype.slice.call(arguments);\n\t\n\t\t\t// Add the `dt` namespace automatically if it isn't already present\n\t\t\targs[0] = $.map( args[0].split( /\\s/ ), function ( e ) {\n\t\t\t\treturn ! e.match(/\\.dt\\b/) ?\n\t\t\t\t\te+'.dt' :\n\t\t\t\t\te;\n\t\t\t\t} ).join( ' ' );\n\t\n\t\t\tvar inst = $( this.tables().nodes() );\n\t\t\tinst[key].apply( inst, args );\n\t\t\treturn this;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnClearTable( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'settings()', function () {\n\t\treturn new _Api( this.context, this.context );\n\t} );\n\t\n\t\n\t_api_register( 'init()', function () {\n\t\tvar ctx = this.context;\n\t\treturn ctx.length ? ctx[0].oInit : null;\n\t} );\n\t\n\t\n\t_api_register( 'data()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\treturn _pluck( settings.aoData, '_aData' );\n\t\t} ).flatten();\n\t} );\n\t\n\t\n\t_api_register( 'destroy()', function ( remove ) {\n\t\tremove = remove || false;\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tvar orig      = settings.nTableWrapper.parentNode;\n\t\t\tvar classes   = settings.oClasses;\n\t\t\tvar table     = settings.nTable;\n\t\t\tvar tbody     = settings.nTBody;\n\t\t\tvar thead     = settings.nTHead;\n\t\t\tvar tfoot     = settings.nTFoot;\n\t\t\tvar jqTable   = $(table);\n\t\t\tvar jqTbody   = $(tbody);\n\t\t\tvar jqWrapper = $(settings.nTableWrapper);\n\t\t\tvar rows      = $.map( settings.aoData, function (r) { return r.nTr; } );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Flag to note that the table is currently being destroyed - no action\n\t\t\t// should be taken\n\t\t\tsettings.bDestroying = true;\n\t\n\t\t\t// Fire off the destroy callbacks for plug-ins etc\n\t\t\t_fnCallbackFire( settings, \"aoDestroyCallback\", \"destroy\", [settings] );\n\t\n\t\t\t// If not being removed from the document, make all columns visible\n\t\t\tif ( ! remove ) {\n\t\t\t\tnew _Api( settings ).columns().visible( true );\n\t\t\t}\n\t\n\t\t\t// Blitz all `DT` namespaced events (these are internal events, the\n\t\t\t// lowercase, `dt` events are user subscribed and they are responsible\n\t\t\t// for removing them\n\t\t\tjqWrapper.off('.DT').find(':not(tbody *)').off('.DT');\n\t\t\t$(window).off('.DT-'+settings.sInstance);\n\t\n\t\t\t// When scrolling we had to break the table up - restore it\n\t\t\tif ( table != thead.parentNode ) {\n\t\t\t\tjqTable.children('thead').detach();\n\t\t\t\tjqTable.append( thead );\n\t\t\t}\n\t\n\t\t\tif ( tfoot && table != tfoot.parentNode ) {\n\t\t\t\tjqTable.children('tfoot').detach();\n\t\t\t\tjqTable.append( tfoot );\n\t\t\t}\n\t\n\t\t\tsettings.aaSorting = [];\n\t\t\tsettings.aaSortingFixed = [];\n\t\t\t_fnSortingClasses( settings );\n\t\n\t\t\t$( rows ).removeClass( settings.asStripeClasses.join(' ') );\n\t\n\t\t\t$('th, td', thead).removeClass( classes.sSortable+' '+\n\t\t\t\tclasses.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone\n\t\t\t);\n\t\n\t\t\tif ( settings.bJUI ) {\n\t\t\t\t$('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();\n\t\t\t\t$('th, td', thead).each( function () {\n\t\t\t\t\tvar wrapper = $('div.'+classes.sSortJUIWrapper, this);\n\t\t\t\t\t$(this).append( wrapper.contents() );\n\t\t\t\t\twrapper.detach();\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Add the TR elements back into the table in their original order\n\t\t\tjqTbody.children().detach();\n\t\t\tjqTbody.append( rows );\n\t\n\t\t\t// Remove the DataTables generated nodes, events and classes\n\t\t\tvar removedMethod = remove ? 'remove' : 'detach';\n\t\t\tjqTable[ removedMethod ]();\n\t\t\tjqWrapper[ removedMethod ]();\n\t\n\t\t\t// If we need to reattach the table to the document\n\t\t\tif ( ! remove && orig ) {\n\t\t\t\t// insertBefore acts like appendChild if !arg[1]\n\t\t\t\torig.insertBefore( table, settings.nTableReinsertBefore );\n\t\n\t\t\t\t// Restore the width of the original table - was read from the style property,\n\t\t\t\t// so we can restore directly to that\n\t\t\t\tjqTable\n\t\t\t\t\t.css( 'width', settings.sDestroyWidth )\n\t\t\t\t\t.removeClass( classes.sTable );\n\t\n\t\t\t\t// If the were originally stripe classes - then we add them back here.\n\t\t\t\t// Note this is not fool proof (for example if not all rows had stripe\n\t\t\t\t// classes - but it's a good effort without getting carried away\n\t\t\t\tien = settings.asDestroyStripes.length;\n\t\n\t\t\t\tif ( ien ) {\n\t\t\t\t\tjqTbody.children().each( function (i) {\n\t\t\t\t\t\t$(this).addClass( settings.asDestroyStripes[i % ien] );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Remove the settings object from the settings array */\n\t\t\tvar idx = $.inArray( settings, DataTable.settings );\n\t\t\tif ( idx !== -1 ) {\n\t\t\t\tDataTable.settings.splice( idx, 1 );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t// Add the `every()` method for rows, columns and cells in a compact form\n\t$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {\n\t\t_api_register( type+'s().every()', function ( fn ) {\n\t\t\tvar opts = this.selector.opts;\n\t\t\tvar api = this;\n\t\n\t\t\treturn this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {\n\t\t\t\t// Rows and columns:\n\t\t\t\t//  arg1 - index\n\t\t\t\t//  arg2 - table counter\n\t\t\t\t//  arg3 - loop counter\n\t\t\t\t//  arg4 - undefined\n\t\t\t\t// Cells:\n\t\t\t\t//  arg1 - row index\n\t\t\t\t//  arg2 - column index\n\t\t\t\t//  arg3 - table counter\n\t\t\t\t//  arg4 - loop counter\n\t\t\t\tfn.call(\n\t\t\t\t\tapi[ type ](\n\t\t\t\t\t\targ1,\n\t\t\t\t\t\ttype==='cell' ? arg2 : opts,\n\t\t\t\t\t\ttype==='cell' ? opts : undefined\n\t\t\t\t\t),\n\t\t\t\t\targ1, arg2, arg3, arg4\n\t\t\t\t);\n\t\t\t} );\n\t\t} );\n\t} );\n\t\n\t\n\t// i18n method for extensions to be able to use the language object from the\n\t// DataTable\n\t_api_register( 'i18n()', function ( token, def, plural ) {\n\t\tvar ctx = this.context[0];\n\t\tvar resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );\n\t\n\t\tif ( resolved === undefined ) {\n\t\t\tresolved = def;\n\t\t}\n\t\n\t\tif ( plural !== undefined && $.isPlainObject( resolved ) ) {\n\t\t\tresolved = resolved[ plural ] !== undefined ?\n\t\t\t\tresolved[ plural ] :\n\t\t\t\tresolved._;\n\t\t}\n\t\n\t\treturn resolved.replace( '%d', plural ); // nb: plural might be undefined,\n\t} );\n\n\t/**\n\t * Version string for plug-ins to check compatibility. Allowed format is\n\t * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used\n\t * only for non-release builds. See http://semver.org/ for more information.\n\t *  @member\n\t *  @type string\n\t *  @default Version number\n\t */\n\tDataTable.version = \"1.10.13\";\n\n\t/**\n\t * Private data store, containing all of the settings objects that are\n\t * created for the tables on a given page.\n\t *\n\t * Note that the `DataTable.settings` object is aliased to\n\t * `jQuery.fn.dataTableExt` through which it may be accessed and\n\t * manipulated, or `jQuery.fn.dataTable.settings`.\n\t *  @member\n\t *  @type array\n\t *  @default []\n\t *  @private\n\t */\n\tDataTable.settings = [];\n\n\t/**\n\t * Object models container, for the various models that DataTables has\n\t * available to it. These models define the objects that are used to hold\n\t * the active state and configuration of the table.\n\t *  @namespace\n\t */\n\tDataTable.models = {};\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * search information for the global filter and individual column filters.\n\t *  @namespace\n\t */\n\tDataTable.models.oSearch = {\n\t\t/**\n\t\t * Flag to indicate if the filtering should be case insensitive or not\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bCaseInsensitive\": true,\n\t\n\t\t/**\n\t\t * Applied search term\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sSearch\": \"\",\n\t\n\t\t/**\n\t\t * Flag to indicate if the search term should be interpreted as a\n\t\t * regular expression (true) or not (false) and therefore and special\n\t\t * regex characters escaped.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bRegex\": false,\n\t\n\t\t/**\n\t\t * Flag to indicate if DataTables is to use its smart filtering or not.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bSmart\": true\n\t};\n\t\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * each individual row. This is the object format used for the settings\n\t * aoData array.\n\t *  @namespace\n\t */\n\tDataTable.models.oRow = {\n\t\t/**\n\t\t * TR element for the row\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTr\": null,\n\t\n\t\t/**\n\t\t * Array of TD elements for each row. This is null until the row has been\n\t\t * created.\n\t\t *  @type array nodes\n\t\t *  @default []\n\t\t */\n\t\t\"anCells\": null,\n\t\n\t\t/**\n\t\t * Data object from the original data source for the row. This is either\n\t\t * an array if using the traditional form of DataTables, or an object if\n\t\t * using mData options. The exact type will depend on the passed in\n\t\t * data from the data source, or will be an array if using DOM a data\n\t\t * source.\n\t\t *  @type array|object\n\t\t *  @default []\n\t\t */\n\t\t\"_aData\": [],\n\t\n\t\t/**\n\t\t * Sorting data cache - this array is ostensibly the same length as the\n\t\t * number of columns (although each index is generated only as it is\n\t\t * needed), and holds the data that is used for sorting each column in the\n\t\t * row. We do this cache generation at the start of the sort in order that\n\t\t * the formatting of the sort data need be done only once for each cell\n\t\t * per sort. This array should not be read from or written to by anything\n\t\t * other than the master sorting methods.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aSortData\": null,\n\t\n\t\t/**\n\t\t * Per cell filtering data cache. As per the sort data cache, used to\n\t\t * increase the performance of the filtering in DataTables\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aFilterData\": null,\n\t\n\t\t/**\n\t\t * Filtering data cache. This is the same as the cell filtering cache, but\n\t\t * in this case a string rather than an array. This is easily computed with\n\t\t * a join on `_aFilterData`, but is provided as a cache so the join isn't\n\t\t * needed on every search (memory traded for performance)\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sFilterRow\": null,\n\t\n\t\t/**\n\t\t * Cache of the class name that DataTables has applied to the row, so we\n\t\t * can quickly look at this variable rather than needing to do a DOM check\n\t\t * on className for the nTr property.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *  @private\n\t\t */\n\t\t\"_sRowStripe\": \"\",\n\t\n\t\t/**\n\t\t * Denote if the original data source was from the DOM, or the data source\n\t\t * object. This is used for invalidating data, so DataTables can\n\t\t * automatically read data from the original source, unless uninstructed\n\t\t * otherwise.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"src\": null,\n\t\n\t\t/**\n\t\t * Index in the aoData array. This saves an indexOf lookup when we have the\n\t\t * object, but want to know the index\n\t\t *  @type integer\n\t\t *  @default -1\n\t\t *  @private\n\t\t */\n\t\t\"idx\": -1\n\t};\n\t\n\t\n\t/**\n\t * Template object for the column information object in DataTables. This object\n\t * is held in the settings aoColumns array and contains all the information that\n\t * DataTables needs about each individual column.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults.column}\n\t * but this one is the internal data store for DataTables's cache of columns.\n\t * It should NOT be manipulated outside of DataTables. Any configuration should\n\t * be done through the initialisation options.\n\t *  @namespace\n\t */\n\tDataTable.models.oColumn = {\n\t\t/**\n\t\t * Column index. This could be worked out on-the-fly with $.inArray, but it\n\t\t * is faster to just hold it as a variable\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"idx\": null,\n\t\n\t\t/**\n\t\t * A list of the columns that sorting should occur on when this column\n\t\t * is sorted. That this property is an array allows multi-column sorting\n\t\t * to be defined for a column (for example first name / last name columns\n\t\t * would benefit from this). The values are integers pointing to the\n\t\t * columns to be sorted on (typically it will be a single integer pointing\n\t\t * at itself, but that doesn't need to be the case).\n\t\t *  @type array\n\t\t */\n\t\t\"aDataSort\": null,\n\t\n\t\t/**\n\t\t * Define the sorting directions that are applied to the column, in sequence\n\t\t * as the column is repeatedly sorted upon - i.e. the first value is used\n\t\t * as the sorting direction when the column if first sorted (clicked on).\n\t\t * Sort it again (click again) and it will move on to the next index.\n\t\t * Repeat until loop.\n\t\t *  @type array\n\t\t */\n\t\t\"asSorting\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is searchable, and thus should be included\n\t\t * in the filtering or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSearchable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is sortable or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is currently visible in the table or not\n\t\t *  @type boolean\n\t\t */\n\t\t\"bVisible\": null,\n\t\n\t\t/**\n\t\t * Store for manual type assignment using the `column.type` option. This\n\t\t * is held in store so we can manipulate the column's `sType` property.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sManualType\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if HTML5 data attributes should be used as the data\n\t\t * source for filtering or sorting. True is either are.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @private\n\t\t */\n\t\t\"_bAttrSrc\": false,\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} nTd The TD node that has been created\n\t\t *  @param {*} sData The Data for the cell\n\t\t *  @param {array|object} oData The data for the whole row\n\t\t *  @param {int} iRow The row index for the aoData data store\n\t\t *  @default null\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\t/**\n\t\t * Function to get data from a cell in a column. You should <b>never</b>\n\t\t * access data directly through _aData internally in DataTables - always use\n\t\t * the method attached to this property. It allows mData to function as\n\t\t * required. This function is automatically assigned by the column\n\t\t * initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {string} sSpecific The specific data type you want to get -\n\t\t *    'display', 'type' 'filter' 'sort'\n\t\t *  @returns {*} The data for the cell from the given row's data\n\t\t *  @default null\n\t\t */\n\t\t\"fnGetData\": null,\n\t\n\t\t/**\n\t\t * Function to set data for a cell in the column. You should <b>never</b>\n\t\t * set the data directly to _aData internally in DataTables - always use\n\t\t * this method. It allows mData to function as required. This function\n\t\t * is automatically assigned by the column initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {*} sValue Value to set\n\t\t *  @default null\n\t\t */\n\t\t\"fnSetData\": null,\n\t\n\t\t/**\n\t\t * Property to read the value for the cells in the column from the data\n\t\t * source array / object. If null, then the default content is used, if a\n\t\t * function is given then the return from the function is used.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\t/**\n\t\t * Partner property to mData which is used (only when defined) to get\n\t\t * the data - i.e. it is basically the same as mData, but without the\n\t\t * 'set' option, and also the data fed to it is the result from mData.\n\t\t * This is the rendering method to match the data method of mData.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\t/**\n\t\t * Unique header TH/TD element for this column - this is what the sorting\n\t\t * listener is attached to (if sorting is enabled.)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTh\": null,\n\t\n\t\t/**\n\t\t * Unique footer TH/TD element for this column (if there is one). Not used\n\t\t * in DataTables as such, but can be used for plug-ins to reference the\n\t\t * footer for each column.\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTf\": null,\n\t\n\t\t/**\n\t\t * The class to apply to all TD elements in the table's TBODY for the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sClass\": null,\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t *  @type string\n\t\t */\n\t\t\"sContentPadding\": null,\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because mData\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\t/**\n\t\t * Name for the column, allowing reference to the column by name as well as\n\t\t * by index (needs a lookup to work by name).\n\t\t *  @type string\n\t\t */\n\t\t\"sName\": null,\n\t\n\t\t/**\n\t\t * Custom sorting data type - defines which of the available plug-ins in\n\t\t * afnSortData the custom sorting will use - if any is defined.\n\t\t *  @type string\n\t\t *  @default std\n\t\t */\n\t\t\"sSortDataType\": 'std',\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClass\": null,\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column -\n\t\t * when jQuery UI theming is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClassJUI\": null,\n\t\n\t\t/**\n\t\t * Title of the column - what is seen in the TH element (nTh).\n\t\t *  @type string\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\t/**\n\t\t * Column sorting and filtering type\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\t/**\n\t\t * Width of the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidth\": null,\n\t\n\t\t/**\n\t\t * Width of the column when it was first \"encountered\"\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidthOrig\": null\n\t};\n\t\n\t\n\t/*\n\t * Developer note: The properties of the object below are given in Hungarian\n\t * notation, that was used as the interface for DataTables prior to v1.10, however\n\t * from v1.10 onwards the primary interface is camel case. In order to avoid\n\t * breaking backwards compatibility utterly with this change, the Hungarian\n\t * version is still, internally the primary interface, but is is not documented\n\t * - hence the @name tags in each doc comment. This allows a Javascript function\n\t * to create a map from Hungarian notation to camel case (going the other direction\n\t * would require each property to be listed, which would at around 3K to the size\n\t * of DataTables, while this method is about a 0.5K hit.\n\t *\n\t * Ultimately this does pave the way for Hungarian notation to be dropped\n\t * completely, but that is a massive amount of work and will break current\n\t * installs (therefore is on-hold until v2).\n\t */\n\t\n\t/**\n\t * Initialisation options that can be given to DataTables at initialisation\n\t * time.\n\t *  @namespace\n\t */\n\tDataTable.defaults = {\n\t\t/**\n\t\t * An array of data to use for the table, passed in at initialisation which\n\t\t * will be used in preference to any data which is already in the DOM. This is\n\t\t * particularly useful for constructing tables purely in Javascript, for\n\t\t * example with a custom Ajax call.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.data\n\t\t *\n\t\t *  @example\n\t\t *    // Using a 2D array data source\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],\n\t\t *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\" },\n\t\t *          { \"title\": \"Browser\" },\n\t\t *          { \"title\": \"Platform\" },\n\t\t *          { \"title\": \"Version\" },\n\t\t *          { \"title\": \"Grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using an array of objects as a data source (`data`)\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 4.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  4,\n\t\t *            \"grade\":    \"X\"\n\t\t *          },\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 5.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  5,\n\t\t *            \"grade\":    \"C\"\n\t\t *          }\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\",   \"data\": \"engine\" },\n\t\t *          { \"title\": \"Browser\",  \"data\": \"browser\" },\n\t\t *          { \"title\": \"Platform\", \"data\": \"platform\" },\n\t\t *          { \"title\": \"Version\",  \"data\": \"version\" },\n\t\t *          { \"title\": \"Grade\",    \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaData\": null,\n\t\n\t\n\t\t/**\n\t\t * If ordering is enabled, then DataTables will perform a first pass sort on\n\t\t * initialisation. You can define which column(s) the sort is performed\n\t\t * upon, and the sorting direction, with this variable. The `sorting` array\n\t\t * should contain an array for each column to be sorted initially containing\n\t\t * the column's index and a direction string ('asc' or 'desc').\n\t\t *  @type array\n\t\t *  @default [[0,'asc']]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.order\n\t\t *\n\t\t *  @example\n\t\t *    // Sort by 3rd column first, and then 4th column\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": [[2,'asc'], [3,'desc']]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *    // No initial sorting\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": []\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaSorting\": [[0,'asc']],\n\t\n\t\n\t\t/**\n\t\t * This parameter is basically identical to the `sorting` parameter, but\n\t\t * cannot be overridden by user interaction with the table. What this means\n\t\t * is that you could have a column (visible or hidden) which the sorting\n\t\t * will always be forced on first - any sorting after that (from the user)\n\t\t * will then be performed as required. This can be useful for grouping rows\n\t\t * together.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.orderFixed\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderFixed\": [[0,'asc']]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\n\t\t/**\n\t\t * DataTables can be instructed to load data to display in the table from a\n\t\t * Ajax source. This option defines how that Ajax call is made and where to.\n\t\t *\n\t\t * The `ajax` property has three different modes of operation, depending on\n\t\t * how it is defined. These are:\n\t\t *\n\t\t * * `string` - Set the URL from where the data should be loaded from.\n\t\t * * `object` - Define properties for `jQuery.ajax`.\n\t\t * * `function` - Custom data get function\n\t\t *\n\t\t * `string`\n\t\t * --------\n\t\t *\n\t\t * As a string, the `ajax` property simply defines the URL from which\n\t\t * DataTables will load data.\n\t\t *\n\t\t * `object`\n\t\t * --------\n\t\t *\n\t\t * As an object, the parameters in the object are passed to\n\t\t * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control\n\t\t * of the Ajax request. DataTables has a number of default parameters which\n\t\t * you can override using this option. Please refer to the jQuery\n\t\t * documentation for a full description of the options available, although\n\t\t * the following parameters provide additional options in DataTables or\n\t\t * require special consideration:\n\t\t *\n\t\t * * `data` - As with jQuery, `data` can be provided as an object, but it\n\t\t *   can also be used as a function to manipulate the data DataTables sends\n\t\t *   to the server. The function takes a single parameter, an object of\n\t\t *   parameters with the values that DataTables has readied for sending. An\n\t\t *   object may be returned which will be merged into the DataTables\n\t\t *   defaults, or you can add the items to the object that was passed in and\n\t\t *   not return anything from the function. This supersedes `fnServerParams`\n\t\t *   from DataTables 1.9-.\n\t\t *\n\t\t * * `dataSrc` - By default DataTables will look for the property `data` (or\n\t\t *   `aaData` for compatibility with DataTables 1.9-) when obtaining data\n\t\t *   from an Ajax source or for server-side processing - this parameter\n\t\t *   allows that property to be changed. You can use Javascript dotted\n\t\t *   object notation to get a data source for multiple levels of nesting, or\n\t\t *   it my be used as a function. As a function it takes a single parameter,\n\t\t *   the JSON returned from the server, which can be manipulated as\n\t\t *   required, with the returned value being that used by DataTables as the\n\t\t *   data source for the table. This supersedes `sAjaxDataProp` from\n\t\t *   DataTables 1.9-.\n\t\t *\n\t\t * * `success` - Should not be overridden it is used internally in\n\t\t *   DataTables. To manipulate / transform the data returned by the server\n\t\t *   use `ajax.dataSrc`, or use `ajax` as a function (see below).\n\t\t *\n\t\t * `function`\n\t\t * ----------\n\t\t *\n\t\t * As a function, making the Ajax call is left up to yourself allowing\n\t\t * complete control of the Ajax request. Indeed, if desired, a method other\n\t\t * than Ajax could be used to obtain the required data, such as Web storage\n\t\t * or an AIR database.\n\t\t *\n\t\t * The function is given four parameters and no return is required. The\n\t\t * parameters are:\n\t\t *\n\t\t * 1. _object_ - Data to send to the server\n\t\t * 2. _function_ - Callback function that must be executed when the required\n\t\t *    data has been obtained. That data should be passed into the callback\n\t\t *    as the only parameter\n\t\t * 3. _object_ - DataTables settings object for the table\n\t\t *\n\t\t * Note that this supersedes `fnServerData` from DataTables 1.9-.\n\t\t *\n\t\t *  @type string|object|function\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.ajax\n\t\t *  @since 1.10.0\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax.\n\t\t *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": \"data.json\"\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to change\n\t\t *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"tableData\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to read data\n\t\t *   // from a plain array rather than an array in an object\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Manipulate the data returned from the server - add a link to data\n\t\t *   // (note this can, should, be done using `render` for the column - this\n\t\t *   // is just a simple example of how the data can be manipulated).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": function ( json ) {\n\t\t *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {\n\t\t *           json[i][0] = '<a href=\"/message/'+json[i][0]+'>View message</a>';\n\t\t *         }\n\t\t *         return json;\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Add data to the request\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"data\": function ( d ) {\n\t\t *         return {\n\t\t *           \"extra_search\": $('#extra').val()\n\t\t *         };\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Send request as POST\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"type\": \"POST\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get the data from localStorage (could interface with a form for\n\t\t *   // adding, editing and removing rows).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": function (data, callback, settings) {\n\t\t *       callback(\n\t\t *         JSON.parse( localStorage.getItem('dataTablesData') )\n\t\t *       );\n\t\t *     }\n\t\t *   } );\n\t\t */\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to readily specify the entries in the length drop\n\t\t * down menu that DataTables shows when pagination is enabled. It can be\n\t\t * either a 1D array of options which will be used for both the displayed\n\t\t * option and the value, or a 2D array which will use the array in the first\n\t\t * position as the value, and the array in the second position as the\n\t\t * displayed options (useful for language strings such as 'All').\n\t\t *\n\t\t * Note that the `pageLength` property will be automatically set to the\n\t\t * first value given in this array, unless `pageLength` is also provided.\n\t\t *  @type array\n\t\t *  @default [ 10, 25, 50, 100 ]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.lengthMenu\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthMenu\": [[10, 25, 50, -1], [10, 25, 50, \"All\"]]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aLengthMenu\": [ 10, 25, 50, 100 ],\n\t\n\t\n\t\t/**\n\t\t * The `columns` option in the initialisation parameter allows you to define\n\t\t * details about the way individual columns behave. For a full list of\n\t\t * column options that can be set, please see\n\t\t * {@link DataTable.defaults.column}. Note that if you use `columns` to\n\t\t * define your columns, you must have an entry in the array for every single\n\t\t * column that you have in your table (these can be null if you don't which\n\t\t * to specify any options).\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.column\n\t\t */\n\t\t\"aoColumns\": null,\n\t\n\t\t/**\n\t\t * Very similar to `columns`, `columnDefs` allows you to target a specific\n\t\t * column, multiple columns, or all columns, using the `targets` property of\n\t\t * each object in the array. This allows great flexibility when creating\n\t\t * tables, as the `columnDefs` arrays can be of any length, targeting the\n\t\t * columns you specifically want. `columnDefs` may use any of the column\n\t\t * options available: {@link DataTable.defaults.column}, but it _must_\n\t\t * have `targets` defined in each object in the array. Values in the `targets`\n\t\t * array may be:\n\t\t *   <ul>\n\t\t *     <li>a string - class name will be matched on the TH for the column</li>\n\t\t *     <li>0 or a positive integer - column index counting from the left</li>\n\t\t *     <li>a negative integer - column index counting from the right</li>\n\t\t *     <li>the string \"_all\" - all columns (i.e. assign a default)</li>\n\t\t *   </ul>\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.columnDefs\n\t\t */\n\t\t\"aoColumnDefs\": null,\n\t\n\t\n\t\t/**\n\t\t * Basically the same as `search`, this parameter defines the individual column\n\t\t * filtering state at initialisation time. The array must be of the same size\n\t\t * as the number of columns, and each element be an object with the parameters\n\t\t * `search` and `escapeRegex` (the latter is optional). 'null' is also\n\t\t * accepted and the default will be used.\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.searchCols\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchCols\": [\n\t\t *          null,\n\t\t *          { \"search\": \"My filter\" },\n\t\t *          null,\n\t\t *          { \"search\": \"^[0-9]\", \"escapeRegex\": false }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aoSearchCols\": [],\n\t\n\t\n\t\t/**\n\t\t * An array of CSS classes that should be applied to displayed rows. This\n\t\t * array may be of any length, and DataTables will apply each class\n\t\t * sequentially, looping when required.\n\t\t *  @type array\n\t\t *  @default null <i>Will take the values determined by the `oClasses.stripe*`\n\t\t *    options</i>\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.stripeClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stripeClasses\": [ 'strip1', 'strip2', 'strip3' ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable automatic column width calculation. This can be disabled\n\t\t * as an optimisation (it takes some time to calculate the widths) if the\n\t\t * tables widths are passed in using `columns`.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.autoWidth\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"autoWidth\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bAutoWidth\": true,\n\t\n\t\n\t\t/**\n\t\t * Deferred rendering can provide DataTables with a huge speed boost when you\n\t\t * are using an Ajax or JS data source for the table. This option, when set to\n\t\t * true, will cause DataTables to defer the creation of the table elements for\n\t\t * each row until they are needed for a draw - saving a significant amount of\n\t\t * time.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.deferRender\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajax\": \"sources/arrays.txt\",\n\t\t *        \"deferRender\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDeferRender\": false,\n\t\n\t\n\t\t/**\n\t\t * Replace a DataTable which matches the given selector and replace it with\n\t\t * one which has the properties of the new initialisation object passed. If no\n\t\t * table matches the selector, then the new DataTable will be constructed as\n\t\t * per normal.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.destroy\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"srollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      // Some time later....\n\t\t *      $('#example').dataTable( {\n\t\t *        \"filter\": false,\n\t\t *        \"destroy\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDestroy\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering of data. Filtering in DataTables is \"smart\" in\n\t\t * that it allows the end user to input multiple words (space separated) and\n\t\t * will match a row containing those words, even if not in the order that was\n\t\t * specified (this allow matching across multiple columns). Note that if you\n\t\t * wish to use filtering in DataTables this must remain 'true' - to remove the\n\t\t * default filtering input box and retain filtering abilities, please use\n\t\t * {@link DataTable.defaults.dom}.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.searching\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searching\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bFilter\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the table information display. This shows information\n\t\t * about the data that is currently visible on the page, including information\n\t\t * about filtered data if that action is being performed.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.info\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"info\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bInfo\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some\n\t\t * slightly different and additional mark-up from what DataTables has\n\t\t * traditionally used).\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.jQueryUI\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"jQueryUI\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bJQueryUI\": false,\n\t\n\t\n\t\t/**\n\t\t * Allows the end user to select the size of a formatted page from a select\n\t\t * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.lengthChange\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthChange\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bLengthChange\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable pagination.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.paging\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"paging\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bPaginate\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of a 'processing' indicator when the table is\n\t\t * being processed (e.g. a sort). This is particularly useful for tables with\n\t\t * large amounts of data where it can take a noticeable amount of time to sort\n\t\t * the entries.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.processing\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"processing\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bProcessing\": false,\n\t\n\t\n\t\t/**\n\t\t * Retrieve the DataTables object for the given selector. Note that if the\n\t\t * table has already been initialised, this parameter will cause DataTables\n\t\t * to simply return the object that has already been set up - it will not take\n\t\t * account of any changes you might have made to the initialisation object\n\t\t * passed to DataTables (setting this parameter to true is an acknowledgement\n\t\t * that you understand this). `destroy` can be used to reinitialise a table if\n\t\t * you need.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.retrieve\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      initTable();\n\t\t *      tableActions();\n\t\t *    } );\n\t\t *\n\t\t *    function initTable ()\n\t\t *    {\n\t\t *      return $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false,\n\t\t *        \"retrieve\": true\n\t\t *      } );\n\t\t *    }\n\t\t *\n\t\t *    function tableActions ()\n\t\t *    {\n\t\t *      var table = initTable();\n\t\t *      // perform API operations with oTable\n\t\t *    }\n\t\t */\n\t\t\"bRetrieve\": false,\n\t\n\t\n\t\t/**\n\t\t * When vertical (y) scrolling is enabled, DataTables will force the height of\n\t\t * the table's viewport to the given height at all times (useful for layout).\n\t\t * However, this can look odd when filtering data down to a small data set,\n\t\t * and the footer is left \"floating\" further down. This parameter (when\n\t\t * enabled) will cause DataTables to collapse the table's viewport down when\n\t\t * the result set will fit within the given Y height.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollCollapse\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200\",\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bScrollCollapse\": false,\n\t\n\t\n\t\t/**\n\t\t * Configure DataTables to use server-side processing. Note that the\n\t\t * `ajax` parameter must also be given in order to give DataTables a\n\t\t * source to obtain the required data for each draw.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverSide\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"xhr.php\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bServerSide\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable sorting of columns. Sorting of individual columns can be\n\t\t * disabled by the `sortable` option for each column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.ordering\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ordering\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSort\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or display DataTables' ability to sort multiple columns at the\n\t\t * same time (activated by shift-click by the user).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderMulti\n\t\t *\n\t\t *  @example\n\t\t *    // Disable multiple column sorting ability\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderMulti\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortMulti\": true,\n\t\n\t\n\t\t/**\n\t\t * Allows control over whether DataTables should use the top (true) unique\n\t\t * cell that is found for a single column, or the bottom (false - default).\n\t\t * This is useful when using complex headers.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderCellsTop\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderCellsTop\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortCellsTop\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the addition of the classes `sorting\\_1`, `sorting\\_2` and\n\t\t * `sorting\\_3` to the columns which are currently being sorted on. This is\n\t\t * presented as a feature switch as it can increase processing time (while\n\t\t * classes are removed and added) so for large data sets you might want to\n\t\t * turn this off.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.orderClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderClasses\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortClasses\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable state saving. When enabled HTML5 `localStorage` will be\n\t\t * used to save table display information such as pagination information,\n\t\t * display length, filtering and sorting. As such when the end user reloads\n\t\t * the page the display display will match what thy had previously set up.\n\t\t *\n\t\t * Due to the use of `localStorage` the default state saving is not supported\n\t\t * in IE6 or 7. If state saving is required in those browsers, use\n\t\t * `stateSaveCallback` to provide a storage solution such as cookies.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.stateSave\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bStateSave\": false,\n\t\n\t\n\t\t/**\n\t\t * This function is called when a TR element is created (and all TD child\n\t\t * elements have been inserted), or registered if using a DOM source, allowing\n\t\t * manipulation of the TR element (adding classes etc).\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} dataIndex The index of this row in the internal aoData array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.createdRow\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"createdRow\": function( row, data, dataIndex ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" )\n\t\t *          {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedRow\": null,\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify any aspect you want about the created DOM.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.drawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"drawCallback\": function( settings ) {\n\t\t *          alert( 'DataTables has redrawn the table' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Identical to fnHeaderCallback() but for the table footer this function\n\t\t * allows you to modify the table footer on every 'draw' event.\n\t\t *  @type function\n\t\t *  @param {node} foot \"TR\" element for the footer\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.footerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"footerCallback\": function( tfoot, data, start, end, display ) {\n\t\t *          tfoot.getElementsByTagName('th')[0].innerHTML = \"Starting index is \"+start;\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnFooterCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * When rendering large numbers in the information element for the table\n\t\t * (i.e. \"Showing 1 to 10 of 57 entries\") DataTables will render large numbers\n\t\t * to have a comma separator for the 'thousands' units (e.g. 1 million is\n\t\t * rendered as \"1,000,000\") to help readability for the end user. This\n\t\t * function will override the default method DataTables uses.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {int} toFormat number to be formatted\n\t\t *  @returns {string} formatted string for DataTables to show the number\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.formatNumber\n\t\t *\n\t\t *  @example\n\t\t *    // Format a number using a single quote for the separator (note that\n\t\t *    // this can also be done with the language.thousands option)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"formatNumber\": function ( toFormat ) {\n\t\t *          return toFormat.toString().replace(\n\t\t *            /\\B(?=(\\d{3})+(?!\\d))/g, \"'\"\n\t\t *          );\n\t\t *        };\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnFormatNumber\": function ( toFormat ) {\n\t\t\treturn toFormat.toString().replace(\n\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g,\n\t\t\t\tthis.oLanguage.sThousands\n\t\t\t);\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify the header row. This can be used to calculate and\n\t\t * display useful information about the table.\n\t\t *  @type function\n\t\t *  @param {node} head \"TR\" element for the header\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.headerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"fheaderCallback\": function( head, data, start, end, display ) {\n\t\t *          head.getElementsByTagName('th')[0].innerHTML = \"Displaying \"+(end-start)+\" records\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnHeaderCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * The information element can be used to convey information about the current\n\t\t * state of the table. Although the internationalisation options presented by\n\t\t * DataTables are quite capable of dealing with most customisations, there may\n\t\t * be times where you wish to customise the string further. This callback\n\t\t * allows you to do exactly that.\n\t\t *  @type function\n\t\t *  @param {object} oSettings DataTables settings object\n\t\t *  @param {int} start Starting position in data for the draw\n\t\t *  @param {int} end End position in data for the draw\n\t\t *  @param {int} max Total number of rows in the table (regardless of\n\t\t *    filtering)\n\t\t *  @param {int} total Total number of rows in the data set, after filtering\n\t\t *  @param {string} pre The string that DataTables has formatted using it's\n\t\t *    own rules\n\t\t *  @returns {string} The string to be displayed in the information element.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.infoCallback\n\t\t *\n\t\t *  @example\n\t\t *    $('#example').dataTable( {\n\t\t *      \"infoCallback\": function( settings, start, end, max, total, pre ) {\n\t\t *        return start +\" to \"+ end;\n\t\t *      }\n\t\t *    } );\n\t\t */\n\t\t\"fnInfoCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Called when the table has been initialised. Normally DataTables will\n\t\t * initialise sequentially and there will be no need for this function,\n\t\t * however, this does not hold true when using external language information\n\t\t * since that is obtained using an async XHR call.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} json The JSON object request from the server - only\n\t\t *    present if client-side Ajax sourced data is used\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.initComplete\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"initComplete\": function(settings, json) {\n\t\t *          alert( 'DataTables has finished its initialisation.' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnInitComplete\": null,\n\t\n\t\n\t\t/**\n\t\t * Called at the very start of each table draw and can be used to cancel the\n\t\t * draw by returning false, any other return (including undefined) results in\n\t\t * the full draw occurring).\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @returns {boolean} False will cancel the draw, anything else (including no\n\t\t *    return) will allow it to complete.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.preDrawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"preDrawCallback\": function( settings ) {\n\t\t *          if ( $('#test').val() == 1 ) {\n\t\t *            return false;\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnPreDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * This function allows you to 'post process' each row after it have been\n\t\t * generated for each table draw, but before it is rendered on screen. This\n\t\t * function might be used for setting the row class name etc.\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} displayIndex The display index for the current table draw\n\t\t *  @param {int} displayIndexFull The index of the data in the full list of\n\t\t *    rows (after filtering)\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.rowCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"rowCallback\": function( row, data, displayIndex, displayIndexFull ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" ) {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnRowCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * This parameter allows you to override the default function which obtains\n\t\t * the data from the server so something more suitable for your application.\n\t\t * For example you could use POST data, or pull information from a Gears or\n\t\t * AIR database.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {string} source HTTP source to obtain the data from (`ajax`)\n\t\t *  @param {array} data A key/value pair object containing the data to send\n\t\t *    to the server\n\t\t *  @param {function} callback to be called on completion of the data get\n\t\t *    process that will draw the data on the page.\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverData\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t *  It is often useful to send extra data to the server when making an Ajax\n\t\t * request - for example custom filtering information, and this callback\n\t\t * function makes it trivial to send extra information to the server. The\n\t\t * passed in parameter is the data set that has been constructed by\n\t\t * DataTables, and you can add to this or modify it as you require.\n\t\t *  @type function\n\t\t *  @param {array} data Data array (array of objects which are name/value\n\t\t *    pairs) that has been constructed by DataTables and will be sent to the\n\t\t *    server. In the case of Ajax sourced data with server-side processing\n\t\t *    this will be an empty array, for server-side processing there will be a\n\t\t *    significant number of parameters!\n\t\t *  @returns {undefined} Ensure that you modify the data array passed in,\n\t\t *    as this is passed by reference.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverParams\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Load the table state. With this function you can define from where, and how, the\n\t\t * state of a table is loaded. By default DataTables will load from `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} callback Callback that can be executed when done. It\n\t\t *    should be passed the loaded state object.\n\t\t *  @return {object} The DataTables state object to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadCallback\": function (settings, callback) {\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_load\",\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"success\": function (json) {\n\t\t *              callback( json );\n\t\t *            }\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadCallback\": function ( settings ) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(\n\t\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(\n\t\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the saved state prior to loading that state.\n\t\t * This callback is called when the table is loading state from the stored data, but\n\t\t * prior to the settings object being modified by the saved state. Note that for\n\t\t * plug-in authors, you should use the `stateLoadParams` event to load parameters for\n\t\t * a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that is to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never loaded\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Disallow state loading by returning false\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          return false;\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Callback that is called when the state has been loaded from the state saving method\n\t\t * and the DataTables settings object has been modified as a result of the loaded state.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that was loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoaded\n\t\t *\n\t\t *  @example\n\t\t *    // Show an alert with the filtering value that was saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoaded\": function (settings, data) {\n\t\t *          alert( 'Saved filter was: '+data.oSearch.sSearch );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoaded\": null,\n\t\n\t\n\t\t/**\n\t\t * Save the table state. This function allows you to define where and how the state\n\t\t * information for the table is stored By default DataTables will use `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveCallback\": function (settings, data) {\n\t\t *          // Send an Ajax request to the server with the state object\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_save\",\n\t\t *            \"data\": data,\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"method\": \"POST\"\n\t\t *            \"success\": function () {}\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveCallback\": function ( settings, data ) {\n\t\t\ttry {\n\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(\n\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname,\n\t\t\t\t\tJSON.stringify( data )\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the state to be saved. Called when the table\n\t\t * has changed state a new state save is required. This method allows modification of\n\t\t * the state saving object prior to actually doing the save, including addition or\n\t\t * other state properties or modification. Note that for plug-in authors, you should\n\t\t * use the `stateSaveParams` event to save parameters for a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Duration for which the saved state information is considered valid. After this period\n\t\t * has elapsed the state will be returned to the default.\n\t\t * Value is given in seconds.\n\t\t *  @type int\n\t\t *  @default 7200 <i>(2 hours)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.stateDuration\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateDuration\": 60*60*24; // 1 day\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iStateDuration\": 7200,\n\t\n\t\n\t\t/**\n\t\t * When enabled DataTables will not make a request to the server for the first\n\t\t * page draw - rather it will use the data already on the page (no sorting etc\n\t\t * will be applied to it), thus saving on an XHR at load time. `deferLoading`\n\t\t * is used to indicate that deferred loading is required, but it is also used\n\t\t * to tell DataTables how many records there are in the full table (allowing\n\t\t * the information element and pagination to be displayed correctly). In the case\n\t\t * where a filtering is applied to the table on initial load, this can be\n\t\t * indicated by giving the parameter as an array, where the first element is\n\t\t * the number of records available after filtering and the second element is the\n\t\t * number of records without filtering (allowing the table information element\n\t\t * to be shown correctly).\n\t\t *  @type int | array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.deferLoading\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records available in the table, no filtering applied\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": 57\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records after filtering, 100 without filtering (an initial filter applied)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": [ 57, 100 ],\n\t\t *        \"search\": {\n\t\t *          \"search\": \"my_filter\"\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iDeferLoading\": null,\n\t\n\t\n\t\t/**\n\t\t * Number of rows to display on a single page when using pagination. If\n\t\t * feature enabled (`lengthChange`) then the end user will be able to override\n\t\t * this to a custom setting using a pop-up menu.\n\t\t *  @type int\n\t\t *  @default 10\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pageLength\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pageLength\": 50\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayLength\": 10,\n\t\n\t\n\t\t/**\n\t\t * Define the starting point for data display when using DataTables with\n\t\t * pagination. Note that this parameter is the number of records, rather than\n\t\t * the page number, so if you have 10 records per page and want to start on\n\t\t * the third page, it should be \"20\".\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.displayStart\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"displayStart\": 20\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayStart\": 0,\n\t\n\t\n\t\t/**\n\t\t * By default DataTables allows keyboard navigation of the table (sorting, paging,\n\t\t * and filtering) by adding a `tabindex` attribute to the required elements. This\n\t\t * allows you to tab through the controls and press the enter key to activate them.\n\t\t * The tabindex is default 0, meaning that the tab follows the flow of the document.\n\t\t * You can overrule this using this parameter if you wish. Use a value of -1 to\n\t\t * disable built-in keyboard navigation.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.tabIndex\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"tabIndex\": 1\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\n\t\t/**\n\t\t * Classes that DataTables assigns to the various components and features\n\t\t * that it adds to the HTML table. This allows classes to be configured\n\t\t * during initialisation in addition to through the static\n\t\t * {@link DataTable.ext.oStdClasses} object).\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.classes\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\n\t\t/**\n\t\t * All strings that DataTables uses in the user interface that it creates\n\t\t * are defined in this object, allowing you to modified them individually or\n\t\t * completely replace them all as required.\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.language\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Strings that are used for WAI-ARIA labels and controls only (these are not\n\t\t\t * actually visible on the page, but will be read by screenreaders, and thus\n\t\t\t * must be internationalised as well).\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.aria\n\t\t\t */\n\t\t\t\"oAria\": {\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted ascending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortAscending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortAscending\": \" - click/return to sort ascending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortAscending\": \": activate to sort column ascending\",\n\t\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted descending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortDescending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortDescending\": \" - click/return to sort descending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortDescending\": \": activate to sort column descending\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * Pagination string used by DataTables for the built-in pagination\n\t\t\t * control types.\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.paginate\n\t\t\t */\n\t\t\t\"oPaginate\": {\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the first page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default First\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.first\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"first\": \"First page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sFirst\": \"First\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the last page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Last\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.last\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"last\": \"Last page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sLast\": \"Last\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'next' pagination button (to take the user to the\n\t\t\t\t * next page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Next\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.next\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"next\": \"Next page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sNext\": \"Next\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'previous' pagination button (to take the user to\n\t\t\t\t * the previous page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Previous\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.previous\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"previous\": \"Previous page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sPrevious\": \"Previous\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * This string is shown in preference to `zeroRecords` when the table is\n\t\t\t * empty of data (regardless of filtering). Note that this is an optional\n\t\t\t * parameter - if it is not given, the value of `zeroRecords` will be used\n\t\t\t * instead (either the default or given value).\n\t\t\t *  @type string\n\t\t\t *  @default No data available in table\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.emptyTable\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"emptyTable\": \"No data available in table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sEmptyTable\": \"No data available in table\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This string gives information to the end user about the information\n\t\t\t * that is current on display on the page. The following tokens can be\n\t\t\t * used in the string and will be dynamically replaced as the table\n\t\t\t * display updates. This tokens can be placed anywhere in the string, or\n\t\t\t * removed as needed by the language requires:\n\t\t\t *\n\t\t\t * * `\\_START\\_` - Display index of the first record on the current page\n\t\t\t * * `\\_END\\_` - Display index of the last record on the current page\n\t\t\t * * `\\_TOTAL\\_` - Number of records in the table after filtering\n\t\t\t * * `\\_MAX\\_` - Number of records in the table without filtering\n\t\t\t * * `\\_PAGE\\_` - Current page number\n\t\t\t * * `\\_PAGES\\_` - Total number of pages of data in the table\n\t\t\t *\n\t\t\t *  @type string\n\t\t\t *  @default Showing _START_ to _END_ of _TOTAL_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.info\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"info\": \"Showing page _PAGE_ of _PAGES_\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfo\": \"Showing _START_ to _END_ of _TOTAL_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Display information string for when the table is empty. Typically the\n\t\t\t * format of this string should match `info`.\n\t\t\t *  @type string\n\t\t\t *  @default Showing 0 to 0 of 0 entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoEmpty\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoEmpty\": \"No entries to show\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoEmpty\": \"Showing 0 to 0 of 0 entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When a user filters the information in a table, this string is appended\n\t\t\t * to the information (`info`) to give an idea of how strong the filtering\n\t\t\t * is. The variable _MAX_ is dynamically updated.\n\t\t\t *  @type string\n\t\t\t *  @default (filtered from _MAX_ total entries)\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoFiltered\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoFiltered\": \" - filtering from _MAX_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoFiltered\": \"(filtered from _MAX_ total entries)\",\n\t\n\t\n\t\t\t/**\n\t\t\t * If can be useful to append extra information to the info string at times,\n\t\t\t * and this variable does exactly that. This information will be appended to\n\t\t\t * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are\n\t\t\t * being used) at all times.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoPostFix\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoPostFix\": \"All records shown are derived from real information.\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoPostFix\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This decimal place operator is a little different from the other\n\t\t\t * language options since DataTables doesn't output floating point\n\t\t\t * numbers, so it won't ever use this for display of a number. Rather,\n\t\t\t * what this parameter does is modify the sort methods of the table so\n\t\t\t * that numbers which are in a format which has a character other than\n\t\t\t * a period (`.`) as a decimal place will be sorted numerically.\n\t\t\t *\n\t\t\t * Note that numbers with different decimal places cannot be shown in\n\t\t\t * the same table and still be sortable, the table must be consistent.\n\t\t\t * However, multiple different tables on the page can use different\n\t\t\t * decimal place characters.\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.decimal\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"decimal\": \",\"\n\t\t\t *          \"thousands\": \".\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sDecimal\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * DataTables has a build in number formatter (`formatNumber`) which is\n\t\t\t * used to format large numbers that are used in the table information.\n\t\t\t * By default a comma is used, but this can be trivially changed to any\n\t\t\t * character you wish with this parameter.\n\t\t\t *  @type string\n\t\t\t *  @default ,\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.thousands\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"thousands\": \"'\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sThousands\": \",\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Detail the action that will be taken when the drop down menu for the\n\t\t\t * pagination length option is changed. The '_MENU_' variable is replaced\n\t\t\t * with a default select list of 10, 25, 50 and 100, and can be replaced\n\t\t\t * with a custom select box if required.\n\t\t\t *  @type string\n\t\t\t *  @default Show _MENU_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.lengthMenu\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language change only\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": \"Display _MENU_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language and options change\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": 'Display <select>'+\n\t\t\t *            '<option value=\"10\">10</option>'+\n\t\t\t *            '<option value=\"20\">20</option>'+\n\t\t\t *            '<option value=\"30\">30</option>'+\n\t\t\t *            '<option value=\"40\">40</option>'+\n\t\t\t *            '<option value=\"50\">50</option>'+\n\t\t\t *            '<option value=\"-1\">All</option>'+\n\t\t\t *            '</select> records'\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLengthMenu\": \"Show _MENU_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When using Ajax sourced data and during the first draw when DataTables is\n\t\t\t * gathering the data, this message is shown in an empty row in the table to\n\t\t\t * indicate to the end user the the data is being loaded. Note that this\n\t\t\t * parameter is not used when loading data by server-side processing, just\n\t\t\t * Ajax sourced data with client-side processing.\n\t\t\t *  @type string\n\t\t\t *  @default Loading...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.loadingRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"loadingRecords\": \"Please wait - loading...\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLoadingRecords\": \"Loading...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text which is displayed when the table is processing a user action\n\t\t\t * (usually a sort command or similar).\n\t\t\t *  @type string\n\t\t\t *  @default Processing...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.processing\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"processing\": \"DataTables is currently busy\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sProcessing\": \"Processing...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Details the actions that will be taken when the user types into the\n\t\t\t * filtering input text box. The variable \"_INPUT_\", if used in the string,\n\t\t\t * is replaced with the HTML text box for the filtering input allowing\n\t\t\t * control over where it appears in the string. If \"_INPUT_\" is not given\n\t\t\t * then the input box is appended to the string automatically.\n\t\t\t *  @type string\n\t\t\t *  @default Search:\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.search\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Input text box will be appended at the end automatically\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Filter records:\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Specify where the filter should appear\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Apply filter _INPUT_ to table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sSearch\": \"Search:\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Assign a `placeholder` attribute to the search `input` element\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.searchPlaceholder\n\t\t\t */\n\t\t\t\"sSearchPlaceholder\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * All of the language information can be stored in a file on the\n\t\t\t * server-side, which DataTables will look up if this parameter is passed.\n\t\t\t * It must store the URL of the language file, which is in a JSON format,\n\t\t\t * and the object has the same properties as the oLanguage object in the\n\t\t\t * initialiser object (i.e. the above parameters). Please refer to one of\n\t\t\t * the example language files to see how this works in action.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string - i.e. disabled</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.url\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"url\": \"http://www.sprymedia.co.uk/dataTables/lang.txt\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sUrl\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text shown inside the table records when the is no information to be\n\t\t\t * displayed after filtering. `emptyTable` is shown when there is simply no\n\t\t\t * information in the table at all (regardless of filtering).\n\t\t\t *  @type string\n\t\t\t *  @default No matching records found\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.zeroRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"zeroRecords\": \"No records to display\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sZeroRecords\": \"No matching records found\"\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to have define the global filtering state at\n\t\t * initialisation time. As an object the `search` parameter must be\n\t\t * defined, but all other parameters are optional. When `regex` is true,\n\t\t * the search string will be treated as a regular expression, when false\n\t\t * (default) it will be treated as a straight string. When `smart`\n\t\t * DataTables will use it's smart filtering methods (to word match at\n\t\t * any point in the data), when false this will not be done.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.search\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"search\": {\"search\": \"Initial search\"}\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"oSearch\": $.extend( {}, DataTable.models.oSearch ),\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * By default DataTables will look for the property `data` (or `aaData` for\n\t\t * compatibility with DataTables 1.9-) when obtaining data from an Ajax\n\t\t * source or for server-side processing - this parameter allows that\n\t\t * property to be changed. You can use Javascript dotted object notation to\n\t\t * get a data source for multiple levels of nesting.\n\t\t *  @type string\n\t\t *  @default data\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxDataProp\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxDataProp\": \"data\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * You can instruct DataTables to load data from an external\n\t\t * source using this parameter (use aData if you want to pass data in you\n\t\t * already have). Simply provide a url a JSON object can be obtained from.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxSource\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\n\t\t/**\n\t\t * This initialisation variable allows you to specify exactly where in the\n\t\t * DOM you want DataTables to inject the various controls it adds to the page\n\t\t * (for example you might want the pagination controls at the top of the\n\t\t * table). DIV elements (with or without a custom class) can also be added to\n\t\t * aid styling. The follow syntax is used:\n\t\t *   <ul>\n\t\t *     <li>The following options are allowed:\n\t\t *       <ul>\n\t\t *         <li>'l' - Length changing</li>\n\t\t *         <li>'f' - Filtering input</li>\n\t\t *         <li>'t' - The table!</li>\n\t\t *         <li>'i' - Information</li>\n\t\t *         <li>'p' - Pagination</li>\n\t\t *         <li>'r' - pRocessing</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following constants are allowed:\n\t\t *       <ul>\n\t\t *         <li>'H' - jQueryUI theme \"header\" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>\n\t\t *         <li>'F' - jQueryUI theme \"footer\" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following syntax is expected:\n\t\t *       <ul>\n\t\t *         <li>'&lt;' and '&gt;' - div elements</li>\n\t\t *         <li>'&lt;\"class\" and '&gt;' - div with a class</li>\n\t\t *         <li>'&lt;\"#id\" and '&gt;' - div with an ID</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>Examples:\n\t\t *       <ul>\n\t\t *         <li>'&lt;\"wrapper\"flipt&gt;'</li>\n\t\t *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *   </ul>\n\t\t *  @type string\n\t\t *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>\n\t\t *    <\"H\"lfr>t<\"F\"ip> <i>(when `jQueryUI` is true)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.dom\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"dom\": '&lt;\"top\"i&gt;rt&lt;\"bottom\"flp&gt;&lt;\"clear\"&gt;'\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDom\": \"lfrtip\",\n\t\n\t\n\t\t/**\n\t\t * Search delay option. This will throttle full table searches that use the\n\t\t * DataTables provided search input element (it does not effect calls to\n\t\t * `dt-api search()`, providing a delay before the search is made.\n\t\t *  @type integer\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.searchDelay\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchDelay\": 200\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\n\t\t/**\n\t\t * DataTables features six different built-in options for the buttons to\n\t\t * display for pagination control:\n\t\t *\n\t\t * * `numbers` - Page number buttons only\n\t\t * * `simple` - 'Previous' and 'Next' buttons only\n\t\t * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers\n\t\t * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons\n\t\t * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers\n\t\t * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers\n\t\t *  \n\t\t * Further methods can be added using {@link DataTable.ext.oPagination}.\n\t\t *  @type string\n\t\t *  @default simple_numbers\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pagingType\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pagingType\": \"full_numbers\"\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"sPaginationType\": \"simple_numbers\",\n\t\n\t\n\t\t/**\n\t\t * Enable horizontal scrolling. When a table is too wide to fit into a\n\t\t * certain layout, or you have a large number of columns in the table, you\n\t\t * can enable x-scrolling to show the table in a viewport, which can be\n\t\t * scrolled. This property can be `true` which will allow the table to\n\t\t * scroll horizontally when needed, or any CSS unit, or a number (in which\n\t\t * case it will be treated as a pixel measurement). Setting as simply `true`\n\t\t * is recommended.\n\t\t *  @type boolean|string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollX\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": true,\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollX\": \"\",\n\t\n\t\n\t\t/**\n\t\t * This property can be used to force a DataTable to use more width than it\n\t\t * might otherwise do when x-scrolling is enabled. For example if you have a\n\t\t * table which requires to be well spaced, this parameter is useful for\n\t\t * \"over-sizing\" the table, and thus forcing scrolling. This property can by\n\t\t * any CSS unit, or a number (in which case it will be treated as a pixel\n\t\t * measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollXInner\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": \"100%\",\n\t\t *        \"scrollXInner\": \"110%\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollXInner\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Enable vertical scrolling. Vertical scrolling will constrain the DataTable\n\t\t * to the given height, and enable scrolling for any data which overflows the\n\t\t * current viewport. This can be used as an alternative to paging to display\n\t\t * a lot of data in a small area (although paging and scrolling can both be\n\t\t * enabled at the same time). This property can be any CSS unit, or a number\n\t\t * (in which case it will be treated as a pixel measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollY\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollY\": \"\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * Set the HTTP method that is used to make the Ajax call for server-side\n\t\t * processing or Ajax sourced data.\n\t\t *  @type string\n\t\t *  @default GET\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverMethod\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sServerMethod\": \"GET\",\n\t\n\t\n\t\t/**\n\t\t * DataTables makes use of renderers when displaying HTML elements for\n\t\t * a table. These renderers can be added or modified by plug-ins to\n\t\t * generate suitable mark-up for a site. For example the Bootstrap\n\t\t * integration plug-in for DataTables uses a paging button renderer to\n\t\t * display pagination buttons in the mark-up required by Bootstrap.\n\t\t *\n\t\t * For further information about the renderers available see\n\t\t * DataTable.ext.renderer\n\t\t *  @type string|object\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.renderer\n\t\t *\n\t\t */\n\t\t\"renderer\": null,\n\t\n\t\n\t\t/**\n\t\t * Set the data property name that DataTables should use to get a row's id\n\t\t * to set as the `id` property in the node.\n\t\t *  @type string\n\t\t *  @default DT_RowId\n\t\t *\n\t\t *  @name DataTable.defaults.rowId\n\t\t */\n\t\t\"rowId\": \"DT_RowId\"\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults );\n\t\n\t\n\t\n\t/*\n\t * Developer note - See note in model.defaults.js about the use of Hungarian\n\t * notation and camel case.\n\t */\n\t\n\t/**\n\t * Column options that can be given to DataTables at initialisation time.\n\t *  @namespace\n\t */\n\tDataTable.defaults.column = {\n\t\t/**\n\t\t * Define which column(s) an order will occur on for this column. This\n\t\t * allows a column's ordering to take multiple columns into account when\n\t\t * doing a sort or use the data from a different column. For example first\n\t\t * name / last name columns make sense to do a multi-column sort over the\n\t\t * two columns.\n\t\t *  @type array|int\n\t\t *  @default null <i>Takes the value of the column index automatically</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderData\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderData\": [ 0, 1 ], \"targets\": [ 0 ] },\n\t\t *          { \"orderData\": [ 1, 0 ], \"targets\": [ 1 ] },\n\t\t *          { \"orderData\": 2, \"targets\": [ 2 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderData\": [ 0, 1 ] },\n\t\t *          { \"orderData\": [ 1, 0 ] },\n\t\t *          { \"orderData\": 2 },\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aDataSort\": null,\n\t\t\"iDataSort\": -1,\n\t\n\t\n\t\t/**\n\t\t * You can control the default ordering direction, and even alter the\n\t\t * behaviour of the sort handler (i.e. only allow ascending ordering etc)\n\t\t * using this parameter.\n\t\t *  @type array\n\t\t *  @default [ 'asc', 'desc' ]\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderSequence\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderSequence\": [ \"asc\" ], \"targets\": [ 1 ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ], \"targets\": [ 2 ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ], \"targets\": [ 3 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          { \"orderSequence\": [ \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ] },\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"asSorting\": [ 'asc', 'desc' ],\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering on the data in this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.searchable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"searchable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"searchable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSearchable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable ordering on this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.visible\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"visible\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"visible\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bVisible\": true,\n\t\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} td The TD node that has been created\n\t\t *  @param {*} cellData The Data for the cell\n\t\t *  @param {array|object} rowData The data for the whole row\n\t\t *  @param {int} row The row index for the aoData data store\n\t\t *  @param {int} col The column index for aoColumns\n\t\t *\n\t\t *  @name DataTable.defaults.column.createdCell\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [3],\n\t\t *          \"createdCell\": function (td, cellData, rowData, row, col) {\n\t\t *            if ( cellData == \"1.7\" ) {\n\t\t *              $(td).css('color', 'blue')\n\t\t *            }\n\t\t *          }\n\t\t *        } ]\n\t\t *      });\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter has been replaced by `data` in DataTables to ensure naming\n\t\t * consistency. `dataProp` can still be used, as there is backwards\n\t\t * compatibility in DataTables for this option, but it is strongly\n\t\t * recommended that you use `data` in preference to `dataProp`.\n\t\t *  @name DataTable.defaults.column.dataProp\n\t\t */\n\t\n\t\n\t\t/**\n\t\t * This property can be used to read data from any data source property,\n\t\t * including deeply nested objects / properties. `data` can be given in a\n\t\t * number of different ways which effect its behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object. Note that\n\t\t *      function notation is recommended for use in `render` rather than\n\t\t *      `data` as it is much simpler to use as a renderer.\n\t\t * * `null` - use the original data source for the row rather than plucking\n\t\t *   data directly from it. This action has effects on two other\n\t\t *   initialisation options:\n\t\t *    * `defaultContent` - When null is given as the `data` option and\n\t\t *      `defaultContent` is specified for the column, the value defined by\n\t\t *      `defaultContent` will be used for the cell.\n\t\t *    * `render` - When null is used for the `data` option and the `render`\n\t\t *      option is specified for the column, the whole data source for the\n\t\t *      row is used for the renderer.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * `{array|object}` The data source for the row\n\t\t *      * `{string}` The type call data requested - this will be 'set' when\n\t\t *        setting data or 'filter', 'display', 'type', 'sort' or undefined\n\t\t *        when gathering data. Note that when `undefined` is given for the\n\t\t *        type DataTables expects to get the raw data for the object back<\n\t\t *      * `{*}` Data to set when the second parameter is 'set'.\n\t\t *    * Return:\n\t\t *      * The return value from the function is not required when 'set' is\n\t\t *        the type of call, but otherwise the return is what will be used\n\t\t *        for the data requested.\n\t\t *\n\t\t * Note that `data` is a getter and setter option. If you just require\n\t\t * formatting of data for output, you will likely want to use `render` which\n\t\t * is simply a getter and thus simpler to use.\n\t\t *\n\t\t * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The\n\t\t * name change reflects the flexibility of this property and is consistent\n\t\t * with the naming of mRender. If 'mDataProp' is given, then it will still\n\t\t * be used by DataTables, as it automatically maps the old name to the new\n\t\t * if required.\n\t\t *\n\t\t *  @type string|int|function|null\n\t\t *  @default null <i>Use automatically calculated column index</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.data\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Read table data from objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {value},\n\t\t *    //      \"version\": {value},\n\t\t *    //      \"grade\": {value}\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/objects.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform\" },\n\t\t *          { \"data\": \"version\" },\n\t\t *          { \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Read information from deeply nested objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {\n\t\t *    //         \"inner\": {value}\n\t\t *    //      },\n\t\t *    //      \"details\": [\n\t\t *    //         {value}, {value}\n\t\t *    //      ]\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform.inner\" },\n\t\t *          { \"data\": \"platform.details.0\" },\n\t\t *          { \"data\": \"platform.details.1\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `data` as a function to provide different information for\n\t\t *    // sorting, filtering and display. In this case, currency (price)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": function ( source, type, val ) {\n\t\t *            if (type === 'set') {\n\t\t *              source.price = val;\n\t\t *              // Store the computed dislay and filter values for efficiency\n\t\t *              source.price_display = val==\"\" ? \"\" : \"$\"+numberFormat(val);\n\t\t *              source.price_filter  = val==\"\" ? \"\" : \"$\"+numberFormat(val)+\" \"+val;\n\t\t *              return;\n\t\t *            }\n\t\t *            else if (type === 'display') {\n\t\t *              return source.price_display;\n\t\t *            }\n\t\t *            else if (type === 'filter') {\n\t\t *              return source.price_filter;\n\t\t *            }\n\t\t *            // 'sort', 'type' and undefined all just use the integer\n\t\t *            return source.price;\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using default content\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null,\n\t\t *          \"defaultContent\": \"Click to edit\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using array notation - outputting a list from an array\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"name[, ]\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\n\t\t/**\n\t\t * This property is the rendering partner to `data` and it is suggested that\n\t\t * when you want to manipulate data for display (including filtering,\n\t\t * sorting etc) without altering the underlying data for the table, use this\n\t\t * property. `render` can be considered to be the the read only companion to\n\t\t * `data` which is read / write (then as such more complex). Like `data`\n\t\t * this option can be given in a number of different ways to effect its\n\t\t * behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object.\n\t\t * * `object` - use different data for the different data types requested by\n\t\t *   DataTables ('filter', 'display', 'type' or 'sort'). The property names\n\t\t *   of the object is the data type the property refers to and the value can\n\t\t *   defined using an integer, string or function using the same rules as\n\t\t *   `render` normally does. Note that an `_` option _must_ be specified.\n\t\t *   This is the default value to use if you haven't specified a value for\n\t\t *   the data type requested by DataTables.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * {array|object} The data source for the row (based on `data`)\n\t\t *      * {string} The type call data requested - this will be 'filter',\n\t\t *        'display', 'type' or 'sort'.\n\t\t *      * {array|object} The full data source for the row (not based on\n\t\t *        `data`)\n\t\t *    * Return:\n\t\t *      * The return value from the function is what will be used for the\n\t\t *        data requested.\n\t\t *\n\t\t *  @type string|int|function|object|null\n\t\t *  @default null Use the data source value.\n\t\t *\n\t\t *  @name DataTable.defaults.column.render\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Create a comma separated list from an array of objects\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          {\n\t\t *            \"data\": \"platform\",\n\t\t *            \"render\": \"[, ].name\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Execute a function to obtain data\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": \"browserName()\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // As an object, extracting different data for the different types\n\t\t *    // This would be used with a data source such as:\n\t\t *    //   { \"phone\": 5552368, \"phone_filter\": \"5552368 555-2368\", \"phone_display\": \"555-2368\" }\n\t\t *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`\n\t\t *    // (which has both forms) is used for filtering for if a user inputs either format, while\n\t\t *    // the formatted phone number is the one that is shown in the table.\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": {\n\t\t *            \"_\": \"phone\",\n\t\t *            \"filter\": \"phone_filter\",\n\t\t *            \"display\": \"phone_display\"\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Use as a function to create a link from the data source\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"download_link\",\n\t\t *          \"render\": function ( data, type, full ) {\n\t\t *            return '<a href=\"'+data+'\">Download</a>';\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\n\t\t/**\n\t\t * Change the cell type created for the column - either TD cells or TH cells. This\n\t\t * can be useful as TH cells have semantic meaning in the table body, allowing them\n\t\t * to act as a header for a row (you may wish to add scope='row' to the TH elements).\n\t\t *  @type string\n\t\t *  @default td\n\t\t *\n\t\t *  @name DataTable.defaults.column.cellType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Make the first column use TH cells\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"cellType\": \"th\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sCellType\": \"td\",\n\t\n\t\n\t\t/**\n\t\t * Class to give to each cell in this column.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.class\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"class\": \"my_class\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"class\": \"my_class\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sClass\": \"\",\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t * Generally you shouldn't need this!\n\t\t *  @type string\n\t\t *  @default <i>Empty string<i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.contentPadding\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"contentPadding\": \"mmm\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sContentPadding\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because `data`\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.column.defaultContent\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\",\n\t\t *            \"targets\": [ -1 ]\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter is only used in DataTables' server-side processing. It can\n\t\t * be exceptionally useful to know what columns are being displayed on the\n\t\t * client side, and to map these to database fields. When defined, the names\n\t\t * also allow DataTables to reorder information from the server if it comes\n\t\t * back in an unexpected order (i.e. if you switch your columns around on the\n\t\t * client-side, your server-side code does not also need updating).\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.name\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"name\": \"engine\", \"targets\": [ 0 ] },\n\t\t *          { \"name\": \"browser\", \"targets\": [ 1 ] },\n\t\t *          { \"name\": \"platform\", \"targets\": [ 2 ] },\n\t\t *          { \"name\": \"version\", \"targets\": [ 3 ] },\n\t\t *          { \"name\": \"grade\", \"targets\": [ 4 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"name\": \"engine\" },\n\t\t *          { \"name\": \"browser\" },\n\t\t *          { \"name\": \"platform\" },\n\t\t *          { \"name\": \"version\" },\n\t\t *          { \"name\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sName\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Defines a data source type for the ordering which can be used to read\n\t\t * real-time information from the table (updating the internally cached\n\t\t * version) prior to ordering. This allows ordering to occur on user\n\t\t * editable elements such as form inputs.\n\t\t *  @type string\n\t\t *  @default std\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderDataType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderDataType\": \"dom-text\", \"targets\": [ 2, 3 ] },\n\t\t *          { \"type\": \"numeric\", \"targets\": [ 3 ] },\n\t\t *          { \"orderDataType\": \"dom-select\", \"targets\": [ 4 ] },\n\t\t *          { \"orderDataType\": \"dom-checkbox\", \"targets\": [ 5 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          { \"orderDataType\": \"dom-text\" },\n\t\t *          { \"orderDataType\": \"dom-text\", \"type\": \"numeric\" },\n\t\t *          { \"orderDataType\": \"dom-select\" },\n\t\t *          { \"orderDataType\": \"dom-checkbox\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sSortDataType\": \"std\",\n\t\n\t\n\t\t/**\n\t\t * The title of this column.\n\t\t *  @type string\n\t\t *  @default null <i>Derived from the 'TH' value for this column in the\n\t\t *    original HTML table.</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.title\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"title\": \"My column title\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"My column title\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\n\t\t/**\n\t\t * The type allows you to specify how the data for this column will be\n\t\t * ordered. Four types (string, numeric, date and html (which will strip\n\t\t * HTML tags before ordering)) are currently available. Note that only date\n\t\t * formats understood by Javascript's Date() object will be accepted as type\n\t\t * date. For example: \"Mar 26, 2008 5:03 PM\". May take the values: 'string',\n\t\t * 'numeric', 'date' or 'html' (by default). Further types can be adding\n\t\t * through plug-ins.\n\t\t *  @type string\n\t\t *  @default null <i>Auto-detected from raw data</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.type\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"type\": \"html\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"type\": \"html\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\n\t\t/**\n\t\t * Defining the width of the column, this parameter may take any CSS value\n\t\t * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not\n\t\t * been given a specific width through this interface ensuring that the table\n\t\t * remains readable.\n\t\t *  @type string\n\t\t *  @default null <i>Automatic</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.width\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"width\": \"20%\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"width\": \"20%\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sWidth\": null\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults.column );\n\t\n\t\n\t\n\t/**\n\t * DataTables settings object - this holds all the information needed for a\n\t * given table, including configuration, data and current application of the\n\t * table options. DataTables does not have a single instance for each DataTable\n\t * with the settings attached to that instance, but rather instances of the\n\t * DataTable \"class\" are created on-the-fly as needed (typically by a\n\t * $().dataTable() call) and the settings object is then applied to that\n\t * instance.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults} but this\n\t * one is the internal data store for DataTables's cache of columns. It should\n\t * NOT be manipulated outside of DataTables. Any configuration should be done\n\t * through the initialisation options.\n\t *  @namespace\n\t *  @todo Really should attach the settings object to individual instances so we\n\t *    don't need to create new instances on each $().dataTable() call (if the\n\t *    table already exists). It would also save passing oSettings around and\n\t *    into every single function. However, this is a very significant\n\t *    architecture change for DataTables and will almost certainly break\n\t *    backwards compatibility with older installations. This is something that\n\t *    will be done in 2.0.\n\t */\n\tDataTable.models.oSettings = {\n\t\t/**\n\t\t * Primary features of DataTables and their enablement state.\n\t\t *  @namespace\n\t\t */\n\t\t\"oFeatures\": {\n\t\n\t\t\t/**\n\t\t\t * Flag to say if DataTables should automatically try to calculate the\n\t\t\t * optimum table and columns widths (true) or not (false).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bAutoWidth\": null,\n\t\n\t\t\t/**\n\t\t\t * Delay the creation of TR and TD elements until they are actually\n\t\t\t * needed by a driven page draw. This can give a significant speed\n\t\t\t * increase for Ajax source and Javascript source data, but makes no\n\t\t\t * difference at all fro DOM and server-side processing tables.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bDeferRender\": null,\n\t\n\t\t\t/**\n\t\t\t * Enable filtering on the table or not. Note that if this is disabled\n\t\t\t * then there is no filtering at all on the table, including fnFilter.\n\t\t\t * To just remove the filtering input use sDom and remove the 'f' option.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bFilter\": null,\n\t\n\t\t\t/**\n\t\t\t * Table information element (the 'Showing x of y records' div) enable\n\t\t\t * flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bInfo\": null,\n\t\n\t\t\t/**\n\t\t\t * Present a user control allowing the end user to change the page size\n\t\t\t * when pagination is enabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bLengthChange\": null,\n\t\n\t\t\t/**\n\t\t\t * Pagination enabled or not. Note that if this is disabled then length\n\t\t\t * changing must also be disabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bPaginate\": null,\n\t\n\t\t\t/**\n\t\t\t * Processing indicator enable flag whenever DataTables is enacting a\n\t\t\t * user request - typically an Ajax request for server-side processing.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bProcessing\": null,\n\t\n\t\t\t/**\n\t\t\t * Server-side processing enabled flag - when enabled DataTables will\n\t\t\t * get all data from the server for every draw - there is no filtering,\n\t\t\t * sorting or paging done on the client-side.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bServerSide\": null,\n\t\n\t\t\t/**\n\t\t\t * Sorting enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSort\": null,\n\t\n\t\t\t/**\n\t\t\t * Multi-column sorting\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortMulti\": null,\n\t\n\t\t\t/**\n\t\t\t * Apply a class to the columns which are being sorted to provide a\n\t\t\t * visual highlight or not. This can slow things down when enabled since\n\t\t\t * there is a lot of DOM interaction.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortClasses\": null,\n\t\n\t\t\t/**\n\t\t\t * State saving enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bStateSave\": null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Scrolling settings for a table.\n\t\t *  @namespace\n\t\t */\n\t\t\"oScroll\": {\n\t\t\t/**\n\t\t\t * When the table is shorter in height than sScrollY, collapse the\n\t\t\t * table container down to the height of the table (when true).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bCollapse\": null,\n\t\n\t\t\t/**\n\t\t\t * Width of the scrollbar for the web-browser's platform. Calculated\n\t\t\t * during table initialisation.\n\t\t\t *  @type int\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"iBarWidth\": 0,\n\t\n\t\t\t/**\n\t\t\t * Viewport width for horizontal scrolling. Horizontal scrolling is\n\t\t\t * disabled if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sX\": null,\n\t\n\t\t\t/**\n\t\t\t * Width to expand the table to when using x-scrolling. Typically you\n\t\t\t * should not need to use this.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t *  @deprecated\n\t\t\t */\n\t\t\t\"sXInner\": null,\n\t\n\t\t\t/**\n\t\t\t * Viewport height for vertical scrolling. Vertical scrolling is disabled\n\t\t\t * if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sY\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Language information for the table.\n\t\t *  @namespace\n\t\t *  @extends DataTable.defaults.oLanguage\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Information callback function. See\n\t\t\t * {@link DataTable.defaults.fnInfoCallback}\n\t\t\t *  @type function\n\t\t\t *  @default null\n\t\t\t */\n\t\t\t\"fnInfoCallback\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Browser support parameters\n\t\t *  @namespace\n\t\t */\n\t\t\"oBrowser\": {\n\t\t\t/**\n\t\t\t * Indicate if the browser incorrectly calculates width:100% inside a\n\t\t\t * scrolling element (IE6/7)\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollOversize\": false,\n\t\n\t\t\t/**\n\t\t\t * Determine if the vertical scrollbar is on the right or left of the\n\t\t\t * scrolling container - needed for rtl language layout, although not\n\t\t\t * all browsers move the scrollbar (Safari).\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollbarLeft\": false,\n\t\n\t\t\t/**\n\t\t\t * Flag for if `getBoundingClientRect` is fully supported or not\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bBounding\": false,\n\t\n\t\t\t/**\n\t\t\t * Browser scrollbar width\n\t\t\t *  @type integer\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"barWidth\": 0\n\t\t},\n\t\n\t\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * Array referencing the nodes which are used for the features. The\n\t\t * parameters of this object match what is allowed by sDom - i.e.\n\t\t *   <ul>\n\t\t *     <li>'l' - Length changing</li>\n\t\t *     <li>'f' - Filtering input</li>\n\t\t *     <li>'t' - The table!</li>\n\t\t *     <li>'i' - Information</li>\n\t\t *     <li>'p' - Pagination</li>\n\t\t *     <li>'r' - pRocessing</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aanFeatures\": [],\n\t\n\t\t/**\n\t\t * Store data information - see {@link DataTable.models.oRow} for detailed\n\t\t * information.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoData\": [],\n\t\n\t\t/**\n\t\t * Array of indexes which are in the current display (after filtering etc)\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplay\": [],\n\t\n\t\t/**\n\t\t * Array of indexes for display - no filtering\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplayMaster\": [],\n\t\n\t\t/**\n\t\t * Map of row ids to data indexes\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"aIds\": {},\n\t\n\t\t/**\n\t\t * Store information about each column that is in use\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoColumns\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's header\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeader\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's footer\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooter\": [],\n\t\n\t\t/**\n\t\t * Store the applied global search information in case we want to force a\n\t\t * research or compare the old search to a new one.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t */\n\t\t\"oPreviousSearch\": {},\n\t\n\t\t/**\n\t\t * Store the applied search for each column - see\n\t\t * {@link DataTable.models.oSearch} for the format that is used for the\n\t\t * filtering information for each column.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreSearchCols\": [],\n\t\n\t\t/**\n\t\t * Sorting that is applied to the table. Note that the inner arrays are\n\t\t * used in the following manner:\n\t\t * <ul>\n\t\t *   <li>Index 0 - column number</li>\n\t\t *   <li>Index 1 - current sorting direction</li>\n\t\t * </ul>\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @todo These inner arrays should really be objects\n\t\t */\n\t\t\"aaSorting\": null,\n\t\n\t\t/**\n\t\t * Sorting that is always applied to the table (i.e. prefixed in front of\n\t\t * aaSorting).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\t/**\n\t\t * Classes to use for the striping of a table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its striping classes as well\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asDestroyStripes\": [],\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its width\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"sDestroyWidth\": 0,\n\t\n\t\t/**\n\t\t * Callback functions array for every time a row is inserted (i.e. on a draw).\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for the header on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeaderCallback\": [],\n\t\n\t\t/**\n\t\t * Callback function for the footer on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooterCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for draw callback functions\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for row created function\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCreatedCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for just before the table is redrawn. A return of\n\t\t * false will be used to cancel the draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for when the table has been initialised.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoInitComplete\": [],\n\t\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings to be stored for state saving, prior to\n\t\t * saving state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSaveParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings that have been stored for state saving\n\t\t * prior to using the stored values to restore the state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoadParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for operating on the settings object once the saved state has been\n\t\t * loaded\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoaded\": [],\n\t\n\t\t/**\n\t\t * Cache the table ID for quick access\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sTableId\": \"\",\n\t\n\t\t/**\n\t\t * The TABLE node for the main table\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTable\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the thead element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTHead\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tfoot element - if it exists\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTFoot\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tbody element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTBody\": null,\n\t\n\t\t/**\n\t\t * Cache the wrapper node (contains all DataTables controlled elements)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTableWrapper\": null,\n\t\n\t\t/**\n\t\t * Indicate if when using server-side processing the loading of data\n\t\t * should be deferred until the second draw.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDeferLoading\": false,\n\t\n\t\t/**\n\t\t * Indicate if all required information has been read in\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bInitialised\": false,\n\t\n\t\t/**\n\t\t * Information about open rows. Each object in the array has the parameters\n\t\t * 'nTr' and 'nParent'\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoOpenRows\": [],\n\t\n\t\t/**\n\t\t * Dictate the positioning of DataTables' control elements - see\n\t\t * {@link DataTable.model.oInit.sDom}.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDom\": null,\n\t\n\t\t/**\n\t\t * Search delay (in mS)\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\t/**\n\t\t * Which type of pagination should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default two_button\n\t\t */\n\t\t\"sPaginationType\": \"two_button\",\n\t\n\t\t/**\n\t\t * The state duration (for `stateSave`) in seconds.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iStateDuration\": 0,\n\t\n\t\t/**\n\t\t * Array of callback functions for state saving. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the JSON string to save that has been thus far created. Returns\n\t\t *       a JSON string to be inserted into a json object\n\t\t *       (i.e. '\"param\": [ 0, 1, 2]')</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSave\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for state loading. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the object stored. May return false to cancel state loading</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoad\": [],\n\t\n\t\t/**\n\t\t * State that was saved. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oSavedState\": null,\n\t\n\t\t/**\n\t\t * State that was loaded. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oLoadedState\": null,\n\t\n\t\t/**\n\t\t * Source url for AJAX data for the table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\t/**\n\t\t * Property from a given object from which to read the table data from. This\n\t\t * can be an empty string (when not server-side processing), in which case\n\t\t * it is  assumed an an array is given directly.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sAjaxDataProp\": null,\n\t\n\t\t/**\n\t\t * Note if draw should be blocked while getting data\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bAjaxDataGet\": true,\n\t\n\t\t/**\n\t\t * The last jQuery XHR object that was used for server-side data gathering.\n\t\t * This can be used for working with the XHR information in one of the\n\t\t * callbacks\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"jqXHR\": null,\n\t\n\t\t/**\n\t\t * JSON returned from the server in the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"json\": undefined,\n\t\n\t\t/**\n\t\t * Data submitted as part of the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"oAjaxData\": undefined,\n\t\n\t\t/**\n\t\t * Function to get the server-side data.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\t/**\n\t\t * Functions which are called prior to sending an Ajax request so extra\n\t\t * parameters can easily be sent to the server\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoServerParams\": [],\n\t\n\t\t/**\n\t\t * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if\n\t\t * required).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sServerMethod\": null,\n\t\n\t\t/**\n\t\t * Format numbers for display.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnFormatNumber\": null,\n\t\n\t\t/**\n\t\t * List of options that can be used for the user selectable length menu.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLengthMenu\": null,\n\t\n\t\t/**\n\t\t * Counter for the draws that the table does. Also used as a tracker for\n\t\t * server-side processing\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iDraw\": 0,\n\t\n\t\t/**\n\t\t * Indicate if a redraw is being done - useful for Ajax\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDrawing\": false,\n\t\n\t\t/**\n\t\t * Draw index (iDraw) of the last error when parsing the returned data\n\t\t *  @type int\n\t\t *  @default -1\n\t\t */\n\t\t\"iDrawError\": -1,\n\t\n\t\t/**\n\t\t * Paging display length\n\t\t *  @type int\n\t\t *  @default 10\n\t\t */\n\t\t\"_iDisplayLength\": 10,\n\t\n\t\t/**\n\t\t * Paging start point - aiDisplay index\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"_iDisplayStart\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the result set\n\t\t * (i.e. before filtering), Use fnRecordsTotal rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsTotal\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the current display set\n\t\t * (i.e. after filtering). Use fnRecordsDisplay rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type boolean\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsDisplay\": 0,\n\t\n\t\t/**\n\t\t * Flag to indicate if jQuery UI marking and classes should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bJUI\": null,\n\t\n\t\t/**\n\t\t * The classes to use for the table\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if filtering has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bFiltered\": false,\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if sorting has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bSorted\": false,\n\t\n\t\t/**\n\t\t * Indicate that if multiple rows are in the header and there is more than\n\t\t * one unique cell per column, if the top one (true) or bottom one (false)\n\t\t * should be used for sorting / title by DataTables.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortCellsTop\": null,\n\t\n\t\t/**\n\t\t * Initialisation object that is used for the table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInit\": null,\n\t\n\t\t/**\n\t\t * Destroy callback functions - for plug-ins to attach themselves to the\n\t\t * destroy so they can clean up markup and events.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDestroyCallback\": [],\n\t\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, before filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsTotal\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsTotal * 1 :\n\t\t\t\tthis.aiDisplayMaster.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, after filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsDisplay\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsDisplay * 1 :\n\t\t\t\tthis.aiDisplay.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the display end point - aiDisplay index\n\t\t *  @type function\n\t\t */\n\t\t\"fnDisplayEnd\": function ()\n\t\t{\n\t\t\tvar\n\t\t\t\tlen      = this._iDisplayLength,\n\t\t\t\tstart    = this._iDisplayStart,\n\t\t\t\tcalc     = start + len,\n\t\t\t\trecords  = this.aiDisplay.length,\n\t\t\t\tfeatures = this.oFeatures,\n\t\t\t\tpaginate = features.bPaginate;\n\t\n\t\t\tif ( features.bServerSide ) {\n\t\t\t\treturn paginate === false || len === -1 ?\n\t\t\t\t\tstart + records :\n\t\t\t\t\tMath.min( start+len, this._iRecordsDisplay );\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn ! paginate || calc>records || len===-1 ?\n\t\t\t\t\trecords :\n\t\t\t\t\tcalc;\n\t\t\t}\n\t\t},\n\t\n\t\t/**\n\t\t * The DataTables object for this table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInstance\": null,\n\t\n\t\t/**\n\t\t * Unique identifier for each instance of the DataTables object. If there\n\t\t * is an ID on the table node, then it takes that value, otherwise an\n\t\t * incrementing internal counter is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sInstance\": null,\n\t\n\t\t/**\n\t\t * tabindex attribute value that is added to DataTables control elements, allowing\n\t\t * keyboard navigation of the table and its controls.\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollHead\": null,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollFoot\": null,\n\t\n\t\t/**\n\t\t * Last applied sort\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLastSort\": [],\n\t\n\t\t/**\n\t\t * Stored plug-in instances\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oPlugins\": {},\n\t\n\t\t/**\n\t\t * Function used to get a row's id from the row's data\n\t\t *  @type function\n\t\t *  @default null\n\t\t */\n\t\t\"rowIdFn\": null,\n\t\n\t\t/**\n\t\t * Data location where to store a row's id\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"rowId\": null\n\t};\n\n\t/**\n\t * Extension object for DataTables that is used to provide all extension\n\t * options.\n\t *\n\t * Note that the `DataTable.ext` object is available through\n\t * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is\n\t * also aliased to `jQuery.fn.dataTableExt` for historic reasons.\n\t *  @namespace\n\t *  @extends DataTable.models.ext\n\t */\n\t\n\t\n\t/**\n\t * DataTables extensions\n\t * \n\t * This namespace acts as a collection area for plug-ins that can be used to\n\t * extend DataTables capabilities. Indeed many of the build in methods\n\t * use this method to provide their own capabilities (sorting methods for\n\t * example).\n\t *\n\t * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy\n\t * reasons\n\t *\n\t *  @namespace\n\t */\n\tDataTable.ext = _ext = {\n\t\t/**\n\t\t * Buttons. For use with the Buttons extension for DataTables. This is\n\t\t * defined here so other extensions can define buttons regardless of load\n\t\t * order. It is _not_ used by DataTables core.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tbuttons: {},\n\t\n\t\n\t\t/**\n\t\t * Element class names\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tclasses: {},\n\t\n\t\n\t\t/**\n\t\t * DataTables build type (expanded by the download builder)\n\t\t *\n\t\t *  @type string\n\t\t */\n\t\tbuilder: \"-source-\",\n\t\n\t\n\t\t/**\n\t\t * Error reporting.\n\t\t * \n\t\t * How should DataTables report an error. Can take the value 'alert',\n\t\t * 'throw', 'none' or a function.\n\t\t *\n\t\t *  @type string|function\n\t\t *  @default alert\n\t\t */\n\t\terrMode: \"alert\",\n\t\n\t\n\t\t/**\n\t\t * Feature plug-ins.\n\t\t * \n\t\t * This is an array of objects which describe the feature plug-ins that are\n\t\t * available to DataTables. These feature plug-ins are then available for\n\t\t * use through the `dom` initialisation option.\n\t\t * \n\t\t * Each feature plug-in is described by an object which must have the\n\t\t * following properties:\n\t\t * \n\t\t * * `fnInit` - function that is used to initialise the plug-in,\n\t\t * * `cFeature` - a character so the feature can be enabled by the `dom`\n\t\t *   instillation option. This is case sensitive.\n\t\t *\n\t\t * The `fnInit` function has the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *\n\t\t * And the following return is expected:\n\t\t * \n\t\t * * {node|null} The element which contains your feature. Note that the\n\t\t *   return may also be void if your plug-in does not require to inject any\n\t\t *   DOM elements into DataTables control (`dom`) - for example this might\n\t\t *   be useful when developing a plug-in which allows table control via\n\t\t *   keyboard entry\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    $.fn.dataTable.ext.features.push( {\n\t\t *      \"fnInit\": function( oSettings ) {\n\t\t *        return new TableTools( { \"oDTSettings\": oSettings } );\n\t\t *      },\n\t\t *      \"cFeature\": \"T\"\n\t\t *    } );\n\t\t */\n\t\tfeature: [],\n\t\n\t\n\t\t/**\n\t\t * Row searching.\n\t\t * \n\t\t * This method of searching is complimentary to the default type based\n\t\t * searching, and a lot more comprehensive as it allows you complete control\n\t\t * over the searching logic. Each element in this array is a function\n\t\t * (parameters described below) that is called for every row in the table,\n\t\t * and your logic decides if it should be included in the searching data set\n\t\t * or not.\n\t\t *\n\t\t * Searching functions have the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{array|object}` Data for the row to be processed (same as the\n\t\t *    original format that was passed in as the data source, or an array\n\t\t *    from a DOM data source\n\t\t * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which\n\t\t *    can be useful to retrieve the `TR` element if you need DOM interaction.\n\t\t *\n\t\t * And the following return is expected:\n\t\t *\n\t\t * * {boolean} Include the row in the searched result set (true) or not\n\t\t *   (false)\n\t\t *\n\t\t * Note that as with the main search ability in DataTables, technically this\n\t\t * is \"filtering\", since it is subtractive. However, for consistency in\n\t\t * naming we call it searching here.\n\t\t *\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @example\n\t\t *    // The following example shows custom search being applied to the\n\t\t *    // fourth column (i.e. the data[3] index) based on two input values\n\t\t *    // from the end-user, matching the data in a certain range.\n\t\t *    $.fn.dataTable.ext.search.push(\n\t\t *      function( settings, data, dataIndex ) {\n\t\t *        var min = document.getElementById('min').value * 1;\n\t\t *        var max = document.getElementById('max').value * 1;\n\t\t *        var version = data[3] == \"-\" ? 0 : data[3]*1;\n\t\t *\n\t\t *        if ( min == \"\" && max == \"\" ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min == \"\" && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && \"\" == max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        return false;\n\t\t *      }\n\t\t *    );\n\t\t */\n\t\tsearch: [],\n\t\n\t\n\t\t/**\n\t\t * Selector extensions\n\t\t *\n\t\t * The `selector` option can be used to extend the options available for the\n\t\t * selector modifier options (`selector-modifier` object data type) that\n\t\t * each of the three built in selector types offer (row, column and cell +\n\t\t * their plural counterparts). For example the Select extension uses this\n\t\t * mechanism to provide an option to select only rows, columns and cells\n\t\t * that have been marked as selected by the end user (`{selected: true}`),\n\t\t * which can be used in conjunction with the existing built in selector\n\t\t * options.\n\t\t *\n\t\t * Each property is an array to which functions can be pushed. The functions\n\t\t * take three attributes:\n\t\t *\n\t\t * * Settings object for the host table\n\t\t * * Options object (`selector-modifier` object type)\n\t\t * * Array of selected item indexes\n\t\t *\n\t\t * The return is an array of the resulting item indexes after the custom\n\t\t * selector has been applied.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tselector: {\n\t\t\tcell: [],\n\t\t\tcolumn: [],\n\t\t\trow: []\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Internal functions, exposed for used in plug-ins.\n\t\t * \n\t\t * Please note that you should not need to use the internal methods for\n\t\t * anything other than a plug-in (and even then, try to avoid if possible).\n\t\t * The internal function may change between releases.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tinternal: {},\n\t\n\t\n\t\t/**\n\t\t * Legacy configuration options. Enable and disable legacy options that\n\t\t * are available in DataTables.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tlegacy: {\n\t\t\t/**\n\t\t\t * Enable / disable DataTables 1.9 compatible server-side processing\n\t\t\t * requests\n\t\t\t *\n\t\t\t *  @type boolean\n\t\t\t *  @default null\n\t\t\t */\n\t\t\tajax: null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Pagination plug-in methods.\n\t\t * \n\t\t * Each entry in this object is a function and defines which buttons should\n\t\t * be shown by the pagination rendering method that is used for the table:\n\t\t * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the\n\t\t * buttons are displayed in the document, while the functions here tell it\n\t\t * what buttons to display. This is done by returning an array of button\n\t\t * descriptions (what each button will do).\n\t\t *\n\t\t * Pagination types (the four built in options and any additional plug-in\n\t\t * options defined here) can be used through the `paginationType`\n\t\t * initialisation parameter.\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{int} page` The current page index\n\t\t * 2. `{int} pages` The number of pages in the table\n\t\t *\n\t\t * Each function is expected to return an array where each element of the\n\t\t * array can be one of:\n\t\t *\n\t\t * * `first` - Jump to first page when activated\n\t\t * * `last` - Jump to last page when activated\n\t\t * * `previous` - Show previous page when activated\n\t\t * * `next` - Show next page when activated\n\t\t * * `{int}` - Show page of the index given\n\t\t * * `{array}` - A nested array containing the above elements to add a\n\t\t *   containing 'DIV' element (might be useful for styling).\n\t\t *\n\t\t * Note that DataTables v1.9- used this object slightly differently whereby\n\t\t * an object with two functions would be defined for each plug-in. That\n\t\t * ability is still supported by DataTables 1.10+ to provide backwards\n\t\t * compatibility, but this option of use is now decremented and no longer\n\t\t * documented in DataTables 1.10+.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t *\n\t\t *  @example\n\t\t *    // Show previous, next and current page buttons only\n\t\t *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {\n\t\t *      return [ 'previous', page, 'next' ];\n\t\t *    };\n\t\t */\n\t\tpager: {},\n\t\n\t\n\t\trenderer: {\n\t\t\tpageButton: {},\n\t\t\theader: {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Ordering plug-ins - custom data source\n\t\t * \n\t\t * The extension options for ordering of data available here is complimentary\n\t\t * to the default type based ordering that DataTables typically uses. It\n\t\t * allows much greater control over the the data that is being used to\n\t\t * order a column, but is necessarily therefore more complex.\n\t\t * \n\t\t * This type of ordering is useful if you want to do ordering based on data\n\t\t * live from the DOM (for example the contents of an 'input' element) rather\n\t\t * than just the static string that DataTables knows of.\n\t\t * \n\t\t * The way these plug-ins work is that you create an array of the values you\n\t\t * wish to be ordering for the column in question and then return that\n\t\t * array. The data in the array much be in the index order of the rows in\n\t\t * the table (not the currently ordering order!). Which order data gathering\n\t\t * function is run here depends on the `dt-init columns.orderDataType`\n\t\t * parameter that is used for the column (if any).\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{int}` Target column index\n\t\t *\n\t\t * Each function is expected to return an array:\n\t\t *\n\t\t * * `{array}` Data for the column to be ordering upon\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    // Ordering using `input` node values\n\t\t *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )\n\t\t *    {\n\t\t *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {\n\t\t *        return $('input', td).val();\n\t\t *      } );\n\t\t *    }\n\t\t */\n\t\torder: {},\n\t\n\t\n\t\t/**\n\t\t * Type based plug-ins.\n\t\t *\n\t\t * Each column in DataTables has a type assigned to it, either by automatic\n\t\t * detection or by direct assignment using the `type` option for the column.\n\t\t * The type of a column will effect how it is ordering and search (plug-ins\n\t\t * can also make use of the column type if required).\n\t\t *\n\t\t * @namespace\n\t\t */\n\t\ttype: {\n\t\t\t/**\n\t\t\t * Type detection functions.\n\t\t\t *\n\t\t\t * The functions defined in this object are used to automatically detect\n\t\t\t * a column's type, making initialisation of DataTables super easy, even\n\t\t\t * when complex data is in the table.\n\t\t\t *\n\t\t\t * The functions defined take two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be analysed\n\t\t     *  2. `{settings}` DataTables settings object. This can be used to\n\t\t     *     perform context specific type detection - for example detection\n\t\t     *     based on language settings such as using a comma for a decimal\n\t\t     *     place. Generally speaking the options from the settings will not\n\t\t     *     be required\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Data type detected, or null if unknown (and thus\n\t\t\t *   pass it on to the other type detection functions.\n\t\t\t *\n\t\t\t *  @type array\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Currency type detection plug-in:\n\t\t\t *    $.fn.dataTable.ext.type.detect.push(\n\t\t\t *      function ( data, settings ) {\n\t\t\t *        // Check the numeric part\n\t\t\t *        if ( ! $.isNumeric( data.substring(1) ) ) {\n\t\t\t *          return null;\n\t\t\t *        }\n\t\t\t *\n\t\t\t *        // Check prefixed by currency\n\t\t\t *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {\n\t\t\t *          return 'currency';\n\t\t\t *        }\n\t\t\t *        return null;\n\t\t\t *      }\n\t\t\t *    );\n\t\t\t */\n\t\t\tdetect: [],\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based search formatting.\n\t\t\t *\n\t\t\t * The type based searching functions can be used to pre-format the\n\t\t\t * data to be search on. For example, it can be used to strip HTML\n\t\t\t * tags or to de-format telephone numbers for numeric only searching.\n\t\t\t *\n\t\t\t * Note that is a search is not defined for a column of a given type,\n\t\t\t * no search formatting will be performed.\n\t\t\t * \n\t\t\t * Pre-processing of searching data plug-ins - When you assign the sType\n\t\t\t * for a column (or have it automatically detected for you by DataTables\n\t\t\t * or a type detection plug-in), you will typically be using this for\n\t\t\t * custom sorting, but it can also be used to provide custom searching\n\t\t\t * by allowing you to pre-processing the data and returning the data in\n\t\t\t * the format that should be searched upon. This is done by adding\n\t\t\t * functions this object with a parameter name which matches the sType\n\t\t\t * for that target column. This is the corollary of <i>afnSortData</i>\n\t\t\t * for searching data.\n\t\t\t *\n\t\t\t * The functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for searching\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Formatted string that will be used for the searching.\n\t\t\t *\n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {\n\t\t\t *      return d.replace(/\\n/g,\" \").replace( /<.*?>/g, \"\" );\n\t\t\t *    }\n\t\t\t */\n\t\t\tsearch: {},\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based ordering.\n\t\t\t *\n\t\t\t * The column type tells DataTables what ordering to apply to the table\n\t\t\t * when a column is sorted upon. The order for each type that is defined,\n\t\t\t * is defined by the functions available in this object.\n\t\t\t *\n\t\t\t * Each ordering option can be described by three properties added to\n\t\t\t * this object:\n\t\t\t *\n\t\t\t * * `{type}-pre` - Pre-formatting function\n\t\t\t * * `{type}-asc` - Ascending order function\n\t\t\t * * `{type}-desc` - Descending order function\n\t\t\t *\n\t\t\t * All three can be used together, only `{type}-pre` or only\n\t\t\t * `{type}-asc` and `{type}-desc` together. It is generally recommended\n\t\t\t * that only `{type}-pre` is used, as this provides the optimal\n\t\t\t * implementation in terms of speed, although the others are provided\n\t\t\t * for compatibility with existing Javascript sort functions.\n\t\t\t *\n\t\t\t * `{type}-pre`: Functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for ordering\n\t\t\t *\n\t\t\t * And return:\n\t\t\t *\n\t\t\t * * `{*}` Data to be sorted upon\n\t\t\t *\n\t\t\t * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort\n\t\t\t * functions, taking two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data to compare to the second parameter\n\t\t     *  2. `{*}` Data to compare to the first parameter\n\t\t\t *\n\t\t\t * And returning:\n\t\t\t *\n\t\t\t * * `{*}` Ordering match: <0 if first parameter should be sorted lower\n\t\t\t *   than the second parameter, ===0 if the two parameters are equal and\n\t\t\t *   >0 if the first parameter should be sorted height than the second\n\t\t\t *   parameter.\n\t\t\t * \n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Numeric ordering of formatted numbers with a pre-formatter\n\t\t\t *    $.extend( $.fn.dataTable.ext.type.order, {\n\t\t\t *      \"string-pre\": function(x) {\n\t\t\t *        a = (a === \"-\" || a === \"\") ? 0 : a.replace( /[^\\d\\-\\.]/g, \"\" );\n\t\t\t *        return parseFloat( a );\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Case-sensitive string ordering, with no pre-formatting method\n\t\t\t *    $.extend( $.fn.dataTable.ext.order, {\n\t\t\t *      \"string-case-asc\": function(x,y) {\n\t\t\t *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t\t *      },\n\t\t\t *      \"string-case-desc\": function(x,y) {\n\t\t\t *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t */\n\t\t\torder: {}\n\t\t},\n\t\n\t\t/**\n\t\t * Unique DataTables instance counter\n\t\t *\n\t\t * @type int\n\t\t * @private\n\t\t */\n\t\t_unique: 0,\n\t\n\t\n\t\t//\n\t\t// Depreciated\n\t\t// The following properties are retained for backwards compatiblity only.\n\t\t// The should not be used in new projects and will be removed in a future\n\t\t// version\n\t\t//\n\t\n\t\t/**\n\t\t * Version check function.\n\t\t *  @type function\n\t\t *  @depreciated Since 1.10\n\t\t */\n\t\tfnVersionCheck: DataTable.fnVersionCheck,\n\t\n\t\n\t\t/**\n\t\t * Index for what 'this' index API functions should use\n\t\t *  @type int\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tiApiIndex: 0,\n\t\n\t\n\t\t/**\n\t\t * jQuery UI class container\n\t\t *  @type object\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\toJUIClasses: {},\n\t\n\t\n\t\t/**\n\t\t * Software version\n\t\t *  @type string\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tsVersion: DataTable.version\n\t};\n\t\n\t\n\t//\n\t// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts\n\t//\n\t$.extend( _ext, {\n\t\tafnFiltering: _ext.search,\n\t\taTypes:       _ext.type.detect,\n\t\tofnSearch:    _ext.type.search,\n\t\toSort:        _ext.type.order,\n\t\tafnSortData:  _ext.order,\n\t\taoFeatures:   _ext.feature,\n\t\toApi:         _ext.internal,\n\t\toStdClasses:  _ext.classes,\n\t\toPagination:  _ext.pager\n\t} );\n\t\n\t\n\t$.extend( DataTable.ext.classes, {\n\t\t\"sTable\": \"dataTable\",\n\t\t\"sNoFooter\": \"no-footer\",\n\t\n\t\t/* Paging buttons */\n\t\t\"sPageButton\": \"paginate_button\",\n\t\t\"sPageButtonActive\": \"current\",\n\t\t\"sPageButtonDisabled\": \"disabled\",\n\t\n\t\t/* Striping classes */\n\t\t\"sStripeOdd\": \"odd\",\n\t\t\"sStripeEven\": \"even\",\n\t\n\t\t/* Empty row */\n\t\t\"sRowEmpty\": \"dataTables_empty\",\n\t\n\t\t/* Features */\n\t\t\"sWrapper\": \"dataTables_wrapper\",\n\t\t\"sFilter\": \"dataTables_filter\",\n\t\t\"sInfo\": \"dataTables_info\",\n\t\t\"sPaging\": \"dataTables_paginate paging_\", /* Note that the type is postfixed */\n\t\t\"sLength\": \"dataTables_length\",\n\t\t\"sProcessing\": \"dataTables_processing\",\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\": \"sorting_asc\",\n\t\t\"sSortDesc\": \"sorting_desc\",\n\t\t\"sSortable\": \"sorting\", /* Sortable in both directions */\n\t\t\"sSortableAsc\": \"sorting_asc_disabled\",\n\t\t\"sSortableDesc\": \"sorting_desc_disabled\",\n\t\t\"sSortableNone\": \"sorting_disabled\",\n\t\t\"sSortColumn\": \"sorting_\", /* Note that an int is postfixed for the sorting order */\n\t\n\t\t/* Filtering */\n\t\t\"sFilterInput\": \"\",\n\t\n\t\t/* Page length */\n\t\t\"sLengthSelect\": \"\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollWrapper\": \"dataTables_scroll\",\n\t\t\"sScrollHead\": \"dataTables_scrollHead\",\n\t\t\"sScrollHeadInner\": \"dataTables_scrollHeadInner\",\n\t\t\"sScrollBody\": \"dataTables_scrollBody\",\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot\",\n\t\t\"sScrollFootInner\": \"dataTables_scrollFootInner\",\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\": \"\",\n\t\t\"sFooterTH\": \"\",\n\t\n\t\t// Deprecated\n\t\t\"sSortJUIAsc\": \"\",\n\t\t\"sSortJUIDesc\": \"\",\n\t\t\"sSortJUI\": \"\",\n\t\t\"sSortJUIAscAllowed\": \"\",\n\t\t\"sSortJUIDescAllowed\": \"\",\n\t\t\"sSortJUIWrapper\": \"\",\n\t\t\"sSortIcon\": \"\",\n\t\t\"sJUIHeader\": \"\",\n\t\t\"sJUIFooter\": \"\"\n\t} );\n\t\n\t\n\t(function() {\n\t\n\t// Reused strings for better compression. Closure compiler appears to have a\n\t// weird edge case where it is trying to expand strings rather than use the\n\t// variable version. This results in about 200 bytes being added, for very\n\t// little preference benefit since it this run on script load only.\n\tvar _empty = '';\n\t_empty = '';\n\t\n\tvar _stateDefault = _empty + 'ui-state-default';\n\tvar _sortIcon     = _empty + 'css_right ui-icon ui-icon-';\n\tvar _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';\n\t\n\t$.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {\n\t\t/* Full numbers paging buttons */\n\t\t\"sPageButton\":         \"fg-button ui-button \"+_stateDefault,\n\t\t\"sPageButtonActive\":   \"ui-state-disabled\",\n\t\t\"sPageButtonDisabled\": \"ui-state-disabled\",\n\t\n\t\t/* Features */\n\t\t\"sPaging\": \"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi \"+\n\t\t\t\"ui-buttonset-multi paging_\", /* Note that the type is postfixed */\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\":            _stateDefault+\" sorting_asc\",\n\t\t\"sSortDesc\":           _stateDefault+\" sorting_desc\",\n\t\t\"sSortable\":           _stateDefault+\" sorting\",\n\t\t\"sSortableAsc\":        _stateDefault+\" sorting_asc_disabled\",\n\t\t\"sSortableDesc\":       _stateDefault+\" sorting_desc_disabled\",\n\t\t\"sSortableNone\":       _stateDefault+\" sorting_disabled\",\n\t\t\"sSortJUIAsc\":         _sortIcon+\"triangle-1-n\",\n\t\t\"sSortJUIDesc\":        _sortIcon+\"triangle-1-s\",\n\t\t\"sSortJUI\":            _sortIcon+\"carat-2-n-s\",\n\t\t\"sSortJUIAscAllowed\":  _sortIcon+\"carat-1-n\",\n\t\t\"sSortJUIDescAllowed\": _sortIcon+\"carat-1-s\",\n\t\t\"sSortJUIWrapper\":     \"DataTables_sort_wrapper\",\n\t\t\"sSortIcon\":           \"DataTables_sort_icon\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollHead\": \"dataTables_scrollHead \"+_stateDefault,\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot \"+_stateDefault,\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\":  _stateDefault,\n\t\t\"sFooterTH\":  _stateDefault,\n\t\t\"sJUIHeader\": _headerFooter+\" ui-corner-tl ui-corner-tr\",\n\t\t\"sJUIFooter\": _headerFooter+\" ui-corner-bl ui-corner-br\"\n\t} );\n\t\n\t}());\n\t\n\t\n\t\n\tvar extPagination = DataTable.ext.pager;\n\t\n\tfunction _numbers ( page, pages ) {\n\t\tvar\n\t\t\tnumbers = [],\n\t\t\tbuttons = extPagination.numbers_length,\n\t\t\thalf = Math.floor( buttons / 2 ),\n\t\t\ti = 1;\n\t\n\t\tif ( pages <= buttons ) {\n\t\t\tnumbers = _range( 0, pages );\n\t\t}\n\t\telse if ( page <= half ) {\n\t\t\tnumbers = _range( 0, buttons-2 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t}\n\t\telse if ( page >= pages - 1 - half ) {\n\t\t\tnumbers = _range( pages-(buttons-2), pages );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\telse {\n\t\t\tnumbers = _range( page-half+2, page+half-1 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' );\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\n\t\tnumbers.DT_el = 'span';\n\t\treturn numbers;\n\t}\n\t\n\t\n\t$.extend( extPagination, {\n\t\tsimple: function ( page, pages ) {\n\t\t\treturn [ 'previous', 'next' ];\n\t\t},\n\t\n\t\tfull: function ( page, pages ) {\n\t\t\treturn [  'first', 'previous', 'next', 'last' ];\n\t\t},\n\t\n\t\tnumbers: function ( page, pages ) {\n\t\t\treturn [ _numbers(page, pages) ];\n\t\t},\n\t\n\t\tsimple_numbers: function ( page, pages ) {\n\t\t\treturn [ 'previous', _numbers(page, pages), 'next' ];\n\t\t},\n\t\n\t\tfull_numbers: function ( page, pages ) {\n\t\t\treturn [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];\n\t\t},\n\t\t\n\t\tfirst_last_numbers: function (page, pages) {\n\t \t\treturn ['first', _numbers(page, pages), 'last'];\n\t \t},\n\t\n\t\t// For testing and plug-ins to use\n\t\t_numbers: _numbers,\n\t\n\t\t// Number of number buttons (including ellipsis) to show. _Must be odd!_\n\t\tnumbers_length: 7\n\t} );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\tpageButton: {\n\t\t\t_: function ( settings, host, idx, buttons, page, pages ) {\n\t\t\t\tvar classes = settings.oClasses;\n\t\t\t\tvar lang = settings.oLanguage.oPaginate;\n\t\t\t\tvar aria = settings.oLanguage.oAria.paginate || {};\n\t\t\t\tvar btnDisplay, btnClass, counter=0;\n\t\n\t\t\t\tvar attach = function( container, buttons ) {\n\t\t\t\t\tvar i, ien, node, button;\n\t\t\t\t\tvar clickHandler = function ( e ) {\n\t\t\t\t\t\t_fnPageChange( settings, e.data.action, true );\n\t\t\t\t\t};\n\t\n\t\t\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tbutton = buttons[i];\n\t\n\t\t\t\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\t\t\t\tvar inner = $( '<'+(button.DT_el || 'div')+'/>' )\n\t\t\t\t\t\t\t\t.appendTo( container );\n\t\t\t\t\t\t\tattach( inner, button );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tbtnDisplay = null;\n\t\t\t\t\t\t\tbtnClass = '';\n\t\n\t\t\t\t\t\t\tswitch ( button ) {\n\t\t\t\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\t\t\t\tcontainer.append('<span class=\"ellipsis\">&#x2026;</span>');\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'first':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'next':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'last':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t\t\t\tclasses.sPageButtonActive : '';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\tif ( btnDisplay !== null ) {\n\t\t\t\t\t\t\t\tnode = $('<a>', {\n\t\t\t\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t\t\t\t.appendTo( container );\n\t\n\t\t\t\t\t\t\t\t_fnBindAction(\n\t\t\t\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t\t\t\t);\n\t\n\t\t\t\t\t\t\t\tcounter++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame. Try / catch the error. Not good for\n\t\t\t\t// accessibility, but neither are frames.\n\t\t\t\tvar activeEl;\n\t\n\t\t\t\ttry {\n\t\t\t\t\t// Because this approach is destroying and recreating the paging\n\t\t\t\t\t// elements, focus is lost on the select button which is bad for\n\t\t\t\t\t// accessibility. So we want to restore focus once the draw has\n\t\t\t\t\t// completed\n\t\t\t\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t\t\t\t}\n\t\t\t\tcatch (e) {}\n\t\n\t\t\t\tattach( $(host).empty(), buttons );\n\t\n\t\t\t\tif ( activeEl !== undefined ) {\n\t\t\t\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t\n\t\n\t// Built in type detection. See model.ext.aTypes for information about\n\t// what is required from this methods.\n\t$.extend( DataTable.ext.type.detect, [\n\t\t// Plain numbers - first since V8 detects some plain numbers as dates\n\t\t// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal ) ? 'num'+decimal : null;\n\t\t},\n\t\n\t\t// Dates (only those recognised by the browser's Date.parse)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\t// V8 tries _very_ hard to make a string passed into `Date.parse()`\n\t\t\t// valid, so we need to use a regex to restrict date formats. Use a\n\t\t\t// plug-in for anything other than ISO8601 style strings\n\t\t\tif ( d && !(d instanceof Date) && ! _re_date.test(d) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tvar parsed = Date.parse(d);\n\t\t\treturn (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;\n\t\t},\n\t\n\t\t// Formatted numbers\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric, formatted\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML (this is strict checking - there must be html)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\treturn _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?\n\t\t\t\t'html' : null;\n\t\t}\n\t] );\n\t\n\t\n\t\n\t// Filter formatting functions. See model.ext.ofnSearch for information about\n\t// what is required from these methods.\n\t// \n\t// Note that additional search methods are added for the html numbers and\n\t// html formatted numbers by `_addNumericSort()` when we know what the decimal\n\t// place is\n\t\n\t\n\t$.extend( DataTable.ext.type.search, {\n\t\thtml: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata\n\t\t\t\t\t\t.replace( _re_new_lines, \" \" )\n\t\t\t\t\t\t.replace( _re_html, \"\" ) :\n\t\t\t\t\t'';\n\t\t},\n\t\n\t\tstring: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata.replace( _re_new_lines, \" \" ) :\n\t\t\t\t\tdata;\n\t\t}\n\t} );\n\t\n\t\n\t\n\tvar __numericReplace = function ( d, decimalPlace, re1, re2 ) {\n\t\tif ( d !== 0 && (!d || d === '-') ) {\n\t\t\treturn -Infinity;\n\t\t}\n\t\n\t\t// If a decimal place other than `.` is used, it needs to be given to the\n\t\t// function so we can detect it and replace with a `.` which is the only\n\t\t// decimal place Javascript recognises - it is not locale aware.\n\t\tif ( decimalPlace ) {\n\t\t\td = _numToDecimal( d, decimalPlace );\n\t\t}\n\t\n\t\tif ( d.replace ) {\n\t\t\tif ( re1 ) {\n\t\t\t\td = d.replace( re1, '' );\n\t\t\t}\n\t\n\t\t\tif ( re2 ) {\n\t\t\t\td = d.replace( re2, '' );\n\t\t\t}\n\t\t}\n\t\n\t\treturn d * 1;\n\t};\n\t\n\t\n\t// Add the numeric 'deformatting' functions for sorting and search. This is done\n\t// in a function to provide an easy ability for the language options to add\n\t// additional methods if a non-period decimal place is used.\n\tfunction _addNumericSort ( decimalPlace ) {\n\t\t$.each(\n\t\t\t{\n\t\t\t\t// Plain numbers\n\t\t\t\t\"num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace );\n\t\t\t\t},\n\t\n\t\t\t\t// Formatted numbers\n\t\t\t\t\"num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_formatted_numeric );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric\n\t\t\t\t\"html-num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric, formatted\n\t\t\t\t\"html-num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );\n\t\t\t\t}\n\t\t\t},\n\t\t\tfunction ( key, fn ) {\n\t\t\t\t// Add the ordering method\n\t\t\t\t_ext.type.order[ key+decimalPlace+'-pre' ] = fn;\n\t\n\t\t\t\t// For HTML types add a search formatter that will strip the HTML\n\t\t\t\tif ( key.match(/^html\\-/) ) {\n\t\t\t\t\t_ext.type.search[ key+decimalPlace ] = _ext.type.search.html;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\t\n\t\n\t// Default sort methods\n\t$.extend( _ext.type.order, {\n\t\t// Dates\n\t\t\"date-pre\": function ( d ) {\n\t\t\treturn Date.parse( d ) || -Infinity;\n\t\t},\n\t\n\t\t// html\n\t\t\"html-pre\": function ( a ) {\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ta.replace ?\n\t\t\t\t\ta.replace( /<.*?>/g, \"\" ).toLowerCase() :\n\t\t\t\t\ta+'';\n\t\t},\n\t\n\t\t// string\n\t\t\"string-pre\": function ( a ) {\n\t\t\t// This is a little complex, but faster than always calling toString,\n\t\t\t// http://jsperf.com/tostring-v-check\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ttypeof a === 'string' ?\n\t\t\t\t\ta.toLowerCase() :\n\t\t\t\t\t! a.toString ?\n\t\t\t\t\t\t'' :\n\t\t\t\t\t\ta.toString();\n\t\t},\n\t\n\t\t// string-asc and -desc are retained only for compatibility with the old\n\t\t// sort methods\n\t\t\"string-asc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t},\n\t\n\t\t\"string-desc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t}\n\t} );\n\t\n\t\n\t// Numeric sorting types - order doesn't matter here\n\t_addNumericSort( '' );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\theader: {\n\t\t\t_: function ( settings, cell, column, classes ) {\n\t\t\t\t// No additional mark-up required\n\t\t\t\t// Attach a sort listener to update on sort - note that using the\n\t\t\t\t// `DT` namespace will allow the event to be removed automatically\n\t\t\t\t// on destroy, while the `dt` namespaced event is the one we are\n\t\t\t\t// listening for\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) { // need to check this this is the host\n\t\t\t\t\t\treturn;               // table, not a nested one\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tcolumn.sSortingClass +' '+\n\t\t\t\t\t\t\tclasses.sSortAsc +' '+\n\t\t\t\t\t\t\tclasses.sSortDesc\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t},\n\t\n\t\t\tjqueryui: function ( settings, cell, column, classes ) {\n\t\t\t\t$('<div/>')\n\t\t\t\t\t.addClass( classes.sSortJUIWrapper )\n\t\t\t\t\t.append( cell.contents() )\n\t\t\t\t\t.append( $('<span/>')\n\t\t\t\t\t\t.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo( cell );\n\t\n\t\t\t\t// Attach a sort listener to update on sort\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.find( 'span.'+classes.sSortIcon )\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tclasses.sSortJUIAsc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDesc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUI +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIAscAllowed +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDescAllowed\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortJUIAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortJUIDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClassJUI\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t/*\n\t * Public helper functions. These aren't used internally by DataTables, or\n\t * called by any of the options passed into DataTables, but they can be used\n\t * externally by developers working with DataTables. They are helper functions\n\t * to make working with DataTables a little bit easier.\n\t */\n\t\n\tvar __htmlEscapeEntities = function ( d ) {\n\t\treturn typeof d === 'string' ?\n\t\t\td.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;') :\n\t\t\td;\n\t};\n\t\n\t/**\n\t * Helpers for `columns.render`.\n\t *\n\t * The options defined here can be used with the `columns.render` initialisation\n\t * option to provide a display renderer. The following functions are defined:\n\t *\n\t * * `number` - Will format numeric data (defined by `columns.data`) for\n\t *   display, retaining the original unformatted data for sorting and filtering.\n\t *   It takes 5 parameters:\n\t *   * `string` - Thousands grouping separator\n\t *   * `string` - Decimal point indicator\n\t *   * `integer` - Number of decimal points to show\n\t *   * `string` (optional) - Prefix.\n\t *   * `string` (optional) - Postfix (/suffix).\n\t * * `text` - Escape HTML to help prevent XSS attacks. It has no optional\n\t *   parameters.\n\t *\n\t * @example\n\t *   // Column definition using the number renderer\n\t *   {\n\t *     data: \"salary\",\n\t *     render: $.fn.dataTable.render.number( '\\'', '.', 0, '$' )\n\t *   }\n\t *\n\t * @namespace\n\t */\n\tDataTable.render = {\n\t\tnumber: function ( thousands, decimal, precision, prefix, postfix ) {\n\t\t\treturn {\n\t\t\t\tdisplay: function ( d ) {\n\t\t\t\t\tif ( typeof d !== 'number' && typeof d !== 'string' ) {\n\t\t\t\t\t\treturn d;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar negative = d < 0 ? '-' : '';\n\t\t\t\t\tvar flo = parseFloat( d );\n\t\n\t\t\t\t\t// If NaN then there isn't much formatting that we can do - just\n\t\t\t\t\t// return immediately, escaping any HTML (this was supposed to\n\t\t\t\t\t// be a number after all)\n\t\t\t\t\tif ( isNaN( flo ) ) {\n\t\t\t\t\t\treturn __htmlEscapeEntities( d );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tflo = flo.toFixed( precision );\n\t\t\t\t\td = Math.abs( flo );\n\t\n\t\t\t\t\tvar intPart = parseInt( d, 10 );\n\t\t\t\t\tvar floatPart = precision ?\n\t\t\t\t\t\tdecimal+(d - intPart).toFixed( precision ).substring( 2 ):\n\t\t\t\t\t\t'';\n\t\n\t\t\t\t\treturn negative + (prefix||'') +\n\t\t\t\t\t\tintPart.toString().replace(\n\t\t\t\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g, thousands\n\t\t\t\t\t\t) +\n\t\t\t\t\t\tfloatPart +\n\t\t\t\t\t\t(postfix||'');\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\ttext: function () {\n\t\t\treturn {\n\t\t\t\tdisplay: __htmlEscapeEntities\n\t\t\t};\n\t\t}\n\t};\n\t\n\t\n\t/*\n\t * This is really a good bit rubbish this method of exposing the internal methods\n\t * publicly... - To be fixed in 2.0 using methods on the prototype\n\t */\n\t\n\t\n\t/**\n\t * Create a wrapper function for exporting an internal functions to an external API.\n\t *  @param {string} fn API function name\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#internal\n\t */\n\tfunction _fnExternApiFunc (fn)\n\t{\n\t\treturn function() {\n\t\t\tvar args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(\n\t\t\t\tArray.prototype.slice.call(arguments)\n\t\t\t);\n\t\t\treturn DataTable.ext.internal[fn].apply( this, args );\n\t\t};\n\t}\n\t\n\t\n\t/**\n\t * Reference to internal functions for use by plug-in developers. Note that\n\t * these methods are references to internal functions and are considered to be\n\t * private. If you use these methods, be aware that they are liable to change\n\t * between versions.\n\t *  @namespace\n\t */\n\t$.extend( DataTable.ext.internal, {\n\t\t_fnExternApiFunc: _fnExternApiFunc,\n\t\t_fnBuildAjax: _fnBuildAjax,\n\t\t_fnAjaxUpdate: _fnAjaxUpdate,\n\t\t_fnAjaxParameters: _fnAjaxParameters,\n\t\t_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,\n\t\t_fnAjaxDataSrc: _fnAjaxDataSrc,\n\t\t_fnAddColumn: _fnAddColumn,\n\t\t_fnColumnOptions: _fnColumnOptions,\n\t\t_fnAdjustColumnSizing: _fnAdjustColumnSizing,\n\t\t_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,\n\t\t_fnColumnIndexToVisible: _fnColumnIndexToVisible,\n\t\t_fnVisbleColumns: _fnVisbleColumns,\n\t\t_fnGetColumns: _fnGetColumns,\n\t\t_fnColumnTypes: _fnColumnTypes,\n\t\t_fnApplyColumnDefs: _fnApplyColumnDefs,\n\t\t_fnHungarianMap: _fnHungarianMap,\n\t\t_fnCamelToHungarian: _fnCamelToHungarian,\n\t\t_fnLanguageCompat: _fnLanguageCompat,\n\t\t_fnBrowserDetect: _fnBrowserDetect,\n\t\t_fnAddData: _fnAddData,\n\t\t_fnAddTr: _fnAddTr,\n\t\t_fnNodeToDataIndex: _fnNodeToDataIndex,\n\t\t_fnNodeToColumnIndex: _fnNodeToColumnIndex,\n\t\t_fnGetCellData: _fnGetCellData,\n\t\t_fnSetCellData: _fnSetCellData,\n\t\t_fnSplitObjNotation: _fnSplitObjNotation,\n\t\t_fnGetObjectDataFn: _fnGetObjectDataFn,\n\t\t_fnSetObjectDataFn: _fnSetObjectDataFn,\n\t\t_fnGetDataMaster: _fnGetDataMaster,\n\t\t_fnClearTable: _fnClearTable,\n\t\t_fnDeleteIndex: _fnDeleteIndex,\n\t\t_fnInvalidate: _fnInvalidate,\n\t\t_fnGetRowElements: _fnGetRowElements,\n\t\t_fnCreateTr: _fnCreateTr,\n\t\t_fnBuildHead: _fnBuildHead,\n\t\t_fnDrawHead: _fnDrawHead,\n\t\t_fnDraw: _fnDraw,\n\t\t_fnReDraw: _fnReDraw,\n\t\t_fnAddOptionsHtml: _fnAddOptionsHtml,\n\t\t_fnDetectHeader: _fnDetectHeader,\n\t\t_fnGetUniqueThs: _fnGetUniqueThs,\n\t\t_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,\n\t\t_fnFilterComplete: _fnFilterComplete,\n\t\t_fnFilterCustom: _fnFilterCustom,\n\t\t_fnFilterColumn: _fnFilterColumn,\n\t\t_fnFilter: _fnFilter,\n\t\t_fnFilterCreateSearch: _fnFilterCreateSearch,\n\t\t_fnEscapeRegex: _fnEscapeRegex,\n\t\t_fnFilterData: _fnFilterData,\n\t\t_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,\n\t\t_fnUpdateInfo: _fnUpdateInfo,\n\t\t_fnInfoMacros: _fnInfoMacros,\n\t\t_fnInitialise: _fnInitialise,\n\t\t_fnInitComplete: _fnInitComplete,\n\t\t_fnLengthChange: _fnLengthChange,\n\t\t_fnFeatureHtmlLength: _fnFeatureHtmlLength,\n\t\t_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,\n\t\t_fnPageChange: _fnPageChange,\n\t\t_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,\n\t\t_fnProcessingDisplay: _fnProcessingDisplay,\n\t\t_fnFeatureHtmlTable: _fnFeatureHtmlTable,\n\t\t_fnScrollDraw: _fnScrollDraw,\n\t\t_fnApplyToChildren: _fnApplyToChildren,\n\t\t_fnCalculateColumnWidths: _fnCalculateColumnWidths,\n\t\t_fnThrottle: _fnThrottle,\n\t\t_fnConvertToWidth: _fnConvertToWidth,\n\t\t_fnGetWidestNode: _fnGetWidestNode,\n\t\t_fnGetMaxLenString: _fnGetMaxLenString,\n\t\t_fnStringToCss: _fnStringToCss,\n\t\t_fnSortFlatten: _fnSortFlatten,\n\t\t_fnSort: _fnSort,\n\t\t_fnSortAria: _fnSortAria,\n\t\t_fnSortListener: _fnSortListener,\n\t\t_fnSortAttachListener: _fnSortAttachListener,\n\t\t_fnSortingClasses: _fnSortingClasses,\n\t\t_fnSortData: _fnSortData,\n\t\t_fnSaveState: _fnSaveState,\n\t\t_fnLoadState: _fnLoadState,\n\t\t_fnSettingsFromNode: _fnSettingsFromNode,\n\t\t_fnLog: _fnLog,\n\t\t_fnMap: _fnMap,\n\t\t_fnBindAction: _fnBindAction,\n\t\t_fnCallbackReg: _fnCallbackReg,\n\t\t_fnCallbackFire: _fnCallbackFire,\n\t\t_fnLengthOverflow: _fnLengthOverflow,\n\t\t_fnRenderer: _fnRenderer,\n\t\t_fnDataSource: _fnDataSource,\n\t\t_fnRowAttributes: _fnRowAttributes,\n\t\t_fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant\n\t\t                                // in 1.10, so this dead-end function is\n\t\t                                // added to prevent errors\n\t} );\n\t\n\n\t// jQuery access\n\t$.fn.dataTable = DataTable;\n\n\t// Provide access to the host jQuery object (circular reference)\n\tDataTable.$ = $;\n\n\t// Legacy aliases\n\t$.fn.dataTableSettings = DataTable.settings;\n\t$.fn.dataTableExt = DataTable.ext;\n\n\t// With a capital `D` we return a DataTables API instance rather than a\n\t// jQuery object\n\t$.fn.DataTable = function ( opts ) {\n\t\treturn $(this).dataTable( opts ).api();\n\t};\n\n\t// All properties that are available to $.fn.dataTable should also be\n\t// available on $.fn.DataTable\n\t$.each( DataTable, function ( prop, val ) {\n\t\t$.fn.DataTable[ prop ] = val;\n\t} );\n\n\n\t// Information about events fired by DataTables - for documentation.\n\t/**\n\t * Draw event, fired whenever the table is redrawn on the page, at the same\n\t * point as fnDrawCallback. This may be useful for binding events or\n\t * performing calculations when the table is altered at all.\n\t *  @name DataTable#draw.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Search event, fired when the searching applied to the table (using the\n\t * built-in global search, or column filters) is altered.\n\t *  @name DataTable#search.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page change event, fired when the paging of the table is altered.\n\t *  @name DataTable#page.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Order event, fired when the ordering applied to the table is altered.\n\t *  @name DataTable#order.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * DataTables initialisation complete event, fired when the table is fully\n\t * drawn, including Ajax data loaded, if Ajax data is required.\n\t *  @name DataTable#init.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The JSON object request from the server - only\n\t *    present if client-side Ajax sourced data is used</li></ol>\n\t */\n\n\t/**\n\t * State save event, fired when the table has changed state a new state save\n\t * is required. This event allows modification of the state saving object\n\t * prior to actually doing the save, including addition or other state\n\t * properties (for plug-ins) or modification of a DataTables core property.\n\t *  @name DataTable#stateSaveParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The state information to be saved\n\t */\n\n\t/**\n\t * State load event, fired when the table is loading state from the stored\n\t * data, but prior to the settings object being modified by the saved state\n\t * - allowing modification of the saved state is required or loading of\n\t * state for a plug-in.\n\t *  @name DataTable#stateLoadParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * State loaded event, fired when state has been loaded from stored data and\n\t * the settings object has been modified by the loaded data.\n\t *  @name DataTable#stateLoaded.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * Processing event, fired when DataTables is doing some kind of processing\n\t * (be it, order, searcg or anything else). It can be used to indicate to\n\t * the end user that there is something happening, or that something has\n\t * finished.\n\t *  @name DataTable#processing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {boolean} bShow Flag for if DataTables is doing processing or not\n\t */\n\n\t/**\n\t * Ajax (XHR) event, fired whenever an Ajax request is completed from a\n\t * request to made to the server for new data. This event is called before\n\t * DataTables processed the returned data, so it can also be used to pre-\n\t * process the data returned from the server, if needed.\n\t *\n\t * Note that this trigger is called in `fnServerData`, if you override\n\t * `fnServerData` and which to use this event, you need to trigger it in you\n\t * success function.\n\t *  @name DataTable#xhr.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {object} json JSON returned from the server\n\t *\n\t *  @example\n\t *     // Use a custom property returned from the server in another DOM element\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       $('#status').html( json.status );\n\t *     } );\n\t *\n\t *  @example\n\t *     // Pre-process the data returned from the server\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {\n\t *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;\n\t *       }\n\t *       // Note no return - manipulate the data directly in the JSON object.\n\t *     } );\n\t */\n\n\t/**\n\t * Destroy event, fired when the DataTable is destroyed by calling fnDestroy\n\t * or passing the bDestroy:true parameter in the initialisation object. This\n\t * can be used to remove bound events, added DOM nodes, etc.\n\t *  @name DataTable#destroy.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page length change event, fired when number of records to show on each\n\t * page (the length) is changed.\n\t *  @name DataTable#length.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {integer} len New length\n\t */\n\n\t/**\n\t * Column sizing has changed.\n\t *  @name DataTable#column-sizing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Column visibility has changed.\n\t *  @name DataTable#column-visibility.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {int} column Column index\n\t *  @param {bool} vis `false` if column now hidden, or `true` if visible\n\t */\n\n\treturn $.fn.dataTable;\n}));\n"
  },
  {
    "path": "www/lib/DataTables/datatables.css",
    "content": "/*\n * This combined file was created by the DataTables downloader builder:\n *   https://datatables.net/download\n *\n * To rebuild or modify this file with the latest versions of the included\n * software please visit:\n *   https://datatables.net/download/#dt/dt-1.10.13\n *\n * Included libraries:\n *   DataTables 1.10.13\n */\n\n/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px;\n  border-bottom: 1px solid #111;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n  border-top: 1px solid #111;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc {\n  cursor: pointer;\n  *cursor: hand;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"DataTables-1.10.13/images/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"DataTables-1.10.13/images/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"DataTables-1.10.13/images/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"DataTables-1.10.13/images/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"DataTables-1.10.13/images/sort_desc_disabled.png\");\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: #f6f6f6;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #fafafa;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #fafafa;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fcfcfc;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fefefe;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ececec;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #efefef;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em 1em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #979797;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  color: white !important;\n  border: 1px solid #111;\n  background-color: #585858;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #585858 0%, #111 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #585858 0%, #111 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #585858 0%, #111 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #585858 0%, #111 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  background-color: #2b2b2b;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);\n  /* W3C */\n  box-shadow: inset 0 0 3px #111;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td {\n  vertical-align: middle;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}\n\n\n"
  },
  {
    "path": "www/lib/DataTables/datatables.js",
    "content": "/*\n * This combined file was created by the DataTables downloader builder:\n *   https://datatables.net/download\n *\n * To rebuild or modify this file with the latest versions of the included\n * software please visit:\n *   https://datatables.net/download/#dt/dt-1.10.13\n *\n * Included libraries:\n *   DataTables 1.10.13\n */\n\n/*! DataTables 1.10.13\n * ©2008-2016 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     DataTables\n * @description Paginate, search and order HTML tables\n * @version     1.10.13\n * @file        jquery.dataTables.js\n * @author      SpryMedia Ltd\n * @contact     www.datatables.net\n * @copyright   Copyright 2008-2016 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n/*jslint evil: true, undef: true, browser: true */\n/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/\n\n(function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\t// CommonJS environments without a window global must pass a\n\t\t\t\t// root. This will give an error otherwise\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ ) {\n\t\t\t\t$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window\n\t\t\t\t\trequire('jquery') :\n\t\t\t\t\trequire('jquery')( root );\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}\n(function( $, window, document, undefined ) {\n\t\"use strict\";\n\n\t/**\n\t * DataTables is a plug-in for the jQuery Javascript library. It is a highly\n\t * flexible tool, based upon the foundations of progressive enhancement,\n\t * which will add advanced interaction controls to any HTML table. For a\n\t * full list of features please refer to\n\t * [DataTables.net](href=\"http://datatables.net).\n\t *\n\t * Note that the `DataTable` object is not a global variable but is aliased\n\t * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may\n\t * be  accessed.\n\t *\n\t *  @class\n\t *  @param {object} [init={}] Configuration object for DataTables. Options\n\t *    are defined by {@link DataTable.defaults}\n\t *  @requires jQuery 1.7+\n\t *\n\t *  @example\n\t *    // Basic initialisation\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable();\n\t *    } );\n\t *\n\t *  @example\n\t *    // Initialisation with configuration options - in this case, disable\n\t *    // pagination and sorting.\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable( {\n\t *        \"paginate\": false,\n\t *        \"sort\": false\n\t *      } );\n\t *    } );\n\t */\n\tvar DataTable = function ( options )\n\t{\n\t\t/**\n\t\t * Perform a jQuery selector action on the table's TR elements (from the tbody) and\n\t\t * return the resulting jQuery object.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter\n\t\t *    criterion (\"applied\") or all TR elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {object} jQuery object, filtered by the given selector.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Highlight every second row\n\t\t *      oTable.$('tr:odd').css('backgroundColor', 'blue');\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to rows with 'Webkit' in them, add a background colour and then\n\t\t *      // remove the filter, thus highlighting the 'Webkit' rows only.\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      oTable.$('tr', {\"search\": \"applied\"}).css('backgroundColor', 'blue');\n\t\t *      oTable.fnFilter('');\n\t\t *    } );\n\t\t */\n\t\tthis.$ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).$( sSelector, oOpts );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Almost identical to $ in operation, but in this case returns the data for the matched\n\t\t * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes\n\t\t * rather than any descendants, so the data can be obtained for the row/cell. If matching\n\t\t * rows are found, the data returned is the original data array/object that was used to\n\t\t * create the row (or a generated array if from a DOM source).\n\t\t *\n\t\t * This method is often useful in-combination with $ where both functions are given the\n\t\t * same parameters and the array indexes will match identically.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select elements that meet the current filter\n\t\t *    criterion (\"applied\") or all elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the data in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {array} Data for the matched elements. If any elements, as a result of the\n\t\t *    selector, were not TR, TD or TH elements in the DataTable, they will have a null\n\t\t *    entry in the array.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the data from the first row in the table\n\t\t *      var data = oTable._('tr:first');\n\t\t *\n\t\t *      // Do something useful with the data\n\t\t *      alert( \"First cell is: \"+data[0] );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to 'Webkit' and get all data for\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      var data = oTable._('tr', {\"search\": \"applied\"});\n\t\t *\n\t\t *      // Do something with the data\n\t\t *      alert( data.length+\" rows matched the search\" );\n\t\t *    } );\n\t\t */\n\t\tthis._ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).rows( sSelector, oOpts ).data();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Create a DataTables Api instance, with the currently selected tables for\n\t\t * the Api's context.\n\t\t * @param {boolean} [traditional=false] Set the API instance's context to be\n\t\t *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was\n\t\t *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),\n\t\t *   or if all tables captured in the jQuery object should be used.\n\t\t * @return {DataTables.Api}\n\t\t */\n\t\tthis.api = function ( traditional )\n\t\t{\n\t\t\treturn traditional ?\n\t\t\t\tnew _Api(\n\t\t\t\t\t_fnSettingsFromNode( this[ _ext.iApiIndex ] )\n\t\t\t\t) :\n\t\t\t\tnew _Api( this );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Add a single new row or multiple rows of data to the table. Please note\n\t\t * that this is suitable for client-side processing only - if you are using\n\t\t * server-side processing (i.e. \"bServerSide\": true), then to add data, you\n\t\t * must add it to the data source, i.e. the server-side, through an Ajax call.\n\t\t *  @param {array|object} data The data to be added to the table. This can be:\n\t\t *    <ul>\n\t\t *      <li>1D array of data - add a single row with the data provided</li>\n\t\t *      <li>2D array of arrays - add multiple rows in a single call</li>\n\t\t *      <li>object - data object when using <i>mData</i></li>\n\t\t *      <li>array of objects - multiple data objects when using <i>mData</i></li>\n\t\t *    </ul>\n\t\t *  @param {bool} [redraw=true] redraw the table or not\n\t\t *  @returns {array} An array of integers, representing the list of indexes in\n\t\t *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to\n\t\t *    the table.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Global var for counter\n\t\t *    var giCount = 2;\n\t\t *\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example').dataTable();\n\t\t *    } );\n\t\t *\n\t\t *    function fnClickAddRow() {\n\t\t *      $('#example').dataTable().fnAddData( [\n\t\t *        giCount+\".1\",\n\t\t *        giCount+\".2\",\n\t\t *        giCount+\".3\",\n\t\t *        giCount+\".4\" ]\n\t\t *      );\n\t\t *\n\t\t *      giCount++;\n\t\t *    }\n\t\t */\n\t\tthis.fnAddData = function( data, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\t/* Check if we want to add multiple rows or not */\n\t\t\tvar rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?\n\t\t\t\tapi.rows.add( data ) :\n\t\t\t\tapi.row.add( data );\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn rows.flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will make DataTables recalculate the column sizes, based on the data\n\t\t * contained in the table and the sizes applied to the columns (in the DOM, CSS or\n\t\t * through the sWidth parameter). This can be useful when the width of the table's\n\t\t * parent element changes (for example a window resize).\n\t\t *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable( {\n\t\t *        \"sScrollY\": \"200px\",\n\t\t *        \"bPaginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      $(window).on('resize', function () {\n\t\t *        oTable.fnAdjustColumnSizing();\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnAdjustColumnSizing = function ( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).columns.adjust();\n\t\t\tvar settings = api.settings()[0];\n\t\t\tvar scroll = settings.oScroll;\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw( false );\n\t\t\t}\n\t\t\telse if ( scroll.sX !== \"\" || scroll.sY !== \"\" ) {\n\t\t\t\t/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */\n\t\t\t\t_fnScrollDraw( settings );\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Quickly and simply clear a table\n\t\t *  @param {bool} [bRedraw=true] redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)\n\t\t *      oTable.fnClearTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClearTable = function( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).clear();\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * The exact opposite of 'opening' a row, this function will close any rows which\n\t\t * are currently 'open'.\n\t\t *  @param {node} nTr the table row to 'close'\n\t\t *  @returns {int} 0 on success, or 1 if failed (can't find the row)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClose = function( nTr )\n\t\t{\n\t\t\tthis.api( true ).row( nTr ).child.hide();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Remove a row for the table\n\t\t *  @param {mixed} target The index of the row from aoData to be deleted, or\n\t\t *    the TR element you want to delete\n\t\t *  @param {function|null} [callBack] Callback function\n\t\t *  @param {bool} [redraw=true] Redraw the table or not\n\t\t *  @returns {array} The row that was deleted\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately remove the first row\n\t\t *      oTable.fnDeleteRow( 0 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnDeleteRow = function( target, callback, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar rows = api.rows( target );\n\t\t\tvar settings = rows.settings()[0];\n\t\t\tvar data = settings.aoData[ rows[0][0] ];\n\t\t\n\t\t\trows.remove();\n\t\t\n\t\t\tif ( callback ) {\n\t\t\t\tcallback.call( this, settings, data );\n\t\t\t}\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn data;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Restore the table to it's original state in the DOM by removing all of DataTables\n\t\t * enhancements, alterations to the DOM structure of the table and event listeners.\n\t\t *  @param {boolean} [remove=false] Completely remove the table from the DOM\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      // This example is fairly pointless in reality, but shows how fnDestroy can be used\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnDestroy();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDestroy = function ( remove )\n\t\t{\n\t\t\tthis.api( true ).destroy( remove );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Redraw the table\n\t\t *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)\n\t\t *      oTable.fnDraw();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDraw = function( complete )\n\t\t{\n\t\t\t// Note that this isn't an exact match to the old call to _fnDraw - it takes\n\t\t\t// into account the new data, but can hold position.\n\t\t\tthis.api( true ).draw( complete );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Filter the input based on data\n\t\t *  @param {string} sInput String to filter the table on\n\t\t *  @param {int|null} [iColumn] Column to limit filtering to\n\t\t *  @param {bool} [bRegex=false] Treat as regular expression or not\n\t\t *  @param {bool} [bSmart=true] Perform smart filtering or not\n\t\t *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)\n\t\t *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sometime later - filter...\n\t\t *      oTable.fnFilter( 'test string' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === null || iColumn === undefined ) {\n\t\t\t\tapi.search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\n\t\t\tapi.draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the data for the whole table, an individual row or an individual cell based on the\n\t\t * provided parameters.\n\t\t *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as\n\t\t *    a TR node then the data source for the whole row will be returned. If given as a\n\t\t *    TD/TH cell node then iCol will be automatically calculated and the data for the\n\t\t *    cell returned. If given as an integer, then this is treated as the aoData internal\n\t\t *    data index for the row (see fnGetPosition) and the data for that row used.\n\t\t *  @param {int} [col] Optional column index that you want the data of.\n\t\t *  @returns {array|object|string} If mRow is undefined, then the data for all rows is\n\t\t *    returned. If mRow is defined, just data for that row, and is iCol is\n\t\t *    defined, only data for the designated cell is returned.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Row data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('tr').click( function () {\n\t\t *        var data = oTable.fnGetData( this );\n\t\t *        // ... do something with the array / object of data for the row\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Individual cell data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('td').click( function () {\n\t\t *        var sData = oTable.fnGetData( this );\n\t\t *        alert( 'The cell clicked on had the value of '+sData );\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetData = function( src, col )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( src !== undefined ) {\n\t\t\t\tvar type = src.nodeName ? src.nodeName.toLowerCase() : '';\n\t\t\n\t\t\t\treturn col !== undefined || type == 'td' || type == 'th' ?\n\t\t\t\t\tapi.cell( src, col ).data() :\n\t\t\t\t\tapi.row( src ).data() || null;\n\t\t\t}\n\t\t\n\t\t\treturn api.data().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get an array of the TR nodes that are used in the table's body. Note that you will\n\t\t * typically want to use the '$' API method in preference to this as it is more\n\t\t * flexible.\n\t\t *  @param {int} [iRow] Optional row index for the TR element you want\n\t\t *  @returns {array|node} If iRow is undefined, returns an array of all TR elements\n\t\t *    in the table's body, or iRow is defined, just the TR element requested.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the nodes from the table\n\t\t *      var nNodes = oTable.fnGetNodes( );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetNodes = function( iRow )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\treturn iRow !== undefined ?\n\t\t\t\tapi.row( iRow ).node() :\n\t\t\t\tapi.rows().nodes().flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the array indexes of a particular cell from it's DOM element\n\t\t * and column index including hidden columns\n\t\t *  @param {node} node this can either be a TR, TD or TH in the table's body\n\t\t *  @returns {int} If nNode is given as a TR, then a single index is returned, or\n\t\t *    if given as a cell, an array of [row index, column index (visible),\n\t\t *    column index (all)] is given.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example tbody td').click( function () {\n\t\t *        // Get the position of the current data from the node\n\t\t *        var aPos = oTable.fnGetPosition( this );\n\t\t *\n\t\t *        // Get the data array for this row\n\t\t *        var aData = oTable.fnGetData( aPos[0] );\n\t\t *\n\t\t *        // Update the data array and return the value\n\t\t *        aData[ aPos[1] ] = 'clicked';\n\t\t *        this.innerHTML = 'clicked';\n\t\t *      } );\n\t\t *\n\t\t *      // Init DataTables\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetPosition = function( node )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar nodeName = node.nodeName.toUpperCase();\n\t\t\n\t\t\tif ( nodeName == 'TR' ) {\n\t\t\t\treturn api.row( node ).index();\n\t\t\t}\n\t\t\telse if ( nodeName == 'TD' || nodeName == 'TH' ) {\n\t\t\t\tvar cell = api.cell( node ).index();\n\t\t\n\t\t\t\treturn [\n\t\t\t\t\tcell.row,\n\t\t\t\t\tcell.columnVisible,\n\t\t\t\t\tcell.column\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Check to see if a row is 'open' or not.\n\t\t *  @param {node} nTr the table row to check\n\t\t *  @returns {boolean} true if the row is currently open, false otherwise\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnIsOpen = function( nTr )\n\t\t{\n\t\t\treturn this.api( true ).row( nTr ).child.isShown();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will place a new row directly after a row which is currently\n\t\t * on display on the page, with the HTML contents that is passed into the\n\t\t * function. This can be used, for example, to ask for confirmation that a\n\t\t * particular record should be deleted.\n\t\t *  @param {node} nTr The table row to 'open'\n\t\t *  @param {string|node|jQuery} mHtml The HTML to put into the row\n\t\t *  @param {string} sClass Class to give the new TD cell\n\t\t *  @returns {node} The row opened. Note that if the table row passed in as the\n\t\t *    first parameter, is not found in the table, this method will silently\n\t\t *    return.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnOpen = function( nTr, mHtml, sClass )\n\t\t{\n\t\t\treturn this.api( true )\n\t\t\t\t.row( nTr )\n\t\t\t\t.child( mHtml, sClass )\n\t\t\t\t.show()\n\t\t\t\t.child()[0];\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Change the pagination - provides the internal logic for pagination in a simple API\n\t\t * function. With this function you can have a DataTables table go to the next,\n\t\t * previous, first or last pages.\n\t\t *  @param {string|int} mAction Paging action to take: \"first\", \"previous\", \"next\" or \"last\"\n\t\t *    or page number to jump to (integer), note that page 0 is the first page.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnPageChange( 'next' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnPageChange = function ( mAction, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).page( mAction );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw(false);\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Show a particular column\n\t\t *  @param {int} iCol The column whose display should be changed\n\t\t *  @param {bool} bShow Show (true) or hide (false) the column\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Hide the second column after initialisation\n\t\t *      oTable.fnSetColumnVis( 1, false );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSetColumnVis = function ( iCol, bShow, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).column( iCol ).visible( bShow );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.columns.adjust().draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the settings for a particular table for external manipulation\n\t\t *  @returns {object} DataTables settings object. See\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      var oSettings = oTable.fnSettings();\n\t\t *\n\t\t *      // Show an example parameter from the settings\n\t\t *      alert( oSettings._iDisplayStart );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSettings = function()\n\t\t{\n\t\t\treturn _fnSettingsFromNode( this[_ext.iApiIndex] );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Sort the table by a particular column\n\t\t *  @param {int} iCol the data index to sort on. Note that this will not match the\n\t\t *    'display index' if you have hidden data entries\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort immediately with columns 0 and 1\n\t\t *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSort = function( aaSort )\n\t\t{\n\t\t\tthis.api( true ).order( aaSort ).draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Attach a sort listener to an element for a given column\n\t\t *  @param {node} nNode the element to attach the sort listener to\n\t\t *  @param {int} iColumn the column that a click on this node will sort on\n\t\t *  @param {function} [fnCallback] callback function when sort is run\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort on column 1, when 'sorter' is clicked on\n\t\t *      oTable.fnSortListener( document.getElementById('sorter'), 1 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSortListener = function( nNode, iColumn, fnCallback )\n\t\t{\n\t\t\tthis.api( true ).order.listener( nNode, iColumn, fnCallback );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Update a table cell or row - this method will accept either a single value to\n\t\t * update the cell with, an array of values with one element for each column or\n\t\t * an object in the same format as the original data source. The function is\n\t\t * self-referencing in order to make the multi column updates easier.\n\t\t *  @param {object|array|string} mData Data to update the cell/row with\n\t\t *  @param {node|int} mRow TR element you want to update or the aoData index\n\t\t *  @param {int} [iColumn] The column to update, give as null or undefined to\n\t\t *    update a whole row.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @param {bool} [bAction=true] Perform pre-draw actions or not\n\t\t *  @returns {int} 0 on success, 1 on error\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell\n\t\t *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row\n\t\t *    } );\n\t\t */\n\t\tthis.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === undefined || iColumn === null ) {\n\t\t\t\tapi.row( mRow ).data( mData );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.cell( mRow, iColumn ).data( mData );\n\t\t\t}\n\t\t\n\t\t\tif ( bAction === undefined || bAction ) {\n\t\t\t\tapi.columns.adjust();\n\t\t\t}\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Provide a common method for plug-ins to check the version of DataTables being used, in order\n\t\t * to ensure compatibility.\n\t\t *  @param {string} sVersion Version string to check for, in the format \"X.Y.Z\". Note that the\n\t\t *    formats \"X\" and \"X.Y\" are also acceptable.\n\t\t *  @returns {boolean} true if this version of DataTables is greater or equal to the required\n\t\t *    version, or false if this version of DataTales is not suitable\n\t\t *  @method\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      alert( oTable.fnVersionCheck( '1.9.0' ) );\n\t\t *    } );\n\t\t */\n\t\tthis.fnVersionCheck = _ext.fnVersionCheck;\n\t\t\n\n\t\tvar _that = this;\n\t\tvar emptyInit = options === undefined;\n\t\tvar len = this.length;\n\n\t\tif ( emptyInit ) {\n\t\t\toptions = {};\n\t\t}\n\n\t\tthis.oApi = this.internal = _ext.internal;\n\n\t\t// Extend with old style plug-in API methods\n\t\tfor ( var fn in DataTable.ext.internal ) {\n\t\t\tif ( fn ) {\n\t\t\t\tthis[fn] = _fnExternApiFunc(fn);\n\t\t\t}\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\t// For each initialisation we want to give it a clean initialisation\n\t\t\t// object that can be bashed around\n\t\t\tvar o = {};\n\t\t\tvar oInit = len > 1 ? // optimisation for single table case\n\t\t\t\t_fnExtend( o, options, true ) :\n\t\t\t\toptions;\n\n\t\t\t/*global oInit,_that,emptyInit*/\n\t\t\tvar i=0, iLen, j, jLen, k, kLen;\n\t\t\tvar sId = this.getAttribute( 'id' );\n\t\t\tvar bInitHandedOff = false;\n\t\t\tvar defaults = DataTable.defaults;\n\t\t\tvar $this = $(this);\n\t\t\t\n\t\t\t\n\t\t\t/* Sanity check */\n\t\t\tif ( this.nodeName.toLowerCase() != 'table' )\n\t\t\t{\n\t\t\t\t_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/* Backwards compatibility for the defaults */\n\t\t\t_fnCompatOpts( defaults );\n\t\t\t_fnCompatCols( defaults.column );\n\t\t\t\n\t\t\t/* Convert the camel-case defaults to Hungarian */\n\t\t\t_fnCamelToHungarian( defaults, defaults, true );\n\t\t\t_fnCamelToHungarian( defaults.column, defaults.column, true );\n\t\t\t\n\t\t\t/* Setting up the initialisation object */\n\t\t\t_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/* Check to see if we are re-initialising a table */\n\t\t\tvar allSettings = DataTable.settings;\n\t\t\tfor ( i=0, iLen=allSettings.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tvar s = allSettings[i];\n\t\t\t\n\t\t\t\t/* Base check on table node */\n\t\t\t\tif ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )\n\t\t\t\t{\n\t\t\t\t\tvar bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;\n\t\t\t\t\tvar bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;\n\t\t\t\n\t\t\t\t\tif ( emptyInit || bRetrieve )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn s.oInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( bDestroy )\n\t\t\t\t\t{\n\t\t\t\t\t\ts.oInstance.fnDestroy();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* If the element we are initialising has the same ID as a table which was previously\n\t\t\t\t * initialised, but the table nodes don't match (from before) then we destroy the old\n\t\t\t\t * instance by simply deleting it. This is under the assumption that the table has been\n\t\t\t\t * destroyed by other methods. Anyone using non-id selectors will need to do this manually\n\t\t\t\t */\n\t\t\t\tif ( s.sTableId == this.id )\n\t\t\t\t{\n\t\t\t\t\tallSettings.splice( i, 1 );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Ensure the table has an ID - required for accessibility */\n\t\t\tif ( sId === null || sId === \"\" )\n\t\t\t{\n\t\t\t\tsId = \"DataTables_Table_\"+(DataTable.ext._unique++);\n\t\t\t\tthis.id = sId;\n\t\t\t}\n\t\t\t\n\t\t\t/* Create the settings object for this table and set some of the default parameters */\n\t\t\tvar oSettings = $.extend( true, {}, DataTable.models.oSettings, {\n\t\t\t\t\"sDestroyWidth\": $this[0].style.width,\n\t\t\t\t\"sInstance\":     sId,\n\t\t\t\t\"sTableId\":      sId\n\t\t\t} );\n\t\t\toSettings.nTable = this;\n\t\t\toSettings.oApi   = _that.internal;\n\t\t\toSettings.oInit  = oInit;\n\t\t\t\n\t\t\tallSettings.push( oSettings );\n\t\t\t\n\t\t\t// Need to add the instance after the instance after the settings object has been added\n\t\t\t// to the settings array, so we can self reference the table instance if more than one\n\t\t\toSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();\n\t\t\t\n\t\t\t// Backwards compatibility, before we apply all the defaults\n\t\t\t_fnCompatOpts( oInit );\n\t\t\t\n\t\t\tif ( oInit.oLanguage )\n\t\t\t{\n\t\t\t\t_fnLanguageCompat( oInit.oLanguage );\n\t\t\t}\n\t\t\t\n\t\t\t// If the length menu is given, but the init display length is not, use the length menu\n\t\t\tif ( oInit.aLengthMenu && ! oInit.iDisplayLength )\n\t\t\t{\n\t\t\t\toInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?\n\t\t\t\t\toInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];\n\t\t\t}\n\t\t\t\n\t\t\t// Apply the defaults and init options to make a single init object will all\n\t\t\t// options defined from defaults and instance options.\n\t\t\toInit = _fnExtend( $.extend( true, {}, defaults ), oInit );\n\t\t\t\n\t\t\t\n\t\t\t// Map the initialisation options onto the settings object\n\t\t\t_fnMap( oSettings.oFeatures, oInit, [\n\t\t\t\t\"bPaginate\",\n\t\t\t\t\"bLengthChange\",\n\t\t\t\t\"bFilter\",\n\t\t\t\t\"bSort\",\n\t\t\t\t\"bSortMulti\",\n\t\t\t\t\"bInfo\",\n\t\t\t\t\"bProcessing\",\n\t\t\t\t\"bAutoWidth\",\n\t\t\t\t\"bSortClasses\",\n\t\t\t\t\"bServerSide\",\n\t\t\t\t\"bDeferRender\"\n\t\t\t] );\n\t\t\t_fnMap( oSettings, oInit, [\n\t\t\t\t\"asStripeClasses\",\n\t\t\t\t\"ajax\",\n\t\t\t\t\"fnServerData\",\n\t\t\t\t\"fnFormatNumber\",\n\t\t\t\t\"sServerMethod\",\n\t\t\t\t\"aaSorting\",\n\t\t\t\t\"aaSortingFixed\",\n\t\t\t\t\"aLengthMenu\",\n\t\t\t\t\"sPaginationType\",\n\t\t\t\t\"sAjaxSource\",\n\t\t\t\t\"sAjaxDataProp\",\n\t\t\t\t\"iStateDuration\",\n\t\t\t\t\"sDom\",\n\t\t\t\t\"bSortCellsTop\",\n\t\t\t\t\"iTabIndex\",\n\t\t\t\t\"fnStateLoadCallback\",\n\t\t\t\t\"fnStateSaveCallback\",\n\t\t\t\t\"renderer\",\n\t\t\t\t\"searchDelay\",\n\t\t\t\t\"rowId\",\n\t\t\t\t[ \"iCookieDuration\", \"iStateDuration\" ], // backwards compat\n\t\t\t\t[ \"oSearch\", \"oPreviousSearch\" ],\n\t\t\t\t[ \"aoSearchCols\", \"aoPreSearchCols\" ],\n\t\t\t\t[ \"iDisplayLength\", \"_iDisplayLength\" ],\n\t\t\t\t[ \"bJQueryUI\", \"bJUI\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oScroll, oInit, [\n\t\t\t\t[ \"sScrollX\", \"sX\" ],\n\t\t\t\t[ \"sScrollXInner\", \"sXInner\" ],\n\t\t\t\t[ \"sScrollY\", \"sY\" ],\n\t\t\t\t[ \"bScrollCollapse\", \"bCollapse\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oLanguage, oInit, \"fnInfoCallback\" );\n\t\t\t\n\t\t\t/* Callback functions which are array driven */\n\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );\n\t\t\t\n\t\t\toSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );\n\t\t\t\n\t\t\t/* Browser support detection */\n\t\t\t_fnBrowserDetect( oSettings );\n\t\t\t\n\t\t\tvar oClasses = oSettings.oClasses;\n\t\t\t\n\t\t\t// @todo Remove in 1.11\n\t\t\tif ( oInit.bJQueryUI )\n\t\t\t{\n\t\t\t\t/* Use the JUI classes object for display. You could clone the oStdClasses object if\n\t\t\t\t * you want to have multiple tables with multiple independent classes\n\t\t\t\t */\n\t\t\t\t$.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );\n\t\t\t\n\t\t\t\tif ( oInit.sDom === defaults.sDom && defaults.sDom === \"lfrtip\" )\n\t\t\t\t{\n\t\t\t\t\t/* Set the DOM to use a layout suitable for jQuery UI's theming */\n\t\t\t\t\toSettings.sDom = '<\"H\"lfr>t<\"F\"ip>';\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( ! oSettings.renderer ) {\n\t\t\t\t\toSettings.renderer = 'jqueryui';\n\t\t\t\t}\n\t\t\t\telse if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {\n\t\t\t\t\toSettings.renderer.header = 'jqueryui';\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );\n\t\t\t}\n\t\t\t$this.addClass( oClasses.sTable );\n\t\t\t\n\t\t\t\n\t\t\tif ( oSettings.iInitDisplayStart === undefined )\n\t\t\t{\n\t\t\t\t/* Display start point, taking into account the save saving */\n\t\t\t\toSettings.iInitDisplayStart = oInit.iDisplayStart;\n\t\t\t\toSettings._iDisplayStart = oInit.iDisplayStart;\n\t\t\t}\n\t\t\t\n\t\t\tif ( oInit.iDeferLoading !== null )\n\t\t\t{\n\t\t\t\toSettings.bDeferLoading = true;\n\t\t\t\tvar tmp = $.isArray( oInit.iDeferLoading );\n\t\t\t\toSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;\n\t\t\t\toSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;\n\t\t\t}\n\t\t\t\n\t\t\t/* Language definitions */\n\t\t\tvar oLanguage = oSettings.oLanguage;\n\t\t\t$.extend( true, oLanguage, oInit.oLanguage );\n\t\t\t\n\t\t\tif ( oLanguage.sUrl )\n\t\t\t{\n\t\t\t\t/* Get the language definitions from a file - because this Ajax call makes the language\n\t\t\t\t * get async to the remainder of this function we use bInitHandedOff to indicate that\n\t\t\t\t * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor\n\t\t\t\t */\n\t\t\t\t$.ajax( {\n\t\t\t\t\tdataType: 'json',\n\t\t\t\t\turl: oLanguage.sUrl,\n\t\t\t\t\tsuccess: function ( json ) {\n\t\t\t\t\t\t_fnLanguageCompat( json );\n\t\t\t\t\t\t_fnCamelToHungarian( defaults.oLanguage, json );\n\t\t\t\t\t\t$.extend( true, oLanguage, json );\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t},\n\t\t\t\t\terror: function () {\n\t\t\t\t\t\t// Error occurred loading language file, continue on as best we can\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tbInitHandedOff = true;\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Stripes\n\t\t\t */\n\t\t\tif ( oInit.asStripeClasses === null )\n\t\t\t{\n\t\t\t\toSettings.asStripeClasses =[\n\t\t\t\t\toClasses.sStripeOdd,\n\t\t\t\t\toClasses.sStripeEven\n\t\t\t\t];\n\t\t\t}\n\t\t\t\n\t\t\t/* Remove row stripe classes if they are already on the table row */\n\t\t\tvar stripeClasses = oSettings.asStripeClasses;\n\t\t\tvar rowOne = $this.children('tbody').find('tr').eq(0);\n\t\t\tif ( $.inArray( true, $.map( stripeClasses, function(el, i) {\n\t\t\t\treturn rowOne.hasClass(el);\n\t\t\t} ) ) !== -1 ) {\n\t\t\t\t$('tbody tr', this).removeClass( stripeClasses.join(' ') );\n\t\t\t\toSettings.asDestroyStripes = stripeClasses.slice();\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Columns\n\t\t\t * See if we should load columns automatically or use defined ones\n\t\t\t */\n\t\t\tvar anThs = [];\n\t\t\tvar aoColumnsInit;\n\t\t\tvar nThead = this.getElementsByTagName('thead');\n\t\t\tif ( nThead.length !== 0 )\n\t\t\t{\n\t\t\t\t_fnDetectHeader( oSettings.aoHeader, nThead[0] );\n\t\t\t\tanThs = _fnGetUniqueThs( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* If not given a column array, generate one with nulls */\n\t\t\tif ( oInit.aoColumns === null )\n\t\t\t{\n\t\t\t\taoColumnsInit = [];\n\t\t\t\tfor ( i=0, iLen=anThs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\taoColumnsInit.push( null );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoColumnsInit = oInit.aoColumns;\n\t\t\t}\n\t\t\t\n\t\t\t/* Add the columns */\n\t\t\tfor ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t_fnAddColumn( oSettings, anThs ? anThs[i] : null );\n\t\t\t}\n\t\t\t\n\t\t\t/* Apply the column definitions */\n\t\t\t_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {\n\t\t\t\t_fnColumnOptions( oSettings, iCol, oDef );\n\t\t\t} );\n\t\t\t\n\t\t\t/* HTML5 attribute detection - build an mData object automatically if the\n\t\t\t * attributes are found\n\t\t\t */\n\t\t\tif ( rowOne.length ) {\n\t\t\t\tvar a = function ( cell, name ) {\n\t\t\t\t\treturn cell.getAttribute( 'data-'+name ) !== null ? name : null;\n\t\t\t\t};\n\t\t\t\n\t\t\t\t$( rowOne[0] ).children('th, td').each( function (i, cell) {\n\t\t\t\t\tvar col = oSettings.aoColumns[i];\n\t\t\t\n\t\t\t\t\tif ( col.mData === i ) {\n\t\t\t\t\t\tvar sort = a( cell, 'sort' ) || a( cell, 'order' );\n\t\t\t\t\t\tvar filter = a( cell, 'filter' ) || a( cell, 'search' );\n\t\t\t\n\t\t\t\t\t\tif ( sort !== null || filter !== null ) {\n\t\t\t\t\t\t\tcol.mData = {\n\t\t\t\t\t\t\t\t_:      i+'.display',\n\t\t\t\t\t\t\t\tsort:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\ttype:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\tfilter: filter !== null ? i+'.@data-'+filter : undefined\n\t\t\t\t\t\t\t};\n\t\t\t\n\t\t\t\t\t\t\t_fnColumnOptions( oSettings, i );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\t\n\t\t\tvar features = oSettings.oFeatures;\n\t\t\tvar loadedInit = function () {\n\t\t\t\t/*\n\t\t\t\t * Sorting\n\t\t\t\t * @todo For modularisation (1.11) this needs to do into a sort start up handler\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// If aaSorting is not defined, then we use the first indicator in asSorting\n\t\t\t\t// in case that has been altered, so the default sort reflects that option\n\t\t\t\tif ( oInit.aaSorting === undefined ) {\n\t\t\t\t\tvar sorting = oSettings.aaSorting;\n\t\t\t\t\tfor ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {\n\t\t\t\t\t\tsorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Do a first pass on the sorting classes (allows any size changes to be taken into\n\t\t\t\t * account, and also will apply sorting disabled classes if disabled\n\t\t\t\t */\n\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\n\t\t\t\tif ( features.bSort ) {\n\t\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\t\tif ( oSettings.bSorted ) {\n\t\t\t\t\t\t\tvar aSort = _fnSortFlatten( oSettings );\n\t\t\t\t\t\t\tvar sortedColumns = {};\n\t\t\t\n\t\t\t\t\t\t\t$.each( aSort, function (i, val) {\n\t\t\t\t\t\t\t\tsortedColumns[ val.src ] = val.dir;\n\t\t\t\t\t\t\t} );\n\t\t\t\n\t\t\t\t\t\t\t_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );\n\t\t\t\t\t\t\t_fnSortAria( oSettings );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\tif ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {\n\t\t\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\t\t}\n\t\t\t\t}, 'sc' );\n\t\t\t\n\t\t\t\n\t\t\t\t/*\n\t\t\t\t * Final init\n\t\t\t\t * Cache the header, body and footer as required, creating them if needed\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// Work around for Webkit bug 83867 - store the caption-side before removing from doc\n\t\t\t\tvar captions = $this.children('caption').each( function () {\n\t\t\t\t\tthis._captionSide = $(this).css('caption-side');\n\t\t\t\t} );\n\t\t\t\n\t\t\t\tvar thead = $this.children('thead');\n\t\t\t\tif ( thead.length === 0 ) {\n\t\t\t\t\tthead = $('<thead/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTHead = thead[0];\n\t\t\t\n\t\t\t\tvar tbody = $this.children('tbody');\n\t\t\t\tif ( tbody.length === 0 ) {\n\t\t\t\t\ttbody = $('<tbody/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTBody = tbody[0];\n\t\t\t\n\t\t\t\tvar tfoot = $this.children('tfoot');\n\t\t\t\tif ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\") ) {\n\t\t\t\t\t// If we are a scrolling table, and no footer has been given, then we need to create\n\t\t\t\t\t// a tfoot element for the caption element to be appended to\n\t\t\t\t\ttfoot = $('<tfoot/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( tfoot.length === 0 || tfoot.children().length === 0 ) {\n\t\t\t\t\t$this.addClass( oClasses.sNoFooter );\n\t\t\t\t}\n\t\t\t\telse if ( tfoot.length > 0 ) {\n\t\t\t\t\toSettings.nTFoot = tfoot[0];\n\t\t\t\t\t_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Check if there is data passing into the constructor */\n\t\t\t\tif ( oInit.aaData ) {\n\t\t\t\t\tfor ( i=0 ; i<oInit.aaData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( oSettings, oInit.aaData[ i ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {\n\t\t\t\t\t/* Grab the data from the page - only do this when deferred loading or no Ajax\n\t\t\t\t\t * source since there is no point in reading the DOM data if we are then going\n\t\t\t\t\t * to replace it with Ajax data\n\t\t\t\t\t */\n\t\t\t\t\t_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Copy the data index array */\n\t\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\n\t\t\t\t/* Initialisation complete - table can be drawn */\n\t\t\t\toSettings.bInitialised = true;\n\t\t\t\n\t\t\t\t/* Check if we need to initialise the table (it might not have been handed off to the\n\t\t\t\t * language processor)\n\t\t\t\t */\n\t\t\t\tif ( bInitHandedOff === false ) {\n\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\t/* Must be done after everything which can be overridden by the state saving! */\n\t\t\tif ( oInit.bStateSave )\n\t\t\t{\n\t\t\t\tfeatures.bStateSave = true;\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );\n\t\t\t\t_fnLoadState( oSettings, oInit, loadedInit );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadedInit();\n\t\t\t}\n\t\t\t\n\t\t} );\n\t\t_that = null;\n\t\treturn this;\n\t};\n\n\t\n\t/*\n\t * It is useful to have variables which are scoped locally so only the\n\t * DataTables functions can access them and they don't leak into global space.\n\t * At the same time these functions are often useful over multiple files in the\n\t * core and API, so we list, or at least document, all variables which are used\n\t * by DataTables as private variables here. This also ensures that there is no\n\t * clashing of variable names and that they can easily referenced for reuse.\n\t */\n\t\n\t\n\t// Defined else where\n\t//  _selector_run\n\t//  _selector_opts\n\t//  _selector_first\n\t//  _selector_row_indexes\n\t\n\tvar _ext; // DataTable.ext\n\tvar _Api; // DataTable.Api\n\tvar _api_register; // DataTable.Api.register\n\tvar _api_registerPlural; // DataTable.Api.registerPlural\n\t\n\tvar _re_dic = {};\n\tvar _re_new_lines = /[\\r\\n]/g;\n\tvar _re_html = /<.*?>/g;\n\t\n\t// This is not strict ISO8601 - Date.parse() is quite lax, although\n\t// implementations differ between browsers.\n\tvar _re_date = /^\\d{2,4}[\\.\\/\\-]\\d{1,2}[\\.\\/\\-]\\d{1,2}([T ]{1}\\d{1,2}[:\\.]\\d{2}([\\.:]\\d{2})?)?$/;\n\t\n\t// Escape regular expression special characters\n\tvar _re_escape_regex = new RegExp( '(\\\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\\\', '$', '^', '-' ].join('|\\\\') + ')', 'g' );\n\t\n\t// http://en.wikipedia.org/wiki/Foreign_exchange_market\n\t// - \\u20BD - Russian ruble.\n\t// - \\u20a9 - South Korean Won\n\t// - \\u20BA - Turkish Lira\n\t// - \\u20B9 - Indian Rupee\n\t// - R - Brazil (R$) and South Africa\n\t// - fr - Swiss Franc\n\t// - kr - Swedish krona, Norwegian krone and Danish krone\n\t// - \\u2009 is thin space and \\u202F is narrow no-break space, both used in many\n\t//   standards as thousands separators.\n\tvar _re_formatted_numeric = /[',$£€¥%\\u2009\\u202F\\u20BD\\u20a9\\u20BArfk]/gi;\n\t\n\t\n\tvar _empty = function ( d ) {\n\t\treturn !d || d === true || d === '-' ? true : false;\n\t};\n\t\n\t\n\tvar _intVal = function ( s ) {\n\t\tvar integer = parseInt( s, 10 );\n\t\treturn !isNaN(integer) && isFinite(s) ? integer : null;\n\t};\n\t\n\t// Convert from a formatted number with characters other than `.` as the\n\t// decimal place, to a Javascript number\n\tvar _numToDecimal = function ( num, decimalPoint ) {\n\t\t// Cache created regular expressions for speed as this function is called often\n\t\tif ( ! _re_dic[ decimalPoint ] ) {\n\t\t\t_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );\n\t\t}\n\t\treturn typeof num === 'string' && decimalPoint !== '.' ?\n\t\t\tnum.replace( /\\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :\n\t\t\tnum;\n\t};\n\t\n\t\n\tvar _isNumber = function ( d, decimalPoint, formatted ) {\n\t\tvar strType = typeof d === 'string';\n\t\n\t\t// If empty return immediately so there must be a number if it is a\n\t\t// formatted string (this stops the string \"k\", or \"kr\", etc being detected\n\t\t// as a formatted number for currency\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tif ( decimalPoint && strType ) {\n\t\t\td = _numToDecimal( d, decimalPoint );\n\t\t}\n\t\n\t\tif ( formatted && strType ) {\n\t\t\td = d.replace( _re_formatted_numeric, '' );\n\t\t}\n\t\n\t\treturn !isNaN( parseFloat(d) ) && isFinite( d );\n\t};\n\t\n\t\n\t// A string without HTML in it can be considered to be HTML still\n\tvar _isHtml = function ( d ) {\n\t\treturn _empty( d ) || typeof d === 'string';\n\t};\n\t\n\t\n\tvar _htmlNumeric = function ( d, decimalPoint, formatted ) {\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tvar html = _isHtml( d );\n\t\treturn ! html ?\n\t\t\tnull :\n\t\t\t_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?\n\t\t\t\ttrue :\n\t\t\t\tnull;\n\t};\n\t\n\t\n\tvar _pluck = function ( a, prop, prop2 ) {\n\t\tvar out = [];\n\t\tvar i=0, ien=a.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] && a[i][ prop ] ) {\n\t\t\t\t\tout.push( a[i][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] ) {\n\t\t\t\t\tout.push( a[i][ prop ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t// Basically the same as _pluck, but rather than looping over `a` we use `order`\n\t// as the indexes to pick from `a`\n\tvar _pluck_order = function ( a, order, prop, prop2 )\n\t{\n\t\tvar out = [];\n\t\tvar i=0, ien=order.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[ order[i] ][ prop ] ) {\n\t\t\t\t\tout.push( a[ order[i] ][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tout.push( a[ order[i] ][ prop ] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _range = function ( len, start )\n\t{\n\t\tvar out = [];\n\t\tvar end;\n\t\n\t\tif ( start === undefined ) {\n\t\t\tstart = 0;\n\t\t\tend = len;\n\t\t}\n\t\telse {\n\t\t\tend = start;\n\t\t\tstart = len;\n\t\t}\n\t\n\t\tfor ( var i=start ; i<end ; i++ ) {\n\t\t\tout.push( i );\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _removeEmpty = function ( a )\n\t{\n\t\tvar out = [];\n\t\n\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\tif ( a[i] ) { // careful - will remove all falsy values!\n\t\t\t\tout.push( a[i] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _stripHtml = function ( d ) {\n\t\treturn d.replace( _re_html, '' );\n\t};\n\t\n\t\n\t/**\n\t * Find the unique elements in a source array.\n\t *\n\t * @param  {array} src Source array\n\t * @return {array} Array of unique items\n\t * @ignore\n\t */\n\tvar _unique = function ( src )\n\t{\n\t\t// A faster unique method is to use object keys to identify used values,\n\t\t// but this doesn't work with arrays or objects, which we must also\n\t\t// consider. See jsperf.com/compare-array-unique-versions/4 for more\n\t\t// information.\n\t\tvar\n\t\t\tout = [],\n\t\t\tval,\n\t\t\ti, ien=src.length,\n\t\t\tj, k=0;\n\t\n\t\tagain: for ( i=0 ; i<ien ; i++ ) {\n\t\t\tval = src[i];\n\t\n\t\t\tfor ( j=0 ; j<k ; j++ ) {\n\t\t\t\tif ( out[j] === val ) {\n\t\t\t\t\tcontinue again;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tout.push( val );\n\t\t\tk++;\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t/**\n\t * DataTables utility methods\n\t * \n\t * This namespace provides helper methods that DataTables uses internally to\n\t * create a DataTable, but which are not exclusively used only for DataTables.\n\t * These methods can be used by extension authors to save the duplication of\n\t * code.\n\t *\n\t *  @namespace\n\t */\n\tDataTable.util = {\n\t\t/**\n\t\t * Throttle the calls to a function. Arguments and context are maintained\n\t\t * for the throttled function.\n\t\t *\n\t\t * @param {function} fn Function to be called\n\t\t * @param {integer} freq Call frequency in mS\n\t\t * @return {function} Wrapped function\n\t\t */\n\t\tthrottle: function ( fn, freq ) {\n\t\t\tvar\n\t\t\t\tfrequency = freq !== undefined ? freq : 200,\n\t\t\t\tlast,\n\t\t\t\ttimer;\n\t\n\t\t\treturn function () {\n\t\t\t\tvar\n\t\t\t\t\tthat = this,\n\t\t\t\t\tnow  = +new Date(),\n\t\t\t\t\targs = arguments;\n\t\n\t\t\t\tif ( last && now < last + frequency ) {\n\t\t\t\t\tclearTimeout( timer );\n\t\n\t\t\t\t\ttimer = setTimeout( function () {\n\t\t\t\t\t\tlast = undefined;\n\t\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t\t}, frequency );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlast = now;\n\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Escape a string such that it can be used in a regular expression\n\t\t *\n\t\t *  @param {string} val string to escape\n\t\t *  @returns {string} escaped string\n\t\t */\n\t\tescapeRegex: function ( val ) {\n\t\t\treturn val.replace( _re_escape_regex, '\\\\$1' );\n\t\t}\n\t};\n\t\n\t\n\t\n\t/**\n\t * Create a mapping object that allows camel case parameters to be looked up\n\t * for their Hungarian counterparts. The mapping is stored in a private\n\t * parameter called `_hungarianMap` which can be accessed on the source object.\n\t *  @param {object} o\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnHungarianMap ( o )\n\t{\n\t\tvar\n\t\t\thungarian = 'a aa ai ao as b fn i m o s ',\n\t\t\tmatch,\n\t\t\tnewKey,\n\t\t\tmap = {};\n\t\n\t\t$.each( o, function (key, val) {\n\t\t\tmatch = key.match(/^([^A-Z]+?)([A-Z])/);\n\t\n\t\t\tif ( match && hungarian.indexOf(match[1]+' ') !== -1 )\n\t\t\t{\n\t\t\t\tnewKey = key.replace( match[0], match[2].toLowerCase() );\n\t\t\t\tmap[ newKey ] = key;\n\t\n\t\t\t\tif ( match[1] === 'o' )\n\t\t\t\t{\n\t\t\t\t\t_fnHungarianMap( o[key] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\n\t\to._hungarianMap = map;\n\t}\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian, based on a Hungarian map\n\t * created by _fnHungarianMap.\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCamelToHungarian ( src, user, force )\n\t{\n\t\tif ( ! src._hungarianMap ) {\n\t\t\t_fnHungarianMap( src );\n\t\t}\n\t\n\t\tvar hungarianKey;\n\t\n\t\t$.each( user, function (key, val) {\n\t\t\thungarianKey = src._hungarianMap[ key ];\n\t\n\t\t\tif ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )\n\t\t\t{\n\t\t\t\t// For objects, we need to buzz down into the object to copy parameters\n\t\t\t\tif ( hungarianKey.charAt(0) === 'o' )\n\t\t\t\t{\n\t\t\t\t\t// Copy the camelCase options over to the hungarian\n\t\t\t\t\tif ( ! user[ hungarianKey ] ) {\n\t\t\t\t\t\tuser[ hungarianKey ] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, user[hungarianKey], user[key] );\n\t\n\t\t\t\t\t_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tuser[hungarianKey] = user[ key ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Language compatibility - when certain options are given, and others aren't, we\n\t * need to duplicate the values over, in order to provide backwards compatibility\n\t * with older language files.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLanguageCompat( lang )\n\t{\n\t\tvar defaults = DataTable.defaults.oLanguage;\n\t\tvar zeroRecords = lang.sZeroRecords;\n\t\n\t\t/* Backwards compatibility - if there is no sEmptyTable given, then use the same as\n\t\t * sZeroRecords - assuming that is given.\n\t\t */\n\t\tif ( ! lang.sEmptyTable && zeroRecords &&\n\t\t\tdefaults.sEmptyTable === \"No data available in table\" )\n\t\t{\n\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );\n\t\t}\n\t\n\t\t/* Likewise with loading records */\n\t\tif ( ! lang.sLoadingRecords && zeroRecords &&\n\t\t\tdefaults.sLoadingRecords === \"Loading...\" )\n\t\t{\n\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );\n\t\t}\n\t\n\t\t// Old parameter name of the thousands separator mapped onto the new\n\t\tif ( lang.sInfoThousands ) {\n\t\t\tlang.sThousands = lang.sInfoThousands;\n\t\t}\n\t\n\t\tvar decimal = lang.sDecimal;\n\t\tif ( decimal ) {\n\t\t\t_addNumericSort( decimal );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Map one parameter onto another\n\t *  @param {object} o Object to map\n\t *  @param {*} knew The new parameter name\n\t *  @param {*} old The old parameter name\n\t */\n\tvar _fnCompatMap = function ( o, knew, old ) {\n\t\tif ( o[ knew ] !== undefined ) {\n\t\t\to[ old ] = o[ knew ];\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for the main DT options. Note that the new\n\t * options are mapped onto the old parameters, so this is an external interface\n\t * change only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatOpts ( init )\n\t{\n\t\t_fnCompatMap( init, 'ordering',      'bSort' );\n\t\t_fnCompatMap( init, 'orderMulti',    'bSortMulti' );\n\t\t_fnCompatMap( init, 'orderClasses',  'bSortClasses' );\n\t\t_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );\n\t\t_fnCompatMap( init, 'order',         'aaSorting' );\n\t\t_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );\n\t\t_fnCompatMap( init, 'paging',        'bPaginate' );\n\t\t_fnCompatMap( init, 'pagingType',    'sPaginationType' );\n\t\t_fnCompatMap( init, 'pageLength',    'iDisplayLength' );\n\t\t_fnCompatMap( init, 'searching',     'bFilter' );\n\t\n\t\t// Boolean initialisation of x-scrolling\n\t\tif ( typeof init.sScrollX === 'boolean' ) {\n\t\t\tinit.sScrollX = init.sScrollX ? '100%' : '';\n\t\t}\n\t\tif ( typeof init.scrollX === 'boolean' ) {\n\t\t\tinit.scrollX = init.scrollX ? '100%' : '';\n\t\t}\n\t\n\t\t// Column search objects are in an array, so it needs to be converted\n\t\t// element by element\n\t\tvar searchCols = init.aoSearchCols;\n\t\n\t\tif ( searchCols ) {\n\t\t\tfor ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {\n\t\t\t\tif ( searchCols[i] ) {\n\t\t\t\t\t_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for column options. Note that the new options\n\t * are mapped onto the old parameters, so this is an external interface change\n\t * only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatCols ( init )\n\t{\n\t\t_fnCompatMap( init, 'orderable',     'bSortable' );\n\t\t_fnCompatMap( init, 'orderData',     'aDataSort' );\n\t\t_fnCompatMap( init, 'orderSequence', 'asSorting' );\n\t\t_fnCompatMap( init, 'orderDataType', 'sortDataType' );\n\t\n\t\t// orderData can be given as an integer\n\t\tvar dataSort = init.aDataSort;\n\t\tif ( dataSort && ! $.isArray( dataSort ) ) {\n\t\t\tinit.aDataSort = [ dataSort ];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Browser feature detection for capabilities, quirks\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBrowserDetect( settings )\n\t{\n\t\t// We don't need to do this every time DataTables is constructed, the values\n\t\t// calculated are specific to the browser and OS configuration which we\n\t\t// don't expect to change between initialisations\n\t\tif ( ! DataTable.__browser ) {\n\t\t\tvar browser = {};\n\t\t\tDataTable.__browser = browser;\n\t\n\t\t\t// Scrolling feature / quirks detection\n\t\t\tvar n = $('<div/>')\n\t\t\t\t.css( {\n\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: $(window).scrollLeft()*-1, // allow for scrolling\n\t\t\t\t\theight: 1,\n\t\t\t\t\twidth: 1,\n\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t} )\n\t\t\t\t.append(\n\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\ttop: 1,\n\t\t\t\t\t\t\tleft: 1,\n\t\t\t\t\t\t\twidth: 100,\n\t\t\t\t\t\t\toverflow: 'scroll'\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t\t\t\theight: 10\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t.appendTo( 'body' );\n\t\n\t\t\tvar outer = n.children();\n\t\t\tvar inner = outer.children();\n\t\n\t\t\t// Numbers below, in order, are:\n\t\t\t// inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth\n\t\t\t//\n\t\t\t// IE6 XP:                           100 100 100  83\n\t\t\t// IE7 Vista:                        100 100 100  83\n\t\t\t// IE 8+ Windows:                     83  83 100  83\n\t\t\t// Evergreen Windows:                 83  83 100  83\n\t\t\t// Evergreen Mac with scrollbars:     85  85 100  85\n\t\t\t// Evergreen Mac without scrollbars: 100 100 100 100\n\t\n\t\t\t// Get scrollbar width\n\t\t\tbrowser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;\n\t\n\t\t\t// IE6/7 will oversize a width 100% element inside a scrolling element, to\n\t\t\t// include the width of the scrollbar, while other browsers ensure the inner\n\t\t\t// element is contained without forcing scrolling\n\t\t\tbrowser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;\n\t\n\t\t\t// In rtl text layout, some browsers (most, but not all) will place the\n\t\t\t// scrollbar on the left, rather than the right.\n\t\t\tbrowser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;\n\t\n\t\t\t// IE8- don't provide height and width for getBoundingClientRect\n\t\t\tbrowser.bBounding = n[0].getBoundingClientRect().width ? true : false;\n\t\n\t\t\tn.remove();\n\t\t}\n\t\n\t\t$.extend( settings.oBrowser, DataTable.__browser );\n\t\tsettings.oScroll.iBarWidth = DataTable.__browser.barWidth;\n\t}\n\t\n\t\n\t/**\n\t * Array.prototype reduce[Right] method, used for browsers which don't support\n\t * JS 1.6. Done this way to reduce code size, since we iterate either way\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReduce ( that, fn, init, start, end, inc )\n\t{\n\t\tvar\n\t\t\ti = start,\n\t\t\tvalue,\n\t\t\tisSet = false;\n\t\n\t\tif ( init !== undefined ) {\n\t\t\tvalue = init;\n\t\t\tisSet = true;\n\t\t}\n\t\n\t\twhile ( i !== end ) {\n\t\t\tif ( ! that.hasOwnProperty(i) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\tvalue = isSet ?\n\t\t\t\tfn( value, that[i], i, that ) :\n\t\t\t\tthat[i];\n\t\n\t\t\tisSet = true;\n\t\t\ti += inc;\n\t\t}\n\t\n\t\treturn value;\n\t}\n\t\n\t/**\n\t * Add a column to the list used for the table with default values\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nTh The th element for this column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddColumn( oSettings, nTh )\n\t{\n\t\t// Add column to aoColumns array\n\t\tvar oDefaults = DataTable.defaults.column;\n\t\tvar iCol = oSettings.aoColumns.length;\n\t\tvar oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {\n\t\t\t\"nTh\": nTh ? nTh : document.createElement('th'),\n\t\t\t\"sTitle\":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',\n\t\t\t\"aDataSort\": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],\n\t\t\t\"mData\": oDefaults.mData ? oDefaults.mData : iCol,\n\t\t\tidx: iCol\n\t\t} );\n\t\toSettings.aoColumns.push( oCol );\n\t\n\t\t// Add search object for column specific search. Note that the `searchCols[ iCol ]`\n\t\t// passed into extend can be undefined. This allows the user to give a default\n\t\t// with only some of the parameters defined, and also not give a default\n\t\tvar searchCols = oSettings.aoPreSearchCols;\n\t\tsearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );\n\t\n\t\t// Use the default column options function to initialise classes etc\n\t\t_fnColumnOptions( oSettings, iCol, $(nTh).data() );\n\t}\n\t\n\t\n\t/**\n\t * Apply options for a column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iCol column index to consider\n\t *  @param {object} oOptions object with sType, bVisible and bSearchable etc\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnOptions( oSettings, iCol, oOptions )\n\t{\n\t\tvar oCol = oSettings.aoColumns[ iCol ];\n\t\tvar oClasses = oSettings.oClasses;\n\t\tvar th = $(oCol.nTh);\n\t\n\t\t// Try to get width information from the DOM. We can't get it from CSS\n\t\t// as we'd need to parse the CSS stylesheet. `width` option can override\n\t\tif ( ! oCol.sWidthOrig ) {\n\t\t\t// Width attribute\n\t\t\toCol.sWidthOrig = th.attr('width') || null;\n\t\n\t\t\t// Style attribute\n\t\t\tvar t = (th.attr('style') || '').match(/width:\\s*(\\d+[pxem%]+)/);\n\t\t\tif ( t ) {\n\t\t\t\toCol.sWidthOrig = t[1];\n\t\t\t}\n\t\t}\n\t\n\t\t/* User specified column options */\n\t\tif ( oOptions !== undefined && oOptions !== null )\n\t\t{\n\t\t\t// Backwards compatibility\n\t\t\t_fnCompatCols( oOptions );\n\t\n\t\t\t// Map camel case parameters to their Hungarian counterparts\n\t\t\t_fnCamelToHungarian( DataTable.defaults.column, oOptions );\n\t\n\t\t\t/* Backwards compatibility for mDataProp */\n\t\t\tif ( oOptions.mDataProp !== undefined && !oOptions.mData )\n\t\t\t{\n\t\t\t\toOptions.mData = oOptions.mDataProp;\n\t\t\t}\n\t\n\t\t\tif ( oOptions.sType )\n\t\t\t{\n\t\t\t\toCol._sManualType = oOptions.sType;\n\t\t\t}\n\t\n\t\t\t// `class` is a reserved word in Javascript, so we need to provide\n\t\t\t// the ability to use a valid name for the camel case input\n\t\t\tif ( oOptions.className && ! oOptions.sClass )\n\t\t\t{\n\t\t\t\toOptions.sClass = oOptions.className;\n\t\t\t}\n\t\n\t\t\t$.extend( oCol, oOptions );\n\t\t\t_fnMap( oCol, oOptions, \"sWidth\", \"sWidthOrig\" );\n\t\n\t\t\t/* iDataSort to be applied (backwards compatibility), but aDataSort will take\n\t\t\t * priority if defined\n\t\t\t */\n\t\t\tif ( oOptions.iDataSort !== undefined )\n\t\t\t{\n\t\t\t\toCol.aDataSort = [ oOptions.iDataSort ];\n\t\t\t}\n\t\t\t_fnMap( oCol, oOptions, \"aDataSort\" );\n\t\t}\n\t\n\t\t/* Cache the data get and set functions for speed */\n\t\tvar mDataSrc = oCol.mData;\n\t\tvar mData = _fnGetObjectDataFn( mDataSrc );\n\t\tvar mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;\n\t\n\t\tvar attrTest = function( src ) {\n\t\t\treturn typeof src === 'string' && src.indexOf('@') !== -1;\n\t\t};\n\t\toCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (\n\t\t\tattrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)\n\t\t);\n\t\toCol._setter = null;\n\t\n\t\toCol.fnGetData = function (rowData, type, meta) {\n\t\t\tvar innerData = mData( rowData, type, undefined, meta );\n\t\n\t\t\treturn mRender && type ?\n\t\t\t\tmRender( innerData, type, rowData, meta ) :\n\t\t\t\tinnerData;\n\t\t};\n\t\toCol.fnSetData = function ( rowData, val, meta ) {\n\t\t\treturn _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );\n\t\t};\n\t\n\t\t// Indicate if DataTables should read DOM data as an object or array\n\t\t// Used in _fnGetRowElements\n\t\tif ( typeof mDataSrc !== 'number' ) {\n\t\t\toSettings._rowReadObject = true;\n\t\t}\n\t\n\t\t/* Feature sorting overrides column specific when off */\n\t\tif ( !oSettings.oFeatures.bSort )\n\t\t{\n\t\t\toCol.bSortable = false;\n\t\t\tth.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called\n\t\t}\n\t\n\t\t/* Check that the class assignment is correct for sorting */\n\t\tvar bAsc = $.inArray('asc', oCol.asSorting) !== -1;\n\t\tvar bDesc = $.inArray('desc', oCol.asSorting) !== -1;\n\t\tif ( !oCol.bSortable || (!bAsc && !bDesc) )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableNone;\n\t\t\toCol.sSortingClassJUI = \"\";\n\t\t}\n\t\telse if ( bAsc && !bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableAsc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;\n\t\t}\n\t\telse if ( !bAsc && bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableDesc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;\n\t\t}\n\t\telse\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortable;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUI;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Adjust the table column widths for new data. Note: you would probably want to\n\t * do a redraw after calling this function!\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAdjustColumnSizing ( settings )\n\t{\n\t\t/* Not interested in doing column width calculation if auto-width is disabled */\n\t\tif ( settings.oFeatures.bAutoWidth !== false )\n\t\t{\n\t\t\tvar columns = settings.aoColumns;\n\t\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t\tfor ( var i=0 , iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tcolumns[i].nTh.style.width = columns[i].sWidth;\n\t\t\t}\n\t\t}\n\t\n\t\tvar scroll = settings.oScroll;\n\t\tif ( scroll.sY !== '' || scroll.sX !== '')\n\t\t{\n\t\t\t_fnScrollDraw( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'column-sizing', [settings] );\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of a visible column to the index in the data array (take account\n\t * of hidden columns)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iMatch Visible column index to lookup\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisibleToColumnIndex( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\n\t\treturn typeof aiVis[iMatch] === 'number' ?\n\t\t\taiVis[iMatch] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of an index in the data array and convert it to the visible\n\t *   column index (take account of hidden columns)\n\t *  @param {int} iMatch Column index to lookup\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnIndexToVisible( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\tvar iPos = $.inArray( iMatch, aiVis );\n\t\n\t\treturn iPos !== -1 ? iPos : null;\n\t}\n\t\n\t\n\t/**\n\t * Get the number of visible columns\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the number of visible columns\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisbleColumns( oSettings )\n\t{\n\t\tvar vis = 0;\n\t\n\t\t// No reduce in IE8, use a loop for now\n\t\t$.each( oSettings.aoColumns, function ( i, col ) {\n\t\t\tif ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {\n\t\t\t\tvis++;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn vis;\n\t}\n\t\n\t\n\t/**\n\t * Get an array of column indexes that match a given property\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sParam Parameter in aoColumns to look for - typically\n\t *    bVisible or bSearchable\n\t *  @returns {array} Array of indexes with matched properties\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetColumns( oSettings, sParam )\n\t{\n\t\tvar a = [];\n\t\n\t\t$.map( oSettings.aoColumns, function(val, i) {\n\t\t\tif ( val[sParam] ) {\n\t\t\t\ta.push( i );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn a;\n\t}\n\t\n\t\n\t/**\n\t * Calculate the 'type' of a column\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnTypes ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar data = settings.aoData;\n\t\tvar types = DataTable.ext.type.detect;\n\t\tvar i, ien, j, jen, k, ken;\n\t\tvar col, cell, detectedType, cache;\n\t\n\t\t// For each column, spin over the \n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcol = columns[i];\n\t\t\tcache = [];\n\t\n\t\t\tif ( ! col.sType && col._sManualType ) {\n\t\t\t\tcol.sType = col._sManualType;\n\t\t\t}\n\t\t\telse if ( ! col.sType ) {\n\t\t\t\tfor ( j=0, jen=types.length ; j<jen ; j++ ) {\n\t\t\t\t\tfor ( k=0, ken=data.length ; k<ken ; k++ ) {\n\t\t\t\t\t\t// Use a cache array so we only need to get the type data\n\t\t\t\t\t\t// from the formatter once (when using multiple detectors)\n\t\t\t\t\t\tif ( cache[k] === undefined ) {\n\t\t\t\t\t\t\tcache[k] = _fnGetCellData( settings, k, i, 'type' );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tdetectedType = types[j]( cache[k], settings );\n\t\n\t\t\t\t\t\t// If null, then this type can't apply to this column, so\n\t\t\t\t\t\t// rather than testing all cells, break out. There is an\n\t\t\t\t\t\t// exception for the last type which is `html`. We need to\n\t\t\t\t\t\t// scan all rows since it is possible to mix string and HTML\n\t\t\t\t\t\t// types\n\t\t\t\t\t\tif ( ! detectedType && j !== types.length-1 ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Only a single match is needed for html type since it is\n\t\t\t\t\t\t// bottom of the pile and very similar to string\n\t\t\t\t\t\tif ( detectedType === 'html' ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Type is valid for all data points in the column - use this\n\t\t\t\t\t// type\n\t\t\t\t\tif ( detectedType ) {\n\t\t\t\t\t\tcol.sType = detectedType;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Fall back - if no type was detected, always use string\n\t\t\t\tif ( ! col.sType ) {\n\t\t\t\t\tcol.sType = 'string';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Take the column definitions and static columns arrays and calculate how\n\t * they relate to column indexes. The callback function will then apply the\n\t * definition found for a column to a suitable configuration object.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aoColDefs The aoColumnDefs array that is to be applied\n\t *  @param {array} aoCols The aoColumns array that defines columns individually\n\t *  @param {function} fn Callback function - takes two parameters, the calculated\n\t *    column index and the definition for that column.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, def;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Column definitions with aTargets\n\t\tif ( aoColDefs )\n\t\t{\n\t\t\t/* Loop over the definitions array - loop in reverse so first instance has priority */\n\t\t\tfor ( i=aoColDefs.length-1 ; i>=0 ; i-- )\n\t\t\t{\n\t\t\t\tdef = aoColDefs[i];\n\t\n\t\t\t\t/* Each definition can target multiple columns, as it is an array */\n\t\t\t\tvar aTargets = def.targets !== undefined ?\n\t\t\t\t\tdef.targets :\n\t\t\t\t\tdef.aTargets;\n\t\n\t\t\t\tif ( ! $.isArray( aTargets ) )\n\t\t\t\t{\n\t\t\t\t\taTargets = [ aTargets ];\n\t\t\t\t}\n\t\n\t\t\t\tfor ( j=0, jLen=aTargets.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Add columns that we don't yet know about */\n\t\t\t\t\t\twhile( columns.length <= aTargets[j] )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_fnAddColumn( oSettings );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t/* Integer, basic index */\n\t\t\t\t\t\tfn( aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Negative integer, right to left column counting */\n\t\t\t\t\t\tfn( columns.length+aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'string' )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Class name matching on TH element */\n\t\t\t\t\t\tfor ( k=0, kLen=columns.length ; k<kLen ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( aTargets[j] == \"_all\" ||\n\t\t\t\t\t\t\t     $(columns[k].nTh).hasClass( aTargets[j] ) )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfn( k, def );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// Statically defined columns array\n\t\tif ( aoCols )\n\t\t{\n\t\t\tfor ( i=0, iLen=aoCols.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfn( i, aoCols[i] );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * Add a data array to the table, creating DOM node etc. This is the parallel to\n\t * _fnGatherData, but for adding rows from a Javascript source, rather than a\n\t * DOM source.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aData data array to be added\n\t *  @param {node} [nTr] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddData ( oSettings, aDataIn, nTr, anTds )\n\t{\n\t\t/* Create the object for storing information about this new row */\n\t\tvar iRow = oSettings.aoData.length;\n\t\tvar oData = $.extend( true, {}, DataTable.models.oRow, {\n\t\t\tsrc: nTr ? 'dom' : 'data',\n\t\t\tidx: iRow\n\t\t} );\n\t\n\t\toData._aData = aDataIn;\n\t\toSettings.aoData.push( oData );\n\t\n\t\t/* Create the cells */\n\t\tvar nTd, sThisType;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Invalidate the column types as the new data needs to be revalidated\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tcolumns[i].sType = null;\n\t\t}\n\t\n\t\t/* Add to the display array */\n\t\toSettings.aiDisplayMaster.push( iRow );\n\t\n\t\tvar id = oSettings.rowIdFn( aDataIn );\n\t\tif ( id !== undefined ) {\n\t\t\toSettings.aIds[ id ] = oData;\n\t\t}\n\t\n\t\t/* Create the DOM information, or register it if already present */\n\t\tif ( nTr || ! oSettings.oFeatures.bDeferRender )\n\t\t{\n\t\t\t_fnCreateTr( oSettings, iRow, nTr, anTds );\n\t\t}\n\t\n\t\treturn iRow;\n\t}\n\t\n\t\n\t/**\n\t * Add one or more TR elements to the table. Generally we'd expect to\n\t * use this for reading data from a DOM sourced table, but it could be\n\t * used for an TR element. Note that if a TR is given, it is used (i.e.\n\t * it is not cloned).\n\t *  @param {object} settings dataTables settings object\n\t *  @param {array|node|jQuery} trs The TR element(s) to add to the table\n\t *  @returns {array} Array of indexes for the added rows\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddTr( settings, trs )\n\t{\n\t\tvar row;\n\t\n\t\t// Allow an individual node to be passed in\n\t\tif ( ! (trs instanceof $) ) {\n\t\t\ttrs = $(trs);\n\t\t}\n\t\n\t\treturn trs.map( function (i, el) {\n\t\t\trow = _fnGetRowElements( settings, el );\n\t\t\treturn _fnAddData( settings, row.data, el, row.cells );\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Take a TR element and convert it to an index in aoData\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} n the TR element to find\n\t *  @returns {int} index if the node is found, null if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToDataIndex( oSettings, n )\n\t{\n\t\treturn (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;\n\t}\n\t\n\t\n\t/**\n\t * Take a TD element and convert it into a column data index (not the visible index)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow The row number the TD/TH can be found in\n\t *  @param {node} n The TD/TH element to find\n\t *  @returns {int} index if the node is found, -1 if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToColumnIndex( oSettings, iRow, n )\n\t{\n\t\treturn $.inArray( n, oSettings.aoData[ iRow ].anCells );\n\t}\n\t\n\t\n\t/**\n\t * Get the data for a given cell from the internal cache, taking into account data mapping\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {string} type data get type ('display', 'type' 'filter' 'sort')\n\t *  @returns {*} Cell data\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetCellData( settings, rowIdx, colIdx, type )\n\t{\n\t\tvar draw           = settings.iDraw;\n\t\tvar col            = settings.aoColumns[colIdx];\n\t\tvar rowData        = settings.aoData[rowIdx]._aData;\n\t\tvar defaultContent = col.sDefaultContent;\n\t\tvar cellData       = col.fnGetData( rowData, type, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t} );\n\t\n\t\tif ( cellData === undefined ) {\n\t\t\tif ( settings.iDrawError != draw && defaultContent === null ) {\n\t\t\t\t_fnLog( settings, 0, \"Requested unknown parameter \"+\n\t\t\t\t\t(typeof col.mData=='function' ? '{function}' : \"'\"+col.mData+\"'\")+\n\t\t\t\t\t\" for row \"+rowIdx+\", column \"+colIdx, 4 );\n\t\t\t\tsettings.iDrawError = draw;\n\t\t\t}\n\t\t\treturn defaultContent;\n\t\t}\n\t\n\t\t// When the data source is null and a specific data type is requested (i.e.\n\t\t// not the original data), we can use default column data\n\t\tif ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {\n\t\t\tcellData = defaultContent;\n\t\t}\n\t\telse if ( typeof cellData === 'function' ) {\n\t\t\t// If the data source is a function, then we run it and use the return,\n\t\t\t// executing in the scope of the data object (for instances)\n\t\t\treturn cellData.call( rowData );\n\t\t}\n\t\n\t\tif ( cellData === null && type == 'display' ) {\n\t\t\treturn '';\n\t\t}\n\t\treturn cellData;\n\t}\n\t\n\t\n\t/**\n\t * Set the value for a specific cell, into the internal data cache\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {*} val Value to set\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetCellData( settings, rowIdx, colIdx, val )\n\t{\n\t\tvar col     = settings.aoColumns[colIdx];\n\t\tvar rowData = settings.aoData[rowIdx]._aData;\n\t\n\t\tcol.fnSetData( rowData, val, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t}  );\n\t}\n\t\n\t\n\t// Private variable that is used to match action syntax in the data property object\n\tvar __reArray = /\\[.*?\\]$/;\n\tvar __reFn = /\\(\\)$/;\n\t\n\t/**\n\t * Split string on periods, taking into account escaped periods\n\t * @param  {string} str String to split\n\t * @return {array} Split string\n\t */\n\tfunction _fnSplitObjNotation( str )\n\t{\n\t\treturn $.map( str.match(/(\\\\.|[^\\.])+/g) || [''], function ( s ) {\n\t\t\treturn s.replace(/\\\\\\./g, '.');\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to get data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data get function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Build an object of get functions, and wrap them in a single call */\n\t\t\tvar o = {};\n\t\t\t$.each( mSource, function (key, val) {\n\t\t\t\tif ( val ) {\n\t\t\t\t\to[key] = _fnGetObjectDataFn( val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\tvar t = o[type] || o._;\n\t\t\t\treturn t !== undefined ?\n\t\t\t\t\tt(data, type, row, meta) :\n\t\t\t\t\tdata;\n\t\t\t};\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Give an empty string for rendering / sorting etc */\n\t\t\treturn function (data) { // type, row and meta also passed, but not used\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\treturn mSource( data, type, row, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* If there is a . in the source string then the data source is in a\n\t\t\t * nested object so we loop over the data for each level to get the next\n\t\t\t * level down. On each loop we test for undefined, and if found immediately\n\t\t\t * return. This allows entire objects to be missing and sDefaultContent to\n\t\t\t * be used if defined, rather than throwing an error\n\t\t\t */\n\t\t\tvar fetchData = function (data, type, src) {\n\t\t\t\tvar arrayNotation, funcNotation, out, innerSrc;\n\t\n\t\t\t\tif ( src !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tvar a = _fnSplitObjNotation( src );\n\t\n\t\t\t\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if we are dealing with special notation\n\t\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Array notation\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\n\t\t\t\t\t\t\t// Condition allows simply [] to be passed in\n\t\t\t\t\t\t\tif ( a[i] !== \"\" ) {\n\t\t\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tout = [];\n\t\n\t\t\t\t\t\t\t// Get the remainder of the nested object to get\n\t\t\t\t\t\t\ta.splice( 0, i+1 );\n\t\t\t\t\t\t\tinnerSrc = a.join('.');\n\t\n\t\t\t\t\t\t\t// Traverse each entry in the array getting the properties requested\n\t\t\t\t\t\t\tif ( $.isArray( data ) ) {\n\t\t\t\t\t\t\t\tfor ( var j=0, jLen=data.length ; j<jLen ; j++ ) {\n\t\t\t\t\t\t\t\t\tout.push( fetchData( data[j], type, innerSrc ) );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\t// If a string is given in between the array notation indicators, that\n\t\t\t\t\t\t\t// is used to join the strings together, otherwise an array is returned\n\t\t\t\t\t\t\tvar join = arrayNotation[0].substring(1, arrayNotation[0].length-1);\n\t\t\t\t\t\t\tdata = (join===\"\") ? out : out.join(join);\n\t\n\t\t\t\t\t\t\t// The inner call to fetchData has already traversed through the remainder\n\t\t\t\t\t\t\t// of the source requested, so we exit from the loop\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Function call\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\t\tdata = data[ a[i] ]();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( data === null || data[ a[i] ] === undefined )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn data;\n\t\t\t};\n\t\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn fetchData( data, type, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn data[mSource];\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to set data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data set function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Unlike get, only the underscore (global) option is used for for\n\t\t\t * setting data since we don't know the type here. This is why an object\n\t\t\t * option is not documented for `mData` (which is read/write), but it is\n\t\t\t * for `mRender` which is read only.\n\t\t\t */\n\t\t\treturn _fnSetObjectDataFn( mSource._ );\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Nothing to do when the data source is null */\n\t\t\treturn function () {};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, val, meta) {\n\t\t\t\tmSource( data, 'set', val, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* Like the get, we need to get data from a nested object */\n\t\t\tvar setData = function (data, val, src) {\n\t\t\t\tvar a = _fnSplitObjNotation( src ), b;\n\t\t\t\tvar aLast = a[a.length-1];\n\t\t\t\tvar arrayNotation, funcNotation, o, innerSrc;\n\t\n\t\t\t\tfor ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\t// Check if we are dealing with an array notation request\n\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\t\t\t\t\tdata[ a[i] ] = [];\n\t\n\t\t\t\t\t\t// Get the remainder of the nested object to set so we can recurse\n\t\t\t\t\t\tb = a.slice();\n\t\t\t\t\t\tb.splice( 0, i+1 );\n\t\t\t\t\t\tinnerSrc = b.join('.');\n\t\n\t\t\t\t\t\t// Traverse each entry in the array setting the properties requested\n\t\t\t\t\t\tif ( $.isArray( val ) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor ( var j=0, jLen=val.length ; j<jLen ; j++ )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\to = {};\n\t\t\t\t\t\t\t\tsetData( o, val[j], innerSrc );\n\t\t\t\t\t\t\t\tdata[ a[i] ].push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We've been asked to save data to an array, but it\n\t\t\t\t\t\t\t// isn't array data to be saved. Best that can be done\n\t\t\t\t\t\t\t// is to just save the value.\n\t\t\t\t\t\t\tdata[ a[i] ] = val;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// The inner call to setData has already traversed through the remainder\n\t\t\t\t\t\t// of the source and has set the data, thus we can exit here\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Function call\n\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\tdata = data[ a[i] ]( val );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If the nested object doesn't currently exist - since we are\n\t\t\t\t\t// trying to set the value - create it\n\t\t\t\t\tif ( data[ a[i] ] === null || data[ a[i] ] === undefined )\n\t\t\t\t\t{\n\t\t\t\t\t\tdata[ a[i] ] = {};\n\t\t\t\t\t}\n\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t}\n\t\n\t\t\t\t// Last item in the input - i.e, the actual set\n\t\t\t\tif ( aLast.match(__reFn ) )\n\t\t\t\t{\n\t\t\t\t\t// Function call\n\t\t\t\t\tdata = data[ aLast.replace(__reFn, '') ]( val );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// If array notation is used, we just want to strip it and use the property name\n\t\t\t\t\t// and assign the value. If it isn't used, then we get the result we want anyway\n\t\t\t\t\tdata[ aLast.replace(__reArray, '') ] = val;\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\treturn setData( data, val, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\tdata[mSource] = val;\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return an array with the full table data\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns array {array} aData Master data array\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetDataMaster ( settings )\n\t{\n\t\treturn _pluck( settings.aoData, '_aData' );\n\t}\n\t\n\t\n\t/**\n\t * Nuke the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnClearTable( settings )\n\t{\n\t\tsettings.aoData.length = 0;\n\t\tsettings.aiDisplayMaster.length = 0;\n\t\tsettings.aiDisplay.length = 0;\n\t\tsettings.aIds = {};\n\t}\n\t\n\t\n\t /**\n\t * Take an array of integers (index array) and remove a target integer (value - not\n\t * the key!)\n\t *  @param {array} a Index array to target\n\t *  @param {int} iTarget value to find\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDeleteIndex( a, iTarget, splice )\n\t{\n\t\tvar iTargetIndex = -1;\n\t\n\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( a[i] == iTarget )\n\t\t\t{\n\t\t\t\tiTargetIndex = i;\n\t\t\t}\n\t\t\telse if ( a[i] > iTarget )\n\t\t\t{\n\t\t\t\ta[i]--;\n\t\t\t}\n\t\t}\n\t\n\t\tif ( iTargetIndex != -1 && splice === undefined )\n\t\t{\n\t\t\ta.splice( iTargetIndex, 1 );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Mark cached data as invalid such that a re-read of the data will occur when\n\t * the cached data is next requested. Also update from the data source object.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {int}    rowIdx   Row index to invalidate\n\t * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'\n\t *     or 'data'\n\t * @param {int}    [colIdx] Column index to invalidate. If undefined the whole\n\t *     row will be invalidated\n\t * @memberof DataTable#oApi\n\t *\n\t * @todo For the modularisation of v1.11 this will need to become a callback, so\n\t *   the sort and filter methods can subscribe to it. That will required\n\t *   initialisation options for sorting, which is why it is not already baked in\n\t */\n\tfunction _fnInvalidate( settings, rowIdx, src, colIdx )\n\t{\n\t\tvar row = settings.aoData[ rowIdx ];\n\t\tvar i, ien;\n\t\tvar cellWrite = function ( cell, col ) {\n\t\t\t// This is very frustrating, but in IE if you just write directly\n\t\t\t// to innerHTML, and elements that are overwritten are GC'ed,\n\t\t\t// even if there is a reference to them elsewhere\n\t\t\twhile ( cell.childNodes.length ) {\n\t\t\t\tcell.removeChild( cell.firstChild );\n\t\t\t}\n\t\n\t\t\tcell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );\n\t\t};\n\t\n\t\t// Are we reading last data from DOM or the data object?\n\t\tif ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {\n\t\t\t// Read the data from the DOM\n\t\t\trow._aData = _fnGetRowElements(\n\t\t\t\t\tsettings, row, colIdx, colIdx === undefined ? undefined : row._aData\n\t\t\t\t)\n\t\t\t\t.data;\n\t\t}\n\t\telse {\n\t\t\t// Reading from data object, update the DOM\n\t\t\tvar cells = row.anCells;\n\t\n\t\t\tif ( cells ) {\n\t\t\t\tif ( colIdx !== undefined ) {\n\t\t\t\t\tcellWrite( cells[colIdx], colIdx );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tcellWrite( cells[i], i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// For both row and cell invalidation, the cached data for sorting and\n\t\t// filtering is nulled out\n\t\trow._aSortData = null;\n\t\trow._aFilterData = null;\n\t\n\t\t// Invalidate the type for a specific column (if given) or all columns since\n\t\t// the data might have changed\n\t\tvar cols = settings.aoColumns;\n\t\tif ( colIdx !== undefined ) {\n\t\t\tcols[ colIdx ].sType = null;\n\t\t}\n\t\telse {\n\t\t\tfor ( i=0, ien=cols.length ; i<ien ; i++ ) {\n\t\t\t\tcols[i].sType = null;\n\t\t\t}\n\t\n\t\t\t// Update DataTables special `DT_*` attributes for the row\n\t\t\t_fnRowAttributes( settings, row );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a data source object from an HTML row, reading the contents of the\n\t * cells that are in the row.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {node|object} TR element from which to read data or existing row\n\t *   object from which to re-read the data from the cells\n\t * @param {int} [colIdx] Optional column index\n\t * @param {array|object} [d] Data source object. If `colIdx` is given then this\n\t *   parameter should also be given and will be used to write the data into.\n\t *   Only the column in question will be written\n\t * @returns {object} Object with two parameters: `data` the data read, in\n\t *   document order, and `cells` and array of nodes (they can be useful to the\n\t *   caller, so rather than needing a second traversal to get them, just return\n\t *   them from here).\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetRowElements( settings, row, colIdx, d )\n\t{\n\t\tvar\n\t\t\ttds = [],\n\t\t\ttd = row.firstChild,\n\t\t\tname, col, o, i=0, contents,\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tobjectRead = settings._rowReadObject;\n\t\n\t\t// Allow the data object to be passed in, or construct\n\t\td = d !== undefined ?\n\t\t\td :\n\t\t\tobjectRead ?\n\t\t\t\t{} :\n\t\t\t\t[];\n\t\n\t\tvar attr = function ( str, td  ) {\n\t\t\tif ( typeof str === 'string' ) {\n\t\t\t\tvar idx = str.indexOf('@');\n\t\n\t\t\t\tif ( idx !== -1 ) {\n\t\t\t\t\tvar attr = str.substring( idx+1 );\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( str );\n\t\t\t\t\tsetter( d, td.getAttribute( attr ) );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\n\t\t// Read data from a cell and store into the data object\n\t\tvar cellProcess = function ( cell ) {\n\t\t\tif ( colIdx === undefined || colIdx === i ) {\n\t\t\t\tcol = columns[i];\n\t\t\t\tcontents = $.trim(cell.innerHTML);\n\t\n\t\t\t\tif ( col && col._bAttrSrc ) {\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( col.mData._ );\n\t\t\t\t\tsetter( d, contents );\n\t\n\t\t\t\t\tattr( col.mData.sort, cell );\n\t\t\t\t\tattr( col.mData.type, cell );\n\t\t\t\t\tattr( col.mData.filter, cell );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Depending on the `data` option for the columns the data can\n\t\t\t\t\t// be read to either an object or an array.\n\t\t\t\t\tif ( objectRead ) {\n\t\t\t\t\t\tif ( ! col._setter ) {\n\t\t\t\t\t\t\t// Cache the setter function\n\t\t\t\t\t\t\tcol._setter = _fnSetObjectDataFn( col.mData );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcol._setter( d, contents );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\td[i] = contents;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t};\n\t\n\t\tif ( td ) {\n\t\t\t// `tr` element was passed in\n\t\t\twhile ( td ) {\n\t\t\t\tname = td.nodeName.toUpperCase();\n\t\n\t\t\t\tif ( name == \"TD\" || name == \"TH\" ) {\n\t\t\t\t\tcellProcess( td );\n\t\t\t\t\ttds.push( td );\n\t\t\t\t}\n\t\n\t\t\t\ttd = td.nextSibling;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Existing row object passed in\n\t\t\ttds = row.anCells;\n\t\n\t\t\tfor ( var j=0, jen=tds.length ; j<jen ; j++ ) {\n\t\t\t\tcellProcess( tds[j] );\n\t\t\t}\n\t\t}\n\t\n\t\t// Read the ID from the DOM if present\n\t\tvar rowNode = row.firstChild ? row : row.nTr;\n\t\n\t\tif ( rowNode ) {\n\t\t\tvar id = rowNode.getAttribute( 'id' );\n\t\n\t\t\tif ( id ) {\n\t\t\t\t_fnSetObjectDataFn( settings.rowId )( d, id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn {\n\t\t\tdata: d,\n\t\t\tcells: tds\n\t\t};\n\t}\n\t/**\n\t * Create a new TR element (and it's TD children) for a row\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow Row to consider\n\t *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCreateTr ( oSettings, iRow, nTrIn, anTds )\n\t{\n\t\tvar\n\t\t\trow = oSettings.aoData[iRow],\n\t\t\trowData = row._aData,\n\t\t\tcells = [],\n\t\t\tnTr, nTd, oCol,\n\t\t\ti, iLen;\n\t\n\t\tif ( row.nTr === null )\n\t\t{\n\t\t\tnTr = nTrIn || document.createElement('tr');\n\t\n\t\t\trow.nTr = nTr;\n\t\t\trow.anCells = cells;\n\t\n\t\t\t/* Use a private property on the node to allow reserve mapping from the node\n\t\t\t * to the aoData array for fast look up\n\t\t\t */\n\t\t\tnTr._DT_RowIndex = iRow;\n\t\n\t\t\t/* Special parameters can be given by the data source to be used on the row */\n\t\t\t_fnRowAttributes( oSettings, row );\n\t\n\t\t\t/* Process each column */\n\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toCol = oSettings.aoColumns[i];\n\t\n\t\t\t\tnTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );\n\t\t\t\tnTd._DT_CellIndex = {\n\t\t\t\t\trow: iRow,\n\t\t\t\t\tcolumn: i\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tcells.push( nTd );\n\t\n\t\t\t\t// Need to create the HTML if new, or if a rendering function is defined\n\t\t\t\tif ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&\n\t\t\t\t\t (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')\n\t\t\t\t) {\n\t\t\t\t\tnTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );\n\t\t\t\t}\n\t\n\t\t\t\t/* Add user defined class */\n\t\t\t\tif ( oCol.sClass )\n\t\t\t\t{\n\t\t\t\t\tnTd.className += ' '+oCol.sClass;\n\t\t\t\t}\n\t\n\t\t\t\t// Visibility - add or remove as required\n\t\t\t\tif ( oCol.bVisible && ! nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTr.appendChild( nTd );\n\t\t\t\t}\n\t\t\t\telse if ( ! oCol.bVisible && nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTd.parentNode.removeChild( nTd );\n\t\t\t\t}\n\t\n\t\t\t\tif ( oCol.fnCreatedCell )\n\t\t\t\t{\n\t\t\t\t\toCol.fnCreatedCell.call( oSettings.oInstance,\n\t\t\t\t\t\tnTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );\n\t\t}\n\t\n\t\t// Remove once webkit bug 131819 and Chromium bug 365619 have been resolved\n\t\t// and deployed\n\t\trow.nTr.setAttribute( 'role', 'row' );\n\t}\n\t\n\t\n\t/**\n\t * Add attributes to a row based on the special `DT_*` parameters in a data\n\t * source object.\n\t *  @param {object} settings DataTables settings object\n\t *  @param {object} DataTables row object for the row to be modified\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnRowAttributes( settings, row )\n\t{\n\t\tvar tr = row.nTr;\n\t\tvar data = row._aData;\n\t\n\t\tif ( tr ) {\n\t\t\tvar id = settings.rowIdFn( data );\n\t\n\t\t\tif ( id ) {\n\t\t\t\ttr.id = id;\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowClass ) {\n\t\t\t\t// Remove any classes added by DT_RowClass before\n\t\t\t\tvar a = data.DT_RowClass.split(' ');\n\t\t\t\trow.__rowc = row.__rowc ?\n\t\t\t\t\t_unique( row.__rowc.concat( a ) ) :\n\t\t\t\t\ta;\n\t\n\t\t\t\t$(tr)\n\t\t\t\t\t.removeClass( row.__rowc.join(' ') )\n\t\t\t\t\t.addClass( data.DT_RowClass );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowAttr ) {\n\t\t\t\t$(tr).attr( data.DT_RowAttr );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowData ) {\n\t\t\t\t$(tr).data( data.DT_RowData );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Create the HTML header for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBuildHead( oSettings )\n\t{\n\t\tvar i, ien, cell, row, column;\n\t\tvar thead = oSettings.nTHead;\n\t\tvar tfoot = oSettings.nTFoot;\n\t\tvar createHeader = $('th, td', thead).length === 0;\n\t\tvar classes = oSettings.oClasses;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\tif ( createHeader ) {\n\t\t\trow = $('<tr/>').appendTo( thead );\n\t\t}\n\t\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcell = $( column.nTh ).addClass( column.sClass );\n\t\n\t\t\tif ( createHeader ) {\n\t\t\t\tcell.appendTo( row );\n\t\t\t}\n\t\n\t\t\t// 1.11 move into sorting\n\t\t\tif ( oSettings.oFeatures.bSort ) {\n\t\t\t\tcell.addClass( column.sSortingClass );\n\t\n\t\t\t\tif ( column.bSortable !== false ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.attr( 'tabindex', oSettings.iTabIndex )\n\t\t\t\t\t\t.attr( 'aria-controls', oSettings.sTableId );\n\t\n\t\t\t\t\t_fnSortAttachListener( oSettings, column.nTh, i );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( column.sTitle != cell[0].innerHTML ) {\n\t\t\t\tcell.html( column.sTitle );\n\t\t\t}\n\t\n\t\t\t_fnRenderer( oSettings, 'header' )(\n\t\t\t\toSettings, cell, column, classes\n\t\t\t);\n\t\t}\n\t\n\t\tif ( createHeader ) {\n\t\t\t_fnDetectHeader( oSettings.aoHeader, thead );\n\t\t}\n\t\t\n\t\t/* ARIA role for the rows */\n\t \t$(thead).find('>tr').attr('role', 'row');\n\t\n\t\t/* Deal with the footer - add classes if required */\n\t\t$(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );\n\t\t$(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );\n\t\n\t\t// Cache the footer cells. Note that we only take the cells from the first\n\t\t// row in the footer. If there is more than one row the user wants to\n\t\t// interact with, they need to use the table().foot() method. Note also this\n\t\t// allows cells to be used for multiple columns using colspan\n\t\tif ( tfoot !== null ) {\n\t\t\tvar cells = oSettings.aoFooter[0];\n\t\n\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tcolumn = columns[i];\n\t\t\t\tcolumn.nTf = cells[i].cell;\n\t\n\t\t\t\tif ( column.sClass ) {\n\t\t\t\t\t$(column.nTf).addClass( column.sClass );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the header (or footer) element based on the column visibility states. The\n\t * methodology here is to use the layout array from _fnDetectHeader, modified for\n\t * the instantaneous column visibility, to construct the new layout. The grid is\n\t * traversed over cell at a time in a rows x columns grid fashion, although each\n\t * cell insert can cover multiple elements in the grid - which is tracks using the\n\t * aApplied array. Cell inserts in the grid will only occur where there isn't\n\t * already a cell in that position.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param array {objects} aoSource Layout array from _fnDetectHeader\n\t *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDrawHead( oSettings, aoSource, bIncludeHidden )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, n, nLocalTr;\n\t\tvar aoLocal = [];\n\t\tvar aApplied = [];\n\t\tvar iColumns = oSettings.aoColumns.length;\n\t\tvar iRowspan, iColspan;\n\t\n\t\tif ( ! aoSource )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif (  bIncludeHidden === undefined )\n\t\t{\n\t\t\tbIncludeHidden = false;\n\t\t}\n\t\n\t\t/* Make a copy of the master layout array, but without the visible columns in it */\n\t\tfor ( i=0, iLen=aoSource.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taoLocal[i] = aoSource[i].slice();\n\t\t\taoLocal[i].nTr = aoSource[i].nTr;\n\t\n\t\t\t/* Remove any columns which are currently hidden */\n\t\t\tfor ( j=iColumns-1 ; j>=0 ; j-- )\n\t\t\t{\n\t\t\t\tif ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )\n\t\t\t\t{\n\t\t\t\t\taoLocal[i].splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Prep the applied array - it needs an element for each row */\n\t\t\taApplied.push( [] );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnLocalTr = aoLocal[i].nTr;\n\t\n\t\t\t/* All cells are going to be replaced, so empty out the row */\n\t\t\tif ( nLocalTr )\n\t\t\t{\n\t\t\t\twhile( (n = nLocalTr.firstChild) )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.removeChild( n );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tfor ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tiRowspan = 1;\n\t\t\t\tiColspan = 1;\n\t\n\t\t\t\t/* Check to see if there is already a cell (row/colspan) covering our target\n\t\t\t\t * insert point. If there is, then there is nothing to do.\n\t\t\t\t */\n\t\t\t\tif ( aApplied[i][j] === undefined )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.appendChild( aoLocal[i][j].cell );\n\t\t\t\t\taApplied[i][j] = 1;\n\t\n\t\t\t\t\t/* Expand the cell to cover as many rows as needed */\n\t\t\t\t\twhile ( aoLocal[i+iRowspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\taApplied[i+iRowspan][j] = 1;\n\t\t\t\t\t\tiRowspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Expand the cell to cover as many columns as needed */\n\t\t\t\t\twhile ( aoLocal[i][j+iColspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Must update the applied array over the rows for the columns */\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taApplied[i+k][j+iColspan] = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiColspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Do the actual expansion in the DOM */\n\t\t\t\t\t$(aoLocal[i][j].cell)\n\t\t\t\t\t\t.attr('rowspan', iRowspan)\n\t\t\t\t\t\t.attr('colspan', iColspan);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Insert the required TR nodes into the table for display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDraw( oSettings )\n\t{\n\t\t/* Provide a pre-callback function which can be used to cancel the draw is false is returned */\n\t\tvar aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );\n\t\tif ( $.inArray( false, aPreDraw ) !== -1 )\n\t\t{\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar i, iLen, n;\n\t\tvar anRows = [];\n\t\tvar iRowCount = 0;\n\t\tvar asStripeClasses = oSettings.asStripeClasses;\n\t\tvar iStripes = asStripeClasses.length;\n\t\tvar iOpenRows = oSettings.aoOpenRows.length;\n\t\tvar oLang = oSettings.oLanguage;\n\t\tvar iInitDisplayStart = oSettings.iInitDisplayStart;\n\t\tvar bServerSide = _fnDataSource( oSettings ) == 'ssp';\n\t\tvar aiDisplay = oSettings.aiDisplay;\n\t\n\t\toSettings.bDrawing = true;\n\t\n\t\t/* Check and see if we have an initial draw position from state saving */\n\t\tif ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )\n\t\t{\n\t\t\toSettings._iDisplayStart = bServerSide ?\n\t\t\t\tiInitDisplayStart :\n\t\t\t\tiInitDisplayStart >= oSettings.fnRecordsDisplay() ?\n\t\t\t\t\t0 :\n\t\t\t\t\tiInitDisplayStart;\n\t\n\t\t\toSettings.iInitDisplayStart = -1;\n\t\t}\n\t\n\t\tvar iDisplayStart = oSettings._iDisplayStart;\n\t\tvar iDisplayEnd = oSettings.fnDisplayEnd();\n\t\n\t\t/* Server-side processing draw intercept */\n\t\tif ( oSettings.bDeferLoading )\n\t\t{\n\t\t\toSettings.bDeferLoading = false;\n\t\t\toSettings.iDraw++;\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t}\n\t\telse if ( !bServerSide )\n\t\t{\n\t\t\toSettings.iDraw++;\n\t\t}\n\t\telse if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( aiDisplay.length !== 0 )\n\t\t{\n\t\t\tvar iStart = bServerSide ? 0 : iDisplayStart;\n\t\t\tvar iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;\n\t\n\t\t\tfor ( var j=iStart ; j<iEnd ; j++ )\n\t\t\t{\n\t\t\t\tvar iDataIndex = aiDisplay[j];\n\t\t\t\tvar aoData = oSettings.aoData[ iDataIndex ];\n\t\t\t\tif ( aoData.nTr === null )\n\t\t\t\t{\n\t\t\t\t\t_fnCreateTr( oSettings, iDataIndex );\n\t\t\t\t}\n\t\n\t\t\t\tvar nRow = aoData.nTr;\n\t\n\t\t\t\t/* Remove the old striping classes and then add the new one */\n\t\t\t\tif ( iStripes !== 0 )\n\t\t\t\t{\n\t\t\t\t\tvar sStripe = asStripeClasses[ iRowCount % iStripes ];\n\t\t\t\t\tif ( aoData._sRowStripe != sStripe )\n\t\t\t\t\t{\n\t\t\t\t\t\t$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );\n\t\t\t\t\t\taoData._sRowStripe = sStripe;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Row callback functions - might want to manipulate the row\n\t\t\t\t// iRowCount and j are not currently documented. Are they at all\n\t\t\t\t// useful?\n\t\t\t\t_fnCallbackFire( oSettings, 'aoRowCallback', null,\n\t\t\t\t\t[nRow, aoData._aData, iRowCount, j] );\n\t\n\t\t\t\tanRows.push( nRow );\n\t\t\t\tiRowCount++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Table is empty - create a row with an empty message in it */\n\t\t\tvar sZero = oLang.sZeroRecords;\n\t\t\tif ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )\n\t\t\t{\n\t\t\t\tsZero = oLang.sLoadingRecords;\n\t\t\t}\n\t\t\telse if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )\n\t\t\t{\n\t\t\t\tsZero = oLang.sEmptyTable;\n\t\t\t}\n\t\n\t\t\tanRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )\n\t\t\t\t.append( $('<td />', {\n\t\t\t\t\t'valign':  'top',\n\t\t\t\t\t'colSpan': _fnVisbleColumns( oSettings ),\n\t\t\t\t\t'class':   oSettings.oClasses.sRowEmpty\n\t\t\t\t} ).html( sZero ) )[0];\n\t\t}\n\t\n\t\t/* Header and footer callbacks */\n\t\t_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\t_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\tvar body = $(oSettings.nTBody);\n\t\n\t\tbody.children().detach();\n\t\tbody.append( $(anRows) );\n\t\n\t\t/* Call all required callback functions for the end of a draw */\n\t\t_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );\n\t\n\t\t/* Draw is complete, sorting and filtering must be as well */\n\t\toSettings.bSorted = false;\n\t\toSettings.bFiltered = false;\n\t\toSettings.bDrawing = false;\n\t}\n\t\n\t\n\t/**\n\t * Redraw the table - taking account of the various features which are enabled\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {boolean} [holdPosition] Keep the current paging position. By default\n\t *    the paging is reset to the first page\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReDraw( settings, holdPosition )\n\t{\n\t\tvar\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tsort     = features.bSort,\n\t\t\tfilter   = features.bFilter;\n\t\n\t\tif ( sort ) {\n\t\t\t_fnSort( settings );\n\t\t}\n\t\n\t\tif ( filter ) {\n\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch );\n\t\t}\n\t\telse {\n\t\t\t// No filtering, so we want to just use the display master\n\t\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\t}\n\t\n\t\tif ( holdPosition !== true ) {\n\t\t\tsettings._iDisplayStart = 0;\n\t\t}\n\t\n\t\t// Let any modules know about the draw hold position state (used by\n\t\t// scrolling internally)\n\t\tsettings._drawHold = holdPosition;\n\t\n\t\t_fnDraw( settings );\n\t\n\t\tsettings._drawHold = false;\n\t}\n\t\n\t\n\t/**\n\t * Add the options to the page HTML for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddOptionsHtml ( oSettings )\n\t{\n\t\tvar classes = oSettings.oClasses;\n\t\tvar table = $(oSettings.nTable);\n\t\tvar holding = $('<div/>').insertBefore( table ); // Holding element for speed\n\t\tvar features = oSettings.oFeatures;\n\t\n\t\t// All DataTables are wrapped in a div\n\t\tvar insert = $('<div/>', {\n\t\t\tid:      oSettings.sTableId+'_wrapper',\n\t\t\t'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)\n\t\t} );\n\t\n\t\toSettings.nHolding = holding[0];\n\t\toSettings.nTableWrapper = insert[0];\n\t\toSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;\n\t\n\t\t/* Loop over the user set positioning and place the elements as needed */\n\t\tvar aDom = oSettings.sDom.split('');\n\t\tvar featureNode, cOption, nNewNode, cNext, sAttr, j;\n\t\tfor ( var i=0 ; i<aDom.length ; i++ )\n\t\t{\n\t\t\tfeatureNode = null;\n\t\t\tcOption = aDom[i];\n\t\n\t\t\tif ( cOption == '<' )\n\t\t\t{\n\t\t\t\t/* New container div */\n\t\t\t\tnNewNode = $('<div/>')[0];\n\t\n\t\t\t\t/* Check to see if we should append an id and/or a class name to the container */\n\t\t\t\tcNext = aDom[i+1];\n\t\t\t\tif ( cNext == \"'\" || cNext == '\"' )\n\t\t\t\t{\n\t\t\t\t\tsAttr = \"\";\n\t\t\t\t\tj = 2;\n\t\t\t\t\twhile ( aDom[i+j] != cNext )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr += aDom[i+j];\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Replace jQuery UI constants @todo depreciated */\n\t\t\t\t\tif ( sAttr == \"H\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIHeader;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr == \"F\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIFooter;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* The attribute can be in the format of \"#id.class\", \"#id\" or \"class\" This logic\n\t\t\t\t\t * breaks the string into parts and applies them as needed\n\t\t\t\t\t */\n\t\t\t\t\tif ( sAttr.indexOf('.') != -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar aSplit = sAttr.split('.');\n\t\t\t\t\t\tnNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);\n\t\t\t\t\t\tnNewNode.className = aSplit[1];\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr.charAt(0) == \"#\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.id = sAttr.substr(1, sAttr.length-1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.className = sAttr;\n\t\t\t\t\t}\n\t\n\t\t\t\t\ti += j; /* Move along the position array */\n\t\t\t\t}\n\t\n\t\t\t\tinsert.append( nNewNode );\n\t\t\t\tinsert = $(nNewNode);\n\t\t\t}\n\t\t\telse if ( cOption == '>' )\n\t\t\t{\n\t\t\t\t/* End container div */\n\t\t\t\tinsert = insert.parent();\n\t\t\t}\n\t\t\t// @todo Move options into their own plugins?\n\t\t\telse if ( cOption == 'l' && features.bPaginate && features.bLengthChange )\n\t\t\t{\n\t\t\t\t/* Length */\n\t\t\t\tfeatureNode = _fnFeatureHtmlLength( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'f' && features.bFilter )\n\t\t\t{\n\t\t\t\t/* Filter */\n\t\t\t\tfeatureNode = _fnFeatureHtmlFilter( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'r' && features.bProcessing )\n\t\t\t{\n\t\t\t\t/* pRocessing */\n\t\t\t\tfeatureNode = _fnFeatureHtmlProcessing( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 't' )\n\t\t\t{\n\t\t\t\t/* Table */\n\t\t\t\tfeatureNode = _fnFeatureHtmlTable( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption ==  'i' && features.bInfo )\n\t\t\t{\n\t\t\t\t/* Info */\n\t\t\t\tfeatureNode = _fnFeatureHtmlInfo( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'p' && features.bPaginate )\n\t\t\t{\n\t\t\t\t/* Pagination */\n\t\t\t\tfeatureNode = _fnFeatureHtmlPaginate( oSettings );\n\t\t\t}\n\t\t\telse if ( DataTable.ext.feature.length !== 0 )\n\t\t\t{\n\t\t\t\t/* Plug-in features */\n\t\t\t\tvar aoFeatures = DataTable.ext.feature;\n\t\t\t\tfor ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )\n\t\t\t\t{\n\t\t\t\t\tif ( cOption == aoFeatures[k].cFeature )\n\t\t\t\t\t{\n\t\t\t\t\t\tfeatureNode = aoFeatures[k].fnInit( oSettings );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Add to the 2D features array */\n\t\t\tif ( featureNode )\n\t\t\t{\n\t\t\t\tvar aanFeatures = oSettings.aanFeatures;\n\t\n\t\t\t\tif ( ! aanFeatures[cOption] )\n\t\t\t\t{\n\t\t\t\t\taanFeatures[cOption] = [];\n\t\t\t\t}\n\t\n\t\t\t\taanFeatures[cOption].push( featureNode );\n\t\t\t\tinsert.append( featureNode );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Built our DOM structure - replace the holding div with what we want */\n\t\tholding.replaceWith( insert );\n\t\toSettings.nHolding = null;\n\t}\n\t\n\t\n\t/**\n\t * Use the DOM source to create up an array of header cells. The idea here is to\n\t * create a layout grid (array) of rows x columns, which contains a reference\n\t * to the cell that that point in the grid (regardless of col/rowspan), such that\n\t * any column / row could be removed and the new grid constructed\n\t *  @param array {object} aLayout Array to store the calculated layout in\n\t *  @param {node} nThead The header/footer element for the table\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDetectHeader ( aLayout, nThead )\n\t{\n\t\tvar nTrs = $(nThead).children('tr');\n\t\tvar nTr, nCell;\n\t\tvar i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;\n\t\tvar bUnique;\n\t\tvar fnShiftCol = function ( a, i, j ) {\n\t\t\tvar k = a[i];\n\t                while ( k[j] ) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\treturn j;\n\t\t};\n\t\n\t\taLayout.splice( 0, aLayout.length );\n\t\n\t\t/* We know how many rows there are in the layout - so prep it */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taLayout.push( [] );\n\t\t}\n\t\n\t\t/* Calculate a layout array */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnTr = nTrs[i];\n\t\t\tiColumn = 0;\n\t\n\t\t\t/* For every cell in the row... */\n\t\t\tnCell = nTr.firstChild;\n\t\t\twhile ( nCell ) {\n\t\t\t\tif ( nCell.nodeName.toUpperCase() == \"TD\" ||\n\t\t\t\t     nCell.nodeName.toUpperCase() == \"TH\" )\n\t\t\t\t{\n\t\t\t\t\t/* Get the col and rowspan attributes from the DOM and sanitise them */\n\t\t\t\t\tiColspan = nCell.getAttribute('colspan') * 1;\n\t\t\t\t\tiRowspan = nCell.getAttribute('rowspan') * 1;\n\t\t\t\t\tiColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;\n\t\t\t\t\tiRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;\n\t\n\t\t\t\t\t/* There might be colspan cells already in this row, so shift our target\n\t\t\t\t\t * accordingly\n\t\t\t\t\t */\n\t\t\t\t\tiColShifted = fnShiftCol( aLayout, i, iColumn );\n\t\n\t\t\t\t\t/* Cache calculation for unique columns */\n\t\t\t\t\tbUnique = iColspan === 1 ? true : false;\n\t\n\t\t\t\t\t/* If there is col / rowspan, copy the information into the layout grid */\n\t\t\t\t\tfor ( l=0 ; l<iColspan ; l++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taLayout[i+k][iColShifted+l] = {\n\t\t\t\t\t\t\t\t\"cell\": nCell,\n\t\t\t\t\t\t\t\t\"unique\": bUnique\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\taLayout[i+k].nTr = nTr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnCell = nCell.nextSibling;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Get an array of unique th elements, one for each column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nHeader automatically detect the layout from this node - optional\n\t *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional\n\t *  @returns array {node} aReturn list of unique th's\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetUniqueThs ( oSettings, nHeader, aLayout )\n\t{\n\t\tvar aReturn = [];\n\t\tif ( !aLayout )\n\t\t{\n\t\t\taLayout = oSettings.aoHeader;\n\t\t\tif ( nHeader )\n\t\t\t{\n\t\t\t\taLayout = [];\n\t\t\t\t_fnDetectHeader( aLayout, nHeader );\n\t\t\t}\n\t\t}\n\t\n\t\tfor ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfor ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( aLayout[i][j].unique &&\n\t\t\t\t\t (!aReturn[j] || !oSettings.bSortCellsTop) )\n\t\t\t\t{\n\t\t\t\t\taReturn[j] = aLayout[i][j].cell;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn aReturn;\n\t}\n\t\n\t/**\n\t * Create an Ajax call based on the table's settings, taking into account that\n\t * parameters can have multiple forms, and backwards compatibility.\n\t *\n\t * @param {object} oSettings dataTables settings object\n\t * @param {array} data Data to send to the server, required by\n\t *     DataTables - may be augmented by developer callbacks\n\t * @param {function} fn Callback function to run when data is obtained\n\t */\n\tfunction _fnBuildAjax( oSettings, data, fn )\n\t{\n\t\t// Compatibility with 1.9-, allow fnServerData and event to manipulate\n\t\t_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );\n\t\n\t\t// Convert to object based for 1.10+ if using the old array scheme which can\n\t\t// come from server-side processing or serverParams\n\t\tif ( data && $.isArray(data) ) {\n\t\t\tvar tmp = {};\n\t\t\tvar rbracket = /(.*?)\\[\\]$/;\n\t\n\t\t\t$.each( data, function (key, val) {\n\t\t\t\tvar match = val.name.match(rbracket);\n\t\n\t\t\t\tif ( match ) {\n\t\t\t\t\t// Support for arrays\n\t\t\t\t\tvar name = match[0];\n\t\n\t\t\t\t\tif ( ! tmp[ name ] ) {\n\t\t\t\t\t\ttmp[ name ] = [];\n\t\t\t\t\t}\n\t\t\t\t\ttmp[ name ].push( val.value );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttmp[val.name] = val.value;\n\t\t\t\t}\n\t\t\t} );\n\t\t\tdata = tmp;\n\t\t}\n\t\n\t\tvar ajaxData;\n\t\tvar ajax = oSettings.ajax;\n\t\tvar instance = oSettings.oInstance;\n\t\tvar callback = function ( json ) {\n\t\t\t_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );\n\t\t\tfn( json );\n\t\t};\n\t\n\t\tif ( $.isPlainObject( ajax ) && ajax.data )\n\t\t{\n\t\t\tajaxData = ajax.data;\n\t\n\t\t\tvar newData = $.isFunction( ajaxData ) ?\n\t\t\t\tajaxData( data, oSettings ) :  // fn can manipulate data or return\n\t\t\t\tajaxData;                      // an object object or array to merge\n\t\n\t\t\t// If the function returned something, use that alone\n\t\t\tdata = $.isFunction( ajaxData ) && newData ?\n\t\t\t\tnewData :\n\t\t\t\t$.extend( true, data, newData );\n\t\n\t\t\t// Remove the data property as we've resolved it already and don't want\n\t\t\t// jQuery to do it again (it is restored at the end of the function)\n\t\t\tdelete ajax.data;\n\t\t}\n\t\n\t\tvar baseAjax = {\n\t\t\t\"data\": data,\n\t\t\t\"success\": function (json) {\n\t\t\t\tvar error = json.error || json.sError;\n\t\t\t\tif ( error ) {\n\t\t\t\t\t_fnLog( oSettings, 0, error );\n\t\t\t\t}\n\t\n\t\t\t\toSettings.json = json;\n\t\t\t\tcallback( json );\n\t\t\t},\n\t\t\t\"dataType\": \"json\",\n\t\t\t\"cache\": false,\n\t\t\t\"type\": oSettings.sServerMethod,\n\t\t\t\"error\": function (xhr, error, thrown) {\n\t\t\t\tvar ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );\n\t\n\t\t\t\tif ( $.inArray( true, ret ) === -1 ) {\n\t\t\t\t\tif ( error == \"parsererror\" ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Invalid JSON response', 1 );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( xhr.readyState === 4 ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Ajax error', 7 );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\t}\n\t\t};\n\t\n\t\t// Store the data submitted for the API\n\t\toSettings.oAjaxData = data;\n\t\n\t\t// Allow plug-ins and external processes to modify the data\n\t\t_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );\n\t\n\t\tif ( oSettings.fnServerData )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.fnServerData.call( instance,\n\t\t\t\toSettings.sAjaxSource,\n\t\t\t\t$.map( data, function (val, key) { // Need to convert back to 1.9 trad format\n\t\t\t\t\treturn { name: key, value: val };\n\t\t\t\t} ),\n\t\t\t\tcallback,\n\t\t\t\toSettings\n\t\t\t);\n\t\t}\n\t\telse if ( oSettings.sAjaxSource || typeof ajax === 'string' )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, {\n\t\t\t\turl: ajax || oSettings.sAjaxSource\n\t\t\t} ) );\n\t\t}\n\t\telse if ( $.isFunction( ajax ) )\n\t\t{\n\t\t\t// Is a function - let the caller define what needs to be done\n\t\t\toSettings.jqXHR = ajax.call( instance, data, callback, oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Object to extend the base settings\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );\n\t\n\t\t\t// Restore for next time around\n\t\t\tajax.data = ajaxData;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Update the table using an Ajax call\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {boolean} Block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdate( settings )\n\t{\n\t\tif ( settings.bAjaxDataGet ) {\n\t\t\tsettings.iDraw++;\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t_fnBuildAjax(\n\t\t\t\tsettings,\n\t\t\t\t_fnAjaxParameters( settings ),\n\t\t\t\tfunction(json) {\n\t\t\t\t\t_fnAjaxUpdateDraw( settings, json );\n\t\t\t\t}\n\t\t\t);\n\t\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\t\n\t/**\n\t * Build up the parameters in an object needed for a server-side processing\n\t * request. Note that this is basically done twice, is different ways - a modern\n\t * method which is used by default in DataTables 1.10 which uses objects and\n\t * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if\n\t * the sAjaxSource option is used in the initialisation, or the legacyAjax\n\t * option is set.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {bool} block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxParameters( settings )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tcolumnCount = columns.length,\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tpreSearch = settings.oPreviousSearch,\n\t\t\tpreColSearch = settings.aoPreSearchCols,\n\t\t\ti, data = [], dataProp, column, columnSearch,\n\t\t\tsort = _fnSortFlatten( settings ),\n\t\t\tdisplayStart = settings._iDisplayStart,\n\t\t\tdisplayLength = features.bPaginate !== false ?\n\t\t\t\tsettings._iDisplayLength :\n\t\t\t\t-1;\n\t\n\t\tvar param = function ( name, value ) {\n\t\t\tdata.push( { 'name': name, 'value': value } );\n\t\t};\n\t\n\t\t// DataTables 1.9- compatible method\n\t\tparam( 'sEcho',          settings.iDraw );\n\t\tparam( 'iColumns',       columnCount );\n\t\tparam( 'sColumns',       _pluck( columns, 'sName' ).join(',') );\n\t\tparam( 'iDisplayStart',  displayStart );\n\t\tparam( 'iDisplayLength', displayLength );\n\t\n\t\t// DataTables 1.10+ method\n\t\tvar d = {\n\t\t\tdraw:    settings.iDraw,\n\t\t\tcolumns: [],\n\t\t\torder:   [],\n\t\t\tstart:   displayStart,\n\t\t\tlength:  displayLength,\n\t\t\tsearch:  {\n\t\t\t\tvalue: preSearch.sSearch,\n\t\t\t\tregex: preSearch.bRegex\n\t\t\t}\n\t\t};\n\t\n\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcolumnSearch = preColSearch[i];\n\t\t\tdataProp = typeof column.mData==\"function\" ? 'function' : column.mData ;\n\t\n\t\t\td.columns.push( {\n\t\t\t\tdata:       dataProp,\n\t\t\t\tname:       column.sName,\n\t\t\t\tsearchable: column.bSearchable,\n\t\t\t\torderable:  column.bSortable,\n\t\t\t\tsearch:     {\n\t\t\t\t\tvalue: columnSearch.sSearch,\n\t\t\t\t\tregex: columnSearch.bRegex\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\tparam( \"mDataProp_\"+i, dataProp );\n\t\n\t\t\tif ( features.bFilter ) {\n\t\t\t\tparam( 'sSearch_'+i,     columnSearch.sSearch );\n\t\t\t\tparam( 'bRegex_'+i,      columnSearch.bRegex );\n\t\t\t\tparam( 'bSearchable_'+i, column.bSearchable );\n\t\t\t}\n\t\n\t\t\tif ( features.bSort ) {\n\t\t\t\tparam( 'bSortable_'+i, column.bSortable );\n\t\t\t}\n\t\t}\n\t\n\t\tif ( features.bFilter ) {\n\t\t\tparam( 'sSearch', preSearch.sSearch );\n\t\t\tparam( 'bRegex', preSearch.bRegex );\n\t\t}\n\t\n\t\tif ( features.bSort ) {\n\t\t\t$.each( sort, function ( i, val ) {\n\t\t\t\td.order.push( { column: val.col, dir: val.dir } );\n\t\n\t\t\t\tparam( 'iSortCol_'+i, val.col );\n\t\t\t\tparam( 'sSortDir_'+i, val.dir );\n\t\t\t} );\n\t\n\t\t\tparam( 'iSortingCols', sort.length );\n\t\t}\n\t\n\t\t// If the legacy.ajax parameter is null, then we automatically decide which\n\t\t// form to use, based on sAjaxSource\n\t\tvar legacy = DataTable.ext.legacy.ajax;\n\t\tif ( legacy === null ) {\n\t\t\treturn settings.sAjaxSource ? data : d;\n\t\t}\n\t\n\t\t// Otherwise, if legacy has been specified then we use that to decide on the\n\t\t// form\n\t\treturn legacy ? data : d;\n\t}\n\t\n\t\n\t/**\n\t * Data the data from the server (nuking the old) and redraw the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} json json data return from the server.\n\t *  @param {string} json.sEcho Tracking flag for DataTables to match requests\n\t *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering\n\t *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering\n\t *  @param {array} json.aaData The data to display on this page\n\t *  @param {string} [json.sColumns] Column ordering (sName, comma separated)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdateDraw ( settings, json )\n\t{\n\t\t// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.\n\t\t// Support both\n\t\tvar compat = function ( old, modern ) {\n\t\t\treturn json[old] !== undefined ? json[old] : json[modern];\n\t\t};\n\t\n\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\tvar draw            = compat( 'sEcho',                'draw' );\n\t\tvar recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );\n\t\tvar recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );\n\t\n\t\tif ( draw ) {\n\t\t\t// Protect against out of sequence returns\n\t\t\tif ( draw*1 < settings.iDraw ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettings.iDraw = draw * 1;\n\t\t}\n\t\n\t\t_fnClearTable( settings );\n\t\tsettings._iRecordsTotal   = parseInt(recordsTotal, 10);\n\t\tsettings._iRecordsDisplay = parseInt(recordsFiltered, 10);\n\t\n\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t_fnAddData( settings, data[i] );\n\t\t}\n\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\n\t\tsettings.bAjaxDataGet = false;\n\t\t_fnDraw( settings );\n\t\n\t\tif ( ! settings._bInitComplete ) {\n\t\t\t_fnInitComplete( settings, json );\n\t\t}\n\t\n\t\tsettings.bAjaxDataGet = true;\n\t\t_fnProcessingDisplay( settings, false );\n\t}\n\t\n\t\n\t/**\n\t * Get the data from the JSON data source to use for drawing a table. Using\n\t * `_fnGetObjectDataFn` allows the data to be sourced from a property of the\n\t * source object, or from a processing function.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param  {object} json Data source object / array from the server\n\t *  @return {array} Array of data to use\n\t */\n\tfunction _fnAjaxDataSrc ( oSettings, json )\n\t{\n\t\tvar dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?\n\t\t\toSettings.ajax.dataSrc :\n\t\t\toSettings.sAjaxDataProp; // Compatibility with 1.9-.\n\t\n\t\t// Compatibility with 1.9-. In order to read from aaData, check if the\n\t\t// default has been changed, if not, check for aaData\n\t\tif ( dataSrc === 'data' ) {\n\t\t\treturn json.aaData || json[dataSrc];\n\t\t}\n\t\n\t\treturn dataSrc !== \"\" ?\n\t\t\t_fnGetObjectDataFn( dataSrc )( json ) :\n\t\t\tjson;\n\t}\n\t\n\t/**\n\t * Generate the node required for filtering text\n\t *  @returns {node} Filter control element\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlFilter ( settings )\n\t{\n\t\tvar classes = settings.oClasses;\n\t\tvar tableId = settings.sTableId;\n\t\tvar language = settings.oLanguage;\n\t\tvar previousSearch = settings.oPreviousSearch;\n\t\tvar features = settings.aanFeatures;\n\t\tvar input = '<input type=\"search\" class=\"'+classes.sFilterInput+'\"/>';\n\t\n\t\tvar str = language.sSearch;\n\t\tstr = str.match(/_INPUT_/) ?\n\t\t\tstr.replace('_INPUT_', input) :\n\t\t\tstr+input;\n\t\n\t\tvar filter = $('<div/>', {\n\t\t\t\t'id': ! features.f ? tableId+'_filter' : null,\n\t\t\t\t'class': classes.sFilter\n\t\t\t} )\n\t\t\t.append( $('<label/>' ).append( str ) );\n\t\n\t\tvar searchFn = function() {\n\t\t\t/* Update all other filter input elements for the new display */\n\t\t\tvar n = features.f;\n\t\t\tvar val = !this.value ? \"\" : this.value; // mental IE8 fix :-(\n\t\n\t\t\t/* Now do the filter */\n\t\t\tif ( val != previousSearch.sSearch ) {\n\t\t\t\t_fnFilterComplete( settings, {\n\t\t\t\t\t\"sSearch\": val,\n\t\t\t\t\t\"bRegex\": previousSearch.bRegex,\n\t\t\t\t\t\"bSmart\": previousSearch.bSmart ,\n\t\t\t\t\t\"bCaseInsensitive\": previousSearch.bCaseInsensitive\n\t\t\t\t} );\n\t\n\t\t\t\t// Need to redraw, without resorting\n\t\t\t\tsettings._iDisplayStart = 0;\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t};\n\t\n\t\tvar searchDelay = settings.searchDelay !== null ?\n\t\t\tsettings.searchDelay :\n\t\t\t_fnDataSource( settings ) === 'ssp' ?\n\t\t\t\t400 :\n\t\t\t\t0;\n\t\n\t\tvar jqFilter = $('input', filter)\n\t\t\t.val( previousSearch.sSearch )\n\t\t\t.attr( 'placeholder', language.sSearchPlaceholder )\n\t\t\t.on(\n\t\t\t\t'keyup.DT search.DT input.DT paste.DT cut.DT',\n\t\t\t\tsearchDelay ?\n\t\t\t\t\t_fnThrottle( searchFn, searchDelay ) :\n\t\t\t\t\tsearchFn\n\t\t\t)\n\t\t\t.on( 'keypress.DT', function(e) {\n\t\t\t\t/* Prevent form submission */\n\t\t\t\tif ( e.keyCode == 13 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.attr('aria-controls', tableId);\n\t\n\t\t// Update the input elements whenever the table is filtered\n\t\t$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame...\n\t\t\t\ttry {\n\t\t\t\t\tif ( jqFilter[0] !== document.activeElement ) {\n\t\t\t\t\t\tjqFilter.val( previousSearch.sSearch );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch ( e ) {}\n\t\t\t}\n\t\t} );\n\t\n\t\treturn filter[0];\n\t}\n\t\n\t\n\t/**\n\t * Filter the table using both the global filter and column based filtering\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oSearch search information\n\t *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterComplete ( oSettings, oInput, iForce )\n\t{\n\t\tvar oPrevSearch = oSettings.oPreviousSearch;\n\t\tvar aoPrevSearch = oSettings.aoPreSearchCols;\n\t\tvar fnSaveFilter = function ( oFilter ) {\n\t\t\t/* Save the filtering values */\n\t\t\toPrevSearch.sSearch = oFilter.sSearch;\n\t\t\toPrevSearch.bRegex = oFilter.bRegex;\n\t\t\toPrevSearch.bSmart = oFilter.bSmart;\n\t\t\toPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;\n\t\t};\n\t\tvar fnRegex = function ( o ) {\n\t\t\t// Backwards compatibility with the bEscapeRegex option\n\t\t\treturn o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;\n\t\t};\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo As per sort - can this be moved into an event handler?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\t/* In server-side processing all filtering is done by the server, so no point hanging around here */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' )\n\t\t{\n\t\t\t/* Global filter */\n\t\t\t_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );\n\t\t\tfnSaveFilter( oInput );\n\t\n\t\t\t/* Now do the individual column filter */\n\t\t\tfor ( var i=0 ; i<aoPrevSearch.length ; i++ )\n\t\t\t{\n\t\t\t\t_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),\n\t\t\t\t\taoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );\n\t\t\t}\n\t\n\t\t\t/* Custom filtering */\n\t\t\t_fnFilterCustom( oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfnSaveFilter( oInput );\n\t\t}\n\t\n\t\t/* Tell the draw function we have been filtering */\n\t\toSettings.bFiltered = true;\n\t\t_fnCallbackFire( oSettings, null, 'search', [oSettings] );\n\t}\n\t\n\t\n\t/**\n\t * Apply custom filtering functions\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCustom( settings )\n\t{\n\t\tvar filters = DataTable.ext.search;\n\t\tvar displayRows = settings.aiDisplay;\n\t\tvar row, rowIdx;\n\t\n\t\tfor ( var i=0, ien=filters.length ; i<ien ; i++ ) {\n\t\t\tvar rows = [];\n\t\n\t\t\t// Loop over each row and see if it should be included\n\t\t\tfor ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {\n\t\t\t\trowIdx = displayRows[ j ];\n\t\t\t\trow = settings.aoData[ rowIdx ];\n\t\n\t\t\t\tif ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {\n\t\t\t\t\trows.push( rowIdx );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// So the array reference doesn't break set the results into the\n\t\t\t// existing array\n\t\t\tdisplayRows.length = 0;\n\t\t\t$.merge( displayRows, rows );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Filter the table on a per-column basis\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sInput string to filter on\n\t *  @param {int} iColumn column to filter\n\t *  @param {bool} bRegex treat search string as a regular expression or not\n\t *  @param {bool} bSmart use smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )\n\t{\n\t\tif ( searchStr === '' ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar data;\n\t\tvar out = [];\n\t\tvar display = settings.aiDisplay;\n\t\tvar rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );\n\t\n\t\tfor ( var i=0 ; i<display.length ; i++ ) {\n\t\t\tdata = settings.aoData[ display[i] ]._aFilterData[ colIdx ];\n\t\n\t\t\tif ( rpSearch.test( data ) ) {\n\t\t\t\tout.push( display[i] );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aiDisplay = out;\n\t}\n\t\n\t\n\t/**\n\t * Filter the data table based on user input and draw the table\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} input string to filter on\n\t *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)\n\t *  @param {bool} regex treat as a regular expression or not\n\t *  @param {bool} smart perform smart filtering or not\n\t *  @param {bool} caseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilter( settings, input, force, regex, smart, caseInsensitive )\n\t{\n\t\tvar rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );\n\t\tvar prevSearch = settings.oPreviousSearch.sSearch;\n\t\tvar displayMaster = settings.aiDisplayMaster;\n\t\tvar display, invalidated, i;\n\t\tvar filtered = [];\n\t\n\t\t// Need to take account of custom filtering functions - always filter\n\t\tif ( DataTable.ext.search.length !== 0 ) {\n\t\t\tforce = true;\n\t\t}\n\t\n\t\t// Check if any of the rows were invalidated\n\t\tinvalidated = _fnFilterData( settings );\n\t\n\t\t// If the input is blank - we just want the full data set\n\t\tif ( input.length <= 0 ) {\n\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t}\n\t\telse {\n\t\t\t// New search - start from the master array\n\t\t\tif ( invalidated ||\n\t\t\t\t force ||\n\t\t\t\t prevSearch.length > input.length ||\n\t\t\t\t input.indexOf(prevSearch) !== 0 ||\n\t\t\t\t settings.bSorted // On resort, the display master needs to be\n\t\t\t\t                  // re-filtered since indexes will have changed\n\t\t\t) {\n\t\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t\t}\n\t\n\t\t\t// Search the display array\n\t\t\tdisplay = settings.aiDisplay;\n\t\n\t\t\tfor ( i=0 ; i<display.length ; i++ ) {\n\t\t\t\tif ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {\n\t\t\t\t\tfiltered.push( display[i] );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tsettings.aiDisplay = filtered;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a regular expression object suitable for searching a table\n\t *  @param {string} sSearch string to search for\n\t *  @param {bool} bRegex treat as a regular expression or not\n\t *  @param {bool} bSmart perform smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insensitive matching or not\n\t *  @returns {RegExp} constructed object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCreateSearch( search, regex, smart, caseInsensitive )\n\t{\n\t\tsearch = regex ?\n\t\t\tsearch :\n\t\t\t_fnEscapeRegex( search );\n\t\t\n\t\tif ( smart ) {\n\t\t\t/* For smart filtering we want to allow the search to work regardless of\n\t\t\t * word order. We also want double quoted text to be preserved, so word\n\t\t\t * order is important - a la google. So this is what we want to\n\t\t\t * generate:\n\t\t\t * \n\t\t\t * ^(?=.*?\\bone\\b)(?=.*?\\btwo three\\b)(?=.*?\\bfour\\b).*$\n\t\t\t */\n\t\t\tvar a = $.map( search.match( /\"[^\"]+\"|[^ ]+/g ) || [''], function ( word ) {\n\t\t\t\tif ( word.charAt(0) === '\"' ) {\n\t\t\t\t\tvar m = word.match( /^\"(.*)\"$/ );\n\t\t\t\t\tword = m ? m[1] : word;\n\t\t\t\t}\n\t\n\t\t\t\treturn word.replace('\"', '');\n\t\t\t} );\n\t\n\t\t\tsearch = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';\n\t\t}\n\t\n\t\treturn new RegExp( search, caseInsensitive ? 'i' : '' );\n\t}\n\t\n\t\n\t/**\n\t * Escape a string such that it can be used in a regular expression\n\t *  @param {string} sVal string to escape\n\t *  @returns {string} escaped string\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnEscapeRegex = DataTable.util.escapeRegex;\n\t\n\tvar __filter_div = $('<div>')[0];\n\tvar __filter_div_textContent = __filter_div.textContent !== undefined;\n\t\n\t// Update the filtering data for each row if needed (by invalidation or first run)\n\tfunction _fnFilterData ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar column;\n\t\tvar i, j, ien, jen, filterData, cellData, row;\n\t\tvar fomatters = DataTable.ext.type.search;\n\t\tvar wasInvalidated = false;\n\t\n\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aFilterData ) {\n\t\t\t\tfilterData = [];\n\t\n\t\t\t\tfor ( j=0, jen=columns.length ; j<jen ; j++ ) {\n\t\t\t\t\tcolumn = columns[j];\n\t\n\t\t\t\t\tif ( column.bSearchable ) {\n\t\t\t\t\t\tcellData = _fnGetCellData( settings, i, j, 'filter' );\n\t\n\t\t\t\t\t\tif ( fomatters[ column.sType ] ) {\n\t\t\t\t\t\t\tcellData = fomatters[ column.sType ]( cellData );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Search in DataTables 1.10 is string based. In 1.11 this\n\t\t\t\t\t\t// should be altered to also allow strict type checking.\n\t\t\t\t\t\tif ( cellData === null ) {\n\t\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( typeof cellData !== 'string' && cellData.toString ) {\n\t\t\t\t\t\t\tcellData = cellData.toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If it looks like there is an HTML entity in the string,\n\t\t\t\t\t// attempt to decode it so sorting works as expected. Note that\n\t\t\t\t\t// we could use a single line of jQuery to do this, but the DOM\n\t\t\t\t\t// method used here is much faster http://jsperf.com/html-decode\n\t\t\t\t\tif ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {\n\t\t\t\t\t\t__filter_div.innerHTML = cellData;\n\t\t\t\t\t\tcellData = __filter_div_textContent ?\n\t\t\t\t\t\t\t__filter_div.textContent :\n\t\t\t\t\t\t\t__filter_div.innerText;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tif ( cellData.replace ) {\n\t\t\t\t\t\tcellData = cellData.replace(/[\\r\\n]/g, '');\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfilterData.push( cellData );\n\t\t\t\t}\n\t\n\t\t\t\trow._aFilterData = filterData;\n\t\t\t\trow._sFilterRow = filterData.join('  ');\n\t\t\t\twasInvalidated = true;\n\t\t\t}\n\t\t}\n\t\n\t\treturn wasInvalidated;\n\t}\n\t\n\t\n\t/**\n\t * Convert from the internal Hungarian notation to camelCase for external\n\t * interaction\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToCamel ( obj )\n\t{\n\t\treturn {\n\t\t\tsearch:          obj.sSearch,\n\t\t\tsmart:           obj.bSmart,\n\t\t\tregex:           obj.bRegex,\n\t\t\tcaseInsensitive: obj.bCaseInsensitive\n\t\t};\n\t}\n\t\n\t\n\t\n\t/**\n\t * Convert from camelCase notation to the internal Hungarian. We could use the\n\t * Hungarian convert function here, but this is cleaner\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToHung ( obj )\n\t{\n\t\treturn {\n\t\t\tsSearch:          obj.search,\n\t\t\tbSmart:           obj.smart,\n\t\t\tbRegex:           obj.regex,\n\t\t\tbCaseInsensitive: obj.caseInsensitive\n\t\t};\n\t}\n\t\n\t/**\n\t * Generate the node required for the info display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Information element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlInfo ( settings )\n\t{\n\t\tvar\n\t\t\ttid = settings.sTableId,\n\t\t\tnodes = settings.aanFeatures.i,\n\t\t\tn = $('<div/>', {\n\t\t\t\t'class': settings.oClasses.sInfo,\n\t\t\t\t'id': ! nodes ? tid+'_info' : null\n\t\t\t} );\n\t\n\t\tif ( ! nodes ) {\n\t\t\t// Update display on each draw\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": _fnUpdateInfo,\n\t\t\t\t\"sName\": \"information\"\n\t\t\t} );\n\t\n\t\t\tn\n\t\t\t\t.attr( 'role', 'status' )\n\t\t\t\t.attr( 'aria-live', 'polite' );\n\t\n\t\t\t// Table is described by our info div\n\t\t\t$(settings.nTable).attr( 'aria-describedby', tid+'_info' );\n\t\t}\n\t\n\t\treturn n[0];\n\t}\n\t\n\t\n\t/**\n\t * Update the information elements in the display\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnUpdateInfo ( settings )\n\t{\n\t\t/* Show information about the table */\n\t\tvar nodes = settings.aanFeatures.i;\n\t\tif ( nodes.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\tlang  = settings.oLanguage,\n\t\t\tstart = settings._iDisplayStart+1,\n\t\t\tend   = settings.fnDisplayEnd(),\n\t\t\tmax   = settings.fnRecordsTotal(),\n\t\t\ttotal = settings.fnRecordsDisplay(),\n\t\t\tout   = total ?\n\t\t\t\tlang.sInfo :\n\t\t\t\tlang.sInfoEmpty;\n\t\n\t\tif ( total !== max ) {\n\t\t\t/* Record set after filtering */\n\t\t\tout += ' ' + lang.sInfoFiltered;\n\t\t}\n\t\n\t\t// Convert the macros\n\t\tout += lang.sInfoPostFix;\n\t\tout = _fnInfoMacros( settings, out );\n\t\n\t\tvar callback = lang.fnInfoCallback;\n\t\tif ( callback !== null ) {\n\t\t\tout = callback.call( settings.oInstance,\n\t\t\t\tsettings, start, end, max, total, out\n\t\t\t);\n\t\t}\n\t\n\t\t$(nodes).html( out );\n\t}\n\t\n\t\n\tfunction _fnInfoMacros ( settings, str )\n\t{\n\t\t// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only\n\t\t// internally\n\t\tvar\n\t\t\tformatter  = settings.fnFormatNumber,\n\t\t\tstart      = settings._iDisplayStart+1,\n\t\t\tlen        = settings._iDisplayLength,\n\t\t\tvis        = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn str.\n\t\t\treplace(/_START_/g, formatter.call( settings, start ) ).\n\t\t\treplace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).\n\t\t\treplace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).\n\t\t\treplace(/_TOTAL_/g, formatter.call( settings, vis ) ).\n\t\t\treplace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).\n\t\t\treplace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );\n\t}\n\t\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitialise ( settings )\n\t{\n\t\tvar i, iLen, iAjaxStart=settings.iInitDisplayStart;\n\t\tvar columns = settings.aoColumns, column;\n\t\tvar features = settings.oFeatures;\n\t\tvar deferLoading = settings.bDeferLoading; // value modified by the draw\n\t\n\t\t/* Ensure that the table data is fully initialised */\n\t\tif ( ! settings.bInitialised ) {\n\t\t\tsetTimeout( function(){ _fnInitialise( settings ); }, 200 );\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Show the display HTML options */\n\t\t_fnAddOptionsHtml( settings );\n\t\n\t\t/* Build and draw the header / footer for the table */\n\t\t_fnBuildHead( settings );\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t/* Okay to show that something is going on now */\n\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t/* Calculate sizes for columns */\n\t\tif ( features.bAutoWidth ) {\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\n\t\t\tif ( column.sWidth ) {\n\t\t\t\tcolumn.nTh.style.width = _fnStringToCss( column.sWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'preInit', [settings] );\n\t\n\t\t// If there is default sorting required - let's do it. The sort function\n\t\t// will do the drawing for us. Otherwise we draw the table regardless of the\n\t\t// Ajax source - this allows the table to look initialised for Ajax sourcing\n\t\t// data (show 'loading' message possibly)\n\t\t_fnReDraw( settings );\n\t\n\t\t// Server-side processing init complete is done by _fnAjaxUpdateDraw\n\t\tvar dataSrc = _fnDataSource( settings );\n\t\tif ( dataSrc != 'ssp' || deferLoading ) {\n\t\t\t// if there is an ajax source load the data\n\t\t\tif ( dataSrc == 'ajax' ) {\n\t\t\t\t_fnBuildAjax( settings, [], function(json) {\n\t\t\t\t\tvar aData = _fnAjaxDataSrc( settings, json );\n\t\n\t\t\t\t\t// Got the data - add it to the table\n\t\t\t\t\tfor ( i=0 ; i<aData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( settings, aData[i] );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Reset the init display for cookie saving. We've already done\n\t\t\t\t\t// a filter, and therefore cleared it before. So we need to make\n\t\t\t\t\t// it appear 'fresh'\n\t\t\t\t\tsettings.iInitDisplayStart = iAjaxStart;\n\t\n\t\t\t\t\t_fnReDraw( settings );\n\t\n\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t_fnInitComplete( settings, json );\n\t\t\t\t}, settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t_fnInitComplete( settings );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} [json] JSON from the server that completed the table, if using Ajax source\n\t *    with client-side processing (optional)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitComplete ( settings, json )\n\t{\n\t\tsettings._bInitComplete = true;\n\t\n\t\t// When data was added after the initialisation (data or Ajax) we need to\n\t\t// calculate the column sizing\n\t\tif ( json || settings.oInit.aaData ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'plugin-init', [settings, json] );\n\t\t_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );\n\t}\n\t\n\t\n\tfunction _fnLengthChange ( settings, val )\n\t{\n\t\tvar len = parseInt( val, 10 );\n\t\tsettings._iDisplayLength = len;\n\t\n\t\t_fnLengthOverflow( settings );\n\t\n\t\t// Fire length change event\n\t\t_fnCallbackFire( settings, null, 'length', [settings, len] );\n\t}\n\t\n\t\n\t/**\n\t * Generate the node required for user display length changing\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Display length feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlLength ( settings )\n\t{\n\t\tvar\n\t\t\tclasses  = settings.oClasses,\n\t\t\ttableId  = settings.sTableId,\n\t\t\tmenu     = settings.aLengthMenu,\n\t\t\td2       = $.isArray( menu[0] ),\n\t\t\tlengths  = d2 ? menu[0] : menu,\n\t\t\tlanguage = d2 ? menu[1] : menu;\n\t\n\t\tvar select = $('<select/>', {\n\t\t\t'name':          tableId+'_length',\n\t\t\t'aria-controls': tableId,\n\t\t\t'class':         classes.sLengthSelect\n\t\t} );\n\t\n\t\tfor ( var i=0, ien=lengths.length ; i<ien ; i++ ) {\n\t\t\tselect[0][ i ] = new Option( language[i], lengths[i] );\n\t\t}\n\t\n\t\tvar div = $('<div><label/></div>').addClass( classes.sLength );\n\t\tif ( ! settings.aanFeatures.l ) {\n\t\t\tdiv[0].id = tableId+'_length';\n\t\t}\n\t\n\t\tdiv.children().append(\n\t\t\tsettings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )\n\t\t);\n\t\n\t\t// Can't use `select` variable as user might provide their own and the\n\t\t// reference is broken by the use of outerHTML\n\t\t$('select', div)\n\t\t\t.val( settings._iDisplayLength )\n\t\t\t.on( 'change.DT', function(e) {\n\t\t\t\t_fnLengthChange( settings, $(this).val() );\n\t\t\t\t_fnDraw( settings );\n\t\t\t} );\n\t\n\t\t// Update node value whenever anything changes the table's length\n\t\t$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t$('select', div).val( len );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn div[0];\n\t}\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Note that most of the paging logic is done in\n\t * DataTable.ext.pager\n\t */\n\t\n\t/**\n\t * Generate the node required for default pagination\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Pagination feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlPaginate ( settings )\n\t{\n\t\tvar\n\t\t\ttype   = settings.sPaginationType,\n\t\t\tplugin = DataTable.ext.pager[ type ],\n\t\t\tmodern = typeof plugin === 'function',\n\t\t\tredraw = function( settings ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t},\n\t\t\tnode = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],\n\t\t\tfeatures = settings.aanFeatures;\n\t\n\t\tif ( ! modern ) {\n\t\t\tplugin.fnInit( settings, node, redraw );\n\t\t}\n\t\n\t\t/* Add a draw callback for the pagination on first instance, to update the paging display */\n\t\tif ( ! features.p )\n\t\t{\n\t\t\tnode.id = settings.sTableId+'_paginate';\n\t\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": function( settings ) {\n\t\t\t\t\tif ( modern ) {\n\t\t\t\t\t\tvar\n\t\t\t\t\t\t\tstart      = settings._iDisplayStart,\n\t\t\t\t\t\t\tlen        = settings._iDisplayLength,\n\t\t\t\t\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\t\t\t\t\tall        = len === -1,\n\t\t\t\t\t\t\tpage = all ? 0 : Math.ceil( start / len ),\n\t\t\t\t\t\t\tpages = all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\t\t\t\tbuttons = plugin(page, pages),\n\t\t\t\t\t\t\ti, ien;\n\t\n\t\t\t\t\t\tfor ( i=0, ien=features.p.length ; i<ien ; i++ ) {\n\t\t\t\t\t\t\t_fnRenderer( settings, 'pageButton' )(\n\t\t\t\t\t\t\t\tsettings, features.p[i], i, buttons, page, pages\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tplugin.fnUpdate( settings, redraw );\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"sName\": \"pagination\"\n\t\t\t} );\n\t\t}\n\t\n\t\treturn node;\n\t}\n\t\n\t\n\t/**\n\t * Alter the display settings to change the page\n\t *  @param {object} settings DataTables settings object\n\t *  @param {string|int} action Paging action to take: \"first\", \"previous\",\n\t *    \"next\" or \"last\" or page number to jump to (integer)\n\t *  @param [bool] redraw Automatically draw the update or not\n\t *  @returns {bool} true page has changed, false - no change\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnPageChange ( settings, action, redraw )\n\t{\n\t\tvar\n\t\t\tstart     = settings._iDisplayStart,\n\t\t\tlen       = settings._iDisplayLength,\n\t\t\trecords   = settings.fnRecordsDisplay();\n\t\n\t\tif ( records === 0 || len === -1 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( typeof action === \"number\" )\n\t\t{\n\t\t\tstart = action * len;\n\t\n\t\t\tif ( start > records )\n\t\t\t{\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"first\" )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( action == \"previous\" )\n\t\t{\n\t\t\tstart = len >= 0 ?\n\t\t\t\tstart - len :\n\t\t\t\t0;\n\t\n\t\t\tif ( start < 0 )\n\t\t\t{\n\t\t\t  start = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"next\" )\n\t\t{\n\t\t\tif ( start + len < records )\n\t\t\t{\n\t\t\t\tstart += len;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"last\" )\n\t\t{\n\t\t\tstart = Math.floor( (records-1) / len) * len;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_fnLog( settings, 0, \"Unknown paging action: \"+action, 5 );\n\t\t}\n\t\n\t\tvar changed = settings._iDisplayStart !== start;\n\t\tsettings._iDisplayStart = start;\n\t\n\t\tif ( changed ) {\n\t\t\t_fnCallbackFire( settings, null, 'page', [settings] );\n\t\n\t\t\tif ( redraw ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t}\n\t\n\t\treturn changed;\n\t}\n\t\n\t\n\t\n\t/**\n\t * Generate the node required for the processing node\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Processing element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlProcessing ( settings )\n\t{\n\t\treturn $('<div/>', {\n\t\t\t\t'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,\n\t\t\t\t'class': settings.oClasses.sProcessing\n\t\t\t} )\n\t\t\t.html( settings.oLanguage.sProcessing )\n\t\t\t.insertBefore( settings.nTable )[0];\n\t}\n\t\n\t\n\t/**\n\t * Display or hide the processing indicator\n\t *  @param {object} settings dataTables settings object\n\t *  @param {bool} show Show the processing indicator (true) or not (false)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnProcessingDisplay ( settings, show )\n\t{\n\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t$(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'processing', [settings, show] );\n\t}\n\t\n\t/**\n\t * Add any control elements for the table - specifically scrolling\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Node to add to the DOM\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlTable ( settings )\n\t{\n\t\tvar table = $(settings.nTable);\n\t\n\t\t// Add the ARIA grid role to the table\n\t\ttable.attr( 'role', 'grid' );\n\t\n\t\t// Scrolling from here on in\n\t\tvar scroll = settings.oScroll;\n\t\n\t\tif ( scroll.sX === '' && scroll.sY === '' ) {\n\t\t\treturn settings.nTable;\n\t\t}\n\t\n\t\tvar scrollX = scroll.sX;\n\t\tvar scrollY = scroll.sY;\n\t\tvar classes = settings.oClasses;\n\t\tvar caption = table.children('caption');\n\t\tvar captionSide = caption.length ? caption[0]._captionSide : null;\n\t\tvar headerClone = $( table[0].cloneNode(false) );\n\t\tvar footerClone = $( table[0].cloneNode(false) );\n\t\tvar footer = table.children('tfoot');\n\t\tvar _div = '<div/>';\n\t\tvar size = function ( s ) {\n\t\t\treturn !s ? null : _fnStringToCss( s );\n\t\t};\n\t\n\t\tif ( ! footer.length ) {\n\t\t\tfooter = null;\n\t\t}\n\t\n\t\t/*\n\t\t * The HTML structure that we want to generate in this function is:\n\t\t *  div - scroller\n\t\t *    div - scroll head\n\t\t *      div - scroll head inner\n\t\t *        table - scroll head table\n\t\t *          thead - thead\n\t\t *    div - scroll body\n\t\t *      table - table (master table)\n\t\t *        thead - thead clone for sizing\n\t\t *        tbody - tbody\n\t\t *    div - scroll foot\n\t\t *      div - scroll foot inner\n\t\t *        table - scroll foot table\n\t\t *          tfoot - tfoot\n\t\t */\n\t\tvar scroller = $( _div, { 'class': classes.sScrollWrapper } )\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollHead } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollHeadInner } )\n\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t'box-sizing': 'content-box',\n\t\t\t\t\t\t\t\twidth: scroll.sXInner || '100%'\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\theaderClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'top' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('thead')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t)\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollBody } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\toverflow: 'auto',\n\t\t\t\t\t\twidth: size( scrollX )\n\t\t\t\t\t} )\n\t\t\t\t\t.append( table )\n\t\t\t);\n\t\n\t\tif ( footer ) {\n\t\t\tscroller.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollFoot } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollFootInner } )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\tfooterClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'bottom' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('tfoot')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\n\t\tvar children = scroller.children();\n\t\tvar scrollHead = children[0];\n\t\tvar scrollBody = children[1];\n\t\tvar scrollFoot = footer ? children[2] : null;\n\t\n\t\t// When the body is scrolled, then we also want to scroll the headers\n\t\tif ( scrollX ) {\n\t\t\t$(scrollBody).on( 'scroll.DT', function (e) {\n\t\t\t\tvar scrollLeft = this.scrollLeft;\n\t\n\t\t\t\tscrollHead.scrollLeft = scrollLeft;\n\t\n\t\t\t\tif ( footer ) {\n\t\t\t\t\tscrollFoot.scrollLeft = scrollLeft;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\n\t\t$(scrollBody).css(\n\t\t\tscrollY && scroll.bCollapse ? 'max-height' : 'height', \n\t\t\tscrollY\n\t\t);\n\t\n\t\tsettings.nScrollHead = scrollHead;\n\t\tsettings.nScrollBody = scrollBody;\n\t\tsettings.nScrollFoot = scrollFoot;\n\t\n\t\t// On redraw - align columns\n\t\tsettings.aoDrawCallback.push( {\n\t\t\t\"fn\": _fnScrollDraw,\n\t\t\t\"sName\": \"scrolling\"\n\t\t} );\n\t\n\t\treturn scroller[0];\n\t}\n\t\n\t\n\t\n\t/**\n\t * Update the header, footer and body tables for resizing - i.e. column\n\t * alignment.\n\t *\n\t * Welcome to the most horrible function DataTables. The process that this\n\t * function follows is basically:\n\t *   1. Re-create the table inside the scrolling div\n\t *   2. Take live measurements from the DOM\n\t *   3. Apply the measurements to align the columns\n\t *   4. Clean up\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnScrollDraw ( settings )\n\t{\n\t\t// Given that this is such a monster function, a lot of variables are use\n\t\t// to try and keep the minimised size as small as possible\n\t\tvar\n\t\t\tscroll         = settings.oScroll,\n\t\t\tscrollX        = scroll.sX,\n\t\t\tscrollXInner   = scroll.sXInner,\n\t\t\tscrollY        = scroll.sY,\n\t\t\tbarWidth       = scroll.iBarWidth,\n\t\t\tdivHeader      = $(settings.nScrollHead),\n\t\t\tdivHeaderStyle = divHeader[0].style,\n\t\t\tdivHeaderInner = divHeader.children('div'),\n\t\t\tdivHeaderInnerStyle = divHeaderInner[0].style,\n\t\t\tdivHeaderTable = divHeaderInner.children('table'),\n\t\t\tdivBodyEl      = settings.nScrollBody,\n\t\t\tdivBody        = $(divBodyEl),\n\t\t\tdivBodyStyle   = divBodyEl.style,\n\t\t\tdivFooter      = $(settings.nScrollFoot),\n\t\t\tdivFooterInner = divFooter.children('div'),\n\t\t\tdivFooterTable = divFooterInner.children('table'),\n\t\t\theader         = $(settings.nTHead),\n\t\t\ttable          = $(settings.nTable),\n\t\t\ttableEl        = table[0],\n\t\t\ttableStyle     = tableEl.style,\n\t\t\tfooter         = settings.nTFoot ? $(settings.nTFoot) : null,\n\t\t\tbrowser        = settings.oBrowser,\n\t\t\tie67           = browser.bScrollOversize,\n\t\t\tdtHeaderCells  = _pluck( settings.aoColumns, 'nTh' ),\n\t\t\theaderTrgEls, footerTrgEls,\n\t\t\theaderSrcEls, footerSrcEls,\n\t\t\theaderCopy, footerCopy,\n\t\t\theaderWidths=[], footerWidths=[],\n\t\t\theaderContent=[], footerContent=[],\n\t\t\tidx, correction, sanityWidth,\n\t\t\tzeroOut = function(nSizer) {\n\t\t\t\tvar style = nSizer.style;\n\t\t\t\tstyle.paddingTop = \"0\";\n\t\t\t\tstyle.paddingBottom = \"0\";\n\t\t\t\tstyle.borderTopWidth = \"0\";\n\t\t\t\tstyle.borderBottomWidth = \"0\";\n\t\t\t\tstyle.height = 0;\n\t\t\t};\n\t\n\t\t// If the scrollbar visibility has changed from the last draw, we need to\n\t\t// adjust the column sizes as the table width will have changed to account\n\t\t// for the scrollbar\n\t\tvar scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;\n\t\t\n\t\tif ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t\treturn; // adjust column sizing will call this function again\n\t\t}\n\t\telse {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t}\n\t\n\t\t/*\n\t\t * 1. Re-create the table inside the scrolling div\n\t\t */\n\t\n\t\t// Remove the old minimised thead and tfoot elements in the inner table\n\t\ttable.children('thead, tfoot').remove();\n\t\n\t\tif ( footer ) {\n\t\t\tfooterCopy = footer.clone().prependTo( table );\n\t\t\tfooterTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized\n\t\t\tfooterSrcEls = footerCopy.find('tr');\n\t\t}\n\t\n\t\t// Clone the current header and footer elements and then place it into the inner table\n\t\theaderCopy = header.clone().prependTo( table );\n\t\theaderTrgEls = header.find('tr'); // original header is in its own table\n\t\theaderSrcEls = headerCopy.find('tr');\n\t\theaderCopy.find('th, td').removeAttr('tabindex');\n\t\n\t\n\t\t/*\n\t\t * 2. Take live measurements from the DOM - do not alter the DOM itself!\n\t\t */\n\t\n\t\t// Remove old sizing and apply the calculated column widths\n\t\t// Get the unique column headers in the newly created (cloned) header. We want to apply the\n\t\t// calculated sizes to this header\n\t\tif ( ! scrollX )\n\t\t{\n\t\t\tdivBodyStyle.width = '100%';\n\t\t\tdivHeader[0].style.width = '100%';\n\t\t}\n\t\n\t\t$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {\n\t\t\tidx = _fnVisibleToColumnIndex( settings, i );\n\t\t\tel.style.width = settings.aoColumns[idx].sWidth;\n\t\t} );\n\t\n\t\tif ( footer ) {\n\t\t\t_fnApplyToChildren( function(n) {\n\t\t\t\tn.style.width = \"\";\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Size the table as a whole\n\t\tsanityWidth = table.outerWidth();\n\t\tif ( scrollX === \"\" ) {\n\t\t\t// No x scrolling\n\t\t\ttableStyle.width = \"100%\";\n\t\n\t\t\t// IE7 will make the width of the table when 100% include the scrollbar\n\t\t\t// - which is shouldn't. When there is a scrollbar we need to take this\n\t\t\t// into account.\n\t\t\tif ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);\n\t\t\t}\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\telse if ( scrollXInner !== \"\" ) {\n\t\t\t// legacy x scroll inner has been given - use it\n\t\t\ttableStyle.width = _fnStringToCss(scrollXInner);\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\n\t\t// Hidden header should have zero height, so remove padding and borders. Then\n\t\t// set the width based on the real headers\n\t\n\t\t// Apply all styles in one pass\n\t\t_fnApplyToChildren( zeroOut, headerSrcEls );\n\t\n\t\t// Read all widths in next pass\n\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\theaderContent.push( nSizer.innerHTML );\n\t\t\theaderWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t}, headerSrcEls );\n\t\n\t\t// Apply all widths in final pass\n\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t// Only apply widths to the DataTables detected header cells - this\n\t\t\t// prevents complex headers from having contradictory sizes applied\n\t\t\tif ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {\n\t\t\t\tnToSize.style.width = headerWidths[i];\n\t\t\t}\n\t\t}, headerTrgEls );\n\t\n\t\t$(headerSrcEls).height(0);\n\t\n\t\t/* Same again with the footer if we have one */\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( zeroOut, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\t\tfooterContent.push( nSizer.innerHTML );\n\t\t\t\tfooterWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t\t}, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t\tnToSize.style.width = footerWidths[i];\n\t\t\t}, footerTrgEls );\n\t\n\t\t\t$(footerSrcEls).height(0);\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 3. Apply the measurements\n\t\t */\n\t\n\t\t// \"Hide\" the header and footer that we used for the sizing. We need to keep\n\t\t// the content of the cell so that the width applied to the header and body\n\t\t// both match, but we want to hide it completely. We want to also fix their\n\t\t// width to what they currently are\n\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\" style=\"height:0;overflow:hidden;\">'+headerContent[i]+'</div>';\n\t\t\tnSizer.style.width = headerWidths[i];\n\t\t}, headerSrcEls );\n\t\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\" style=\"height:0;overflow:hidden;\">'+footerContent[i]+'</div>';\n\t\t\t\tnSizer.style.width = footerWidths[i];\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Sanity check that the table is of a sensible width. If not then we are going to get\n\t\t// misalignment - try to prevent this by not allowing the table to shrink below its min width\n\t\tif ( table.outerWidth() < sanityWidth )\n\t\t{\n\t\t\t// The min width depends upon if we have a vertical scrollbar visible or not */\n\t\t\tcorrection = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")) ?\n\t\t\t\t\tsanityWidth+barWidth :\n\t\t\t\t\tsanityWidth;\n\t\n\t\t\t// IE6/7 are a law unto themselves...\n\t\t\tif ( ie67 && (divBodyEl.scrollHeight >\n\t\t\t\tdivBodyEl.offsetHeight || divBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( correction-barWidth );\n\t\t\t}\n\t\n\t\t\t// And give the user a warning that we've stopped the table getting too small\n\t\t\tif ( scrollX === \"\" || scrollXInner !== \"\" ) {\n\t\t\t\t_fnLog( settings, 1, 'Possible column misalignment', 6 );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcorrection = '100%';\n\t\t}\n\t\n\t\t// Apply to the container elements\n\t\tdivBodyStyle.width = _fnStringToCss( correction );\n\t\tdivHeaderStyle.width = _fnStringToCss( correction );\n\t\n\t\tif ( footer ) {\n\t\t\tsettings.nScrollFoot.style.width = _fnStringToCss( correction );\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 4. Clean up\n\t\t */\n\t\tif ( ! scrollY ) {\n\t\t\t/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting\n\t\t\t * the scrollbar height from the visible display, rather than adding it on. We need to\n\t\t\t * set the height in order to sort this. Don't want to do it in any other browsers.\n\t\t\t */\n\t\t\tif ( ie67 ) {\n\t\t\t\tdivBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Finally set the width's of the header and footer tables */\n\t\tvar iOuterWidth = table.outerWidth();\n\t\tdivHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\tdivHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );\n\t\n\t\t// Figure out if there are scrollbar present - if so then we need a the header and footer to\n\t\t// provide a bit more space to allow \"overflow\" scrolling (i.e. past the scrollbar)\n\t\tvar bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == \"scroll\";\n\t\tvar padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );\n\t\tdivHeaderInnerStyle[ padding ] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\n\t\tif ( footer ) {\n\t\t\tdivFooterTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style[padding] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\t}\n\t\n\t\t// Correct DOM ordering for colgroup - comes before the thead\n\t\ttable.children('colgroup').insertBefore( table.children('thead') );\n\t\n\t\t/* Adjust the position of the header in case we loose the y-scrollbar */\n\t\tdivBody.scroll();\n\t\n\t\t// If sorting or filtering has occurred, jump the scrolling back to the top\n\t\t// only if we aren't holding the position\n\t\tif ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {\n\t\t\tdivBodyEl.scrollTop = 0;\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Apply a given function to the display child nodes of an element array (typically\n\t * TD children of TR rows\n\t *  @param {function} fn Method to apply to the objects\n\t *  @param array {nodes} an1 List of elements to look through for display children\n\t *  @param array {nodes} an2 Another list (identical structure to the first) - optional\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyToChildren( fn, an1, an2 )\n\t{\n\t\tvar index=0, i=0, iLen=an1.length;\n\t\tvar nNode1, nNode2;\n\t\n\t\twhile ( i < iLen ) {\n\t\t\tnNode1 = an1[i].firstChild;\n\t\t\tnNode2 = an2 ? an2[i].firstChild : null;\n\t\n\t\t\twhile ( nNode1 ) {\n\t\t\t\tif ( nNode1.nodeType === 1 ) {\n\t\t\t\t\tif ( an2 ) {\n\t\t\t\t\t\tfn( nNode1, nNode2, index );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfn( nNode1, index );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\n\t\t\t\tnNode1 = nNode1.nextSibling;\n\t\t\t\tnNode2 = an2 ? nNode2.nextSibling : null;\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t}\n\t}\n\t\n\t\n\t\n\tvar __re_html_remove = /<.*?>/g;\n\t\n\t\n\t/**\n\t * Calculate the width of columns for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCalculateColumnWidths ( oSettings )\n\t{\n\t\tvar\n\t\t\ttable = oSettings.nTable,\n\t\t\tcolumns = oSettings.aoColumns,\n\t\t\tscroll = oSettings.oScroll,\n\t\t\tscrollY = scroll.sY,\n\t\t\tscrollX = scroll.sX,\n\t\t\tscrollXInner = scroll.sXInner,\n\t\t\tcolumnCount = columns.length,\n\t\t\tvisibleColumns = _fnGetColumns( oSettings, 'bVisible' ),\n\t\t\theaderCells = $('th', oSettings.nTHead),\n\t\t\ttableWidthAttr = table.getAttribute('width'), // from DOM element\n\t\t\ttableContainer = table.parentNode,\n\t\t\tuserInputs = false,\n\t\t\ti, column, columnIdx, width, outerWidth,\n\t\t\tbrowser = oSettings.oBrowser,\n\t\t\tie67 = browser.bScrollOversize;\n\t\n\t\tvar styleWidth = table.style.width;\n\t\tif ( styleWidth && styleWidth.indexOf('%') !== -1 ) {\n\t\t\ttableWidthAttr = styleWidth;\n\t\t}\n\t\n\t\t/* Convert any user input sizes into pixel sizes */\n\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\tif ( column.sWidth !== null ) {\n\t\t\t\tcolumn.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );\n\t\n\t\t\t\tuserInputs = true;\n\t\t\t}\n\t\t}\n\t\n\t\t/* If the number of columns in the DOM equals the number that we have to\n\t\t * process in DataTables, then we can use the offsets that are created by\n\t\t * the web- browser. No custom sizes can be set in order for this to happen,\n\t\t * nor scrolling used\n\t\t */\n\t\tif ( ie67 || ! userInputs && ! scrollX && ! scrollY &&\n\t\t     columnCount == _fnVisbleColumns( oSettings ) &&\n\t\t     columnCount == headerCells.length\n\t\t) {\n\t\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\t\tvar colIdx = _fnVisibleToColumnIndex( oSettings, i );\n\t\n\t\t\t\tif ( colIdx !== null ) {\n\t\t\t\t\tcolumns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise construct a single row, worst case, table with the widest\n\t\t\t// node in the data, assign any user defined widths, then insert it into\n\t\t\t// the DOM and allow the browser to do all the hard work of calculating\n\t\t\t// table widths\n\t\t\tvar tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table\n\t\t\t\t.css( 'visibility', 'hidden' )\n\t\t\t\t.removeAttr( 'id' );\n\t\n\t\t\t// Clean up the table body\n\t\t\ttmpTable.find('tbody tr').remove();\n\t\t\tvar tr = $('<tr/>').appendTo( tmpTable.find('tbody') );\n\t\n\t\t\t// Clone the table header and footer - we can't use the header / footer\n\t\t\t// from the cloned table, since if scrolling is active, the table's\n\t\t\t// real header and footer are contained in different table tags\n\t\t\ttmpTable.find('thead, tfoot').remove();\n\t\t\ttmpTable\n\t\t\t\t.append( $(oSettings.nTHead).clone() )\n\t\t\t\t.append( $(oSettings.nTFoot).clone() );\n\t\n\t\t\t// Remove any assigned widths from the footer (from scrolling)\n\t\t\ttmpTable.find('tfoot th, tfoot td').css('width', '');\n\t\n\t\t\t// Apply custom sizing to the cloned header\n\t\t\theaderCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );\n\t\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\t\theaderCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?\n\t\t\t\t\t_fnStringToCss( column.sWidthOrig ) :\n\t\t\t\t\t'';\n\t\n\t\t\t\t// For scrollX we need to force the column width otherwise the\n\t\t\t\t// browser will collapse it. If this width is smaller than the\n\t\t\t\t// width the column requires, then it will have no effect\n\t\t\t\tif ( column.sWidthOrig && scrollX ) {\n\t\t\t\t\t$( headerCells[i] ).append( $('<div/>').css( {\n\t\t\t\t\t\twidth: column.sWidthOrig,\n\t\t\t\t\t\tmargin: 0,\n\t\t\t\t\t\tpadding: 0,\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\theight: 1\n\t\t\t\t\t} ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Find the widest cell for each column and put it into the table\n\t\t\tif ( oSettings.aoData.length ) {\n\t\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\t\tcolumnIdx = visibleColumns[i];\n\t\t\t\t\tcolumn = columns[ columnIdx ];\n\t\n\t\t\t\t\t$( _fnGetWidestNode( oSettings, columnIdx ) )\n\t\t\t\t\t\t.clone( false )\n\t\t\t\t\t\t.append( column.sContentPadding )\n\t\t\t\t\t\t.appendTo( tr );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Tidy the temporary table - remove name attributes so there aren't\n\t\t\t// duplicated in the dom (radio elements for example)\n\t\t\t$('[name]', tmpTable).removeAttr('name');\n\t\n\t\t\t// Table has been built, attach to the document so we can work with it.\n\t\t\t// A holding element is used, positioned at the top of the container\n\t\t\t// with minimal height, so it has no effect on if the container scrolls\n\t\t\t// or not. Otherwise it might trigger scrolling when it actually isn't\n\t\t\t// needed\n\t\t\tvar holder = $('<div/>').css( scrollX || scrollY ?\n\t\t\t\t\t{\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\theight: 1,\n\t\t\t\t\t\tright: 0,\n\t\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t\t} :\n\t\t\t\t\t{}\n\t\t\t\t)\n\t\t\t\t.append( tmpTable )\n\t\t\t\t.appendTo( tableContainer );\n\t\n\t\t\t// When scrolling (X or Y) we want to set the width of the table as \n\t\t\t// appropriate. However, when not scrolling leave the table width as it\n\t\t\t// is. This results in slightly different, but I think correct behaviour\n\t\t\tif ( scrollX && scrollXInner ) {\n\t\t\t\ttmpTable.width( scrollXInner );\n\t\t\t}\n\t\t\telse if ( scrollX ) {\n\t\t\t\ttmpTable.css( 'width', 'auto' );\n\t\t\t\ttmpTable.removeAttr('width');\n\t\n\t\t\t\t// If there is no width attribute or style, then allow the table to\n\t\t\t\t// collapse\n\t\t\t\tif ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {\n\t\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( scrollY ) {\n\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t}\n\t\t\telse if ( tableWidthAttr ) {\n\t\t\t\ttmpTable.width( tableWidthAttr );\n\t\t\t}\n\t\n\t\t\t// Get the width of each column in the constructed table - we need to\n\t\t\t// know the inner width (so it can be assigned to the other table's\n\t\t\t// cells) and the outer width so we can calculate the full width of the\n\t\t\t// table. This is safe since DataTables requires a unique cell for each\n\t\t\t// column, but if ever a header can span multiple columns, this will\n\t\t\t// need to be modified.\n\t\t\tvar total = 0;\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tvar cell = $(headerCells[i]);\n\t\t\t\tvar border = cell.outerWidth() - cell.width();\n\t\n\t\t\t\t// Use getBounding... where possible (not IE8-) because it can give\n\t\t\t\t// sub-pixel accuracy, which we then want to round up!\n\t\t\t\tvar bounding = browser.bBounding ?\n\t\t\t\t\tMath.ceil( headerCells[i].getBoundingClientRect().width ) :\n\t\t\t\t\tcell.outerWidth();\n\t\n\t\t\t\t// Total is tracked to remove any sub-pixel errors as the outerWidth\n\t\t\t\t// of the table might not equal the total given here (IE!).\n\t\t\t\ttotal += bounding;\n\t\n\t\t\t\t// Width for each column to use\n\t\t\t\tcolumns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );\n\t\t\t}\n\t\n\t\t\ttable.style.width = _fnStringToCss( total );\n\t\n\t\t\t// Finished with the table - ditch it\n\t\t\tholder.remove();\n\t\t}\n\t\n\t\t// If there is a width attr, we want to attach an event listener which\n\t\t// allows the table sizing to automatically adjust when the window is\n\t\t// resized. Use the width attr rather than CSS, since we can't know if the\n\t\t// CSS is a relative value or absolute - DOM read is always px.\n\t\tif ( tableWidthAttr ) {\n\t\t\ttable.style.width = _fnStringToCss( tableWidthAttr );\n\t\t}\n\t\n\t\tif ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {\n\t\t\tvar bindResize = function () {\n\t\t\t\t$(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {\n\t\t\t\t\t_fnAdjustColumnSizing( oSettings );\n\t\t\t\t} ) );\n\t\t\t};\n\t\n\t\t\t// IE6/7 will crash if we bind a resize event handler on page load.\n\t\t\t// To be removed in 1.11 which drops IE6/7 support\n\t\t\tif ( ie67 ) {\n\t\t\t\tsetTimeout( bindResize, 1000 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbindResize();\n\t\t\t}\n\t\n\t\t\toSettings._reszEvt = true;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Throttle the calls to a function. Arguments and context are maintained for\n\t * the throttled function\n\t *  @param {function} fn Function to be called\n\t *  @param {int} [freq=200] call frequency in mS\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnThrottle = DataTable.util.throttle;\n\t\n\t\n\t/**\n\t * Convert a CSS unit width to pixels (e.g. 2em)\n\t *  @param {string} width width to be converted\n\t *  @param {node} parent parent to get the with for (required for relative widths) - optional\n\t *  @returns {int} width in pixels\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnConvertToWidth ( width, parent )\n\t{\n\t\tif ( ! width ) {\n\t\t\treturn 0;\n\t\t}\n\t\n\t\tvar n = $('<div/>')\n\t\t\t.css( 'width', _fnStringToCss( width ) )\n\t\t\t.appendTo( parent || document.body );\n\t\n\t\tvar val = n[0].offsetWidth;\n\t\tn.remove();\n\t\n\t\treturn val;\n\t}\n\t\n\t\n\t/**\n\t * Get the widest node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {node} widest table node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetWidestNode( settings, colIdx )\n\t{\n\t\tvar idx = _fnGetMaxLenString( settings, colIdx );\n\t\tif ( idx < 0 ) {\n\t\t\treturn null;\n\t\t}\n\t\n\t\tvar data = settings.aoData[ idx ];\n\t\treturn ! data.nTr ? // Might not have been created when deferred rendering\n\t\t\t$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :\n\t\t\tdata.anCells[ colIdx ];\n\t}\n\t\n\t\n\t/**\n\t * Get the maximum strlen for each data column\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {string} max string length for each column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetMaxLenString( settings, colIdx )\n\t{\n\t\tvar s, max=-1, maxIdx = -1;\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\ts = _fnGetCellData( settings, i, colIdx, 'display' )+'';\n\t\t\ts = s.replace( __re_html_remove, '' );\n\t\t\ts = s.replace( /&nbsp;/g, ' ' );\n\t\n\t\t\tif ( s.length > max ) {\n\t\t\t\tmax = s.length;\n\t\t\t\tmaxIdx = i;\n\t\t\t}\n\t\t}\n\t\n\t\treturn maxIdx;\n\t}\n\t\n\t\n\t/**\n\t * Append a CSS unit (only if required) to a string\n\t *  @param {string} value to css-ify\n\t *  @returns {string} value with css unit\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnStringToCss( s )\n\t{\n\t\tif ( s === null ) {\n\t\t\treturn '0px';\n\t\t}\n\t\n\t\tif ( typeof s == 'number' ) {\n\t\t\treturn s < 0 ?\n\t\t\t\t'0px' :\n\t\t\t\ts+'px';\n\t\t}\n\t\n\t\t// Check it has a unit character already\n\t\treturn s.match(/\\d$/) ?\n\t\t\ts+'px' :\n\t\t\ts;\n\t}\n\t\n\t\n\t\n\tfunction _fnSortFlatten ( settings )\n\t{\n\t\tvar\n\t\t\ti, iLen, k, kLen,\n\t\t\taSort = [],\n\t\t\taiOrig = [],\n\t\t\taoColumns = settings.aoColumns,\n\t\t\taDataSort, iCol, sType, srcCol,\n\t\t\tfixed = settings.aaSortingFixed,\n\t\t\tfixedObj = $.isPlainObject( fixed ),\n\t\t\tnestedSort = [],\n\t\t\tadd = function ( a ) {\n\t\t\t\tif ( a.length && ! $.isArray( a[0] ) ) {\n\t\t\t\t\t// 1D array\n\t\t\t\t\tnestedSort.push( a );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// 2D array\n\t\t\t\t\t$.merge( nestedSort, a );\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t// Build the sort array, with pre-fix and post-fix options if they have been\n\t\t// specified\n\t\tif ( $.isArray( fixed ) ) {\n\t\t\tadd( fixed );\n\t\t}\n\t\n\t\tif ( fixedObj && fixed.pre ) {\n\t\t\tadd( fixed.pre );\n\t\t}\n\t\n\t\tadd( settings.aaSorting );\n\t\n\t\tif (fixedObj && fixed.post ) {\n\t\t\tadd( fixed.post );\n\t\t}\n\t\n\t\tfor ( i=0 ; i<nestedSort.length ; i++ )\n\t\t{\n\t\t\tsrcCol = nestedSort[i][0];\n\t\t\taDataSort = aoColumns[ srcCol ].aDataSort;\n\t\n\t\t\tfor ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )\n\t\t\t{\n\t\t\t\tiCol = aDataSort[k];\n\t\t\t\tsType = aoColumns[ iCol ].sType || 'string';\n\t\n\t\t\t\tif ( nestedSort[i]._idx === undefined ) {\n\t\t\t\t\tnestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );\n\t\t\t\t}\n\t\n\t\t\t\taSort.push( {\n\t\t\t\t\tsrc:       srcCol,\n\t\t\t\t\tcol:       iCol,\n\t\t\t\t\tdir:       nestedSort[i][1],\n\t\t\t\t\tindex:     nestedSort[i]._idx,\n\t\t\t\t\ttype:      sType,\n\t\t\t\t\tformatter: DataTable.ext.type.order[ sType+\"-pre\" ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\treturn aSort;\n\t}\n\t\n\t/**\n\t * Change the order of the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t *  @todo This really needs split up!\n\t */\n\tfunction _fnSort ( oSettings )\n\t{\n\t\tvar\n\t\t\ti, ien, iLen, j, jLen, k, kLen,\n\t\t\tsDataType, nTh,\n\t\t\taiOrig = [],\n\t\t\toExtSort = DataTable.ext.type.order,\n\t\t\taoData = oSettings.aoData,\n\t\t\taoColumns = oSettings.aoColumns,\n\t\t\taDataSort, data, iCol, sType, oSort,\n\t\t\tformatters = 0,\n\t\t\tsortCol,\n\t\t\tdisplayMaster = oSettings.aiDisplayMaster,\n\t\t\taSort;\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo Can this be moved into a 'data-ready' handler which is called when\n\t\t//   data is going to be used in the table?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\taSort = _fnSortFlatten( oSettings );\n\t\n\t\tfor ( i=0, ien=aSort.length ; i<ien ; i++ ) {\n\t\t\tsortCol = aSort[i];\n\t\n\t\t\t// Track if we can use the fast sort algorithm\n\t\t\tif ( sortCol.formatter ) {\n\t\t\t\tformatters++;\n\t\t\t}\n\t\n\t\t\t// Load the data needed for the sort, for each cell\n\t\t\t_fnSortData( oSettings, sortCol.col );\n\t\t}\n\t\n\t\t/* No sorting required if server-side or no sorting array */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )\n\t\t{\n\t\t\t// Create a value - key array of the current row positions such that we can use their\n\t\t\t// current position during the sort, if values match, in order to perform stable sorting\n\t\t\tfor ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {\n\t\t\t\taiOrig[ displayMaster[i] ] = i;\n\t\t\t}\n\t\n\t\t\t/* Do the sort - here we want multi-column sorting based on a given data source (column)\n\t\t\t * and sorting function (from oSort) in a certain direction. It's reasonably complex to\n\t\t\t * follow on it's own, but this is what we want (example two column sorting):\n\t\t\t *  fnLocalSorting = function(a,b){\n\t\t\t *    var iTest;\n\t\t\t *    iTest = oSort['string-asc']('data11', 'data12');\n\t\t\t *      if (iTest !== 0)\n\t\t\t *        return iTest;\n\t\t\t *    iTest = oSort['numeric-desc']('data21', 'data22');\n\t\t\t *    if (iTest !== 0)\n\t\t\t *      return iTest;\n\t\t\t *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );\n\t\t\t *  }\n\t\t\t * Basically we have a test for each sorting column, if the data in that column is equal,\n\t\t\t * test the next column. If all columns match, then we use a numeric sort on the row\n\t\t\t * positions in the original data array to provide a stable sort.\n\t\t\t *\n\t\t\t * Note - I know it seems excessive to have two sorting methods, but the first is around\n\t\t\t * 15% faster, so the second is only maintained for backwards compatibility with sorting\n\t\t\t * methods which do not have a pre-sort formatting function.\n\t\t\t */\n\t\t\tif ( formatters === aSort.length ) {\n\t\t\t\t// All sort types have formatting functions\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, test, sort,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\ttest = x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn sort.dir === 'asc' ? test : -test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Depreciated - remove in 1.11 (providing a plug-in option)\n\t\t\t\t// Not all sort types have formatting methods, so we have to call their sorting\n\t\t\t\t// methods.\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, l, test, sort, fn,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\tfn = oExtSort[ sort.type+\"-\"+sort.dir ] || oExtSort[ \"string-\"+sort.dir ];\n\t\t\t\t\t\ttest = fn( x, y );\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Tell the draw function that we have sorted the data */\n\t\toSettings.bSorted = true;\n\t}\n\t\n\t\n\tfunction _fnSortAria ( settings )\n\t{\n\t\tvar label;\n\t\tvar nextSort;\n\t\tvar columns = settings.aoColumns;\n\t\tvar aSort = _fnSortFlatten( settings );\n\t\tvar oAria = settings.oLanguage.oAria;\n\t\n\t\t// ARIA attributes - need to loop all columns, to update all (removing old\n\t\t// attributes as needed)\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar col = columns[i];\n\t\t\tvar asSorting = col.asSorting;\n\t\t\tvar sTitle = col.sTitle.replace( /<.*?>/g, \"\" );\n\t\t\tvar th = col.nTh;\n\t\n\t\t\t// IE7 is throwing an error when setting these properties with jQuery's\n\t\t\t// attr() and removeAttr() methods...\n\t\t\tth.removeAttribute('aria-sort');\n\t\n\t\t\t/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */\n\t\t\tif ( col.bSortable ) {\n\t\t\t\tif ( aSort.length > 0 && aSort[0].col == i ) {\n\t\t\t\t\tth.setAttribute('aria-sort', aSort[0].dir==\"asc\" ? \"ascending\" : \"descending\" );\n\t\t\t\t\tnextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnextSort = asSorting[0];\n\t\t\t\t}\n\t\n\t\t\t\tlabel = sTitle + ( nextSort === \"asc\" ?\n\t\t\t\t\toAria.sSortAscending :\n\t\t\t\t\toAria.sSortDescending\n\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlabel = sTitle;\n\t\t\t}\n\t\n\t\t\tth.setAttribute('aria-label', label);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Function to run on user sort request\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {boolean} [append=false] Append the requested sort to the existing\n\t *    sort if true (i.e. multi-column sort)\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortListener ( settings, colIdx, append, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\tvar sorting = settings.aaSorting;\n\t\tvar asSorting = col.asSorting;\n\t\tvar nextSortIdx;\n\t\tvar next = function ( a, overflow ) {\n\t\t\tvar idx = a._idx;\n\t\t\tif ( idx === undefined ) {\n\t\t\t\tidx = $.inArray( a[1], asSorting );\n\t\t\t}\n\t\n\t\t\treturn idx+1 < asSorting.length ?\n\t\t\t\tidx+1 :\n\t\t\t\toverflow ?\n\t\t\t\t\tnull :\n\t\t\t\t\t0;\n\t\t};\n\t\n\t\t// Convert to 2D array if needed\n\t\tif ( typeof sorting[0] === 'number' ) {\n\t\t\tsorting = settings.aaSorting = [ sorting ];\n\t\t}\n\t\n\t\t// If appending the sort then we are multi-column sorting\n\t\tif ( append && settings.oFeatures.bSortMulti ) {\n\t\t\t// Are we already doing some kind of sort on this column?\n\t\t\tvar sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );\n\t\n\t\t\tif ( sortIdx !== -1 ) {\n\t\t\t\t// Yes, modify the sort\n\t\t\t\tnextSortIdx = next( sorting[sortIdx], true );\n\t\n\t\t\t\tif ( nextSortIdx === null && sorting.length === 1 ) {\n\t\t\t\t\tnextSortIdx = 0; // can't remove sorting completely\n\t\t\t\t}\n\t\n\t\t\t\tif ( nextSortIdx === null ) {\n\t\t\t\t\tsorting.splice( sortIdx, 1 );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tsorting[sortIdx][1] = asSorting[ nextSortIdx ];\n\t\t\t\t\tsorting[sortIdx]._idx = nextSortIdx;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// No sort on this column yet\n\t\t\t\tsorting.push( [ colIdx, asSorting[0], 0 ] );\n\t\t\t\tsorting[sorting.length-1]._idx = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( sorting.length && sorting[0][0] == colIdx ) {\n\t\t\t// Single column - already sorting on this column, modify the sort\n\t\t\tnextSortIdx = next( sorting[0] );\n\t\n\t\t\tsorting.length = 1;\n\t\t\tsorting[0][1] = asSorting[ nextSortIdx ];\n\t\t\tsorting[0]._idx = nextSortIdx;\n\t\t}\n\t\telse {\n\t\t\t// Single column - sort only on this column\n\t\t\tsorting.length = 0;\n\t\t\tsorting.push( [ colIdx, asSorting[0] ] );\n\t\t\tsorting[0]._idx = 0;\n\t\t}\n\t\n\t\t// Run the sort by calling a full redraw\n\t\t_fnReDraw( settings );\n\t\n\t\t// callback used for async user interaction\n\t\tif ( typeof callback == 'function' ) {\n\t\t\tcallback( settings );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Attach a sort handler (click) to a node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortAttachListener ( settings, attachTo, colIdx, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\n\t\t_fnBindAction( attachTo, {}, function (e) {\n\t\t\t/* If the column is not sortable - don't to anything */\n\t\t\tif ( col.bSortable === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If processing is enabled use a timeout to allow the processing\n\t\t\t// display to be shown - otherwise to it synchronously\n\t\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t\tsetTimeout( function() {\n\t\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\n\t\t\t\t\t// In server-side processing, the draw callback will remove the\n\t\t\t\t\t// processing display\n\t\t\t\t\tif ( _fnDataSource( settings ) !== 'ssp' ) {\n\t\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t}\n\t\t\t\t}, 0 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Set the sorting classes on table's body, Note: it is safe to call this function\n\t * when bSort and bSortClasses are false\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortingClasses( settings )\n\t{\n\t\tvar oldSort = settings.aLastSort;\n\t\tvar sortClass = settings.oClasses.sSortColumn;\n\t\tvar sort = _fnSortFlatten( settings );\n\t\tvar features = settings.oFeatures;\n\t\tvar i, ien, colIdx;\n\t\n\t\tif ( features.bSort && features.bSortClasses ) {\n\t\t\t// Remove old sorting classes\n\t\t\tfor ( i=0, ien=oldSort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = oldSort[i].src;\n\t\n\t\t\t\t// Remove column sorting\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.removeClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\n\t\t\t// Add new column sorting\n\t\t\tfor ( i=0, ien=sort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = sort[i].src;\n\t\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.addClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aLastSort = sort;\n\t}\n\t\n\t\n\t// Get the data to sort a column, be it from cache, fresh (populating the\n\t// cache), or from a sort formatter\n\tfunction _fnSortData( settings, idx )\n\t{\n\t\t// Custom sorting function - provided by the sort data type\n\t\tvar column = settings.aoColumns[ idx ];\n\t\tvar customSort = DataTable.ext.order[ column.sSortDataType ];\n\t\tvar customData;\n\t\n\t\tif ( customSort ) {\n\t\t\tcustomData = customSort.call( settings.oInstance, settings, idx,\n\t\t\t\t_fnColumnIndexToVisible( settings, idx )\n\t\t\t);\n\t\t}\n\t\n\t\t// Use / populate cache\n\t\tvar row, cellData;\n\t\tvar formatter = DataTable.ext.type.order[ column.sType+\"-pre\" ];\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aSortData ) {\n\t\t\t\trow._aSortData = [];\n\t\t\t}\n\t\n\t\t\tif ( ! row._aSortData[idx] || customSort ) {\n\t\t\t\tcellData = customSort ?\n\t\t\t\t\tcustomData[i] : // If there was a custom sort function, use data from there\n\t\t\t\t\t_fnGetCellData( settings, i, idx, 'sort' );\n\t\n\t\t\t\trow._aSortData[ idx ] = formatter ?\n\t\t\t\t\tformatter( cellData ) :\n\t\t\t\t\tcellData;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Save the state of a table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSaveState ( settings )\n\t{\n\t\tif ( !settings.oFeatures.bStateSave || settings.bDestroying )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Store the interesting variables */\n\t\tvar state = {\n\t\t\ttime:    +new Date(),\n\t\t\tstart:   settings._iDisplayStart,\n\t\t\tlength:  settings._iDisplayLength,\n\t\t\torder:   $.extend( true, [], settings.aaSorting ),\n\t\t\tsearch:  _fnSearchToCamel( settings.oPreviousSearch ),\n\t\t\tcolumns: $.map( settings.aoColumns, function ( col, i ) {\n\t\t\t\treturn {\n\t\t\t\t\tvisible: col.bVisible,\n\t\t\t\t\tsearch: _fnSearchToCamel( settings.aoPreSearchCols[i] )\n\t\t\t\t};\n\t\t\t} )\n\t\t};\n\t\n\t\t_fnCallbackFire( settings, \"aoStateSaveParams\", 'stateSaveParams', [settings, state] );\n\t\n\t\tsettings.oSavedState = state;\n\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, state );\n\t}\n\t\n\t\n\t/**\n\t * Attempt to load a saved table state\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oInit DataTables init object so we can override settings\n\t *  @param {function} callback Callback to execute when the state has been loaded\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLoadState ( settings, oInit, callback )\n\t{\n\t\tvar i, ien;\n\t\tvar columns = settings.aoColumns;\n\t\tvar loaded = function ( s ) {\n\t\t\tif ( ! s || ! s.time ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Allow custom and plug-in manipulation functions to alter the saved data set and\n\t\t\t// cancelling of loading by returning false\n\t\t\tvar abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );\n\t\t\tif ( $.inArray( false, abStateLoad ) !== -1 ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Reject old data\n\t\t\tvar duration = settings.iStateDuration;\n\t\t\tif ( duration > 0 && s.time < +new Date() - (duration*1000) ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Number of columns have changed - all bets are off, no restore of settings\n\t\t\tif ( s.columns && columns.length !== s.columns.length ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Store the saved state so it might be accessed at any time\n\t\t\tsettings.oLoadedState = $.extend( true, {}, state );\n\t\n\t\t\t// Restore key features - todo - for 1.11 this needs to be done by\n\t\t\t// subscribed events\n\t\t\tif ( s.start !== undefined ) {\n\t\t\t\tsettings._iDisplayStart    = s.start;\n\t\t\t\tsettings.iInitDisplayStart = s.start;\n\t\t\t}\n\t\t\tif ( s.length !== undefined ) {\n\t\t\t\tsettings._iDisplayLength   = s.length;\n\t\t\t}\n\t\n\t\t\t// Order\n\t\t\tif ( s.order !== undefined ) {\n\t\t\t\tsettings.aaSorting = [];\n\t\t\t\t$.each( s.order, function ( i, col ) {\n\t\t\t\t\tsettings.aaSorting.push( col[0] >= columns.length ?\n\t\t\t\t\t\t[ 0, col[1] ] :\n\t\t\t\t\t\tcol\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Search\n\t\t\tif ( s.search !== undefined ) {\n\t\t\t\t$.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );\n\t\t\t}\n\t\n\t\t\t// Columns\n\t\t\t// \n\t\t\tif ( s.columns ) {\n\t\t\t\tfor ( i=0, ien=s.columns.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar col = s.columns[i];\n\t\n\t\t\t\t\t// Visibility\n\t\t\t\t\tif ( col.visible !== undefined ) {\n\t\t\t\t\t\tcolumns[i].bVisible = col.visible;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Search\n\t\t\t\t\tif ( col.search !== undefined ) {\n\t\t\t\t\t\t$.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );\n\t\t\tcallback();\n\t\t}\n\t\n\t\tif ( ! settings.oFeatures.bStateSave ) {\n\t\t\tcallback();\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );\n\t\n\t\tif ( state !== undefined ) {\n\t\t\tloaded( state );\n\t\t}\n\t\t// otherwise, wait for the loaded callback to be executed\n\t}\n\t\n\t\n\t/**\n\t * Return the settings object for a particular table\n\t *  @param {node} table table we are using as a dataTable\n\t *  @returns {object} Settings object - or null if not found\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSettingsFromNode ( table )\n\t{\n\t\tvar settings = DataTable.settings;\n\t\tvar idx = $.inArray( table, _pluck( settings, 'nTable' ) );\n\t\n\t\treturn idx !== -1 ?\n\t\t\tsettings[ idx ] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Log an error message\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} level log error messages, or display them to the user\n\t *  @param {string} msg error message\n\t *  @param {int} tn Technical note id to get more information about the error.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLog( settings, level, msg, tn )\n\t{\n\t\tmsg = 'DataTables warning: '+\n\t\t\t(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;\n\t\n\t\tif ( tn ) {\n\t\t\tmsg += '. For more information about this error, please see '+\n\t\t\t'http://datatables.net/tn/'+tn;\n\t\t}\n\t\n\t\tif ( ! level  ) {\n\t\t\t// Backwards compatibility pre 1.10\n\t\t\tvar ext = DataTable.ext;\n\t\t\tvar type = ext.sErrMode || ext.errMode;\n\t\n\t\t\tif ( settings ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );\n\t\t\t}\n\t\n\t\t\tif ( type == 'alert' ) {\n\t\t\t\talert( msg );\n\t\t\t}\n\t\t\telse if ( type == 'throw' ) {\n\t\t\t\tthrow new Error(msg);\n\t\t\t}\n\t\t\telse if ( typeof type == 'function' ) {\n\t\t\t\ttype( settings, tn, msg );\n\t\t\t}\n\t\t}\n\t\telse if ( window.console && console.log ) {\n\t\t\tconsole.log( msg );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * See if a property is defined on one object, if so assign it to the other object\n\t *  @param {object} ret target object\n\t *  @param {object} src source object\n\t *  @param {string} name property\n\t *  @param {string} [mappedName] name to map too - optional, name used if not given\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnMap( ret, src, name, mappedName )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\t$.each( name, function (i, val) {\n\t\t\t\tif ( $.isArray( val ) ) {\n\t\t\t\t\t_fnMap( ret, src, val[0], val[1] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_fnMap( ret, src, val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( mappedName === undefined ) {\n\t\t\tmappedName = name;\n\t\t}\n\t\n\t\tif ( src[name] !== undefined ) {\n\t\t\tret[mappedName] = src[name];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Extend objects - very similar to jQuery.extend, but deep copy objects, and\n\t * shallow copy arrays. The reason we need to do this, is that we don't want to\n\t * deep copy array init values (such as aaSorting) since the dev wouldn't be\n\t * able to override them, but we do want to deep copy arrays.\n\t *  @param {object} out Object to extend\n\t *  @param {object} extender Object from which the properties will be applied to\n\t *      out\n\t *  @param {boolean} breakRefs If true, then arrays will be sliced to take an\n\t *      independent copy with the exception of the `data` or `aaData` parameters\n\t *      if they are present. This is so you can pass in a collection to\n\t *      DataTables and have that used as your data source without breaking the\n\t *      references\n\t *  @returns {object} out Reference, just for convenience - out === the return.\n\t *  @memberof DataTable#oApi\n\t *  @todo This doesn't take account of arrays inside the deep copied objects.\n\t */\n\tfunction _fnExtend( out, extender, breakRefs )\n\t{\n\t\tvar val;\n\t\n\t\tfor ( var prop in extender ) {\n\t\t\tif ( extender.hasOwnProperty(prop) ) {\n\t\t\t\tval = extender[prop];\n\t\n\t\t\t\tif ( $.isPlainObject( val ) ) {\n\t\t\t\t\tif ( ! $.isPlainObject( out[prop] ) ) {\n\t\t\t\t\t\tout[prop] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, out[prop], val );\n\t\t\t\t}\n\t\t\t\telse if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {\n\t\t\t\t\tout[prop] = val.slice();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tout[prop] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t}\n\t\n\t\n\t/**\n\t * Bind an event handers to allow a click or return key to activate the callback.\n\t * This is good for accessibility since a return on the keyboard will have the\n\t * same effect as a click, if the element has focus.\n\t *  @param {element} n Element to bind the action to\n\t *  @param {object} oData Data object to pass to the triggered function\n\t *  @param {function} fn Callback function for when the event is triggered\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBindAction( n, oData, fn )\n\t{\n\t\t$(n)\n\t\t\t.on( 'click.DT', oData, function (e) {\n\t\t\t\t\tn.blur(); // Remove focus outline for mouse users\n\t\t\t\t\tfn(e);\n\t\t\t\t} )\n\t\t\t.on( 'keypress.DT', oData, function (e){\n\t\t\t\t\tif ( e.which === 13 ) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tfn(e);\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t.on( 'selectstart.DT', function () {\n\t\t\t\t\t/* Take the brutal approach to cancelling text selection */\n\t\t\t\t\treturn false;\n\t\t\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Register a callback function. Easily allows a callback function to be added to\n\t * an array store of callback functions that can then all be called together.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sStore Name of the array storage for the callbacks in oSettings\n\t *  @param {function} fn Function to be called back\n\t *  @param {string} sName Identifying name for the callback (i.e. a label)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackReg( oSettings, sStore, fn, sName )\n\t{\n\t\tif ( fn )\n\t\t{\n\t\t\toSettings[sStore].push( {\n\t\t\t\t\"fn\": fn,\n\t\t\t\t\"sName\": sName\n\t\t\t} );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Fire callback functions and trigger events. Note that the loop over the\n\t * callback array store is done backwards! Further note that you do not want to\n\t * fire off triggers in time sensitive applications (for example cell creation)\n\t * as its slow.\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} callbackArr Name of the array storage for the callbacks in\n\t *      oSettings\n\t *  @param {string} eventName Name of the jQuery custom event to trigger. If\n\t *      null no trigger is fired\n\t *  @param {array} args Array of arguments to pass to the callback function /\n\t *      trigger\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackFire( settings, callbackArr, eventName, args )\n\t{\n\t\tvar ret = [];\n\t\n\t\tif ( callbackArr ) {\n\t\t\tret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {\n\t\t\t\treturn val.fn.apply( settings.oInstance, args );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( eventName !== null ) {\n\t\t\tvar e = $.Event( eventName+'.dt' );\n\t\n\t\t\t$(settings.nTable).trigger( e, args );\n\t\n\t\t\tret.push( e.result );\n\t\t}\n\t\n\t\treturn ret;\n\t}\n\t\n\t\n\tfunction _fnLengthOverflow ( settings )\n\t{\n\t\tvar\n\t\t\tstart = settings._iDisplayStart,\n\t\t\tend = settings.fnDisplayEnd(),\n\t\t\tlen = settings._iDisplayLength;\n\t\n\t\t/* If we have space to show extra rows (backing up from the end point - then do so */\n\t\tif ( start >= end )\n\t\t{\n\t\t\tstart = end - len;\n\t\t}\n\t\n\t\t// Keep the start record on the current page\n\t\tstart -= (start % len);\n\t\n\t\tif ( len === -1 || start < 0 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\n\t\tsettings._iDisplayStart = start;\n\t}\n\t\n\t\n\tfunction _fnRenderer( settings, type )\n\t{\n\t\tvar renderer = settings.renderer;\n\t\tvar host = DataTable.ext.renderer[type];\n\t\n\t\tif ( $.isPlainObject( renderer ) && renderer[type] ) {\n\t\t\t// Specific renderer for this type. If available use it, otherwise use\n\t\t\t// the default.\n\t\t\treturn host[renderer[type]] || host._;\n\t\t}\n\t\telse if ( typeof renderer === 'string' ) {\n\t\t\t// Common renderer - if there is one available for this type use it,\n\t\t\t// otherwise use the default\n\t\t\treturn host[renderer] || host._;\n\t\t}\n\t\n\t\t// Use the default\n\t\treturn host._;\n\t}\n\t\n\t\n\t/**\n\t * Detect the data source being used for the table. Used to simplify the code\n\t * a little (ajax) and to make it compress a little smaller.\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {string} Data source\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDataSource ( settings )\n\t{\n\t\tif ( settings.oFeatures.bServerSide ) {\n\t\t\treturn 'ssp';\n\t\t}\n\t\telse if ( settings.ajax || settings.sAjaxSource ) {\n\t\t\treturn 'ajax';\n\t\t}\n\t\treturn 'dom';\n\t}\n\t\n\n\t\n\t\n\t/**\n\t * Computed structure of the DataTables API, defined by the options passed to\n\t * `DataTable.Api.register()` when building the API.\n\t *\n\t * The structure is built in order to speed creation and extension of the Api\n\t * objects since the extensions are effectively pre-parsed.\n\t *\n\t * The array is an array of objects with the following structure, where this\n\t * base array represents the Api prototype base:\n\t *\n\t *     [\n\t *       {\n\t *         name:      'data'                -- string   - Property name\n\t *         val:       function () {},       -- function - Api method (or undefined if just an object\n\t *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t *       },\n\t *       {\n\t *         name:     'row'\n\t *         val:       {},\n\t *         methodExt: [ ... ],\n\t *         propExt:   [\n\t *           {\n\t *             name:      'data'\n\t *             val:       function () {},\n\t *             methodExt: [ ... ],\n\t *             propExt:   [ ... ]\n\t *           },\n\t *           ...\n\t *         ]\n\t *       }\n\t *     ]\n\t *\n\t * @type {Array}\n\t * @ignore\n\t */\n\tvar __apiStruct = [];\n\t\n\t\n\t/**\n\t * `Array.prototype` reference.\n\t *\n\t * @type object\n\t * @ignore\n\t */\n\tvar __arrayProto = Array.prototype;\n\t\n\t\n\t/**\n\t * Abstraction for `context` parameter of the `Api` constructor to allow it to\n\t * take several different forms for ease of use.\n\t *\n\t * Each of the input parameter types will be converted to a DataTables settings\n\t * object where possible.\n\t *\n\t * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one\n\t *   of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t *   * `DataTables.Api` - API instance\n\t * @return {array|null} Matching DataTables settings objects. `null` or\n\t *   `undefined` is returned if no matching DataTable is found.\n\t * @ignore\n\t */\n\tvar _toSettings = function ( mixed )\n\t{\n\t\tvar idx, jq;\n\t\tvar settings = DataTable.settings;\n\t\tvar tables = $.map( settings, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\tif ( ! mixed ) {\n\t\t\treturn [];\n\t\t}\n\t\telse if ( mixed.nTable && mixed.oApi ) {\n\t\t\t// DataTables settings object\n\t\t\treturn [ mixed ];\n\t\t}\n\t\telse if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {\n\t\t\t// Table node\n\t\t\tidx = $.inArray( mixed, tables );\n\t\t\treturn idx !== -1 ? [ settings[idx] ] : null;\n\t\t}\n\t\telse if ( mixed && typeof mixed.settings === 'function' ) {\n\t\t\treturn mixed.settings().toArray();\n\t\t}\n\t\telse if ( typeof mixed === 'string' ) {\n\t\t\t// jQuery selector\n\t\t\tjq = $(mixed);\n\t\t}\n\t\telse if ( mixed instanceof $ ) {\n\t\t\t// jQuery object (also DataTables instance)\n\t\t\tjq = mixed;\n\t\t}\n\t\n\t\tif ( jq ) {\n\t\t\treturn jq.map( function(i) {\n\t\t\t\tidx = $.inArray( this, tables );\n\t\t\t\treturn idx !== -1 ? settings[idx] : null;\n\t\t\t} ).toArray();\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * DataTables API class - used to control and interface with  one or more\n\t * DataTables enhanced tables.\n\t *\n\t * The API class is heavily based on jQuery, presenting a chainable interface\n\t * that you can use to interact with tables. Each instance of the API class has\n\t * a \"context\" - i.e. the tables that it will operate on. This could be a single\n\t * table, all tables on a page or a sub-set thereof.\n\t *\n\t * Additionally the API is designed to allow you to easily work with the data in\n\t * the tables, retrieving and manipulating it as required. This is done by\n\t * presenting the API class as an array like interface. The contents of the\n\t * array depend upon the actions requested by each method (for example\n\t * `rows().nodes()` will return an array of nodes, while `rows().data()` will\n\t * return an array of objects or arrays depending upon your table's\n\t * configuration). The API object has a number of array like methods (`push`,\n\t * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,\n\t * `unique` etc) to assist your working with the data held in a table.\n\t *\n\t * Most methods (those which return an Api instance) are chainable, which means\n\t * the return from a method call also has all of the methods available that the\n\t * top level object had. For example, these two calls are equivalent:\n\t *\n\t *     // Not chained\n\t *     api.row.add( {...} );\n\t *     api.draw();\n\t *\n\t *     // Chained\n\t *     api.row.add( {...} ).draw();\n\t *\n\t * @class DataTable.Api\n\t * @param {array|object|string|jQuery} context DataTable identifier. This is\n\t *   used to define which DataTables enhanced tables this API will operate on.\n\t *   Can be one of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t * @param {array} [data] Data to initialise the Api instance with.\n\t *\n\t * @example\n\t *   // Direct initialisation during DataTables construction\n\t *   var api = $('#example').DataTable();\n\t *\n\t * @example\n\t *   // Initialisation using a DataTables jQuery object\n\t *   var api = $('#example').dataTable().api();\n\t *\n\t * @example\n\t *   // Initialisation as a constructor\n\t *   var api = new $.fn.DataTable.Api( 'table.dataTable' );\n\t */\n\t_Api = function ( context, data )\n\t{\n\t\tif ( ! (this instanceof _Api) ) {\n\t\t\treturn new _Api( context, data );\n\t\t}\n\t\n\t\tvar settings = [];\n\t\tvar ctxSettings = function ( o ) {\n\t\t\tvar a = _toSettings( o );\n\t\t\tif ( a ) {\n\t\t\t\tsettings = settings.concat( a );\n\t\t\t}\n\t\t};\n\t\n\t\tif ( $.isArray( context ) ) {\n\t\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tctxSettings( context[i] );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tctxSettings( context );\n\t\t}\n\t\n\t\t// Remove duplicates\n\t\tthis.context = _unique( settings );\n\t\n\t\t// Initial data\n\t\tif ( data ) {\n\t\t\t$.merge( this, data );\n\t\t}\n\t\n\t\t// selector\n\t\tthis.selector = {\n\t\t\trows: null,\n\t\t\tcols: null,\n\t\t\topts: null\n\t\t};\n\t\n\t\t_Api.extend( this, this, __apiStruct );\n\t};\n\t\n\tDataTable.Api = _Api;\n\t\n\t// Don't destroy the existing prototype, just extend it. Required for jQuery 2's\n\t// isPlainObject.\n\t$.extend( _Api.prototype, {\n\t\tany: function ()\n\t\t{\n\t\t\treturn this.count() !== 0;\n\t\t},\n\t\n\t\n\t\tconcat:  __arrayProto.concat,\n\t\n\t\n\t\tcontext: [], // array of table settings objects\n\t\n\t\n\t\tcount: function ()\n\t\t{\n\t\t\treturn this.flatten().length;\n\t\t},\n\t\n\t\n\t\teach: function ( fn )\n\t\t{\n\t\t\tfor ( var i=0, ien=this.length ; i<ien; i++ ) {\n\t\t\t\tfn.call( this, this[i], i, this );\n\t\t\t}\n\t\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\teq: function ( idx )\n\t\t{\n\t\t\tvar ctx = this.context;\n\t\n\t\t\treturn ctx.length > idx ?\n\t\t\t\tnew _Api( ctx[idx], this[idx] ) :\n\t\t\t\tnull;\n\t\t},\n\t\n\t\n\t\tfilter: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.filter ) {\n\t\t\t\ta = __arrayProto.filter.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( fn.call( this, this[i], i, this ) ) {\n\t\t\t\t\t\ta.push( this[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tflatten: function ()\n\t\t{\n\t\t\tvar a = [];\n\t\t\treturn new _Api( this.context, a.concat.apply( a, this.toArray() ) );\n\t\t},\n\t\n\t\n\t\tjoin:    __arrayProto.join,\n\t\n\t\n\t\tindexOf: __arrayProto.indexOf || function (obj, start)\n\t\t{\n\t\t\tfor ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {\n\t\t\t\tif ( this[i] === obj ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1;\n\t\t},\n\t\n\t\titerator: function ( flatten, type, fn, alwaysNew ) {\n\t\t\tvar\n\t\t\t\ta = [], ret,\n\t\t\t\ti, ien, j, jen,\n\t\t\t\tcontext = this.context,\n\t\t\t\trows, items, item,\n\t\t\t\tselector = this.selector;\n\t\n\t\t\t// Argument shifting\n\t\t\tif ( typeof flatten === 'string' ) {\n\t\t\t\talwaysNew = fn;\n\t\t\t\tfn = type;\n\t\t\t\ttype = flatten;\n\t\t\t\tflatten = false;\n\t\t\t}\n\t\n\t\t\tfor ( i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tvar apiInst = new _Api( context[i] );\n\t\n\t\t\t\tif ( type === 'table' ) {\n\t\t\t\t\tret = fn.call( apiInst, context[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'columns' || type === 'rows' ) {\n\t\t\t\t\t// this has same length as context - one entry for each table\n\t\t\t\t\tret = fn.call( apiInst, context[i], this[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {\n\t\t\t\t\t// columns and rows share the same structure.\n\t\t\t\t\t// 'this' is an array of column indexes for each context\n\t\t\t\t\titems = this[i];\n\t\n\t\t\t\t\tif ( type === 'column-rows' ) {\n\t\t\t\t\t\trows = _selector_row_indexes( context[i], selector.opts );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfor ( j=0, jen=items.length ; j<jen ; j++ ) {\n\t\t\t\t\t\titem = items[j];\n\t\n\t\t\t\t\t\tif ( type === 'cell' ) {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item.row, item.column, i, j );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item, i, j, rows );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( a.length || alwaysNew ) {\n\t\t\t\tvar api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );\n\t\t\t\tvar apiSelector = api.selector;\n\t\t\t\tapiSelector.rows = selector.rows;\n\t\t\t\tapiSelector.cols = selector.cols;\n\t\t\t\tapiSelector.opts = selector.opts;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\tlastIndexOf: __arrayProto.lastIndexOf || function (obj, start)\n\t\t{\n\t\t\t// Bit cheeky...\n\t\t\treturn this.indexOf.apply( this.toArray.reverse(), arguments );\n\t\t},\n\t\n\t\n\t\tlength:  0,\n\t\n\t\n\t\tmap: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.map ) {\n\t\t\t\ta = __arrayProto.map.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\ta.push( fn.call( this, this[i], i ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tpluck: function ( prop )\n\t\t{\n\t\t\treturn this.map( function ( el ) {\n\t\t\t\treturn el[ prop ];\n\t\t\t} );\n\t\t},\n\t\n\t\tpop:     __arrayProto.pop,\n\t\n\t\n\t\tpush:    __arrayProto.push,\n\t\n\t\n\t\t// Does not return an API instance\n\t\treduce: __arrayProto.reduce || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, 0, this.length, 1 );\n\t\t},\n\t\n\t\n\t\treduceRight: __arrayProto.reduceRight || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, this.length-1, -1, -1 );\n\t\t},\n\t\n\t\n\t\treverse: __arrayProto.reverse,\n\t\n\t\n\t\t// Object with rows, columns and opts\n\t\tselector: null,\n\t\n\t\n\t\tshift:   __arrayProto.shift,\n\t\n\t\n\t\tsort:    __arrayProto.sort, // ? name - order?\n\t\n\t\n\t\tsplice:  __arrayProto.splice,\n\t\n\t\n\t\ttoArray: function ()\n\t\t{\n\t\t\treturn __arrayProto.slice.call( this );\n\t\t},\n\t\n\t\n\t\tto$: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\ttoJQuery: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\tunique: function ()\n\t\t{\n\t\t\treturn new _Api( this.context, _unique(this) );\n\t\t},\n\t\n\t\n\t\tunshift: __arrayProto.unshift\n\t} );\n\t\n\t\n\t_Api.extend = function ( scope, obj, ext )\n\t{\n\t\t// Only extend API instances and static properties of the API\n\t\tif ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\tj, jen,\n\t\t\tstruct, inner,\n\t\t\tmethodScoping = function ( scope, fn, struc ) {\n\t\t\t\treturn function () {\n\t\t\t\t\tvar ret = fn.apply( scope, arguments );\n\t\n\t\t\t\t\t// Method extension\n\t\t\t\t\t_Api.extend( ret, ret, struc.methodExt );\n\t\t\t\t\treturn ret;\n\t\t\t\t};\n\t\t\t};\n\t\n\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\tstruct = ext[i];\n\t\n\t\t\t// Value\n\t\t\tobj[ struct.name ] = typeof struct.val === 'function' ?\n\t\t\t\tmethodScoping( scope, struct.val, struct ) :\n\t\t\t\t$.isPlainObject( struct.val ) ?\n\t\t\t\t\t{} :\n\t\t\t\t\tstruct.val;\n\t\n\t\t\tobj[ struct.name ].__dt_wrapper = true;\n\t\n\t\t\t// Property extension\n\t\t\t_Api.extend( scope, obj[ struct.name ], struct.propExt );\n\t\t}\n\t};\n\t\n\t\n\t// @todo - Is there need for an augment function?\n\t// _Api.augment = function ( inst, name )\n\t// {\n\t// \t// Find src object in the structure from the name\n\t// \tvar parts = name.split('.');\n\t\n\t// \t_Api.extend( inst, obj );\n\t// };\n\t\n\t\n\t//     [\n\t//       {\n\t//         name:      'data'                -- string   - Property name\n\t//         val:       function () {},       -- function - Api method (or undefined if just an object\n\t//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t//       },\n\t//       {\n\t//         name:     'row'\n\t//         val:       {},\n\t//         methodExt: [ ... ],\n\t//         propExt:   [\n\t//           {\n\t//             name:      'data'\n\t//             val:       function () {},\n\t//             methodExt: [ ... ],\n\t//             propExt:   [ ... ]\n\t//           },\n\t//           ...\n\t//         ]\n\t//       }\n\t//     ]\n\t\n\t_Api.register = _api_register = function ( name, val )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\tfor ( var j=0, jen=name.length ; j<jen ; j++ ) {\n\t\t\t\t_Api.register( name[j], val );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\their = name.split('.'),\n\t\t\tstruct = __apiStruct,\n\t\t\tkey, method;\n\t\n\t\tvar find = function ( src, name ) {\n\t\t\tfor ( var i=0, ien=src.length ; i<ien ; i++ ) {\n\t\t\t\tif ( src[i].name === name ) {\n\t\t\t\t\treturn src[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\n\t\tfor ( i=0, ien=heir.length ; i<ien ; i++ ) {\n\t\t\tmethod = heir[i].indexOf('()') !== -1;\n\t\t\tkey = method ?\n\t\t\t\their[i].replace('()', '') :\n\t\t\t\their[i];\n\t\n\t\t\tvar src = find( struct, key );\n\t\t\tif ( ! src ) {\n\t\t\t\tsrc = {\n\t\t\t\t\tname:      key,\n\t\t\t\t\tval:       {},\n\t\t\t\t\tmethodExt: [],\n\t\t\t\t\tpropExt:   []\n\t\t\t\t};\n\t\t\t\tstruct.push( src );\n\t\t\t}\n\t\n\t\t\tif ( i === ien-1 ) {\n\t\t\t\tsrc.val = val;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstruct = method ?\n\t\t\t\t\tsrc.methodExt :\n\t\t\t\t\tsrc.propExt;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\t_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {\n\t\t_Api.register( pluralName, val );\n\t\n\t\t_Api.register( singularName, function () {\n\t\t\tvar ret = val.apply( this, arguments );\n\t\n\t\t\tif ( ret === this ) {\n\t\t\t\t// Returned item is the API instance that was passed in, return it\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\telse if ( ret instanceof _Api ) {\n\t\t\t\t// New API instance returned, want the value from the first item\n\t\t\t\t// in the returned array for the singular result.\n\t\t\t\treturn ret.length ?\n\t\t\t\t\t$.isArray( ret[0] ) ?\n\t\t\t\t\t\tnew _Api( ret.context, ret[0] ) : // Array results are 'enhanced'\n\t\t\t\t\t\tret[0] :\n\t\t\t\t\tundefined;\n\t\t\t}\n\t\n\t\t\t// Non-API return - just fire it back\n\t\t\treturn ret;\n\t\t} );\n\t};\n\t\n\t\n\t/**\n\t * Selector for HTML tables. Apply the given selector to the give array of\n\t * DataTables settings objects.\n\t *\n\t * @param {string|integer} [selector] jQuery selector string or integer\n\t * @param  {array} Array of DataTables settings objects to be filtered\n\t * @return {array}\n\t * @ignore\n\t */\n\tvar __table_selector = function ( selector, a )\n\t{\n\t\t// Integer is used to pick out a table by index\n\t\tif ( typeof selector === 'number' ) {\n\t\t\treturn [ a[ selector ] ];\n\t\t}\n\t\n\t\t// Perform a jQuery selector on the table nodes\n\t\tvar nodes = $.map( a, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\treturn $(nodes)\n\t\t\t.filter( selector )\n\t\t\t.map( function (i) {\n\t\t\t\t// Need to translate back from the table node to the settings\n\t\t\t\tvar idx = $.inArray( this, nodes );\n\t\t\t\treturn a[ idx ];\n\t\t\t} )\n\t\t\t.toArray();\n\t};\n\t\n\t\n\t\n\t/**\n\t * Context selector for the API's context (i.e. the tables the API instance\n\t * refers to.\n\t *\n\t * @name    DataTable.Api#tables\n\t * @param {string|integer} [selector] Selector to pick which tables the iterator\n\t *   should operate on. If not given, all tables in the current context are\n\t *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to\n\t *   select multiple tables or as an integer to select a single table.\n\t * @returns {DataTable.Api} Returns a new API instance if a selector is given.\n\t */\n\t_api_register( 'tables()', function ( selector ) {\n\t\t// A new instance is created if there was a selector specified\n\t\treturn selector ?\n\t\t\tnew _Api( __table_selector( selector, this.context ) ) :\n\t\t\tthis;\n\t} );\n\t\n\t\n\t_api_register( 'table()', function ( selector ) {\n\t\tvar tables = this.tables( selector );\n\t\tvar ctx = tables.context;\n\t\n\t\t// Truncate to the first matched table\n\t\treturn ctx.length ?\n\t\t\tnew _Api( ctx[0] ) :\n\t\t\ttables;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTable;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().body()', 'table().body()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTBody;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().header()', 'table().header()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTHead;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTFoot;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().containers()', 'table().container()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTableWrapper;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Redraw the tables in the current context.\n\t */\n\t_api_register( 'draw()', function ( paging ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( paging === 'page' ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ( typeof paging === 'string' ) {\n\t\t\t\t\tpaging = paging === 'full-hold' ?\n\t\t\t\t\t\tfalse :\n\t\t\t\t\t\ttrue;\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, paging===false );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get the current page index.\n\t *\n\t * @return {integer} Current page index (zero based)\n\t *//**\n\t * Set the current page.\n\t *\n\t * Note that if you attempt to show a page which does not exist, DataTables will\n\t * not throw an error, but rather reset the paging.\n\t *\n\t * @param {integer|string} action The paging action to take. This can be one of:\n\t *  * `integer` - The page index to jump to\n\t *  * `string` - An action to take:\n\t *    * `first` - Jump to first page.\n\t *    * `next` - Jump to the next page\n\t *    * `previous` - Jump to previous page\n\t *    * `last` - Jump to the last page.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page()', function ( action ) {\n\t\tif ( action === undefined ) {\n\t\t\treturn this.page.info().page; // not an expensive call\n\t\t}\n\t\n\t\t// else, have an action to take on all tables\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnPageChange( settings, action );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Paging information for the first table in the current context.\n\t *\n\t * If you require paging information for another table, use the `table()` method\n\t * with a suitable selector.\n\t *\n\t * @return {object} Object with the following properties set:\n\t *  * `page` - Current page index (zero based - i.e. the first page is `0`)\n\t *  * `pages` - Total number of pages\n\t *  * `start` - Display index for the first record shown on the current page\n\t *  * `end` - Display index for the last record shown on the current page\n\t *  * `length` - Display length (number of records). Note that generally `start\n\t *    + length = end`, but this is not always true, for example if there are\n\t *    only 2 records to show on the final page, with a length of 10.\n\t *  * `recordsTotal` - Full data set length\n\t *  * `recordsDisplay` - Data set length once the current filtering criterion\n\t *    are applied.\n\t */\n\t_api_register( 'page.info()', function ( action ) {\n\t\tif ( this.context.length === 0 ) {\n\t\t\treturn undefined;\n\t\t}\n\t\n\t\tvar\n\t\t\tsettings   = this.context[0],\n\t\t\tstart      = settings._iDisplayStart,\n\t\t\tlen        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,\n\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn {\n\t\t\t\"page\":           all ? 0 : Math.floor( start / len ),\n\t\t\t\"pages\":          all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\"start\":          start,\n\t\t\t\"end\":            settings.fnDisplayEnd(),\n\t\t\t\"length\":         len,\n\t\t\t\"recordsTotal\":   settings.fnRecordsTotal(),\n\t\t\t\"recordsDisplay\": visRecords,\n\t\t\t\"serverSide\":     _fnDataSource( settings ) === 'ssp'\n\t\t};\n\t} );\n\t\n\t\n\t/**\n\t * Get the current page length.\n\t *\n\t * @return {integer} Current page length. Note `-1` indicates that all records\n\t *   are to be shown.\n\t *//**\n\t * Set the current page length.\n\t *\n\t * @param {integer} Page length to set. Use `-1` to show all records.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page.len()', function ( len ) {\n\t\t// Note that we can't call this function 'length()' because `length`\n\t\t// is a Javascript property of functions which defines how many arguments\n\t\t// the function expects.\n\t\tif ( len === undefined ) {\n\t\t\treturn this.context.length !== 0 ?\n\t\t\t\tthis.context[0]._iDisplayLength :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// else, set the page length\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnLengthChange( settings, len );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\tvar __reload = function ( settings, holdPosition, callback ) {\n\t\t// Use the draw event to trigger a callback\n\t\tif ( callback ) {\n\t\t\tvar api = new _Api( settings );\n\t\n\t\t\tapi.one( 'draw', function () {\n\t\t\t\tcallback( api.ajax.json() );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t_fnReDraw( settings, holdPosition );\n\t\t}\n\t\telse {\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t// Cancel an existing request\n\t\t\tvar xhr = settings.jqXHR;\n\t\t\tif ( xhr && xhr.readyState !== 4 ) {\n\t\t\t\txhr.abort();\n\t\t\t}\n\t\n\t\t\t// Trigger xhr\n\t\t\t_fnBuildAjax( settings, [], function( json ) {\n\t\t\t\t_fnClearTable( settings );\n\t\n\t\t\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\t_fnAddData( settings, data[i] );\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, holdPosition );\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Get the JSON response from the last Ajax request that DataTables made to the\n\t * server. Note that this returns the JSON from the first table in the current\n\t * context.\n\t *\n\t * @return {object} JSON received from the server.\n\t */\n\t_api_register( 'ajax.json()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].json;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Get the data submitted in the last Ajax request\n\t */\n\t_api_register( 'ajax.params()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].oAjaxData;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Reload tables from the Ajax data source. Note that this function will\n\t * automatically re-draw the table when the remote data has been loaded.\n\t *\n\t * @param {boolean} [reset=true] Reset (default) or hold the current paging\n\t *   position. A full re-sort and re-filter is performed when this method is\n\t *   called, which is why the pagination reset is the default action.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.reload()', function ( callback, resetPaging ) {\n\t\treturn this.iterator( 'table', function (settings) {\n\t\t\t__reload( settings, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Get the current Ajax URL. Note that this returns the URL from the first\n\t * table in the current context.\n\t *\n\t * @return {string} Current Ajax source URL\n\t *//**\n\t * Set the Ajax URL. Note that this will set the URL for all tables in the\n\t * current context.\n\t *\n\t * @param {string} url URL to set.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url()', function ( url ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( url === undefined ) {\n\t\t\t// get\n\t\t\tif ( ctx.length === 0 ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tctx = ctx[0];\n\t\n\t\t\treturn ctx.ajax ?\n\t\t\t\t$.isPlainObject( ctx.ajax ) ?\n\t\t\t\t\tctx.ajax.url :\n\t\t\t\t\tctx.ajax :\n\t\t\t\tctx.sAjaxSource;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( $.isPlainObject( settings.ajax ) ) {\n\t\t\t\tsettings.ajax.url = url;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsettings.ajax = url;\n\t\t\t}\n\t\t\t// No need to consider sAjaxSource here since DataTables gives priority\n\t\t\t// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any\n\t\t\t// value of `sAjaxSource` redundant.\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Load data from the newly set Ajax URL. Note that this method is only\n\t * available when `ajax.url()` is used to set a URL. Additionally, this method\n\t * has the same effect as calling `ajax.reload()` but is provided for\n\t * convenience when setting a new URL. Like `ajax.reload()` it will\n\t * automatically redraw the table once the remote data has been loaded.\n\t *\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {\n\t\t// Same as a reload, but makes sense to present it for easy access after a\n\t\t// url change\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\t__reload( ctx, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t\n\tvar _selector_run = function ( type, selector, selectFn, settings, opts )\n\t{\n\t\tvar\n\t\t\tout = [], res,\n\t\t\ta, i, ien, j, jen,\n\t\t\tselectorType = typeof selector;\n\t\n\t\t// Can't just check for isArray here, as an API or jQuery instance might be\n\t\t// given with their array like look\n\t\tif ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {\n\t\t\tselector = [ selector ];\n\t\t}\n\t\n\t\tfor ( i=0, ien=selector.length ; i<ien ; i++ ) {\n\t\t\t// Only split on simple strings - complex expressions will be jQuery selectors\n\t\t\ta = selector[i] && selector[i].split && ! selector[i].match(/[\\[\\(:]/) ?\n\t\t\t\tselector[i].split(',') :\n\t\t\t\t[ selector[i] ];\n\t\n\t\t\tfor ( j=0, jen=a.length ; j<jen ; j++ ) {\n\t\t\t\tres = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );\n\t\n\t\t\t\tif ( res && res.length ) {\n\t\t\t\t\tout = out.concat( res );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// selector extensions\n\t\tvar ext = _ext.selector[ type ];\n\t\tif ( ext.length ) {\n\t\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\t\tout = ext[i]( settings, opts, out );\n\t\t\t}\n\t\t}\n\t\n\t\treturn _unique( out );\n\t};\n\t\n\t\n\tvar _selector_opts = function ( opts )\n\t{\n\t\tif ( ! opts ) {\n\t\t\topts = {};\n\t\t}\n\t\n\t\t// Backwards compatibility for 1.9- which used the terminology filter rather\n\t\t// than search\n\t\tif ( opts.filter && opts.search === undefined ) {\n\t\t\topts.search = opts.filter;\n\t\t}\n\t\n\t\treturn $.extend( {\n\t\t\tsearch: 'none',\n\t\t\torder: 'current',\n\t\t\tpage: 'all'\n\t\t}, opts );\n\t};\n\t\n\t\n\tvar _selector_first = function ( inst )\n\t{\n\t\t// Reduce the API instance to the first item found\n\t\tfor ( var i=0, ien=inst.length ; i<ien ; i++ ) {\n\t\t\tif ( inst[i].length > 0 ) {\n\t\t\t\t// Assign the first element to the first item in the instance\n\t\t\t\t// and truncate the instance and context\n\t\t\t\tinst[0] = inst[i];\n\t\t\t\tinst[0].length = 1;\n\t\t\t\tinst.length = 1;\n\t\t\t\tinst.context = [ inst.context[i] ];\n\t\n\t\t\t\treturn inst;\n\t\t\t}\n\t\t}\n\t\n\t\t// Not found - return an empty instance\n\t\tinst.length = 0;\n\t\treturn inst;\n\t};\n\t\n\t\n\tvar _selector_row_indexes = function ( settings, opts )\n\t{\n\t\tvar\n\t\t\ti, ien, tmp, a=[],\n\t\t\tdisplayFiltered = settings.aiDisplay,\n\t\t\tdisplayMaster = settings.aiDisplayMaster;\n\t\n\t\tvar\n\t\t\tsearch = opts.search,  // none, applied, removed\n\t\t\torder  = opts.order,   // applied, current, index (original - compatibility with 1.9)\n\t\t\tpage   = opts.page;    // all, current\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t// In server-side processing mode, most options are irrelevant since\n\t\t\t// rows not shown don't exist and the index order is the applied order\n\t\t\t// Removed is a special case - for consistency just return an empty\n\t\t\t// array\n\t\t\treturn search === 'removed' ?\n\t\t\t\t[] :\n\t\t\t\t_range( 0, displayMaster.length );\n\t\t}\n\t\telse if ( page == 'current' ) {\n\t\t\t// Current page implies that order=current and fitler=applied, since it is\n\t\t\t// fairly senseless otherwise, regardless of what order and search actually\n\t\t\t// are\n\t\t\tfor ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {\n\t\t\t\ta.push( displayFiltered[i] );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'current' || order == 'applied' ) {\n\t\t\ta = search == 'none' ?\n\t\t\t\tdisplayMaster.slice() :                      // no search\n\t\t\t\tsearch == 'applied' ?\n\t\t\t\t\tdisplayFiltered.slice() :                // applied search\n\t\t\t\t\t$.map( displayMaster, function (el, i) { // removed search\n\t\t\t\t\t\treturn $.inArray( el, displayFiltered ) === -1 ? el : null;\n\t\t\t\t\t} );\n\t\t}\n\t\telse if ( order == 'index' || order == 'original' ) {\n\t\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tif ( search == 'none' ) {\n\t\t\t\t\ta.push( i );\n\t\t\t\t}\n\t\t\t\telse { // applied | removed\n\t\t\t\t\ttmp = $.inArray( i, displayFiltered );\n\t\n\t\t\t\t\tif ((tmp === -1 && search == 'removed') ||\n\t\t\t\t\t\t(tmp >= 0   && search == 'applied') )\n\t\t\t\t\t{\n\t\t\t\t\t\ta.push( i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn a;\n\t};\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Rows\n\t *\n\t * {}          - no selector - use all available rows\n\t * {integer}   - row aoData index\n\t * {node}      - TR node\n\t * {string}    - jQuery selector to apply to the TR elements\n\t * {array}     - jQuery array of nodes, or simply an array of TR nodes\n\t *\n\t */\n\t\n\t\n\tvar __row_selector = function ( settings, selector, opts )\n\t{\n\t\tvar rows;\n\t\tvar run = function ( sel ) {\n\t\t\tvar selInt = _intVal( sel );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Short cut - selector is a number and no options provided (default is\n\t\t\t// all records, so no need to check if the index is in there, since it\n\t\t\t// must be - dev error if the index doesn't exist).\n\t\t\tif ( selInt !== null && ! opts ) {\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\n\t\t\tif ( ! rows ) {\n\t\t\t\trows = _selector_row_indexes( settings, opts );\n\t\t\t}\n\t\n\t\t\tif ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {\n\t\t\t\t// Selector - integer\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\t\telse if ( sel === null || sel === undefined || sel === '' ) {\n\t\t\t\t// Selector - none\n\t\t\t\treturn rows;\n\t\t\t}\n\t\n\t\t\t// Selector - function\n\t\t\tif ( typeof sel === 'function' ) {\n\t\t\t\treturn $.map( rows, function (idx) {\n\t\t\t\t\tvar row = settings.aoData[ idx ];\n\t\t\t\t\treturn sel( idx, row._aData, row.nTr ) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Get nodes in the order from the `rows` array with null values removed\n\t\t\tvar nodes = _removeEmpty(\n\t\t\t\t_pluck_order( settings.aoData, rows, 'nTr' )\n\t\t\t);\n\t\n\t\t\t// Selector - node\n\t\t\tif ( sel.nodeName ) {\n\t\t\t\tif ( sel._DT_RowIndex !== undefined ) {\n\t\t\t\t\treturn [ sel._DT_RowIndex ]; // Property added by DT for fast lookup\n\t\t\t\t}\n\t\t\t\telse if ( sel._DT_CellIndex ) {\n\t\t\t\t\treturn [ sel._DT_CellIndex.row ];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tvar host = $(sel).closest('*[data-dt-row]');\n\t\t\t\t\treturn host.length ?\n\t\t\t\t\t\t[ host.data('dt-row') ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// ID selector. Want to always be able to select rows by id, regardless\n\t\t\t// of if the tr element has been created or not, so can't rely upon\n\t\t\t// jQuery here - hence a custom implementation. This does not match\n\t\t\t// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,\n\t\t\t// but to select it using a CSS selector engine (like Sizzle or\n\t\t\t// querySelect) it would need to need to be escaped for some characters.\n\t\t\t// DataTables simplifies this for row selectors since you can select\n\t\t\t// only a row. A # indicates an id any anything that follows is the id -\n\t\t\t// unescaped.\n\t\t\tif ( typeof sel === 'string' && sel.charAt(0) === '#' ) {\n\t\t\t\t// get row index from id\n\t\t\t\tvar rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];\n\t\t\t\tif ( rowObj !== undefined ) {\n\t\t\t\t\treturn [ rowObj.idx ];\n\t\t\t\t}\n\t\n\t\t\t\t// need to fall through to jQuery in case there is DOM id that\n\t\t\t\t// matches\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery selector string, array of nodes or jQuery object/\n\t\t\t// As jQuery's .filter() allows jQuery objects to be passed in filter,\n\t\t\t// it also allows arrays, so this will cope with all three options\n\t\t\treturn $(nodes)\n\t\t\t\t.filter( sel )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn this._DT_RowIndex;\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\t};\n\t\n\t\treturn _selector_run( 'row', selector, run, settings, opts );\n\t};\n\t\n\t\n\t_api_register( 'rows()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __row_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in __row_selector?\n\t\tinst.selector.rows = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_register( 'rows().nodes()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn settings.aoData[ row ].nTr || undefined;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'rows().data()', function () {\n\t\treturn this.iterator( true, 'rows', function ( settings, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, '_aData' );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\tvar r = settings.aoData[ row ];\n\t\t\treturn type === 'search' ? r._aFilterData : r._aSortData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\t_fnInvalidate( settings, row, src );\n\t\t} );\n\t} );\n\t\n\t_api_registerPlural( 'rows().indexes()', 'row().index()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn row;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {\n\t\tvar a = [];\n\t\tvar context = this.context;\n\t\n\t\t// `iterator` will drop undefined values, but in this case we want them\n\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\tfor ( var j=0, jen=this[i].length ; j<jen ; j++ ) {\n\t\t\t\tvar id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );\n\t\t\t\ta.push( (hash === true ? '#' : '' )+ id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn new _Api( context, a );\n\t} );\n\t\n\t_api_registerPlural( 'rows().remove()', 'row().remove()', function () {\n\t\tvar that = this;\n\t\n\t\tthis.iterator( 'row', function ( settings, row, thatIdx ) {\n\t\t\tvar data = settings.aoData;\n\t\t\tvar rowData = data[ row ];\n\t\t\tvar i, ien, j, jen;\n\t\t\tvar loopRow, loopCells;\n\t\n\t\t\tdata.splice( row, 1 );\n\t\n\t\t\t// Update the cached indexes\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\tloopRow = data[i];\n\t\t\t\tloopCells = loopRow.anCells;\n\t\n\t\t\t\t// Rows\n\t\t\t\tif ( loopRow.nTr !== null ) {\n\t\t\t\t\tloopRow.nTr._DT_RowIndex = i;\n\t\t\t\t}\n\t\n\t\t\t\t// Cells\n\t\t\t\tif ( loopCells !== null ) {\n\t\t\t\t\tfor ( j=0, jen=loopCells.length ; j<jen ; j++ ) {\n\t\t\t\t\t\tloopCells[j]._DT_CellIndex.row = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Delete from the display arrays\n\t\t\t_fnDeleteIndex( settings.aiDisplayMaster, row );\n\t\t\t_fnDeleteIndex( settings.aiDisplay, row );\n\t\t\t_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes\n\t\n\t\t\t// Check for an 'overflow' they case for displaying the table\n\t\t\t_fnLengthOverflow( settings );\n\t\n\t\t\t// Remove the row's ID reference if there is one\n\t\t\tvar id = settings.rowIdFn( rowData._aData );\n\t\t\tif ( id !== undefined ) {\n\t\t\t\tdelete settings.aIds[ id ];\n\t\t\t}\n\t\t} );\n\t\n\t\tthis.iterator( 'table', function ( settings ) {\n\t\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tsettings.aoData[i].idx = i;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'rows.add()', function ( rows ) {\n\t\tvar newRows = this.iterator( 'table', function ( settings ) {\n\t\t\t\tvar row, i, ien;\n\t\t\t\tvar out = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\t\t\tout.push( _fnAddTr( settings, row )[0] );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tout.push( _fnAddData( settings, row ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn out;\n\t\t\t}, 1 );\n\t\n\t\t// Return an Api.rows() extended instance, so rows().nodes() etc can be used\n\t\tvar modRows = this.rows( -1 );\n\t\tmodRows.pop();\n\t\t$.merge( modRows, newRows );\n\t\n\t\treturn modRows;\n\t} );\n\t\n\t\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( 'row()', function ( selector, opts ) {\n\t\treturn _selector_first( this.rows( selector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'row().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._aData :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\tctx[0].aoData[ this[0] ]._aData = data;\n\t\n\t\t// Automatically invalidate\n\t\t_fnInvalidate( ctx[0], this[0], 'data' );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'row().node()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\treturn ctx.length && this.length ?\n\t\t\tctx[0].aoData[ this[0] ].nTr || null :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'row.add()', function ( row ) {\n\t\t// Allow a jQuery object to be passed in - only a single row is added from\n\t\t// it though - the first element in the set\n\t\tif ( row instanceof $ && row.length ) {\n\t\t\trow = row[0];\n\t\t}\n\t\n\t\tvar rows = this.iterator( 'table', function ( settings ) {\n\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\treturn _fnAddTr( settings, row )[0];\n\t\t\t}\n\t\t\treturn _fnAddData( settings, row );\n\t\t} );\n\t\n\t\t// Return an Api.rows() extended instance, with the newly added row selected\n\t\treturn this.row( rows[0] );\n\t} );\n\t\n\t\n\t\n\tvar __details_add = function ( ctx, row, data, klass )\n\t{\n\t\t// Convert to array of TR elements\n\t\tvar rows = [];\n\t\tvar addRow = function ( r, k ) {\n\t\t\t// Recursion to allow for arrays of jQuery objects\n\t\t\tif ( $.isArray( r ) || r instanceof $ ) {\n\t\t\t\tfor ( var i=0, ien=r.length ; i<ien ; i++ ) {\n\t\t\t\t\taddRow( r[i], k );\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If we get a TR element, then just add it directly - up to the dev\n\t\t\t// to add the correct number of columns etc\n\t\t\tif ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {\n\t\t\t\trows.push( r );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Otherwise create a row with a wrapper\n\t\t\t\tvar created = $('<tr><td/></tr>').addClass( k );\n\t\t\t\t$('td', created)\n\t\t\t\t\t.addClass( k )\n\t\t\t\t\t.html( r )\n\t\t\t\t\t[0].colSpan = _fnVisbleColumns( ctx );\n\t\n\t\t\t\trows.push( created[0] );\n\t\t\t}\n\t\t};\n\t\n\t\taddRow( data, klass );\n\t\n\t\tif ( row._details ) {\n\t\t\trow._details.detach();\n\t\t}\n\t\n\t\trow._details = $(rows);\n\t\n\t\t// If the children were already shown, that state should be retained\n\t\tif ( row._detailsShow ) {\n\t\t\trow._details.insertAfter( row.nTr );\n\t\t}\n\t};\n\t\n\t\n\tvar __details_remove = function ( api, idx )\n\t{\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length ) {\n\t\t\tvar row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];\n\t\n\t\t\tif ( row && row._details ) {\n\t\t\t\trow._details.remove();\n\t\n\t\t\t\trow._detailsShow = undefined;\n\t\t\t\trow._details = undefined;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_display = function ( api, show ) {\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length && api.length ) {\n\t\t\tvar row = ctx[0].aoData[ api[0] ];\n\t\n\t\t\tif ( row._details ) {\n\t\t\t\trow._detailsShow = show;\n\t\n\t\t\t\tif ( show ) {\n\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\trow._details.detach();\n\t\t\t\t}\n\t\n\t\t\t\t__details_events( ctx[0] );\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_events = function ( settings )\n\t{\n\t\tvar api = new _Api( settings );\n\t\tvar namespace = '.dt.DT_details';\n\t\tvar drawEvent = 'draw'+namespace;\n\t\tvar colvisEvent = 'column-visibility'+namespace;\n\t\tvar destroyEvent = 'destroy'+namespace;\n\t\tvar data = settings.aoData;\n\t\n\t\tapi.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );\n\t\n\t\tif ( _pluck( data, '_details' ).length > 0 ) {\n\t\t\t// On each draw, insert the required elements into the document\n\t\t\tapi.on( drawEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tapi.rows( {page:'current'} ).eq(0).each( function (idx) {\n\t\t\t\t\t// Internal data grab\n\t\t\t\t\tvar row = data[ idx ];\n\t\n\t\t\t\t\tif ( row._detailsShow ) {\n\t\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\n\t\t\t// Column visibility change - update the colspan\n\t\t\tapi.on( colvisEvent, function ( e, ctx, idx, vis ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t// Update the colspan for the details rows (note, only if it already has\n\t\t\t\t// a colspan)\n\t\t\t\tvar row, visible = _fnVisbleColumns( ctx );\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = data[i];\n\t\n\t\t\t\t\tif ( row._details ) {\n\t\t\t\t\t\trow._details.children('td[colspan]').attr('colspan', visible );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\t// Table destroyed - nuke any child rows\n\t\t\tapi.on( destroyEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( data[i]._details ) {\n\t\t\t\t\t\t__details_remove( api, i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t// Strings for the method names to help minification\n\tvar _emp = '';\n\tvar _child_obj = _emp+'row().child';\n\tvar _child_mth = _child_obj+'()';\n\t\n\t// data can be:\n\t//  tr\n\t//  string\n\t//  jQuery or array of any of the above\n\t_api_register( _child_mth, function ( data, klass ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._details :\n\t\t\t\tundefined;\n\t\t}\n\t\telse if ( data === true ) {\n\t\t\t// show\n\t\t\tthis.child.show();\n\t\t}\n\t\telse if ( data === false ) {\n\t\t\t// remove\n\t\t\t__details_remove( this );\n\t\t}\n\t\telse if ( ctx.length && this.length ) {\n\t\t\t// set\n\t\t\t__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );\n\t\t}\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.show()',\n\t\t_child_mth+'.show()' // only when `child()` was called with parameters (without\n\t], function ( show ) {   // it returns an object and this method is not executed)\n\t\t__details_display( this, true );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.hide()',\n\t\t_child_mth+'.hide()' // only when `child()` was called with parameters (without\n\t], function () {         // it returns an object and this method is not executed)\n\t\t__details_display( this, false );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.remove()',\n\t\t_child_mth+'.remove()' // only when `child()` was called with parameters (without\n\t], function () {           // it returns an object and this method is not executed)\n\t\t__details_remove( this );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( _child_obj+'.isShown()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length && this.length ) {\n\t\t\t// _detailsShown as false or undefined will fall through to return false\n\t\t\treturn ctx[0].aoData[ this[0] ]._detailsShow || false;\n\t\t}\n\t\treturn false;\n\t} );\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Columns\n\t *\n\t * {integer}           - column index (>=0 count from left, <0 count from right)\n\t * \"{integer}:visIdx\"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)\n\t * \"{integer}:visible\" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)\n\t * \"{string}:name\"     - column name\n\t * \"{string}\"          - jQuery selector on column header nodes\n\t *\n\t */\n\t\n\t// can be an array of these items, comma separated list, or an array of comma\n\t// separated lists\n\t\n\tvar __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;\n\t\n\t\n\t// r1 and r2 are redundant - but it means that the parameters match for the\n\t// iterator callback in columns().data()\n\tvar __columnData = function ( settings, column, r1, r2, rows ) {\n\t\tvar a = [];\n\t\tfor ( var row=0, ien=rows.length ; row<ien ; row++ ) {\n\t\t\ta.push( _fnGetCellData( settings, rows[row], column ) );\n\t\t}\n\t\treturn a;\n\t};\n\t\n\t\n\tvar __column_selector = function ( settings, selector, opts )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tnames = _pluck( columns, 'sName' ),\n\t\t\tnodes = _pluck( columns, 'nTh' );\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar selInt = _intVal( s );\n\t\n\t\t\t// Selector - all\n\t\t\tif ( s === '' ) {\n\t\t\t\treturn _range( columns.length );\n\t\t\t}\n\t\n\t\t\t// Selector - index\n\t\t\tif ( selInt !== null ) {\n\t\t\t\treturn [ selInt >= 0 ?\n\t\t\t\t\tselInt : // Count from left\n\t\t\t\t\tcolumns.length + selInt // Count from right (+ because its a negative value)\n\t\t\t\t];\n\t\t\t}\n\t\n\t\t\t// Selector = function\n\t\t\tif ( typeof s === 'function' ) {\n\t\t\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\n\t\t\t\treturn $.map( columns, function (col, idx) {\n\t\t\t\t\treturn s(\n\t\t\t\t\t\t\tidx,\n\t\t\t\t\t\t\t__columnData( settings, idx, 0, 0, rows ),\n\t\t\t\t\t\t\tnodes[ idx ]\n\t\t\t\t\t\t) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// jQuery or string selector\n\t\t\tvar match = typeof s === 'string' ?\n\t\t\t\ts.match( __re_column_selector ) :\n\t\t\t\t'';\n\t\n\t\t\tif ( match ) {\n\t\t\t\tswitch( match[2] ) {\n\t\t\t\t\tcase 'visIdx':\n\t\t\t\t\tcase 'visible':\n\t\t\t\t\t\tvar idx = parseInt( match[1], 10 );\n\t\t\t\t\t\t// Visible index given, convert to column index\n\t\t\t\t\t\tif ( idx < 0 ) {\n\t\t\t\t\t\t\t// Counting from the right\n\t\t\t\t\t\t\tvar visColumns = $.map( columns, function (col,i) {\n\t\t\t\t\t\t\t\treturn col.bVisible ? i : null;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\treturn [ visColumns[ visColumns.length + idx ] ];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Counting from the left\n\t\t\t\t\t\treturn [ _fnVisibleToColumnIndex( settings, idx ) ];\n\t\n\t\t\t\t\tcase 'name':\n\t\t\t\t\t\t// match by name. `names` is column index complete and in order\n\t\t\t\t\t\treturn $.map( names, function (name, i) {\n\t\t\t\t\t\t\treturn name === match[1] ? i : null;\n\t\t\t\t\t\t} );\n\t\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Cell in the table body\n\t\t\tif ( s.nodeName && s._DT_CellIndex ) {\n\t\t\t\treturn [ s._DT_CellIndex.column ];\n\t\t\t}\n\t\n\t\t\t// jQuery selector on the TH elements for the columns\n\t\t\tvar jqResult = $( nodes )\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn $.inArray( this, nodes ); // `nodes` is column index complete and in order\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise a node which might have a `dt-column` data attribute, or be\n\t\t\t// a child or such an element\n\t\t\tvar host = $(s).closest('*[data-dt-column]');\n\t\t\treturn host.length ?\n\t\t\t\t[ host.data('dt-column') ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'column', selector, run, settings, opts );\n\t};\n\t\n\t\n\tvar __setColumnVis = function ( settings, column, vis ) {\n\t\tvar\n\t\t\tcols = settings.aoColumns,\n\t\t\tcol  = cols[ column ],\n\t\t\tdata = settings.aoData,\n\t\t\trow, cells, i, ien, tr;\n\t\n\t\t// Get\n\t\tif ( vis === undefined ) {\n\t\t\treturn col.bVisible;\n\t\t}\n\t\n\t\t// Set\n\t\t// No change\n\t\tif ( col.bVisible === vis ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( vis ) {\n\t\t\t// Insert column\n\t\t\t// Need to decide if we should use appendChild or insertBefore\n\t\t\tvar insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );\n\t\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\ttr = data[i].nTr;\n\t\t\t\tcells = data[i].anCells;\n\t\n\t\t\t\tif ( tr ) {\n\t\t\t\t\t// insertBefore can act like appendChild if 2nd arg is null\n\t\t\t\t\ttr.insertBefore( cells[ column ], cells[ insertBefore ] || null );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Remove column\n\t\t\t$( _pluck( settings.aoData, 'anCells', column ) ).detach();\n\t\t}\n\t\n\t\t// Common actions\n\t\tcol.bVisible = vis;\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t_fnSaveState( settings );\n\t};\n\t\n\t\n\t_api_register( 'columns()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __column_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in _row_selector?\n\t\tinst.selector.cols = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTh;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTf;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().data()', 'column().data()', function () {\n\t\treturn this.iterator( 'column-rows', __columnData, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].mData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows,\n\t\t\t\ttype === 'search' ? '_aFilterData' : '_aSortData', column\n\t\t\t);\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, 'anCells', column ) ;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {\n\t\tvar ret = this.iterator( 'column', function ( settings, column ) {\n\t\t\tif ( vis === undefined ) {\n\t\t\t\treturn settings.aoColumns[ column ].bVisible;\n\t\t\t} // else\n\t\t\t__setColumnVis( settings, column, vis );\n\t\t} );\n\t\n\t\t// Group the column visibility changes\n\t\tif ( vis !== undefined ) {\n\t\t\t// Second loop once the first is done for events\n\t\t\tthis.iterator( 'column', function ( settings, column ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );\n\t\t\t} );\n\t\n\t\t\tif ( calc === undefined || calc ) {\n\t\t\t\tthis.columns.adjust();\n\t\t\t}\n\t\t}\n\t\n\t\treturn ret;\n\t} );\n\t\n\t_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn type === 'visible' ?\n\t\t\t\t_fnColumnIndexToVisible( settings, column ) :\n\t\t\t\tcolumn;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'columns.adjust()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'column.index()', function ( type, idx ) {\n\t\tif ( this.context.length !== 0 ) {\n\t\t\tvar ctx = this.context[0];\n\t\n\t\t\tif ( type === 'fromVisible' || type === 'toData' ) {\n\t\t\t\treturn _fnVisibleToColumnIndex( ctx, idx );\n\t\t\t}\n\t\t\telse if ( type === 'fromData' || type === 'toVisible' ) {\n\t\t\t\treturn _fnColumnIndexToVisible( ctx, idx );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t_api_register( 'column()', function ( selector, opts ) {\n\t\treturn _selector_first( this.columns( selector, opts ) );\n\t} );\n\t\n\t\n\t\n\tvar __cell_selector = function ( settings, selector, opts )\n\t{\n\t\tvar data = settings.aoData;\n\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\tvar cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );\n\t\tvar allCells = $( [].concat.apply([], cells) );\n\t\tvar row;\n\t\tvar columns = settings.aoColumns.length;\n\t\tvar a, i, ien, j, o, host;\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar fnSelector = typeof s === 'function';\n\t\n\t\t\tif ( s === null || s === undefined || fnSelector ) {\n\t\t\t\t// All cells and function selectors\n\t\t\t\ta = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tfor ( j=0 ; j<columns ; j++ ) {\n\t\t\t\t\t\to = {\n\t\t\t\t\t\t\trow: row,\n\t\t\t\t\t\t\tcolumn: j\n\t\t\t\t\t\t};\n\t\n\t\t\t\t\t\tif ( fnSelector ) {\n\t\t\t\t\t\t\t// Selector - function\n\t\t\t\t\t\t\thost = data[ row ];\n\t\n\t\t\t\t\t\t\tif ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {\n\t\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Selector - all\n\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn a;\n\t\t\t}\n\t\t\t\n\t\t\t// Selector - index\n\t\t\tif ( $.isPlainObject( s ) ) {\n\t\t\t\treturn [s];\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery filtered cells\n\t\t\tvar jqResult = allCells\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function (i, el) {\n\t\t\t\t\treturn { // use a new object, in case someone changes the values\n\t\t\t\t\t\trow:    el._DT_CellIndex.row,\n\t\t\t\t\t\tcolumn: el._DT_CellIndex.column\n\t \t\t\t\t};\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise the selector is a node, and there is one last option - the\n\t\t\t// element might be a child of an element which has dt-row and dt-column\n\t\t\t// data attributes\n\t\t\thost = $(s).closest('*[data-dt-row]');\n\t\t\treturn host.length ?\n\t\t\t\t[ {\n\t\t\t\t\trow: host.data('dt-row'),\n\t\t\t\t\tcolumn: host.data('dt-column')\n\t\t\t\t} ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'cell', selector, run, settings, opts );\n\t};\n\t\n\t\n\t\n\t\n\t_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {\n\t\t// Argument shifting\n\t\tif ( $.isPlainObject( rowSelector ) ) {\n\t\t\t// Indexes\n\t\t\tif ( rowSelector.row === undefined ) {\n\t\t\t\t// Selector options in first parameter\n\t\t\t\topts = rowSelector;\n\t\t\t\trowSelector = null;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Cell index objects in first parameter\n\t\t\t\topts = columnSelector;\n\t\t\t\tcolumnSelector = null;\n\t\t\t}\n\t\t}\n\t\tif ( $.isPlainObject( columnSelector ) ) {\n\t\t\topts = columnSelector;\n\t\t\tcolumnSelector = null;\n\t\t}\n\t\n\t\t// Cell selector\n\t\tif ( columnSelector === null || columnSelector === undefined ) {\n\t\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t\treturn __cell_selector( settings, rowSelector, _selector_opts( opts ) );\n\t\t\t} );\n\t\t}\n\t\n\t\t// Row + column selector\n\t\tvar columns = this.columns( columnSelector, opts );\n\t\tvar rows = this.rows( rowSelector, opts );\n\t\tvar a, i, ien, j, jen;\n\t\n\t\tvar cells = this.iterator( 'table', function ( settings, idx ) {\n\t\t\ta = [];\n\t\n\t\t\tfor ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {\n\t\t\t\tfor ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {\n\t\t\t\t\ta.push( {\n\t\t\t\t\t\trow:    rows[idx][i],\n\t\t\t\t\t\tcolumn: columns[idx][j]\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn a;\n\t\t}, 1 );\n\t\n\t\t$.extend( cells.selector, {\n\t\t\tcols: columnSelector,\n\t\t\trows: rowSelector,\n\t\t\topts: opts\n\t\t} );\n\t\n\t\treturn cells;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\tvar data = settings.aoData[ row ];\n\t\n\t\t\treturn data && data.anCells ?\n\t\t\t\tdata.anCells[ column ] :\n\t\t\t\tundefined;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_register( 'cells().data()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {\n\t\ttype = type === 'search' ? '_aFilterData' : '_aSortData';\n\t\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn settings.aoData[ row ][ type ][ column ];\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column, type );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn {\n\t\t\t\trow: row,\n\t\t\t\tcolumn: column,\n\t\t\t\tcolumnVisible: _fnColumnIndexToVisible( settings, column )\n\t\t\t};\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\t_fnInvalidate( settings, row, src, column );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {\n\t\treturn _selector_first( this.cells( rowSelector, columnSelector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'cell().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\tvar cell = this[0];\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && cell.length ?\n\t\t\t\t_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\t_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );\n\t\t_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get current ordering (sorting) that has been applied to the table.\n\t *\n\t * @returns {array} 2D array containing the sorting information for the first\n\t *   table in the current context. Each element in the parent array represents\n\t *   a column being sorted upon (i.e. multi-sorting with two columns would have\n\t *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is\n\t *   the column index that the sorting condition applies to, the second is the\n\t *   direction of the sort (`desc` or `asc`) and, optionally, the third is the\n\t *   index of the sorting order from the `column.sorting` initialisation array.\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {integer} order Column index to sort upon.\n\t * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 1D array of sorting information to be applied.\n\t * @param {array} [...] Optional additional sorting conditions\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 2D array of sorting information to be applied.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order()', function ( order, dir ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( order === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].aaSorting :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\tif ( typeof order === 'number' ) {\n\t\t\t// Simple column / direction passed in\n\t\t\torder = [ [ order, dir ] ];\n\t\t}\n\t\telse if ( order.length && ! $.isArray( order[0] ) ) {\n\t\t\t// Arguments passed in (list of 1D arrays)\n\t\t\torder = Array.prototype.slice.call( arguments );\n\t\t}\n\t\t// otherwise a 2D array was passed in\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSorting = order.slice();\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Attach a sort listener to an element for a given column\n\t *\n\t * @param {node|jQuery|string} node Identifier for the element(s) to attach the\n\t *   listener to. This can take the form of a single DOM node, a jQuery\n\t *   collection of nodes or a jQuery selector which will identify the node(s).\n\t * @param {integer} column the column that a click on this node will sort on\n\t * @param {function} [callback] callback function when sort is run\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order.listener()', function ( node, column, callback ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSortAttachListener( settings, node, column, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'order.fixed()', function ( set ) {\n\t\tif ( ! set ) {\n\t\t\tvar ctx = this.context;\n\t\t\tvar fixed = ctx.length ?\n\t\t\t\tctx[0].aaSortingFixed :\n\t\t\t\tundefined;\n\t\n\t\t\treturn $.isArray( fixed ) ?\n\t\t\t\t{ pre: fixed } :\n\t\t\t\tfixed;\n\t\t}\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSortingFixed = $.extend( true, {}, set );\n\t\t} );\n\t} );\n\t\n\t\n\t// Order by the selected column(s)\n\t_api_register( [\n\t\t'columns().order()',\n\t\t'column().order()'\n\t], function ( dir ) {\n\t\tvar that = this;\n\t\n\t\treturn this.iterator( 'table', function ( settings, i ) {\n\t\t\tvar sort = [];\n\t\n\t\t\t$.each( that[i], function (j, col) {\n\t\t\t\tsort.push( [ col, dir ] );\n\t\t\t} );\n\t\n\t\t\tsettings.aaSorting = sort;\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'search()', function ( input, regex, smart, caseInsen ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( input === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].oPreviousSearch.sSearch :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {\n\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t} ), 1 );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural(\n\t\t'columns().search()',\n\t\t'column().search()',\n\t\tfunction ( input, regex, smart, caseInsen ) {\n\t\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\t\tvar preSearch = settings.aoPreSearchCols;\n\t\n\t\t\t\tif ( input === undefined ) {\n\t\t\t\t\t// get\n\t\t\t\t\treturn preSearch[ column ].sSearch;\n\t\t\t\t}\n\t\n\t\t\t\t// set\n\t\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t$.extend( preSearch[ column ], {\n\t\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t\t} );\n\t\n\t\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch, 1 );\n\t\t\t} );\n\t\t}\n\t);\n\t\n\t/*\n\t * State API methods\n\t */\n\t\n\t_api_register( 'state()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oSavedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t// Save an empty object\n\t\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, {} );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'state.loaded()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oLoadedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.save()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSaveState( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Provide a common method for plug-ins to check the version of DataTables being\n\t * used, in order to ensure compatibility.\n\t *\n\t *  @param {string} version Version string to check for, in the format \"X.Y.Z\".\n\t *    Note that the formats \"X\" and \"X.Y\" are also acceptable.\n\t *  @returns {boolean} true if this version of DataTables is greater or equal to\n\t *    the required version, or false if this version of DataTales is not\n\t *    suitable\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );\n\t */\n\tDataTable.versionCheck = DataTable.fnVersionCheck = function( version )\n\t{\n\t\tvar aThis = DataTable.version.split('.');\n\t\tvar aThat = version.split('.');\n\t\tvar iThis, iThat;\n\t\n\t\tfor ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {\n\t\t\tiThis = parseInt( aThis[i], 10 ) || 0;\n\t\t\tiThat = parseInt( aThat[i], 10 ) || 0;\n\t\n\t\t\t// Parts are the same, keep comparing\n\t\t\tif (iThis === iThat) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\t// Parts are different, return immediately\n\t\t\treturn iThis > iThat;\n\t\t}\n\t\n\t\treturn true;\n\t};\n\t\n\t\n\t/**\n\t * Check if a `<table>` node is a DataTable table already or not.\n\t *\n\t *  @param {node|jquery|string} table Table node, jQuery object or jQuery\n\t *      selector for the table to test. Note that if more than more than one\n\t *      table is passed on, only the first will be checked\n\t *  @returns {boolean} true the table given is a DataTable, or false otherwise\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {\n\t *      $('#example').dataTable();\n\t *    }\n\t */\n\tDataTable.isDataTable = DataTable.fnIsDataTable = function ( table )\n\t{\n\t\tvar t = $(table).get(0);\n\t\tvar is = false;\n\t\n\t\tif ( table instanceof DataTable.Api ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\t$.each( DataTable.settings, function (i, o) {\n\t\t\tvar head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;\n\t\t\tvar foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;\n\t\n\t\t\tif ( o.nTable === t || head === t || foot === t ) {\n\t\t\t\tis = true;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn is;\n\t};\n\t\n\t\n\t/**\n\t * Get all DataTable tables that have been initialised - optionally you can\n\t * select to get only currently visible tables.\n\t *\n\t *  @param {boolean} [visible=false] Flag to indicate if you want all (default)\n\t *    or visible tables only.\n\t *  @returns {array} Array of `table` nodes (not DataTable instances) which are\n\t *    DataTables\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    $.each( $.fn.dataTable.tables(true), function () {\n\t *      $(table).DataTable().columns.adjust();\n\t *    } );\n\t */\n\tDataTable.tables = DataTable.fnTables = function ( visible )\n\t{\n\t\tvar api = false;\n\t\n\t\tif ( $.isPlainObject( visible ) ) {\n\t\t\tapi = visible.api;\n\t\t\tvisible = visible.visible;\n\t\t}\n\t\n\t\tvar a = $.map( DataTable.settings, function (o) {\n\t\t\tif ( !visible || (visible && $(o.nTable).is(':visible')) ) {\n\t\t\t\treturn o.nTable;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn api ?\n\t\t\tnew _Api( a ) :\n\t\t\ta;\n\t};\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian notation. This is made public\n\t * for the extensions to provide the same ability as DataTables core to accept\n\t * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase\n\t * parameters.\n\t *\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t */\n\tDataTable.camelToHungarian = _fnCamelToHungarian;\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( '$()', function ( selector, opts ) {\n\t\tvar\n\t\t\trows   = this.rows( opts ).nodes(), // Get all rows\n\t\t\tjqRows = $(rows);\n\t\n\t\treturn $( [].concat(\n\t\t\tjqRows.filter( selector ).toArray(),\n\t\t\tjqRows.find( selector ).toArray()\n\t\t) );\n\t} );\n\t\n\t\n\t// jQuery functions to operate on the tables\n\t$.each( [ 'on', 'one', 'off' ], function (i, key) {\n\t\t_api_register( key+'()', function ( /* event, handler */ ) {\n\t\t\tvar args = Array.prototype.slice.call(arguments);\n\t\n\t\t\t// Add the `dt` namespace automatically if it isn't already present\n\t\t\targs[0] = $.map( args[0].split( /\\s/ ), function ( e ) {\n\t\t\t\treturn ! e.match(/\\.dt\\b/) ?\n\t\t\t\t\te+'.dt' :\n\t\t\t\t\te;\n\t\t\t\t} ).join( ' ' );\n\t\n\t\t\tvar inst = $( this.tables().nodes() );\n\t\t\tinst[key].apply( inst, args );\n\t\t\treturn this;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnClearTable( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'settings()', function () {\n\t\treturn new _Api( this.context, this.context );\n\t} );\n\t\n\t\n\t_api_register( 'init()', function () {\n\t\tvar ctx = this.context;\n\t\treturn ctx.length ? ctx[0].oInit : null;\n\t} );\n\t\n\t\n\t_api_register( 'data()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\treturn _pluck( settings.aoData, '_aData' );\n\t\t} ).flatten();\n\t} );\n\t\n\t\n\t_api_register( 'destroy()', function ( remove ) {\n\t\tremove = remove || false;\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tvar orig      = settings.nTableWrapper.parentNode;\n\t\t\tvar classes   = settings.oClasses;\n\t\t\tvar table     = settings.nTable;\n\t\t\tvar tbody     = settings.nTBody;\n\t\t\tvar thead     = settings.nTHead;\n\t\t\tvar tfoot     = settings.nTFoot;\n\t\t\tvar jqTable   = $(table);\n\t\t\tvar jqTbody   = $(tbody);\n\t\t\tvar jqWrapper = $(settings.nTableWrapper);\n\t\t\tvar rows      = $.map( settings.aoData, function (r) { return r.nTr; } );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Flag to note that the table is currently being destroyed - no action\n\t\t\t// should be taken\n\t\t\tsettings.bDestroying = true;\n\t\n\t\t\t// Fire off the destroy callbacks for plug-ins etc\n\t\t\t_fnCallbackFire( settings, \"aoDestroyCallback\", \"destroy\", [settings] );\n\t\n\t\t\t// If not being removed from the document, make all columns visible\n\t\t\tif ( ! remove ) {\n\t\t\t\tnew _Api( settings ).columns().visible( true );\n\t\t\t}\n\t\n\t\t\t// Blitz all `DT` namespaced events (these are internal events, the\n\t\t\t// lowercase, `dt` events are user subscribed and they are responsible\n\t\t\t// for removing them\n\t\t\tjqWrapper.off('.DT').find(':not(tbody *)').off('.DT');\n\t\t\t$(window).off('.DT-'+settings.sInstance);\n\t\n\t\t\t// When scrolling we had to break the table up - restore it\n\t\t\tif ( table != thead.parentNode ) {\n\t\t\t\tjqTable.children('thead').detach();\n\t\t\t\tjqTable.append( thead );\n\t\t\t}\n\t\n\t\t\tif ( tfoot && table != tfoot.parentNode ) {\n\t\t\t\tjqTable.children('tfoot').detach();\n\t\t\t\tjqTable.append( tfoot );\n\t\t\t}\n\t\n\t\t\tsettings.aaSorting = [];\n\t\t\tsettings.aaSortingFixed = [];\n\t\t\t_fnSortingClasses( settings );\n\t\n\t\t\t$( rows ).removeClass( settings.asStripeClasses.join(' ') );\n\t\n\t\t\t$('th, td', thead).removeClass( classes.sSortable+' '+\n\t\t\t\tclasses.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone\n\t\t\t);\n\t\n\t\t\tif ( settings.bJUI ) {\n\t\t\t\t$('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();\n\t\t\t\t$('th, td', thead).each( function () {\n\t\t\t\t\tvar wrapper = $('div.'+classes.sSortJUIWrapper, this);\n\t\t\t\t\t$(this).append( wrapper.contents() );\n\t\t\t\t\twrapper.detach();\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Add the TR elements back into the table in their original order\n\t\t\tjqTbody.children().detach();\n\t\t\tjqTbody.append( rows );\n\t\n\t\t\t// Remove the DataTables generated nodes, events and classes\n\t\t\tvar removedMethod = remove ? 'remove' : 'detach';\n\t\t\tjqTable[ removedMethod ]();\n\t\t\tjqWrapper[ removedMethod ]();\n\t\n\t\t\t// If we need to reattach the table to the document\n\t\t\tif ( ! remove && orig ) {\n\t\t\t\t// insertBefore acts like appendChild if !arg[1]\n\t\t\t\torig.insertBefore( table, settings.nTableReinsertBefore );\n\t\n\t\t\t\t// Restore the width of the original table - was read from the style property,\n\t\t\t\t// so we can restore directly to that\n\t\t\t\tjqTable\n\t\t\t\t\t.css( 'width', settings.sDestroyWidth )\n\t\t\t\t\t.removeClass( classes.sTable );\n\t\n\t\t\t\t// If the were originally stripe classes - then we add them back here.\n\t\t\t\t// Note this is not fool proof (for example if not all rows had stripe\n\t\t\t\t// classes - but it's a good effort without getting carried away\n\t\t\t\tien = settings.asDestroyStripes.length;\n\t\n\t\t\t\tif ( ien ) {\n\t\t\t\t\tjqTbody.children().each( function (i) {\n\t\t\t\t\t\t$(this).addClass( settings.asDestroyStripes[i % ien] );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Remove the settings object from the settings array */\n\t\t\tvar idx = $.inArray( settings, DataTable.settings );\n\t\t\tif ( idx !== -1 ) {\n\t\t\t\tDataTable.settings.splice( idx, 1 );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t// Add the `every()` method for rows, columns and cells in a compact form\n\t$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {\n\t\t_api_register( type+'s().every()', function ( fn ) {\n\t\t\tvar opts = this.selector.opts;\n\t\t\tvar api = this;\n\t\n\t\t\treturn this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {\n\t\t\t\t// Rows and columns:\n\t\t\t\t//  arg1 - index\n\t\t\t\t//  arg2 - table counter\n\t\t\t\t//  arg3 - loop counter\n\t\t\t\t//  arg4 - undefined\n\t\t\t\t// Cells:\n\t\t\t\t//  arg1 - row index\n\t\t\t\t//  arg2 - column index\n\t\t\t\t//  arg3 - table counter\n\t\t\t\t//  arg4 - loop counter\n\t\t\t\tfn.call(\n\t\t\t\t\tapi[ type ](\n\t\t\t\t\t\targ1,\n\t\t\t\t\t\ttype==='cell' ? arg2 : opts,\n\t\t\t\t\t\ttype==='cell' ? opts : undefined\n\t\t\t\t\t),\n\t\t\t\t\targ1, arg2, arg3, arg4\n\t\t\t\t);\n\t\t\t} );\n\t\t} );\n\t} );\n\t\n\t\n\t// i18n method for extensions to be able to use the language object from the\n\t// DataTable\n\t_api_register( 'i18n()', function ( token, def, plural ) {\n\t\tvar ctx = this.context[0];\n\t\tvar resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );\n\t\n\t\tif ( resolved === undefined ) {\n\t\t\tresolved = def;\n\t\t}\n\t\n\t\tif ( plural !== undefined && $.isPlainObject( resolved ) ) {\n\t\t\tresolved = resolved[ plural ] !== undefined ?\n\t\t\t\tresolved[ plural ] :\n\t\t\t\tresolved._;\n\t\t}\n\t\n\t\treturn resolved.replace( '%d', plural ); // nb: plural might be undefined,\n\t} );\n\n\t/**\n\t * Version string for plug-ins to check compatibility. Allowed format is\n\t * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used\n\t * only for non-release builds. See http://semver.org/ for more information.\n\t *  @member\n\t *  @type string\n\t *  @default Version number\n\t */\n\tDataTable.version = \"1.10.13\";\n\n\t/**\n\t * Private data store, containing all of the settings objects that are\n\t * created for the tables on a given page.\n\t *\n\t * Note that the `DataTable.settings` object is aliased to\n\t * `jQuery.fn.dataTableExt` through which it may be accessed and\n\t * manipulated, or `jQuery.fn.dataTable.settings`.\n\t *  @member\n\t *  @type array\n\t *  @default []\n\t *  @private\n\t */\n\tDataTable.settings = [];\n\n\t/**\n\t * Object models container, for the various models that DataTables has\n\t * available to it. These models define the objects that are used to hold\n\t * the active state and configuration of the table.\n\t *  @namespace\n\t */\n\tDataTable.models = {};\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * search information for the global filter and individual column filters.\n\t *  @namespace\n\t */\n\tDataTable.models.oSearch = {\n\t\t/**\n\t\t * Flag to indicate if the filtering should be case insensitive or not\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bCaseInsensitive\": true,\n\t\n\t\t/**\n\t\t * Applied search term\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sSearch\": \"\",\n\t\n\t\t/**\n\t\t * Flag to indicate if the search term should be interpreted as a\n\t\t * regular expression (true) or not (false) and therefore and special\n\t\t * regex characters escaped.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bRegex\": false,\n\t\n\t\t/**\n\t\t * Flag to indicate if DataTables is to use its smart filtering or not.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bSmart\": true\n\t};\n\t\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * each individual row. This is the object format used for the settings\n\t * aoData array.\n\t *  @namespace\n\t */\n\tDataTable.models.oRow = {\n\t\t/**\n\t\t * TR element for the row\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTr\": null,\n\t\n\t\t/**\n\t\t * Array of TD elements for each row. This is null until the row has been\n\t\t * created.\n\t\t *  @type array nodes\n\t\t *  @default []\n\t\t */\n\t\t\"anCells\": null,\n\t\n\t\t/**\n\t\t * Data object from the original data source for the row. This is either\n\t\t * an array if using the traditional form of DataTables, or an object if\n\t\t * using mData options. The exact type will depend on the passed in\n\t\t * data from the data source, or will be an array if using DOM a data\n\t\t * source.\n\t\t *  @type array|object\n\t\t *  @default []\n\t\t */\n\t\t\"_aData\": [],\n\t\n\t\t/**\n\t\t * Sorting data cache - this array is ostensibly the same length as the\n\t\t * number of columns (although each index is generated only as it is\n\t\t * needed), and holds the data that is used for sorting each column in the\n\t\t * row. We do this cache generation at the start of the sort in order that\n\t\t * the formatting of the sort data need be done only once for each cell\n\t\t * per sort. This array should not be read from or written to by anything\n\t\t * other than the master sorting methods.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aSortData\": null,\n\t\n\t\t/**\n\t\t * Per cell filtering data cache. As per the sort data cache, used to\n\t\t * increase the performance of the filtering in DataTables\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aFilterData\": null,\n\t\n\t\t/**\n\t\t * Filtering data cache. This is the same as the cell filtering cache, but\n\t\t * in this case a string rather than an array. This is easily computed with\n\t\t * a join on `_aFilterData`, but is provided as a cache so the join isn't\n\t\t * needed on every search (memory traded for performance)\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sFilterRow\": null,\n\t\n\t\t/**\n\t\t * Cache of the class name that DataTables has applied to the row, so we\n\t\t * can quickly look at this variable rather than needing to do a DOM check\n\t\t * on className for the nTr property.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *  @private\n\t\t */\n\t\t\"_sRowStripe\": \"\",\n\t\n\t\t/**\n\t\t * Denote if the original data source was from the DOM, or the data source\n\t\t * object. This is used for invalidating data, so DataTables can\n\t\t * automatically read data from the original source, unless uninstructed\n\t\t * otherwise.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"src\": null,\n\t\n\t\t/**\n\t\t * Index in the aoData array. This saves an indexOf lookup when we have the\n\t\t * object, but want to know the index\n\t\t *  @type integer\n\t\t *  @default -1\n\t\t *  @private\n\t\t */\n\t\t\"idx\": -1\n\t};\n\t\n\t\n\t/**\n\t * Template object for the column information object in DataTables. This object\n\t * is held in the settings aoColumns array and contains all the information that\n\t * DataTables needs about each individual column.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults.column}\n\t * but this one is the internal data store for DataTables's cache of columns.\n\t * It should NOT be manipulated outside of DataTables. Any configuration should\n\t * be done through the initialisation options.\n\t *  @namespace\n\t */\n\tDataTable.models.oColumn = {\n\t\t/**\n\t\t * Column index. This could be worked out on-the-fly with $.inArray, but it\n\t\t * is faster to just hold it as a variable\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"idx\": null,\n\t\n\t\t/**\n\t\t * A list of the columns that sorting should occur on when this column\n\t\t * is sorted. That this property is an array allows multi-column sorting\n\t\t * to be defined for a column (for example first name / last name columns\n\t\t * would benefit from this). The values are integers pointing to the\n\t\t * columns to be sorted on (typically it will be a single integer pointing\n\t\t * at itself, but that doesn't need to be the case).\n\t\t *  @type array\n\t\t */\n\t\t\"aDataSort\": null,\n\t\n\t\t/**\n\t\t * Define the sorting directions that are applied to the column, in sequence\n\t\t * as the column is repeatedly sorted upon - i.e. the first value is used\n\t\t * as the sorting direction when the column if first sorted (clicked on).\n\t\t * Sort it again (click again) and it will move on to the next index.\n\t\t * Repeat until loop.\n\t\t *  @type array\n\t\t */\n\t\t\"asSorting\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is searchable, and thus should be included\n\t\t * in the filtering or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSearchable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is sortable or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is currently visible in the table or not\n\t\t *  @type boolean\n\t\t */\n\t\t\"bVisible\": null,\n\t\n\t\t/**\n\t\t * Store for manual type assignment using the `column.type` option. This\n\t\t * is held in store so we can manipulate the column's `sType` property.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sManualType\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if HTML5 data attributes should be used as the data\n\t\t * source for filtering or sorting. True is either are.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @private\n\t\t */\n\t\t\"_bAttrSrc\": false,\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} nTd The TD node that has been created\n\t\t *  @param {*} sData The Data for the cell\n\t\t *  @param {array|object} oData The data for the whole row\n\t\t *  @param {int} iRow The row index for the aoData data store\n\t\t *  @default null\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\t/**\n\t\t * Function to get data from a cell in a column. You should <b>never</b>\n\t\t * access data directly through _aData internally in DataTables - always use\n\t\t * the method attached to this property. It allows mData to function as\n\t\t * required. This function is automatically assigned by the column\n\t\t * initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {string} sSpecific The specific data type you want to get -\n\t\t *    'display', 'type' 'filter' 'sort'\n\t\t *  @returns {*} The data for the cell from the given row's data\n\t\t *  @default null\n\t\t */\n\t\t\"fnGetData\": null,\n\t\n\t\t/**\n\t\t * Function to set data for a cell in the column. You should <b>never</b>\n\t\t * set the data directly to _aData internally in DataTables - always use\n\t\t * this method. It allows mData to function as required. This function\n\t\t * is automatically assigned by the column initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {*} sValue Value to set\n\t\t *  @default null\n\t\t */\n\t\t\"fnSetData\": null,\n\t\n\t\t/**\n\t\t * Property to read the value for the cells in the column from the data\n\t\t * source array / object. If null, then the default content is used, if a\n\t\t * function is given then the return from the function is used.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\t/**\n\t\t * Partner property to mData which is used (only when defined) to get\n\t\t * the data - i.e. it is basically the same as mData, but without the\n\t\t * 'set' option, and also the data fed to it is the result from mData.\n\t\t * This is the rendering method to match the data method of mData.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\t/**\n\t\t * Unique header TH/TD element for this column - this is what the sorting\n\t\t * listener is attached to (if sorting is enabled.)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTh\": null,\n\t\n\t\t/**\n\t\t * Unique footer TH/TD element for this column (if there is one). Not used\n\t\t * in DataTables as such, but can be used for plug-ins to reference the\n\t\t * footer for each column.\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTf\": null,\n\t\n\t\t/**\n\t\t * The class to apply to all TD elements in the table's TBODY for the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sClass\": null,\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t *  @type string\n\t\t */\n\t\t\"sContentPadding\": null,\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because mData\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\t/**\n\t\t * Name for the column, allowing reference to the column by name as well as\n\t\t * by index (needs a lookup to work by name).\n\t\t *  @type string\n\t\t */\n\t\t\"sName\": null,\n\t\n\t\t/**\n\t\t * Custom sorting data type - defines which of the available plug-ins in\n\t\t * afnSortData the custom sorting will use - if any is defined.\n\t\t *  @type string\n\t\t *  @default std\n\t\t */\n\t\t\"sSortDataType\": 'std',\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClass\": null,\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column -\n\t\t * when jQuery UI theming is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClassJUI\": null,\n\t\n\t\t/**\n\t\t * Title of the column - what is seen in the TH element (nTh).\n\t\t *  @type string\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\t/**\n\t\t * Column sorting and filtering type\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\t/**\n\t\t * Width of the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidth\": null,\n\t\n\t\t/**\n\t\t * Width of the column when it was first \"encountered\"\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidthOrig\": null\n\t};\n\t\n\t\n\t/*\n\t * Developer note: The properties of the object below are given in Hungarian\n\t * notation, that was used as the interface for DataTables prior to v1.10, however\n\t * from v1.10 onwards the primary interface is camel case. In order to avoid\n\t * breaking backwards compatibility utterly with this change, the Hungarian\n\t * version is still, internally the primary interface, but is is not documented\n\t * - hence the @name tags in each doc comment. This allows a Javascript function\n\t * to create a map from Hungarian notation to camel case (going the other direction\n\t * would require each property to be listed, which would at around 3K to the size\n\t * of DataTables, while this method is about a 0.5K hit.\n\t *\n\t * Ultimately this does pave the way for Hungarian notation to be dropped\n\t * completely, but that is a massive amount of work and will break current\n\t * installs (therefore is on-hold until v2).\n\t */\n\t\n\t/**\n\t * Initialisation options that can be given to DataTables at initialisation\n\t * time.\n\t *  @namespace\n\t */\n\tDataTable.defaults = {\n\t\t/**\n\t\t * An array of data to use for the table, passed in at initialisation which\n\t\t * will be used in preference to any data which is already in the DOM. This is\n\t\t * particularly useful for constructing tables purely in Javascript, for\n\t\t * example with a custom Ajax call.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.data\n\t\t *\n\t\t *  @example\n\t\t *    // Using a 2D array data source\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],\n\t\t *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\" },\n\t\t *          { \"title\": \"Browser\" },\n\t\t *          { \"title\": \"Platform\" },\n\t\t *          { \"title\": \"Version\" },\n\t\t *          { \"title\": \"Grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using an array of objects as a data source (`data`)\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 4.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  4,\n\t\t *            \"grade\":    \"X\"\n\t\t *          },\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 5.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  5,\n\t\t *            \"grade\":    \"C\"\n\t\t *          }\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\",   \"data\": \"engine\" },\n\t\t *          { \"title\": \"Browser\",  \"data\": \"browser\" },\n\t\t *          { \"title\": \"Platform\", \"data\": \"platform\" },\n\t\t *          { \"title\": \"Version\",  \"data\": \"version\" },\n\t\t *          { \"title\": \"Grade\",    \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaData\": null,\n\t\n\t\n\t\t/**\n\t\t * If ordering is enabled, then DataTables will perform a first pass sort on\n\t\t * initialisation. You can define which column(s) the sort is performed\n\t\t * upon, and the sorting direction, with this variable. The `sorting` array\n\t\t * should contain an array for each column to be sorted initially containing\n\t\t * the column's index and a direction string ('asc' or 'desc').\n\t\t *  @type array\n\t\t *  @default [[0,'asc']]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.order\n\t\t *\n\t\t *  @example\n\t\t *    // Sort by 3rd column first, and then 4th column\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": [[2,'asc'], [3,'desc']]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *    // No initial sorting\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": []\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaSorting\": [[0,'asc']],\n\t\n\t\n\t\t/**\n\t\t * This parameter is basically identical to the `sorting` parameter, but\n\t\t * cannot be overridden by user interaction with the table. What this means\n\t\t * is that you could have a column (visible or hidden) which the sorting\n\t\t * will always be forced on first - any sorting after that (from the user)\n\t\t * will then be performed as required. This can be useful for grouping rows\n\t\t * together.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.orderFixed\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderFixed\": [[0,'asc']]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\n\t\t/**\n\t\t * DataTables can be instructed to load data to display in the table from a\n\t\t * Ajax source. This option defines how that Ajax call is made and where to.\n\t\t *\n\t\t * The `ajax` property has three different modes of operation, depending on\n\t\t * how it is defined. These are:\n\t\t *\n\t\t * * `string` - Set the URL from where the data should be loaded from.\n\t\t * * `object` - Define properties for `jQuery.ajax`.\n\t\t * * `function` - Custom data get function\n\t\t *\n\t\t * `string`\n\t\t * --------\n\t\t *\n\t\t * As a string, the `ajax` property simply defines the URL from which\n\t\t * DataTables will load data.\n\t\t *\n\t\t * `object`\n\t\t * --------\n\t\t *\n\t\t * As an object, the parameters in the object are passed to\n\t\t * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control\n\t\t * of the Ajax request. DataTables has a number of default parameters which\n\t\t * you can override using this option. Please refer to the jQuery\n\t\t * documentation for a full description of the options available, although\n\t\t * the following parameters provide additional options in DataTables or\n\t\t * require special consideration:\n\t\t *\n\t\t * * `data` - As with jQuery, `data` can be provided as an object, but it\n\t\t *   can also be used as a function to manipulate the data DataTables sends\n\t\t *   to the server. The function takes a single parameter, an object of\n\t\t *   parameters with the values that DataTables has readied for sending. An\n\t\t *   object may be returned which will be merged into the DataTables\n\t\t *   defaults, or you can add the items to the object that was passed in and\n\t\t *   not return anything from the function. This supersedes `fnServerParams`\n\t\t *   from DataTables 1.9-.\n\t\t *\n\t\t * * `dataSrc` - By default DataTables will look for the property `data` (or\n\t\t *   `aaData` for compatibility with DataTables 1.9-) when obtaining data\n\t\t *   from an Ajax source or for server-side processing - this parameter\n\t\t *   allows that property to be changed. You can use Javascript dotted\n\t\t *   object notation to get a data source for multiple levels of nesting, or\n\t\t *   it my be used as a function. As a function it takes a single parameter,\n\t\t *   the JSON returned from the server, which can be manipulated as\n\t\t *   required, with the returned value being that used by DataTables as the\n\t\t *   data source for the table. This supersedes `sAjaxDataProp` from\n\t\t *   DataTables 1.9-.\n\t\t *\n\t\t * * `success` - Should not be overridden it is used internally in\n\t\t *   DataTables. To manipulate / transform the data returned by the server\n\t\t *   use `ajax.dataSrc`, or use `ajax` as a function (see below).\n\t\t *\n\t\t * `function`\n\t\t * ----------\n\t\t *\n\t\t * As a function, making the Ajax call is left up to yourself allowing\n\t\t * complete control of the Ajax request. Indeed, if desired, a method other\n\t\t * than Ajax could be used to obtain the required data, such as Web storage\n\t\t * or an AIR database.\n\t\t *\n\t\t * The function is given four parameters and no return is required. The\n\t\t * parameters are:\n\t\t *\n\t\t * 1. _object_ - Data to send to the server\n\t\t * 2. _function_ - Callback function that must be executed when the required\n\t\t *    data has been obtained. That data should be passed into the callback\n\t\t *    as the only parameter\n\t\t * 3. _object_ - DataTables settings object for the table\n\t\t *\n\t\t * Note that this supersedes `fnServerData` from DataTables 1.9-.\n\t\t *\n\t\t *  @type string|object|function\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.ajax\n\t\t *  @since 1.10.0\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax.\n\t\t *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": \"data.json\"\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to change\n\t\t *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"tableData\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to read data\n\t\t *   // from a plain array rather than an array in an object\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Manipulate the data returned from the server - add a link to data\n\t\t *   // (note this can, should, be done using `render` for the column - this\n\t\t *   // is just a simple example of how the data can be manipulated).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": function ( json ) {\n\t\t *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {\n\t\t *           json[i][0] = '<a href=\"/message/'+json[i][0]+'>View message</a>';\n\t\t *         }\n\t\t *         return json;\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Add data to the request\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"data\": function ( d ) {\n\t\t *         return {\n\t\t *           \"extra_search\": $('#extra').val()\n\t\t *         };\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Send request as POST\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"type\": \"POST\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get the data from localStorage (could interface with a form for\n\t\t *   // adding, editing and removing rows).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": function (data, callback, settings) {\n\t\t *       callback(\n\t\t *         JSON.parse( localStorage.getItem('dataTablesData') )\n\t\t *       );\n\t\t *     }\n\t\t *   } );\n\t\t */\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to readily specify the entries in the length drop\n\t\t * down menu that DataTables shows when pagination is enabled. It can be\n\t\t * either a 1D array of options which will be used for both the displayed\n\t\t * option and the value, or a 2D array which will use the array in the first\n\t\t * position as the value, and the array in the second position as the\n\t\t * displayed options (useful for language strings such as 'All').\n\t\t *\n\t\t * Note that the `pageLength` property will be automatically set to the\n\t\t * first value given in this array, unless `pageLength` is also provided.\n\t\t *  @type array\n\t\t *  @default [ 10, 25, 50, 100 ]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.lengthMenu\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthMenu\": [[10, 25, 50, -1], [10, 25, 50, \"All\"]]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aLengthMenu\": [ 10, 25, 50, 100 ],\n\t\n\t\n\t\t/**\n\t\t * The `columns` option in the initialisation parameter allows you to define\n\t\t * details about the way individual columns behave. For a full list of\n\t\t * column options that can be set, please see\n\t\t * {@link DataTable.defaults.column}. Note that if you use `columns` to\n\t\t * define your columns, you must have an entry in the array for every single\n\t\t * column that you have in your table (these can be null if you don't which\n\t\t * to specify any options).\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.column\n\t\t */\n\t\t\"aoColumns\": null,\n\t\n\t\t/**\n\t\t * Very similar to `columns`, `columnDefs` allows you to target a specific\n\t\t * column, multiple columns, or all columns, using the `targets` property of\n\t\t * each object in the array. This allows great flexibility when creating\n\t\t * tables, as the `columnDefs` arrays can be of any length, targeting the\n\t\t * columns you specifically want. `columnDefs` may use any of the column\n\t\t * options available: {@link DataTable.defaults.column}, but it _must_\n\t\t * have `targets` defined in each object in the array. Values in the `targets`\n\t\t * array may be:\n\t\t *   <ul>\n\t\t *     <li>a string - class name will be matched on the TH for the column</li>\n\t\t *     <li>0 or a positive integer - column index counting from the left</li>\n\t\t *     <li>a negative integer - column index counting from the right</li>\n\t\t *     <li>the string \"_all\" - all columns (i.e. assign a default)</li>\n\t\t *   </ul>\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.columnDefs\n\t\t */\n\t\t\"aoColumnDefs\": null,\n\t\n\t\n\t\t/**\n\t\t * Basically the same as `search`, this parameter defines the individual column\n\t\t * filtering state at initialisation time. The array must be of the same size\n\t\t * as the number of columns, and each element be an object with the parameters\n\t\t * `search` and `escapeRegex` (the latter is optional). 'null' is also\n\t\t * accepted and the default will be used.\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.searchCols\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchCols\": [\n\t\t *          null,\n\t\t *          { \"search\": \"My filter\" },\n\t\t *          null,\n\t\t *          { \"search\": \"^[0-9]\", \"escapeRegex\": false }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aoSearchCols\": [],\n\t\n\t\n\t\t/**\n\t\t * An array of CSS classes that should be applied to displayed rows. This\n\t\t * array may be of any length, and DataTables will apply each class\n\t\t * sequentially, looping when required.\n\t\t *  @type array\n\t\t *  @default null <i>Will take the values determined by the `oClasses.stripe*`\n\t\t *    options</i>\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.stripeClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stripeClasses\": [ 'strip1', 'strip2', 'strip3' ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable automatic column width calculation. This can be disabled\n\t\t * as an optimisation (it takes some time to calculate the widths) if the\n\t\t * tables widths are passed in using `columns`.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.autoWidth\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"autoWidth\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bAutoWidth\": true,\n\t\n\t\n\t\t/**\n\t\t * Deferred rendering can provide DataTables with a huge speed boost when you\n\t\t * are using an Ajax or JS data source for the table. This option, when set to\n\t\t * true, will cause DataTables to defer the creation of the table elements for\n\t\t * each row until they are needed for a draw - saving a significant amount of\n\t\t * time.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.deferRender\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajax\": \"sources/arrays.txt\",\n\t\t *        \"deferRender\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDeferRender\": false,\n\t\n\t\n\t\t/**\n\t\t * Replace a DataTable which matches the given selector and replace it with\n\t\t * one which has the properties of the new initialisation object passed. If no\n\t\t * table matches the selector, then the new DataTable will be constructed as\n\t\t * per normal.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.destroy\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"srollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      // Some time later....\n\t\t *      $('#example').dataTable( {\n\t\t *        \"filter\": false,\n\t\t *        \"destroy\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDestroy\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering of data. Filtering in DataTables is \"smart\" in\n\t\t * that it allows the end user to input multiple words (space separated) and\n\t\t * will match a row containing those words, even if not in the order that was\n\t\t * specified (this allow matching across multiple columns). Note that if you\n\t\t * wish to use filtering in DataTables this must remain 'true' - to remove the\n\t\t * default filtering input box and retain filtering abilities, please use\n\t\t * {@link DataTable.defaults.dom}.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.searching\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searching\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bFilter\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the table information display. This shows information\n\t\t * about the data that is currently visible on the page, including information\n\t\t * about filtered data if that action is being performed.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.info\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"info\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bInfo\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some\n\t\t * slightly different and additional mark-up from what DataTables has\n\t\t * traditionally used).\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.jQueryUI\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"jQueryUI\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bJQueryUI\": false,\n\t\n\t\n\t\t/**\n\t\t * Allows the end user to select the size of a formatted page from a select\n\t\t * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.lengthChange\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthChange\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bLengthChange\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable pagination.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.paging\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"paging\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bPaginate\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of a 'processing' indicator when the table is\n\t\t * being processed (e.g. a sort). This is particularly useful for tables with\n\t\t * large amounts of data where it can take a noticeable amount of time to sort\n\t\t * the entries.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.processing\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"processing\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bProcessing\": false,\n\t\n\t\n\t\t/**\n\t\t * Retrieve the DataTables object for the given selector. Note that if the\n\t\t * table has already been initialised, this parameter will cause DataTables\n\t\t * to simply return the object that has already been set up - it will not take\n\t\t * account of any changes you might have made to the initialisation object\n\t\t * passed to DataTables (setting this parameter to true is an acknowledgement\n\t\t * that you understand this). `destroy` can be used to reinitialise a table if\n\t\t * you need.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.retrieve\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      initTable();\n\t\t *      tableActions();\n\t\t *    } );\n\t\t *\n\t\t *    function initTable ()\n\t\t *    {\n\t\t *      return $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false,\n\t\t *        \"retrieve\": true\n\t\t *      } );\n\t\t *    }\n\t\t *\n\t\t *    function tableActions ()\n\t\t *    {\n\t\t *      var table = initTable();\n\t\t *      // perform API operations with oTable\n\t\t *    }\n\t\t */\n\t\t\"bRetrieve\": false,\n\t\n\t\n\t\t/**\n\t\t * When vertical (y) scrolling is enabled, DataTables will force the height of\n\t\t * the table's viewport to the given height at all times (useful for layout).\n\t\t * However, this can look odd when filtering data down to a small data set,\n\t\t * and the footer is left \"floating\" further down. This parameter (when\n\t\t * enabled) will cause DataTables to collapse the table's viewport down when\n\t\t * the result set will fit within the given Y height.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollCollapse\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200\",\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bScrollCollapse\": false,\n\t\n\t\n\t\t/**\n\t\t * Configure DataTables to use server-side processing. Note that the\n\t\t * `ajax` parameter must also be given in order to give DataTables a\n\t\t * source to obtain the required data for each draw.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverSide\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"xhr.php\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bServerSide\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable sorting of columns. Sorting of individual columns can be\n\t\t * disabled by the `sortable` option for each column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.ordering\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ordering\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSort\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or display DataTables' ability to sort multiple columns at the\n\t\t * same time (activated by shift-click by the user).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderMulti\n\t\t *\n\t\t *  @example\n\t\t *    // Disable multiple column sorting ability\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderMulti\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortMulti\": true,\n\t\n\t\n\t\t/**\n\t\t * Allows control over whether DataTables should use the top (true) unique\n\t\t * cell that is found for a single column, or the bottom (false - default).\n\t\t * This is useful when using complex headers.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderCellsTop\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderCellsTop\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortCellsTop\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the addition of the classes `sorting\\_1`, `sorting\\_2` and\n\t\t * `sorting\\_3` to the columns which are currently being sorted on. This is\n\t\t * presented as a feature switch as it can increase processing time (while\n\t\t * classes are removed and added) so for large data sets you might want to\n\t\t * turn this off.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.orderClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderClasses\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortClasses\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable state saving. When enabled HTML5 `localStorage` will be\n\t\t * used to save table display information such as pagination information,\n\t\t * display length, filtering and sorting. As such when the end user reloads\n\t\t * the page the display display will match what thy had previously set up.\n\t\t *\n\t\t * Due to the use of `localStorage` the default state saving is not supported\n\t\t * in IE6 or 7. If state saving is required in those browsers, use\n\t\t * `stateSaveCallback` to provide a storage solution such as cookies.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.stateSave\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bStateSave\": false,\n\t\n\t\n\t\t/**\n\t\t * This function is called when a TR element is created (and all TD child\n\t\t * elements have been inserted), or registered if using a DOM source, allowing\n\t\t * manipulation of the TR element (adding classes etc).\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} dataIndex The index of this row in the internal aoData array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.createdRow\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"createdRow\": function( row, data, dataIndex ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" )\n\t\t *          {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedRow\": null,\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify any aspect you want about the created DOM.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.drawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"drawCallback\": function( settings ) {\n\t\t *          alert( 'DataTables has redrawn the table' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Identical to fnHeaderCallback() but for the table footer this function\n\t\t * allows you to modify the table footer on every 'draw' event.\n\t\t *  @type function\n\t\t *  @param {node} foot \"TR\" element for the footer\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.footerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"footerCallback\": function( tfoot, data, start, end, display ) {\n\t\t *          tfoot.getElementsByTagName('th')[0].innerHTML = \"Starting index is \"+start;\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnFooterCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * When rendering large numbers in the information element for the table\n\t\t * (i.e. \"Showing 1 to 10 of 57 entries\") DataTables will render large numbers\n\t\t * to have a comma separator for the 'thousands' units (e.g. 1 million is\n\t\t * rendered as \"1,000,000\") to help readability for the end user. This\n\t\t * function will override the default method DataTables uses.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {int} toFormat number to be formatted\n\t\t *  @returns {string} formatted string for DataTables to show the number\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.formatNumber\n\t\t *\n\t\t *  @example\n\t\t *    // Format a number using a single quote for the separator (note that\n\t\t *    // this can also be done with the language.thousands option)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"formatNumber\": function ( toFormat ) {\n\t\t *          return toFormat.toString().replace(\n\t\t *            /\\B(?=(\\d{3})+(?!\\d))/g, \"'\"\n\t\t *          );\n\t\t *        };\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnFormatNumber\": function ( toFormat ) {\n\t\t\treturn toFormat.toString().replace(\n\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g,\n\t\t\t\tthis.oLanguage.sThousands\n\t\t\t);\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify the header row. This can be used to calculate and\n\t\t * display useful information about the table.\n\t\t *  @type function\n\t\t *  @param {node} head \"TR\" element for the header\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.headerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"fheaderCallback\": function( head, data, start, end, display ) {\n\t\t *          head.getElementsByTagName('th')[0].innerHTML = \"Displaying \"+(end-start)+\" records\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnHeaderCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * The information element can be used to convey information about the current\n\t\t * state of the table. Although the internationalisation options presented by\n\t\t * DataTables are quite capable of dealing with most customisations, there may\n\t\t * be times where you wish to customise the string further. This callback\n\t\t * allows you to do exactly that.\n\t\t *  @type function\n\t\t *  @param {object} oSettings DataTables settings object\n\t\t *  @param {int} start Starting position in data for the draw\n\t\t *  @param {int} end End position in data for the draw\n\t\t *  @param {int} max Total number of rows in the table (regardless of\n\t\t *    filtering)\n\t\t *  @param {int} total Total number of rows in the data set, after filtering\n\t\t *  @param {string} pre The string that DataTables has formatted using it's\n\t\t *    own rules\n\t\t *  @returns {string} The string to be displayed in the information element.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.infoCallback\n\t\t *\n\t\t *  @example\n\t\t *    $('#example').dataTable( {\n\t\t *      \"infoCallback\": function( settings, start, end, max, total, pre ) {\n\t\t *        return start +\" to \"+ end;\n\t\t *      }\n\t\t *    } );\n\t\t */\n\t\t\"fnInfoCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Called when the table has been initialised. Normally DataTables will\n\t\t * initialise sequentially and there will be no need for this function,\n\t\t * however, this does not hold true when using external language information\n\t\t * since that is obtained using an async XHR call.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} json The JSON object request from the server - only\n\t\t *    present if client-side Ajax sourced data is used\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.initComplete\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"initComplete\": function(settings, json) {\n\t\t *          alert( 'DataTables has finished its initialisation.' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnInitComplete\": null,\n\t\n\t\n\t\t/**\n\t\t * Called at the very start of each table draw and can be used to cancel the\n\t\t * draw by returning false, any other return (including undefined) results in\n\t\t * the full draw occurring).\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @returns {boolean} False will cancel the draw, anything else (including no\n\t\t *    return) will allow it to complete.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.preDrawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"preDrawCallback\": function( settings ) {\n\t\t *          if ( $('#test').val() == 1 ) {\n\t\t *            return false;\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnPreDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * This function allows you to 'post process' each row after it have been\n\t\t * generated for each table draw, but before it is rendered on screen. This\n\t\t * function might be used for setting the row class name etc.\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} displayIndex The display index for the current table draw\n\t\t *  @param {int} displayIndexFull The index of the data in the full list of\n\t\t *    rows (after filtering)\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.rowCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"rowCallback\": function( row, data, displayIndex, displayIndexFull ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" ) {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnRowCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * This parameter allows you to override the default function which obtains\n\t\t * the data from the server so something more suitable for your application.\n\t\t * For example you could use POST data, or pull information from a Gears or\n\t\t * AIR database.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {string} source HTTP source to obtain the data from (`ajax`)\n\t\t *  @param {array} data A key/value pair object containing the data to send\n\t\t *    to the server\n\t\t *  @param {function} callback to be called on completion of the data get\n\t\t *    process that will draw the data on the page.\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverData\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t *  It is often useful to send extra data to the server when making an Ajax\n\t\t * request - for example custom filtering information, and this callback\n\t\t * function makes it trivial to send extra information to the server. The\n\t\t * passed in parameter is the data set that has been constructed by\n\t\t * DataTables, and you can add to this or modify it as you require.\n\t\t *  @type function\n\t\t *  @param {array} data Data array (array of objects which are name/value\n\t\t *    pairs) that has been constructed by DataTables and will be sent to the\n\t\t *    server. In the case of Ajax sourced data with server-side processing\n\t\t *    this will be an empty array, for server-side processing there will be a\n\t\t *    significant number of parameters!\n\t\t *  @returns {undefined} Ensure that you modify the data array passed in,\n\t\t *    as this is passed by reference.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverParams\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Load the table state. With this function you can define from where, and how, the\n\t\t * state of a table is loaded. By default DataTables will load from `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} callback Callback that can be executed when done. It\n\t\t *    should be passed the loaded state object.\n\t\t *  @return {object} The DataTables state object to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadCallback\": function (settings, callback) {\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_load\",\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"success\": function (json) {\n\t\t *              callback( json );\n\t\t *            }\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadCallback\": function ( settings ) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(\n\t\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(\n\t\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the saved state prior to loading that state.\n\t\t * This callback is called when the table is loading state from the stored data, but\n\t\t * prior to the settings object being modified by the saved state. Note that for\n\t\t * plug-in authors, you should use the `stateLoadParams` event to load parameters for\n\t\t * a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that is to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never loaded\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Disallow state loading by returning false\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          return false;\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Callback that is called when the state has been loaded from the state saving method\n\t\t * and the DataTables settings object has been modified as a result of the loaded state.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that was loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoaded\n\t\t *\n\t\t *  @example\n\t\t *    // Show an alert with the filtering value that was saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoaded\": function (settings, data) {\n\t\t *          alert( 'Saved filter was: '+data.oSearch.sSearch );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoaded\": null,\n\t\n\t\n\t\t/**\n\t\t * Save the table state. This function allows you to define where and how the state\n\t\t * information for the table is stored By default DataTables will use `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveCallback\": function (settings, data) {\n\t\t *          // Send an Ajax request to the server with the state object\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_save\",\n\t\t *            \"data\": data,\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"method\": \"POST\"\n\t\t *            \"success\": function () {}\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveCallback\": function ( settings, data ) {\n\t\t\ttry {\n\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(\n\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname,\n\t\t\t\t\tJSON.stringify( data )\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the state to be saved. Called when the table\n\t\t * has changed state a new state save is required. This method allows modification of\n\t\t * the state saving object prior to actually doing the save, including addition or\n\t\t * other state properties or modification. Note that for plug-in authors, you should\n\t\t * use the `stateSaveParams` event to save parameters for a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Duration for which the saved state information is considered valid. After this period\n\t\t * has elapsed the state will be returned to the default.\n\t\t * Value is given in seconds.\n\t\t *  @type int\n\t\t *  @default 7200 <i>(2 hours)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.stateDuration\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateDuration\": 60*60*24; // 1 day\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iStateDuration\": 7200,\n\t\n\t\n\t\t/**\n\t\t * When enabled DataTables will not make a request to the server for the first\n\t\t * page draw - rather it will use the data already on the page (no sorting etc\n\t\t * will be applied to it), thus saving on an XHR at load time. `deferLoading`\n\t\t * is used to indicate that deferred loading is required, but it is also used\n\t\t * to tell DataTables how many records there are in the full table (allowing\n\t\t * the information element and pagination to be displayed correctly). In the case\n\t\t * where a filtering is applied to the table on initial load, this can be\n\t\t * indicated by giving the parameter as an array, where the first element is\n\t\t * the number of records available after filtering and the second element is the\n\t\t * number of records without filtering (allowing the table information element\n\t\t * to be shown correctly).\n\t\t *  @type int | array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.deferLoading\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records available in the table, no filtering applied\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": 57\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records after filtering, 100 without filtering (an initial filter applied)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": [ 57, 100 ],\n\t\t *        \"search\": {\n\t\t *          \"search\": \"my_filter\"\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iDeferLoading\": null,\n\t\n\t\n\t\t/**\n\t\t * Number of rows to display on a single page when using pagination. If\n\t\t * feature enabled (`lengthChange`) then the end user will be able to override\n\t\t * this to a custom setting using a pop-up menu.\n\t\t *  @type int\n\t\t *  @default 10\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pageLength\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pageLength\": 50\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayLength\": 10,\n\t\n\t\n\t\t/**\n\t\t * Define the starting point for data display when using DataTables with\n\t\t * pagination. Note that this parameter is the number of records, rather than\n\t\t * the page number, so if you have 10 records per page and want to start on\n\t\t * the third page, it should be \"20\".\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.displayStart\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"displayStart\": 20\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayStart\": 0,\n\t\n\t\n\t\t/**\n\t\t * By default DataTables allows keyboard navigation of the table (sorting, paging,\n\t\t * and filtering) by adding a `tabindex` attribute to the required elements. This\n\t\t * allows you to tab through the controls and press the enter key to activate them.\n\t\t * The tabindex is default 0, meaning that the tab follows the flow of the document.\n\t\t * You can overrule this using this parameter if you wish. Use a value of -1 to\n\t\t * disable built-in keyboard navigation.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.tabIndex\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"tabIndex\": 1\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\n\t\t/**\n\t\t * Classes that DataTables assigns to the various components and features\n\t\t * that it adds to the HTML table. This allows classes to be configured\n\t\t * during initialisation in addition to through the static\n\t\t * {@link DataTable.ext.oStdClasses} object).\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.classes\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\n\t\t/**\n\t\t * All strings that DataTables uses in the user interface that it creates\n\t\t * are defined in this object, allowing you to modified them individually or\n\t\t * completely replace them all as required.\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.language\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Strings that are used for WAI-ARIA labels and controls only (these are not\n\t\t\t * actually visible on the page, but will be read by screenreaders, and thus\n\t\t\t * must be internationalised as well).\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.aria\n\t\t\t */\n\t\t\t\"oAria\": {\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted ascending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortAscending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortAscending\": \" - click/return to sort ascending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortAscending\": \": activate to sort column ascending\",\n\t\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted descending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortDescending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortDescending\": \" - click/return to sort descending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortDescending\": \": activate to sort column descending\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * Pagination string used by DataTables for the built-in pagination\n\t\t\t * control types.\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.paginate\n\t\t\t */\n\t\t\t\"oPaginate\": {\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the first page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default First\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.first\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"first\": \"First page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sFirst\": \"First\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the last page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Last\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.last\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"last\": \"Last page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sLast\": \"Last\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'next' pagination button (to take the user to the\n\t\t\t\t * next page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Next\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.next\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"next\": \"Next page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sNext\": \"Next\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'previous' pagination button (to take the user to\n\t\t\t\t * the previous page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Previous\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.previous\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"previous\": \"Previous page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sPrevious\": \"Previous\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * This string is shown in preference to `zeroRecords` when the table is\n\t\t\t * empty of data (regardless of filtering). Note that this is an optional\n\t\t\t * parameter - if it is not given, the value of `zeroRecords` will be used\n\t\t\t * instead (either the default or given value).\n\t\t\t *  @type string\n\t\t\t *  @default No data available in table\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.emptyTable\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"emptyTable\": \"No data available in table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sEmptyTable\": \"No data available in table\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This string gives information to the end user about the information\n\t\t\t * that is current on display on the page. The following tokens can be\n\t\t\t * used in the string and will be dynamically replaced as the table\n\t\t\t * display updates. This tokens can be placed anywhere in the string, or\n\t\t\t * removed as needed by the language requires:\n\t\t\t *\n\t\t\t * * `\\_START\\_` - Display index of the first record on the current page\n\t\t\t * * `\\_END\\_` - Display index of the last record on the current page\n\t\t\t * * `\\_TOTAL\\_` - Number of records in the table after filtering\n\t\t\t * * `\\_MAX\\_` - Number of records in the table without filtering\n\t\t\t * * `\\_PAGE\\_` - Current page number\n\t\t\t * * `\\_PAGES\\_` - Total number of pages of data in the table\n\t\t\t *\n\t\t\t *  @type string\n\t\t\t *  @default Showing _START_ to _END_ of _TOTAL_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.info\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"info\": \"Showing page _PAGE_ of _PAGES_\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfo\": \"Showing _START_ to _END_ of _TOTAL_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Display information string for when the table is empty. Typically the\n\t\t\t * format of this string should match `info`.\n\t\t\t *  @type string\n\t\t\t *  @default Showing 0 to 0 of 0 entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoEmpty\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoEmpty\": \"No entries to show\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoEmpty\": \"Showing 0 to 0 of 0 entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When a user filters the information in a table, this string is appended\n\t\t\t * to the information (`info`) to give an idea of how strong the filtering\n\t\t\t * is. The variable _MAX_ is dynamically updated.\n\t\t\t *  @type string\n\t\t\t *  @default (filtered from _MAX_ total entries)\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoFiltered\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoFiltered\": \" - filtering from _MAX_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoFiltered\": \"(filtered from _MAX_ total entries)\",\n\t\n\t\n\t\t\t/**\n\t\t\t * If can be useful to append extra information to the info string at times,\n\t\t\t * and this variable does exactly that. This information will be appended to\n\t\t\t * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are\n\t\t\t * being used) at all times.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoPostFix\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoPostFix\": \"All records shown are derived from real information.\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoPostFix\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This decimal place operator is a little different from the other\n\t\t\t * language options since DataTables doesn't output floating point\n\t\t\t * numbers, so it won't ever use this for display of a number. Rather,\n\t\t\t * what this parameter does is modify the sort methods of the table so\n\t\t\t * that numbers which are in a format which has a character other than\n\t\t\t * a period (`.`) as a decimal place will be sorted numerically.\n\t\t\t *\n\t\t\t * Note that numbers with different decimal places cannot be shown in\n\t\t\t * the same table and still be sortable, the table must be consistent.\n\t\t\t * However, multiple different tables on the page can use different\n\t\t\t * decimal place characters.\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.decimal\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"decimal\": \",\"\n\t\t\t *          \"thousands\": \".\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sDecimal\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * DataTables has a build in number formatter (`formatNumber`) which is\n\t\t\t * used to format large numbers that are used in the table information.\n\t\t\t * By default a comma is used, but this can be trivially changed to any\n\t\t\t * character you wish with this parameter.\n\t\t\t *  @type string\n\t\t\t *  @default ,\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.thousands\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"thousands\": \"'\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sThousands\": \",\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Detail the action that will be taken when the drop down menu for the\n\t\t\t * pagination length option is changed. The '_MENU_' variable is replaced\n\t\t\t * with a default select list of 10, 25, 50 and 100, and can be replaced\n\t\t\t * with a custom select box if required.\n\t\t\t *  @type string\n\t\t\t *  @default Show _MENU_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.lengthMenu\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language change only\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": \"Display _MENU_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language and options change\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": 'Display <select>'+\n\t\t\t *            '<option value=\"10\">10</option>'+\n\t\t\t *            '<option value=\"20\">20</option>'+\n\t\t\t *            '<option value=\"30\">30</option>'+\n\t\t\t *            '<option value=\"40\">40</option>'+\n\t\t\t *            '<option value=\"50\">50</option>'+\n\t\t\t *            '<option value=\"-1\">All</option>'+\n\t\t\t *            '</select> records'\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLengthMenu\": \"Show _MENU_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When using Ajax sourced data and during the first draw when DataTables is\n\t\t\t * gathering the data, this message is shown in an empty row in the table to\n\t\t\t * indicate to the end user the the data is being loaded. Note that this\n\t\t\t * parameter is not used when loading data by server-side processing, just\n\t\t\t * Ajax sourced data with client-side processing.\n\t\t\t *  @type string\n\t\t\t *  @default Loading...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.loadingRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"loadingRecords\": \"Please wait - loading...\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLoadingRecords\": \"Loading...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text which is displayed when the table is processing a user action\n\t\t\t * (usually a sort command or similar).\n\t\t\t *  @type string\n\t\t\t *  @default Processing...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.processing\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"processing\": \"DataTables is currently busy\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sProcessing\": \"Processing...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Details the actions that will be taken when the user types into the\n\t\t\t * filtering input text box. The variable \"_INPUT_\", if used in the string,\n\t\t\t * is replaced with the HTML text box for the filtering input allowing\n\t\t\t * control over where it appears in the string. If \"_INPUT_\" is not given\n\t\t\t * then the input box is appended to the string automatically.\n\t\t\t *  @type string\n\t\t\t *  @default Search:\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.search\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Input text box will be appended at the end automatically\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Filter records:\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Specify where the filter should appear\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Apply filter _INPUT_ to table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sSearch\": \"Search:\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Assign a `placeholder` attribute to the search `input` element\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.searchPlaceholder\n\t\t\t */\n\t\t\t\"sSearchPlaceholder\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * All of the language information can be stored in a file on the\n\t\t\t * server-side, which DataTables will look up if this parameter is passed.\n\t\t\t * It must store the URL of the language file, which is in a JSON format,\n\t\t\t * and the object has the same properties as the oLanguage object in the\n\t\t\t * initialiser object (i.e. the above parameters). Please refer to one of\n\t\t\t * the example language files to see how this works in action.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string - i.e. disabled</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.url\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"url\": \"http://www.sprymedia.co.uk/dataTables/lang.txt\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sUrl\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text shown inside the table records when the is no information to be\n\t\t\t * displayed after filtering. `emptyTable` is shown when there is simply no\n\t\t\t * information in the table at all (regardless of filtering).\n\t\t\t *  @type string\n\t\t\t *  @default No matching records found\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.zeroRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"zeroRecords\": \"No records to display\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sZeroRecords\": \"No matching records found\"\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to have define the global filtering state at\n\t\t * initialisation time. As an object the `search` parameter must be\n\t\t * defined, but all other parameters are optional. When `regex` is true,\n\t\t * the search string will be treated as a regular expression, when false\n\t\t * (default) it will be treated as a straight string. When `smart`\n\t\t * DataTables will use it's smart filtering methods (to word match at\n\t\t * any point in the data), when false this will not be done.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.search\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"search\": {\"search\": \"Initial search\"}\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"oSearch\": $.extend( {}, DataTable.models.oSearch ),\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * By default DataTables will look for the property `data` (or `aaData` for\n\t\t * compatibility with DataTables 1.9-) when obtaining data from an Ajax\n\t\t * source or for server-side processing - this parameter allows that\n\t\t * property to be changed. You can use Javascript dotted object notation to\n\t\t * get a data source for multiple levels of nesting.\n\t\t *  @type string\n\t\t *  @default data\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxDataProp\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxDataProp\": \"data\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * You can instruct DataTables to load data from an external\n\t\t * source using this parameter (use aData if you want to pass data in you\n\t\t * already have). Simply provide a url a JSON object can be obtained from.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxSource\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\n\t\t/**\n\t\t * This initialisation variable allows you to specify exactly where in the\n\t\t * DOM you want DataTables to inject the various controls it adds to the page\n\t\t * (for example you might want the pagination controls at the top of the\n\t\t * table). DIV elements (with or without a custom class) can also be added to\n\t\t * aid styling. The follow syntax is used:\n\t\t *   <ul>\n\t\t *     <li>The following options are allowed:\n\t\t *       <ul>\n\t\t *         <li>'l' - Length changing</li>\n\t\t *         <li>'f' - Filtering input</li>\n\t\t *         <li>'t' - The table!</li>\n\t\t *         <li>'i' - Information</li>\n\t\t *         <li>'p' - Pagination</li>\n\t\t *         <li>'r' - pRocessing</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following constants are allowed:\n\t\t *       <ul>\n\t\t *         <li>'H' - jQueryUI theme \"header\" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>\n\t\t *         <li>'F' - jQueryUI theme \"footer\" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following syntax is expected:\n\t\t *       <ul>\n\t\t *         <li>'&lt;' and '&gt;' - div elements</li>\n\t\t *         <li>'&lt;\"class\" and '&gt;' - div with a class</li>\n\t\t *         <li>'&lt;\"#id\" and '&gt;' - div with an ID</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>Examples:\n\t\t *       <ul>\n\t\t *         <li>'&lt;\"wrapper\"flipt&gt;'</li>\n\t\t *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *   </ul>\n\t\t *  @type string\n\t\t *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>\n\t\t *    <\"H\"lfr>t<\"F\"ip> <i>(when `jQueryUI` is true)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.dom\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"dom\": '&lt;\"top\"i&gt;rt&lt;\"bottom\"flp&gt;&lt;\"clear\"&gt;'\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDom\": \"lfrtip\",\n\t\n\t\n\t\t/**\n\t\t * Search delay option. This will throttle full table searches that use the\n\t\t * DataTables provided search input element (it does not effect calls to\n\t\t * `dt-api search()`, providing a delay before the search is made.\n\t\t *  @type integer\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.searchDelay\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchDelay\": 200\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\n\t\t/**\n\t\t * DataTables features six different built-in options for the buttons to\n\t\t * display for pagination control:\n\t\t *\n\t\t * * `numbers` - Page number buttons only\n\t\t * * `simple` - 'Previous' and 'Next' buttons only\n\t\t * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers\n\t\t * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons\n\t\t * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers\n\t\t * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers\n\t\t *  \n\t\t * Further methods can be added using {@link DataTable.ext.oPagination}.\n\t\t *  @type string\n\t\t *  @default simple_numbers\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pagingType\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pagingType\": \"full_numbers\"\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"sPaginationType\": \"simple_numbers\",\n\t\n\t\n\t\t/**\n\t\t * Enable horizontal scrolling. When a table is too wide to fit into a\n\t\t * certain layout, or you have a large number of columns in the table, you\n\t\t * can enable x-scrolling to show the table in a viewport, which can be\n\t\t * scrolled. This property can be `true` which will allow the table to\n\t\t * scroll horizontally when needed, or any CSS unit, or a number (in which\n\t\t * case it will be treated as a pixel measurement). Setting as simply `true`\n\t\t * is recommended.\n\t\t *  @type boolean|string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollX\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": true,\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollX\": \"\",\n\t\n\t\n\t\t/**\n\t\t * This property can be used to force a DataTable to use more width than it\n\t\t * might otherwise do when x-scrolling is enabled. For example if you have a\n\t\t * table which requires to be well spaced, this parameter is useful for\n\t\t * \"over-sizing\" the table, and thus forcing scrolling. This property can by\n\t\t * any CSS unit, or a number (in which case it will be treated as a pixel\n\t\t * measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollXInner\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": \"100%\",\n\t\t *        \"scrollXInner\": \"110%\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollXInner\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Enable vertical scrolling. Vertical scrolling will constrain the DataTable\n\t\t * to the given height, and enable scrolling for any data which overflows the\n\t\t * current viewport. This can be used as an alternative to paging to display\n\t\t * a lot of data in a small area (although paging and scrolling can both be\n\t\t * enabled at the same time). This property can be any CSS unit, or a number\n\t\t * (in which case it will be treated as a pixel measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollY\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollY\": \"\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * Set the HTTP method that is used to make the Ajax call for server-side\n\t\t * processing or Ajax sourced data.\n\t\t *  @type string\n\t\t *  @default GET\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverMethod\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sServerMethod\": \"GET\",\n\t\n\t\n\t\t/**\n\t\t * DataTables makes use of renderers when displaying HTML elements for\n\t\t * a table. These renderers can be added or modified by plug-ins to\n\t\t * generate suitable mark-up for a site. For example the Bootstrap\n\t\t * integration plug-in for DataTables uses a paging button renderer to\n\t\t * display pagination buttons in the mark-up required by Bootstrap.\n\t\t *\n\t\t * For further information about the renderers available see\n\t\t * DataTable.ext.renderer\n\t\t *  @type string|object\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.renderer\n\t\t *\n\t\t */\n\t\t\"renderer\": null,\n\t\n\t\n\t\t/**\n\t\t * Set the data property name that DataTables should use to get a row's id\n\t\t * to set as the `id` property in the node.\n\t\t *  @type string\n\t\t *  @default DT_RowId\n\t\t *\n\t\t *  @name DataTable.defaults.rowId\n\t\t */\n\t\t\"rowId\": \"DT_RowId\"\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults );\n\t\n\t\n\t\n\t/*\n\t * Developer note - See note in model.defaults.js about the use of Hungarian\n\t * notation and camel case.\n\t */\n\t\n\t/**\n\t * Column options that can be given to DataTables at initialisation time.\n\t *  @namespace\n\t */\n\tDataTable.defaults.column = {\n\t\t/**\n\t\t * Define which column(s) an order will occur on for this column. This\n\t\t * allows a column's ordering to take multiple columns into account when\n\t\t * doing a sort or use the data from a different column. For example first\n\t\t * name / last name columns make sense to do a multi-column sort over the\n\t\t * two columns.\n\t\t *  @type array|int\n\t\t *  @default null <i>Takes the value of the column index automatically</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderData\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderData\": [ 0, 1 ], \"targets\": [ 0 ] },\n\t\t *          { \"orderData\": [ 1, 0 ], \"targets\": [ 1 ] },\n\t\t *          { \"orderData\": 2, \"targets\": [ 2 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderData\": [ 0, 1 ] },\n\t\t *          { \"orderData\": [ 1, 0 ] },\n\t\t *          { \"orderData\": 2 },\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aDataSort\": null,\n\t\t\"iDataSort\": -1,\n\t\n\t\n\t\t/**\n\t\t * You can control the default ordering direction, and even alter the\n\t\t * behaviour of the sort handler (i.e. only allow ascending ordering etc)\n\t\t * using this parameter.\n\t\t *  @type array\n\t\t *  @default [ 'asc', 'desc' ]\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderSequence\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderSequence\": [ \"asc\" ], \"targets\": [ 1 ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ], \"targets\": [ 2 ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ], \"targets\": [ 3 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          { \"orderSequence\": [ \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ] },\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"asSorting\": [ 'asc', 'desc' ],\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering on the data in this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.searchable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"searchable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"searchable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSearchable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable ordering on this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.visible\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"visible\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"visible\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bVisible\": true,\n\t\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} td The TD node that has been created\n\t\t *  @param {*} cellData The Data for the cell\n\t\t *  @param {array|object} rowData The data for the whole row\n\t\t *  @param {int} row The row index for the aoData data store\n\t\t *  @param {int} col The column index for aoColumns\n\t\t *\n\t\t *  @name DataTable.defaults.column.createdCell\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [3],\n\t\t *          \"createdCell\": function (td, cellData, rowData, row, col) {\n\t\t *            if ( cellData == \"1.7\" ) {\n\t\t *              $(td).css('color', 'blue')\n\t\t *            }\n\t\t *          }\n\t\t *        } ]\n\t\t *      });\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter has been replaced by `data` in DataTables to ensure naming\n\t\t * consistency. `dataProp` can still be used, as there is backwards\n\t\t * compatibility in DataTables for this option, but it is strongly\n\t\t * recommended that you use `data` in preference to `dataProp`.\n\t\t *  @name DataTable.defaults.column.dataProp\n\t\t */\n\t\n\t\n\t\t/**\n\t\t * This property can be used to read data from any data source property,\n\t\t * including deeply nested objects / properties. `data` can be given in a\n\t\t * number of different ways which effect its behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object. Note that\n\t\t *      function notation is recommended for use in `render` rather than\n\t\t *      `data` as it is much simpler to use as a renderer.\n\t\t * * `null` - use the original data source for the row rather than plucking\n\t\t *   data directly from it. This action has effects on two other\n\t\t *   initialisation options:\n\t\t *    * `defaultContent` - When null is given as the `data` option and\n\t\t *      `defaultContent` is specified for the column, the value defined by\n\t\t *      `defaultContent` will be used for the cell.\n\t\t *    * `render` - When null is used for the `data` option and the `render`\n\t\t *      option is specified for the column, the whole data source for the\n\t\t *      row is used for the renderer.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * `{array|object}` The data source for the row\n\t\t *      * `{string}` The type call data requested - this will be 'set' when\n\t\t *        setting data or 'filter', 'display', 'type', 'sort' or undefined\n\t\t *        when gathering data. Note that when `undefined` is given for the\n\t\t *        type DataTables expects to get the raw data for the object back<\n\t\t *      * `{*}` Data to set when the second parameter is 'set'.\n\t\t *    * Return:\n\t\t *      * The return value from the function is not required when 'set' is\n\t\t *        the type of call, but otherwise the return is what will be used\n\t\t *        for the data requested.\n\t\t *\n\t\t * Note that `data` is a getter and setter option. If you just require\n\t\t * formatting of data for output, you will likely want to use `render` which\n\t\t * is simply a getter and thus simpler to use.\n\t\t *\n\t\t * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The\n\t\t * name change reflects the flexibility of this property and is consistent\n\t\t * with the naming of mRender. If 'mDataProp' is given, then it will still\n\t\t * be used by DataTables, as it automatically maps the old name to the new\n\t\t * if required.\n\t\t *\n\t\t *  @type string|int|function|null\n\t\t *  @default null <i>Use automatically calculated column index</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.data\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Read table data from objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {value},\n\t\t *    //      \"version\": {value},\n\t\t *    //      \"grade\": {value}\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/objects.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform\" },\n\t\t *          { \"data\": \"version\" },\n\t\t *          { \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Read information from deeply nested objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {\n\t\t *    //         \"inner\": {value}\n\t\t *    //      },\n\t\t *    //      \"details\": [\n\t\t *    //         {value}, {value}\n\t\t *    //      ]\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform.inner\" },\n\t\t *          { \"data\": \"platform.details.0\" },\n\t\t *          { \"data\": \"platform.details.1\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `data` as a function to provide different information for\n\t\t *    // sorting, filtering and display. In this case, currency (price)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": function ( source, type, val ) {\n\t\t *            if (type === 'set') {\n\t\t *              source.price = val;\n\t\t *              // Store the computed dislay and filter values for efficiency\n\t\t *              source.price_display = val==\"\" ? \"\" : \"$\"+numberFormat(val);\n\t\t *              source.price_filter  = val==\"\" ? \"\" : \"$\"+numberFormat(val)+\" \"+val;\n\t\t *              return;\n\t\t *            }\n\t\t *            else if (type === 'display') {\n\t\t *              return source.price_display;\n\t\t *            }\n\t\t *            else if (type === 'filter') {\n\t\t *              return source.price_filter;\n\t\t *            }\n\t\t *            // 'sort', 'type' and undefined all just use the integer\n\t\t *            return source.price;\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using default content\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null,\n\t\t *          \"defaultContent\": \"Click to edit\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using array notation - outputting a list from an array\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"name[, ]\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\n\t\t/**\n\t\t * This property is the rendering partner to `data` and it is suggested that\n\t\t * when you want to manipulate data for display (including filtering,\n\t\t * sorting etc) without altering the underlying data for the table, use this\n\t\t * property. `render` can be considered to be the the read only companion to\n\t\t * `data` which is read / write (then as such more complex). Like `data`\n\t\t * this option can be given in a number of different ways to effect its\n\t\t * behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object.\n\t\t * * `object` - use different data for the different data types requested by\n\t\t *   DataTables ('filter', 'display', 'type' or 'sort'). The property names\n\t\t *   of the object is the data type the property refers to and the value can\n\t\t *   defined using an integer, string or function using the same rules as\n\t\t *   `render` normally does. Note that an `_` option _must_ be specified.\n\t\t *   This is the default value to use if you haven't specified a value for\n\t\t *   the data type requested by DataTables.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * {array|object} The data source for the row (based on `data`)\n\t\t *      * {string} The type call data requested - this will be 'filter',\n\t\t *        'display', 'type' or 'sort'.\n\t\t *      * {array|object} The full data source for the row (not based on\n\t\t *        `data`)\n\t\t *    * Return:\n\t\t *      * The return value from the function is what will be used for the\n\t\t *        data requested.\n\t\t *\n\t\t *  @type string|int|function|object|null\n\t\t *  @default null Use the data source value.\n\t\t *\n\t\t *  @name DataTable.defaults.column.render\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Create a comma separated list from an array of objects\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          {\n\t\t *            \"data\": \"platform\",\n\t\t *            \"render\": \"[, ].name\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Execute a function to obtain data\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": \"browserName()\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // As an object, extracting different data for the different types\n\t\t *    // This would be used with a data source such as:\n\t\t *    //   { \"phone\": 5552368, \"phone_filter\": \"5552368 555-2368\", \"phone_display\": \"555-2368\" }\n\t\t *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`\n\t\t *    // (which has both forms) is used for filtering for if a user inputs either format, while\n\t\t *    // the formatted phone number is the one that is shown in the table.\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": {\n\t\t *            \"_\": \"phone\",\n\t\t *            \"filter\": \"phone_filter\",\n\t\t *            \"display\": \"phone_display\"\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Use as a function to create a link from the data source\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"download_link\",\n\t\t *          \"render\": function ( data, type, full ) {\n\t\t *            return '<a href=\"'+data+'\">Download</a>';\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\n\t\t/**\n\t\t * Change the cell type created for the column - either TD cells or TH cells. This\n\t\t * can be useful as TH cells have semantic meaning in the table body, allowing them\n\t\t * to act as a header for a row (you may wish to add scope='row' to the TH elements).\n\t\t *  @type string\n\t\t *  @default td\n\t\t *\n\t\t *  @name DataTable.defaults.column.cellType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Make the first column use TH cells\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"cellType\": \"th\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sCellType\": \"td\",\n\t\n\t\n\t\t/**\n\t\t * Class to give to each cell in this column.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.class\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"class\": \"my_class\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"class\": \"my_class\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sClass\": \"\",\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t * Generally you shouldn't need this!\n\t\t *  @type string\n\t\t *  @default <i>Empty string<i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.contentPadding\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"contentPadding\": \"mmm\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sContentPadding\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because `data`\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.column.defaultContent\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\",\n\t\t *            \"targets\": [ -1 ]\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter is only used in DataTables' server-side processing. It can\n\t\t * be exceptionally useful to know what columns are being displayed on the\n\t\t * client side, and to map these to database fields. When defined, the names\n\t\t * also allow DataTables to reorder information from the server if it comes\n\t\t * back in an unexpected order (i.e. if you switch your columns around on the\n\t\t * client-side, your server-side code does not also need updating).\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.name\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"name\": \"engine\", \"targets\": [ 0 ] },\n\t\t *          { \"name\": \"browser\", \"targets\": [ 1 ] },\n\t\t *          { \"name\": \"platform\", \"targets\": [ 2 ] },\n\t\t *          { \"name\": \"version\", \"targets\": [ 3 ] },\n\t\t *          { \"name\": \"grade\", \"targets\": [ 4 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"name\": \"engine\" },\n\t\t *          { \"name\": \"browser\" },\n\t\t *          { \"name\": \"platform\" },\n\t\t *          { \"name\": \"version\" },\n\t\t *          { \"name\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sName\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Defines a data source type for the ordering which can be used to read\n\t\t * real-time information from the table (updating the internally cached\n\t\t * version) prior to ordering. This allows ordering to occur on user\n\t\t * editable elements such as form inputs.\n\t\t *  @type string\n\t\t *  @default std\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderDataType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderDataType\": \"dom-text\", \"targets\": [ 2, 3 ] },\n\t\t *          { \"type\": \"numeric\", \"targets\": [ 3 ] },\n\t\t *          { \"orderDataType\": \"dom-select\", \"targets\": [ 4 ] },\n\t\t *          { \"orderDataType\": \"dom-checkbox\", \"targets\": [ 5 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          { \"orderDataType\": \"dom-text\" },\n\t\t *          { \"orderDataType\": \"dom-text\", \"type\": \"numeric\" },\n\t\t *          { \"orderDataType\": \"dom-select\" },\n\t\t *          { \"orderDataType\": \"dom-checkbox\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sSortDataType\": \"std\",\n\t\n\t\n\t\t/**\n\t\t * The title of this column.\n\t\t *  @type string\n\t\t *  @default null <i>Derived from the 'TH' value for this column in the\n\t\t *    original HTML table.</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.title\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"title\": \"My column title\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"My column title\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\n\t\t/**\n\t\t * The type allows you to specify how the data for this column will be\n\t\t * ordered. Four types (string, numeric, date and html (which will strip\n\t\t * HTML tags before ordering)) are currently available. Note that only date\n\t\t * formats understood by Javascript's Date() object will be accepted as type\n\t\t * date. For example: \"Mar 26, 2008 5:03 PM\". May take the values: 'string',\n\t\t * 'numeric', 'date' or 'html' (by default). Further types can be adding\n\t\t * through plug-ins.\n\t\t *  @type string\n\t\t *  @default null <i>Auto-detected from raw data</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.type\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"type\": \"html\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"type\": \"html\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\n\t\t/**\n\t\t * Defining the width of the column, this parameter may take any CSS value\n\t\t * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not\n\t\t * been given a specific width through this interface ensuring that the table\n\t\t * remains readable.\n\t\t *  @type string\n\t\t *  @default null <i>Automatic</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.width\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"width\": \"20%\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"width\": \"20%\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sWidth\": null\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults.column );\n\t\n\t\n\t\n\t/**\n\t * DataTables settings object - this holds all the information needed for a\n\t * given table, including configuration, data and current application of the\n\t * table options. DataTables does not have a single instance for each DataTable\n\t * with the settings attached to that instance, but rather instances of the\n\t * DataTable \"class\" are created on-the-fly as needed (typically by a\n\t * $().dataTable() call) and the settings object is then applied to that\n\t * instance.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults} but this\n\t * one is the internal data store for DataTables's cache of columns. It should\n\t * NOT be manipulated outside of DataTables. Any configuration should be done\n\t * through the initialisation options.\n\t *  @namespace\n\t *  @todo Really should attach the settings object to individual instances so we\n\t *    don't need to create new instances on each $().dataTable() call (if the\n\t *    table already exists). It would also save passing oSettings around and\n\t *    into every single function. However, this is a very significant\n\t *    architecture change for DataTables and will almost certainly break\n\t *    backwards compatibility with older installations. This is something that\n\t *    will be done in 2.0.\n\t */\n\tDataTable.models.oSettings = {\n\t\t/**\n\t\t * Primary features of DataTables and their enablement state.\n\t\t *  @namespace\n\t\t */\n\t\t\"oFeatures\": {\n\t\n\t\t\t/**\n\t\t\t * Flag to say if DataTables should automatically try to calculate the\n\t\t\t * optimum table and columns widths (true) or not (false).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bAutoWidth\": null,\n\t\n\t\t\t/**\n\t\t\t * Delay the creation of TR and TD elements until they are actually\n\t\t\t * needed by a driven page draw. This can give a significant speed\n\t\t\t * increase for Ajax source and Javascript source data, but makes no\n\t\t\t * difference at all fro DOM and server-side processing tables.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bDeferRender\": null,\n\t\n\t\t\t/**\n\t\t\t * Enable filtering on the table or not. Note that if this is disabled\n\t\t\t * then there is no filtering at all on the table, including fnFilter.\n\t\t\t * To just remove the filtering input use sDom and remove the 'f' option.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bFilter\": null,\n\t\n\t\t\t/**\n\t\t\t * Table information element (the 'Showing x of y records' div) enable\n\t\t\t * flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bInfo\": null,\n\t\n\t\t\t/**\n\t\t\t * Present a user control allowing the end user to change the page size\n\t\t\t * when pagination is enabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bLengthChange\": null,\n\t\n\t\t\t/**\n\t\t\t * Pagination enabled or not. Note that if this is disabled then length\n\t\t\t * changing must also be disabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bPaginate\": null,\n\t\n\t\t\t/**\n\t\t\t * Processing indicator enable flag whenever DataTables is enacting a\n\t\t\t * user request - typically an Ajax request for server-side processing.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bProcessing\": null,\n\t\n\t\t\t/**\n\t\t\t * Server-side processing enabled flag - when enabled DataTables will\n\t\t\t * get all data from the server for every draw - there is no filtering,\n\t\t\t * sorting or paging done on the client-side.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bServerSide\": null,\n\t\n\t\t\t/**\n\t\t\t * Sorting enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSort\": null,\n\t\n\t\t\t/**\n\t\t\t * Multi-column sorting\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortMulti\": null,\n\t\n\t\t\t/**\n\t\t\t * Apply a class to the columns which are being sorted to provide a\n\t\t\t * visual highlight or not. This can slow things down when enabled since\n\t\t\t * there is a lot of DOM interaction.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortClasses\": null,\n\t\n\t\t\t/**\n\t\t\t * State saving enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bStateSave\": null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Scrolling settings for a table.\n\t\t *  @namespace\n\t\t */\n\t\t\"oScroll\": {\n\t\t\t/**\n\t\t\t * When the table is shorter in height than sScrollY, collapse the\n\t\t\t * table container down to the height of the table (when true).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bCollapse\": null,\n\t\n\t\t\t/**\n\t\t\t * Width of the scrollbar for the web-browser's platform. Calculated\n\t\t\t * during table initialisation.\n\t\t\t *  @type int\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"iBarWidth\": 0,\n\t\n\t\t\t/**\n\t\t\t * Viewport width for horizontal scrolling. Horizontal scrolling is\n\t\t\t * disabled if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sX\": null,\n\t\n\t\t\t/**\n\t\t\t * Width to expand the table to when using x-scrolling. Typically you\n\t\t\t * should not need to use this.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t *  @deprecated\n\t\t\t */\n\t\t\t\"sXInner\": null,\n\t\n\t\t\t/**\n\t\t\t * Viewport height for vertical scrolling. Vertical scrolling is disabled\n\t\t\t * if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sY\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Language information for the table.\n\t\t *  @namespace\n\t\t *  @extends DataTable.defaults.oLanguage\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Information callback function. See\n\t\t\t * {@link DataTable.defaults.fnInfoCallback}\n\t\t\t *  @type function\n\t\t\t *  @default null\n\t\t\t */\n\t\t\t\"fnInfoCallback\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Browser support parameters\n\t\t *  @namespace\n\t\t */\n\t\t\"oBrowser\": {\n\t\t\t/**\n\t\t\t * Indicate if the browser incorrectly calculates width:100% inside a\n\t\t\t * scrolling element (IE6/7)\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollOversize\": false,\n\t\n\t\t\t/**\n\t\t\t * Determine if the vertical scrollbar is on the right or left of the\n\t\t\t * scrolling container - needed for rtl language layout, although not\n\t\t\t * all browsers move the scrollbar (Safari).\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollbarLeft\": false,\n\t\n\t\t\t/**\n\t\t\t * Flag for if `getBoundingClientRect` is fully supported or not\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bBounding\": false,\n\t\n\t\t\t/**\n\t\t\t * Browser scrollbar width\n\t\t\t *  @type integer\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"barWidth\": 0\n\t\t},\n\t\n\t\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * Array referencing the nodes which are used for the features. The\n\t\t * parameters of this object match what is allowed by sDom - i.e.\n\t\t *   <ul>\n\t\t *     <li>'l' - Length changing</li>\n\t\t *     <li>'f' - Filtering input</li>\n\t\t *     <li>'t' - The table!</li>\n\t\t *     <li>'i' - Information</li>\n\t\t *     <li>'p' - Pagination</li>\n\t\t *     <li>'r' - pRocessing</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aanFeatures\": [],\n\t\n\t\t/**\n\t\t * Store data information - see {@link DataTable.models.oRow} for detailed\n\t\t * information.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoData\": [],\n\t\n\t\t/**\n\t\t * Array of indexes which are in the current display (after filtering etc)\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplay\": [],\n\t\n\t\t/**\n\t\t * Array of indexes for display - no filtering\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplayMaster\": [],\n\t\n\t\t/**\n\t\t * Map of row ids to data indexes\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"aIds\": {},\n\t\n\t\t/**\n\t\t * Store information about each column that is in use\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoColumns\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's header\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeader\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's footer\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooter\": [],\n\t\n\t\t/**\n\t\t * Store the applied global search information in case we want to force a\n\t\t * research or compare the old search to a new one.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t */\n\t\t\"oPreviousSearch\": {},\n\t\n\t\t/**\n\t\t * Store the applied search for each column - see\n\t\t * {@link DataTable.models.oSearch} for the format that is used for the\n\t\t * filtering information for each column.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreSearchCols\": [],\n\t\n\t\t/**\n\t\t * Sorting that is applied to the table. Note that the inner arrays are\n\t\t * used in the following manner:\n\t\t * <ul>\n\t\t *   <li>Index 0 - column number</li>\n\t\t *   <li>Index 1 - current sorting direction</li>\n\t\t * </ul>\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @todo These inner arrays should really be objects\n\t\t */\n\t\t\"aaSorting\": null,\n\t\n\t\t/**\n\t\t * Sorting that is always applied to the table (i.e. prefixed in front of\n\t\t * aaSorting).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\t/**\n\t\t * Classes to use for the striping of a table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its striping classes as well\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asDestroyStripes\": [],\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its width\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"sDestroyWidth\": 0,\n\t\n\t\t/**\n\t\t * Callback functions array for every time a row is inserted (i.e. on a draw).\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for the header on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeaderCallback\": [],\n\t\n\t\t/**\n\t\t * Callback function for the footer on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooterCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for draw callback functions\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for row created function\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCreatedCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for just before the table is redrawn. A return of\n\t\t * false will be used to cancel the draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for when the table has been initialised.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoInitComplete\": [],\n\t\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings to be stored for state saving, prior to\n\t\t * saving state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSaveParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings that have been stored for state saving\n\t\t * prior to using the stored values to restore the state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoadParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for operating on the settings object once the saved state has been\n\t\t * loaded\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoaded\": [],\n\t\n\t\t/**\n\t\t * Cache the table ID for quick access\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sTableId\": \"\",\n\t\n\t\t/**\n\t\t * The TABLE node for the main table\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTable\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the thead element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTHead\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tfoot element - if it exists\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTFoot\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tbody element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTBody\": null,\n\t\n\t\t/**\n\t\t * Cache the wrapper node (contains all DataTables controlled elements)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTableWrapper\": null,\n\t\n\t\t/**\n\t\t * Indicate if when using server-side processing the loading of data\n\t\t * should be deferred until the second draw.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDeferLoading\": false,\n\t\n\t\t/**\n\t\t * Indicate if all required information has been read in\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bInitialised\": false,\n\t\n\t\t/**\n\t\t * Information about open rows. Each object in the array has the parameters\n\t\t * 'nTr' and 'nParent'\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoOpenRows\": [],\n\t\n\t\t/**\n\t\t * Dictate the positioning of DataTables' control elements - see\n\t\t * {@link DataTable.model.oInit.sDom}.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDom\": null,\n\t\n\t\t/**\n\t\t * Search delay (in mS)\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\t/**\n\t\t * Which type of pagination should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default two_button\n\t\t */\n\t\t\"sPaginationType\": \"two_button\",\n\t\n\t\t/**\n\t\t * The state duration (for `stateSave`) in seconds.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iStateDuration\": 0,\n\t\n\t\t/**\n\t\t * Array of callback functions for state saving. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the JSON string to save that has been thus far created. Returns\n\t\t *       a JSON string to be inserted into a json object\n\t\t *       (i.e. '\"param\": [ 0, 1, 2]')</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSave\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for state loading. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the object stored. May return false to cancel state loading</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoad\": [],\n\t\n\t\t/**\n\t\t * State that was saved. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oSavedState\": null,\n\t\n\t\t/**\n\t\t * State that was loaded. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oLoadedState\": null,\n\t\n\t\t/**\n\t\t * Source url for AJAX data for the table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\t/**\n\t\t * Property from a given object from which to read the table data from. This\n\t\t * can be an empty string (when not server-side processing), in which case\n\t\t * it is  assumed an an array is given directly.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sAjaxDataProp\": null,\n\t\n\t\t/**\n\t\t * Note if draw should be blocked while getting data\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bAjaxDataGet\": true,\n\t\n\t\t/**\n\t\t * The last jQuery XHR object that was used for server-side data gathering.\n\t\t * This can be used for working with the XHR information in one of the\n\t\t * callbacks\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"jqXHR\": null,\n\t\n\t\t/**\n\t\t * JSON returned from the server in the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"json\": undefined,\n\t\n\t\t/**\n\t\t * Data submitted as part of the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"oAjaxData\": undefined,\n\t\n\t\t/**\n\t\t * Function to get the server-side data.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\t/**\n\t\t * Functions which are called prior to sending an Ajax request so extra\n\t\t * parameters can easily be sent to the server\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoServerParams\": [],\n\t\n\t\t/**\n\t\t * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if\n\t\t * required).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sServerMethod\": null,\n\t\n\t\t/**\n\t\t * Format numbers for display.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnFormatNumber\": null,\n\t\n\t\t/**\n\t\t * List of options that can be used for the user selectable length menu.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLengthMenu\": null,\n\t\n\t\t/**\n\t\t * Counter for the draws that the table does. Also used as a tracker for\n\t\t * server-side processing\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iDraw\": 0,\n\t\n\t\t/**\n\t\t * Indicate if a redraw is being done - useful for Ajax\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDrawing\": false,\n\t\n\t\t/**\n\t\t * Draw index (iDraw) of the last error when parsing the returned data\n\t\t *  @type int\n\t\t *  @default -1\n\t\t */\n\t\t\"iDrawError\": -1,\n\t\n\t\t/**\n\t\t * Paging display length\n\t\t *  @type int\n\t\t *  @default 10\n\t\t */\n\t\t\"_iDisplayLength\": 10,\n\t\n\t\t/**\n\t\t * Paging start point - aiDisplay index\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"_iDisplayStart\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the result set\n\t\t * (i.e. before filtering), Use fnRecordsTotal rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsTotal\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the current display set\n\t\t * (i.e. after filtering). Use fnRecordsDisplay rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type boolean\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsDisplay\": 0,\n\t\n\t\t/**\n\t\t * Flag to indicate if jQuery UI marking and classes should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bJUI\": null,\n\t\n\t\t/**\n\t\t * The classes to use for the table\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if filtering has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bFiltered\": false,\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if sorting has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bSorted\": false,\n\t\n\t\t/**\n\t\t * Indicate that if multiple rows are in the header and there is more than\n\t\t * one unique cell per column, if the top one (true) or bottom one (false)\n\t\t * should be used for sorting / title by DataTables.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortCellsTop\": null,\n\t\n\t\t/**\n\t\t * Initialisation object that is used for the table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInit\": null,\n\t\n\t\t/**\n\t\t * Destroy callback functions - for plug-ins to attach themselves to the\n\t\t * destroy so they can clean up markup and events.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDestroyCallback\": [],\n\t\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, before filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsTotal\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsTotal * 1 :\n\t\t\t\tthis.aiDisplayMaster.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, after filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsDisplay\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsDisplay * 1 :\n\t\t\t\tthis.aiDisplay.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the display end point - aiDisplay index\n\t\t *  @type function\n\t\t */\n\t\t\"fnDisplayEnd\": function ()\n\t\t{\n\t\t\tvar\n\t\t\t\tlen      = this._iDisplayLength,\n\t\t\t\tstart    = this._iDisplayStart,\n\t\t\t\tcalc     = start + len,\n\t\t\t\trecords  = this.aiDisplay.length,\n\t\t\t\tfeatures = this.oFeatures,\n\t\t\t\tpaginate = features.bPaginate;\n\t\n\t\t\tif ( features.bServerSide ) {\n\t\t\t\treturn paginate === false || len === -1 ?\n\t\t\t\t\tstart + records :\n\t\t\t\t\tMath.min( start+len, this._iRecordsDisplay );\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn ! paginate || calc>records || len===-1 ?\n\t\t\t\t\trecords :\n\t\t\t\t\tcalc;\n\t\t\t}\n\t\t},\n\t\n\t\t/**\n\t\t * The DataTables object for this table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInstance\": null,\n\t\n\t\t/**\n\t\t * Unique identifier for each instance of the DataTables object. If there\n\t\t * is an ID on the table node, then it takes that value, otherwise an\n\t\t * incrementing internal counter is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sInstance\": null,\n\t\n\t\t/**\n\t\t * tabindex attribute value that is added to DataTables control elements, allowing\n\t\t * keyboard navigation of the table and its controls.\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollHead\": null,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollFoot\": null,\n\t\n\t\t/**\n\t\t * Last applied sort\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLastSort\": [],\n\t\n\t\t/**\n\t\t * Stored plug-in instances\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oPlugins\": {},\n\t\n\t\t/**\n\t\t * Function used to get a row's id from the row's data\n\t\t *  @type function\n\t\t *  @default null\n\t\t */\n\t\t\"rowIdFn\": null,\n\t\n\t\t/**\n\t\t * Data location where to store a row's id\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"rowId\": null\n\t};\n\n\t/**\n\t * Extension object for DataTables that is used to provide all extension\n\t * options.\n\t *\n\t * Note that the `DataTable.ext` object is available through\n\t * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is\n\t * also aliased to `jQuery.fn.dataTableExt` for historic reasons.\n\t *  @namespace\n\t *  @extends DataTable.models.ext\n\t */\n\t\n\t\n\t/**\n\t * DataTables extensions\n\t * \n\t * This namespace acts as a collection area for plug-ins that can be used to\n\t * extend DataTables capabilities. Indeed many of the build in methods\n\t * use this method to provide their own capabilities (sorting methods for\n\t * example).\n\t *\n\t * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy\n\t * reasons\n\t *\n\t *  @namespace\n\t */\n\tDataTable.ext = _ext = {\n\t\t/**\n\t\t * Buttons. For use with the Buttons extension for DataTables. This is\n\t\t * defined here so other extensions can define buttons regardless of load\n\t\t * order. It is _not_ used by DataTables core.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tbuttons: {},\n\t\n\t\n\t\t/**\n\t\t * Element class names\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tclasses: {},\n\t\n\t\n\t\t/**\n\t\t * DataTables build type (expanded by the download builder)\n\t\t *\n\t\t *  @type string\n\t\t */\n\t\tbuild:\"dt/dt-1.10.13\",\n\t\n\t\n\t\t/**\n\t\t * Error reporting.\n\t\t * \n\t\t * How should DataTables report an error. Can take the value 'alert',\n\t\t * 'throw', 'none' or a function.\n\t\t *\n\t\t *  @type string|function\n\t\t *  @default alert\n\t\t */\n\t\terrMode: \"alert\",\n\t\n\t\n\t\t/**\n\t\t * Feature plug-ins.\n\t\t * \n\t\t * This is an array of objects which describe the feature plug-ins that are\n\t\t * available to DataTables. These feature plug-ins are then available for\n\t\t * use through the `dom` initialisation option.\n\t\t * \n\t\t * Each feature plug-in is described by an object which must have the\n\t\t * following properties:\n\t\t * \n\t\t * * `fnInit` - function that is used to initialise the plug-in,\n\t\t * * `cFeature` - a character so the feature can be enabled by the `dom`\n\t\t *   instillation option. This is case sensitive.\n\t\t *\n\t\t * The `fnInit` function has the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *\n\t\t * And the following return is expected:\n\t\t * \n\t\t * * {node|null} The element which contains your feature. Note that the\n\t\t *   return may also be void if your plug-in does not require to inject any\n\t\t *   DOM elements into DataTables control (`dom`) - for example this might\n\t\t *   be useful when developing a plug-in which allows table control via\n\t\t *   keyboard entry\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    $.fn.dataTable.ext.features.push( {\n\t\t *      \"fnInit\": function( oSettings ) {\n\t\t *        return new TableTools( { \"oDTSettings\": oSettings } );\n\t\t *      },\n\t\t *      \"cFeature\": \"T\"\n\t\t *    } );\n\t\t */\n\t\tfeature: [],\n\t\n\t\n\t\t/**\n\t\t * Row searching.\n\t\t * \n\t\t * This method of searching is complimentary to the default type based\n\t\t * searching, and a lot more comprehensive as it allows you complete control\n\t\t * over the searching logic. Each element in this array is a function\n\t\t * (parameters described below) that is called for every row in the table,\n\t\t * and your logic decides if it should be included in the searching data set\n\t\t * or not.\n\t\t *\n\t\t * Searching functions have the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{array|object}` Data for the row to be processed (same as the\n\t\t *    original format that was passed in as the data source, or an array\n\t\t *    from a DOM data source\n\t\t * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which\n\t\t *    can be useful to retrieve the `TR` element if you need DOM interaction.\n\t\t *\n\t\t * And the following return is expected:\n\t\t *\n\t\t * * {boolean} Include the row in the searched result set (true) or not\n\t\t *   (false)\n\t\t *\n\t\t * Note that as with the main search ability in DataTables, technically this\n\t\t * is \"filtering\", since it is subtractive. However, for consistency in\n\t\t * naming we call it searching here.\n\t\t *\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @example\n\t\t *    // The following example shows custom search being applied to the\n\t\t *    // fourth column (i.e. the data[3] index) based on two input values\n\t\t *    // from the end-user, matching the data in a certain range.\n\t\t *    $.fn.dataTable.ext.search.push(\n\t\t *      function( settings, data, dataIndex ) {\n\t\t *        var min = document.getElementById('min').value * 1;\n\t\t *        var max = document.getElementById('max').value * 1;\n\t\t *        var version = data[3] == \"-\" ? 0 : data[3]*1;\n\t\t *\n\t\t *        if ( min == \"\" && max == \"\" ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min == \"\" && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && \"\" == max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        return false;\n\t\t *      }\n\t\t *    );\n\t\t */\n\t\tsearch: [],\n\t\n\t\n\t\t/**\n\t\t * Selector extensions\n\t\t *\n\t\t * The `selector` option can be used to extend the options available for the\n\t\t * selector modifier options (`selector-modifier` object data type) that\n\t\t * each of the three built in selector types offer (row, column and cell +\n\t\t * their plural counterparts). For example the Select extension uses this\n\t\t * mechanism to provide an option to select only rows, columns and cells\n\t\t * that have been marked as selected by the end user (`{selected: true}`),\n\t\t * which can be used in conjunction with the existing built in selector\n\t\t * options.\n\t\t *\n\t\t * Each property is an array to which functions can be pushed. The functions\n\t\t * take three attributes:\n\t\t *\n\t\t * * Settings object for the host table\n\t\t * * Options object (`selector-modifier` object type)\n\t\t * * Array of selected item indexes\n\t\t *\n\t\t * The return is an array of the resulting item indexes after the custom\n\t\t * selector has been applied.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tselector: {\n\t\t\tcell: [],\n\t\t\tcolumn: [],\n\t\t\trow: []\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Internal functions, exposed for used in plug-ins.\n\t\t * \n\t\t * Please note that you should not need to use the internal methods for\n\t\t * anything other than a plug-in (and even then, try to avoid if possible).\n\t\t * The internal function may change between releases.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tinternal: {},\n\t\n\t\n\t\t/**\n\t\t * Legacy configuration options. Enable and disable legacy options that\n\t\t * are available in DataTables.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tlegacy: {\n\t\t\t/**\n\t\t\t * Enable / disable DataTables 1.9 compatible server-side processing\n\t\t\t * requests\n\t\t\t *\n\t\t\t *  @type boolean\n\t\t\t *  @default null\n\t\t\t */\n\t\t\tajax: null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Pagination plug-in methods.\n\t\t * \n\t\t * Each entry in this object is a function and defines which buttons should\n\t\t * be shown by the pagination rendering method that is used for the table:\n\t\t * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the\n\t\t * buttons are displayed in the document, while the functions here tell it\n\t\t * what buttons to display. This is done by returning an array of button\n\t\t * descriptions (what each button will do).\n\t\t *\n\t\t * Pagination types (the four built in options and any additional plug-in\n\t\t * options defined here) can be used through the `paginationType`\n\t\t * initialisation parameter.\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{int} page` The current page index\n\t\t * 2. `{int} pages` The number of pages in the table\n\t\t *\n\t\t * Each function is expected to return an array where each element of the\n\t\t * array can be one of:\n\t\t *\n\t\t * * `first` - Jump to first page when activated\n\t\t * * `last` - Jump to last page when activated\n\t\t * * `previous` - Show previous page when activated\n\t\t * * `next` - Show next page when activated\n\t\t * * `{int}` - Show page of the index given\n\t\t * * `{array}` - A nested array containing the above elements to add a\n\t\t *   containing 'DIV' element (might be useful for styling).\n\t\t *\n\t\t * Note that DataTables v1.9- used this object slightly differently whereby\n\t\t * an object with two functions would be defined for each plug-in. That\n\t\t * ability is still supported by DataTables 1.10+ to provide backwards\n\t\t * compatibility, but this option of use is now decremented and no longer\n\t\t * documented in DataTables 1.10+.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t *\n\t\t *  @example\n\t\t *    // Show previous, next and current page buttons only\n\t\t *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {\n\t\t *      return [ 'previous', page, 'next' ];\n\t\t *    };\n\t\t */\n\t\tpager: {},\n\t\n\t\n\t\trenderer: {\n\t\t\tpageButton: {},\n\t\t\theader: {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Ordering plug-ins - custom data source\n\t\t * \n\t\t * The extension options for ordering of data available here is complimentary\n\t\t * to the default type based ordering that DataTables typically uses. It\n\t\t * allows much greater control over the the data that is being used to\n\t\t * order a column, but is necessarily therefore more complex.\n\t\t * \n\t\t * This type of ordering is useful if you want to do ordering based on data\n\t\t * live from the DOM (for example the contents of an 'input' element) rather\n\t\t * than just the static string that DataTables knows of.\n\t\t * \n\t\t * The way these plug-ins work is that you create an array of the values you\n\t\t * wish to be ordering for the column in question and then return that\n\t\t * array. The data in the array much be in the index order of the rows in\n\t\t * the table (not the currently ordering order!). Which order data gathering\n\t\t * function is run here depends on the `dt-init columns.orderDataType`\n\t\t * parameter that is used for the column (if any).\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{int}` Target column index\n\t\t *\n\t\t * Each function is expected to return an array:\n\t\t *\n\t\t * * `{array}` Data for the column to be ordering upon\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    // Ordering using `input` node values\n\t\t *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )\n\t\t *    {\n\t\t *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {\n\t\t *        return $('input', td).val();\n\t\t *      } );\n\t\t *    }\n\t\t */\n\t\torder: {},\n\t\n\t\n\t\t/**\n\t\t * Type based plug-ins.\n\t\t *\n\t\t * Each column in DataTables has a type assigned to it, either by automatic\n\t\t * detection or by direct assignment using the `type` option for the column.\n\t\t * The type of a column will effect how it is ordering and search (plug-ins\n\t\t * can also make use of the column type if required).\n\t\t *\n\t\t * @namespace\n\t\t */\n\t\ttype: {\n\t\t\t/**\n\t\t\t * Type detection functions.\n\t\t\t *\n\t\t\t * The functions defined in this object are used to automatically detect\n\t\t\t * a column's type, making initialisation of DataTables super easy, even\n\t\t\t * when complex data is in the table.\n\t\t\t *\n\t\t\t * The functions defined take two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be analysed\n\t\t     *  2. `{settings}` DataTables settings object. This can be used to\n\t\t     *     perform context specific type detection - for example detection\n\t\t     *     based on language settings such as using a comma for a decimal\n\t\t     *     place. Generally speaking the options from the settings will not\n\t\t     *     be required\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Data type detected, or null if unknown (and thus\n\t\t\t *   pass it on to the other type detection functions.\n\t\t\t *\n\t\t\t *  @type array\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Currency type detection plug-in:\n\t\t\t *    $.fn.dataTable.ext.type.detect.push(\n\t\t\t *      function ( data, settings ) {\n\t\t\t *        // Check the numeric part\n\t\t\t *        if ( ! $.isNumeric( data.substring(1) ) ) {\n\t\t\t *          return null;\n\t\t\t *        }\n\t\t\t *\n\t\t\t *        // Check prefixed by currency\n\t\t\t *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {\n\t\t\t *          return 'currency';\n\t\t\t *        }\n\t\t\t *        return null;\n\t\t\t *      }\n\t\t\t *    );\n\t\t\t */\n\t\t\tdetect: [],\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based search formatting.\n\t\t\t *\n\t\t\t * The type based searching functions can be used to pre-format the\n\t\t\t * data to be search on. For example, it can be used to strip HTML\n\t\t\t * tags or to de-format telephone numbers for numeric only searching.\n\t\t\t *\n\t\t\t * Note that is a search is not defined for a column of a given type,\n\t\t\t * no search formatting will be performed.\n\t\t\t * \n\t\t\t * Pre-processing of searching data plug-ins - When you assign the sType\n\t\t\t * for a column (or have it automatically detected for you by DataTables\n\t\t\t * or a type detection plug-in), you will typically be using this for\n\t\t\t * custom sorting, but it can also be used to provide custom searching\n\t\t\t * by allowing you to pre-processing the data and returning the data in\n\t\t\t * the format that should be searched upon. This is done by adding\n\t\t\t * functions this object with a parameter name which matches the sType\n\t\t\t * for that target column. This is the corollary of <i>afnSortData</i>\n\t\t\t * for searching data.\n\t\t\t *\n\t\t\t * The functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for searching\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Formatted string that will be used for the searching.\n\t\t\t *\n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {\n\t\t\t *      return d.replace(/\\n/g,\" \").replace( /<.*?>/g, \"\" );\n\t\t\t *    }\n\t\t\t */\n\t\t\tsearch: {},\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based ordering.\n\t\t\t *\n\t\t\t * The column type tells DataTables what ordering to apply to the table\n\t\t\t * when a column is sorted upon. The order for each type that is defined,\n\t\t\t * is defined by the functions available in this object.\n\t\t\t *\n\t\t\t * Each ordering option can be described by three properties added to\n\t\t\t * this object:\n\t\t\t *\n\t\t\t * * `{type}-pre` - Pre-formatting function\n\t\t\t * * `{type}-asc` - Ascending order function\n\t\t\t * * `{type}-desc` - Descending order function\n\t\t\t *\n\t\t\t * All three can be used together, only `{type}-pre` or only\n\t\t\t * `{type}-asc` and `{type}-desc` together. It is generally recommended\n\t\t\t * that only `{type}-pre` is used, as this provides the optimal\n\t\t\t * implementation in terms of speed, although the others are provided\n\t\t\t * for compatibility with existing Javascript sort functions.\n\t\t\t *\n\t\t\t * `{type}-pre`: Functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for ordering\n\t\t\t *\n\t\t\t * And return:\n\t\t\t *\n\t\t\t * * `{*}` Data to be sorted upon\n\t\t\t *\n\t\t\t * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort\n\t\t\t * functions, taking two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data to compare to the second parameter\n\t\t     *  2. `{*}` Data to compare to the first parameter\n\t\t\t *\n\t\t\t * And returning:\n\t\t\t *\n\t\t\t * * `{*}` Ordering match: <0 if first parameter should be sorted lower\n\t\t\t *   than the second parameter, ===0 if the two parameters are equal and\n\t\t\t *   >0 if the first parameter should be sorted height than the second\n\t\t\t *   parameter.\n\t\t\t * \n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Numeric ordering of formatted numbers with a pre-formatter\n\t\t\t *    $.extend( $.fn.dataTable.ext.type.order, {\n\t\t\t *      \"string-pre\": function(x) {\n\t\t\t *        a = (a === \"-\" || a === \"\") ? 0 : a.replace( /[^\\d\\-\\.]/g, \"\" );\n\t\t\t *        return parseFloat( a );\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Case-sensitive string ordering, with no pre-formatting method\n\t\t\t *    $.extend( $.fn.dataTable.ext.order, {\n\t\t\t *      \"string-case-asc\": function(x,y) {\n\t\t\t *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t\t *      },\n\t\t\t *      \"string-case-desc\": function(x,y) {\n\t\t\t *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t */\n\t\t\torder: {}\n\t\t},\n\t\n\t\t/**\n\t\t * Unique DataTables instance counter\n\t\t *\n\t\t * @type int\n\t\t * @private\n\t\t */\n\t\t_unique: 0,\n\t\n\t\n\t\t//\n\t\t// Depreciated\n\t\t// The following properties are retained for backwards compatiblity only.\n\t\t// The should not be used in new projects and will be removed in a future\n\t\t// version\n\t\t//\n\t\n\t\t/**\n\t\t * Version check function.\n\t\t *  @type function\n\t\t *  @depreciated Since 1.10\n\t\t */\n\t\tfnVersionCheck: DataTable.fnVersionCheck,\n\t\n\t\n\t\t/**\n\t\t * Index for what 'this' index API functions should use\n\t\t *  @type int\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tiApiIndex: 0,\n\t\n\t\n\t\t/**\n\t\t * jQuery UI class container\n\t\t *  @type object\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\toJUIClasses: {},\n\t\n\t\n\t\t/**\n\t\t * Software version\n\t\t *  @type string\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tsVersion: DataTable.version\n\t};\n\t\n\t\n\t//\n\t// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts\n\t//\n\t$.extend( _ext, {\n\t\tafnFiltering: _ext.search,\n\t\taTypes:       _ext.type.detect,\n\t\tofnSearch:    _ext.type.search,\n\t\toSort:        _ext.type.order,\n\t\tafnSortData:  _ext.order,\n\t\taoFeatures:   _ext.feature,\n\t\toApi:         _ext.internal,\n\t\toStdClasses:  _ext.classes,\n\t\toPagination:  _ext.pager\n\t} );\n\t\n\t\n\t$.extend( DataTable.ext.classes, {\n\t\t\"sTable\": \"dataTable\",\n\t\t\"sNoFooter\": \"no-footer\",\n\t\n\t\t/* Paging buttons */\n\t\t\"sPageButton\": \"paginate_button\",\n\t\t\"sPageButtonActive\": \"current\",\n\t\t\"sPageButtonDisabled\": \"disabled\",\n\t\n\t\t/* Striping classes */\n\t\t\"sStripeOdd\": \"odd\",\n\t\t\"sStripeEven\": \"even\",\n\t\n\t\t/* Empty row */\n\t\t\"sRowEmpty\": \"dataTables_empty\",\n\t\n\t\t/* Features */\n\t\t\"sWrapper\": \"dataTables_wrapper\",\n\t\t\"sFilter\": \"dataTables_filter\",\n\t\t\"sInfo\": \"dataTables_info\",\n\t\t\"sPaging\": \"dataTables_paginate paging_\", /* Note that the type is postfixed */\n\t\t\"sLength\": \"dataTables_length\",\n\t\t\"sProcessing\": \"dataTables_processing\",\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\": \"sorting_asc\",\n\t\t\"sSortDesc\": \"sorting_desc\",\n\t\t\"sSortable\": \"sorting\", /* Sortable in both directions */\n\t\t\"sSortableAsc\": \"sorting_asc_disabled\",\n\t\t\"sSortableDesc\": \"sorting_desc_disabled\",\n\t\t\"sSortableNone\": \"sorting_disabled\",\n\t\t\"sSortColumn\": \"sorting_\", /* Note that an int is postfixed for the sorting order */\n\t\n\t\t/* Filtering */\n\t\t\"sFilterInput\": \"\",\n\t\n\t\t/* Page length */\n\t\t\"sLengthSelect\": \"\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollWrapper\": \"dataTables_scroll\",\n\t\t\"sScrollHead\": \"dataTables_scrollHead\",\n\t\t\"sScrollHeadInner\": \"dataTables_scrollHeadInner\",\n\t\t\"sScrollBody\": \"dataTables_scrollBody\",\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot\",\n\t\t\"sScrollFootInner\": \"dataTables_scrollFootInner\",\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\": \"\",\n\t\t\"sFooterTH\": \"\",\n\t\n\t\t// Deprecated\n\t\t\"sSortJUIAsc\": \"\",\n\t\t\"sSortJUIDesc\": \"\",\n\t\t\"sSortJUI\": \"\",\n\t\t\"sSortJUIAscAllowed\": \"\",\n\t\t\"sSortJUIDescAllowed\": \"\",\n\t\t\"sSortJUIWrapper\": \"\",\n\t\t\"sSortIcon\": \"\",\n\t\t\"sJUIHeader\": \"\",\n\t\t\"sJUIFooter\": \"\"\n\t} );\n\t\n\t\n\t(function() {\n\t\n\t// Reused strings for better compression. Closure compiler appears to have a\n\t// weird edge case where it is trying to expand strings rather than use the\n\t// variable version. This results in about 200 bytes being added, for very\n\t// little preference benefit since it this run on script load only.\n\tvar _empty = '';\n\t_empty = '';\n\t\n\tvar _stateDefault = _empty + 'ui-state-default';\n\tvar _sortIcon     = _empty + 'css_right ui-icon ui-icon-';\n\tvar _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';\n\t\n\t$.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {\n\t\t/* Full numbers paging buttons */\n\t\t\"sPageButton\":         \"fg-button ui-button \"+_stateDefault,\n\t\t\"sPageButtonActive\":   \"ui-state-disabled\",\n\t\t\"sPageButtonDisabled\": \"ui-state-disabled\",\n\t\n\t\t/* Features */\n\t\t\"sPaging\": \"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi \"+\n\t\t\t\"ui-buttonset-multi paging_\", /* Note that the type is postfixed */\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\":            _stateDefault+\" sorting_asc\",\n\t\t\"sSortDesc\":           _stateDefault+\" sorting_desc\",\n\t\t\"sSortable\":           _stateDefault+\" sorting\",\n\t\t\"sSortableAsc\":        _stateDefault+\" sorting_asc_disabled\",\n\t\t\"sSortableDesc\":       _stateDefault+\" sorting_desc_disabled\",\n\t\t\"sSortableNone\":       _stateDefault+\" sorting_disabled\",\n\t\t\"sSortJUIAsc\":         _sortIcon+\"triangle-1-n\",\n\t\t\"sSortJUIDesc\":        _sortIcon+\"triangle-1-s\",\n\t\t\"sSortJUI\":            _sortIcon+\"carat-2-n-s\",\n\t\t\"sSortJUIAscAllowed\":  _sortIcon+\"carat-1-n\",\n\t\t\"sSortJUIDescAllowed\": _sortIcon+\"carat-1-s\",\n\t\t\"sSortJUIWrapper\":     \"DataTables_sort_wrapper\",\n\t\t\"sSortIcon\":           \"DataTables_sort_icon\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollHead\": \"dataTables_scrollHead \"+_stateDefault,\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot \"+_stateDefault,\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\":  _stateDefault,\n\t\t\"sFooterTH\":  _stateDefault,\n\t\t\"sJUIHeader\": _headerFooter+\" ui-corner-tl ui-corner-tr\",\n\t\t\"sJUIFooter\": _headerFooter+\" ui-corner-bl ui-corner-br\"\n\t} );\n\t\n\t}());\n\t\n\t\n\t\n\tvar extPagination = DataTable.ext.pager;\n\t\n\tfunction _numbers ( page, pages ) {\n\t\tvar\n\t\t\tnumbers = [],\n\t\t\tbuttons = extPagination.numbers_length,\n\t\t\thalf = Math.floor( buttons / 2 ),\n\t\t\ti = 1;\n\t\n\t\tif ( pages <= buttons ) {\n\t\t\tnumbers = _range( 0, pages );\n\t\t}\n\t\telse if ( page <= half ) {\n\t\t\tnumbers = _range( 0, buttons-2 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t}\n\t\telse if ( page >= pages - 1 - half ) {\n\t\t\tnumbers = _range( pages-(buttons-2), pages );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\telse {\n\t\t\tnumbers = _range( page-half+2, page+half-1 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' );\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\n\t\tnumbers.DT_el = 'span';\n\t\treturn numbers;\n\t}\n\t\n\t\n\t$.extend( extPagination, {\n\t\tsimple: function ( page, pages ) {\n\t\t\treturn [ 'previous', 'next' ];\n\t\t},\n\t\n\t\tfull: function ( page, pages ) {\n\t\t\treturn [  'first', 'previous', 'next', 'last' ];\n\t\t},\n\t\n\t\tnumbers: function ( page, pages ) {\n\t\t\treturn [ _numbers(page, pages) ];\n\t\t},\n\t\n\t\tsimple_numbers: function ( page, pages ) {\n\t\t\treturn [ 'previous', _numbers(page, pages), 'next' ];\n\t\t},\n\t\n\t\tfull_numbers: function ( page, pages ) {\n\t\t\treturn [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];\n\t\t},\n\t\t\n\t\tfirst_last_numbers: function (page, pages) {\n\t \t\treturn ['first', _numbers(page, pages), 'last'];\n\t \t},\n\t\n\t\t// For testing and plug-ins to use\n\t\t_numbers: _numbers,\n\t\n\t\t// Number of number buttons (including ellipsis) to show. _Must be odd!_\n\t\tnumbers_length: 7\n\t} );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\tpageButton: {\n\t\t\t_: function ( settings, host, idx, buttons, page, pages ) {\n\t\t\t\tvar classes = settings.oClasses;\n\t\t\t\tvar lang = settings.oLanguage.oPaginate;\n\t\t\t\tvar aria = settings.oLanguage.oAria.paginate || {};\n\t\t\t\tvar btnDisplay, btnClass, counter=0;\n\t\n\t\t\t\tvar attach = function( container, buttons ) {\n\t\t\t\t\tvar i, ien, node, button;\n\t\t\t\t\tvar clickHandler = function ( e ) {\n\t\t\t\t\t\t_fnPageChange( settings, e.data.action, true );\n\t\t\t\t\t};\n\t\n\t\t\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tbutton = buttons[i];\n\t\n\t\t\t\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\t\t\t\tvar inner = $( '<'+(button.DT_el || 'div')+'/>' )\n\t\t\t\t\t\t\t\t.appendTo( container );\n\t\t\t\t\t\t\tattach( inner, button );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tbtnDisplay = null;\n\t\t\t\t\t\t\tbtnClass = '';\n\t\n\t\t\t\t\t\t\tswitch ( button ) {\n\t\t\t\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\t\t\t\tcontainer.append('<span class=\"ellipsis\">&#x2026;</span>');\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'first':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'next':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'last':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t\t\t\tclasses.sPageButtonActive : '';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\tif ( btnDisplay !== null ) {\n\t\t\t\t\t\t\t\tnode = $('<a>', {\n\t\t\t\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t\t\t\t.appendTo( container );\n\t\n\t\t\t\t\t\t\t\t_fnBindAction(\n\t\t\t\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t\t\t\t);\n\t\n\t\t\t\t\t\t\t\tcounter++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame. Try / catch the error. Not good for\n\t\t\t\t// accessibility, but neither are frames.\n\t\t\t\tvar activeEl;\n\t\n\t\t\t\ttry {\n\t\t\t\t\t// Because this approach is destroying and recreating the paging\n\t\t\t\t\t// elements, focus is lost on the select button which is bad for\n\t\t\t\t\t// accessibility. So we want to restore focus once the draw has\n\t\t\t\t\t// completed\n\t\t\t\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t\t\t\t}\n\t\t\t\tcatch (e) {}\n\t\n\t\t\t\tattach( $(host).empty(), buttons );\n\t\n\t\t\t\tif ( activeEl !== undefined ) {\n\t\t\t\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t\n\t\n\t// Built in type detection. See model.ext.aTypes for information about\n\t// what is required from this methods.\n\t$.extend( DataTable.ext.type.detect, [\n\t\t// Plain numbers - first since V8 detects some plain numbers as dates\n\t\t// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal ) ? 'num'+decimal : null;\n\t\t},\n\t\n\t\t// Dates (only those recognised by the browser's Date.parse)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\t// V8 tries _very_ hard to make a string passed into `Date.parse()`\n\t\t\t// valid, so we need to use a regex to restrict date formats. Use a\n\t\t\t// plug-in for anything other than ISO8601 style strings\n\t\t\tif ( d && !(d instanceof Date) && ! _re_date.test(d) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tvar parsed = Date.parse(d);\n\t\t\treturn (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;\n\t\t},\n\t\n\t\t// Formatted numbers\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric, formatted\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML (this is strict checking - there must be html)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\treturn _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?\n\t\t\t\t'html' : null;\n\t\t}\n\t] );\n\t\n\t\n\t\n\t// Filter formatting functions. See model.ext.ofnSearch for information about\n\t// what is required from these methods.\n\t// \n\t// Note that additional search methods are added for the html numbers and\n\t// html formatted numbers by `_addNumericSort()` when we know what the decimal\n\t// place is\n\t\n\t\n\t$.extend( DataTable.ext.type.search, {\n\t\thtml: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata\n\t\t\t\t\t\t.replace( _re_new_lines, \" \" )\n\t\t\t\t\t\t.replace( _re_html, \"\" ) :\n\t\t\t\t\t'';\n\t\t},\n\t\n\t\tstring: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata.replace( _re_new_lines, \" \" ) :\n\t\t\t\t\tdata;\n\t\t}\n\t} );\n\t\n\t\n\t\n\tvar __numericReplace = function ( d, decimalPlace, re1, re2 ) {\n\t\tif ( d !== 0 && (!d || d === '-') ) {\n\t\t\treturn -Infinity;\n\t\t}\n\t\n\t\t// If a decimal place other than `.` is used, it needs to be given to the\n\t\t// function so we can detect it and replace with a `.` which is the only\n\t\t// decimal place Javascript recognises - it is not locale aware.\n\t\tif ( decimalPlace ) {\n\t\t\td = _numToDecimal( d, decimalPlace );\n\t\t}\n\t\n\t\tif ( d.replace ) {\n\t\t\tif ( re1 ) {\n\t\t\t\td = d.replace( re1, '' );\n\t\t\t}\n\t\n\t\t\tif ( re2 ) {\n\t\t\t\td = d.replace( re2, '' );\n\t\t\t}\n\t\t}\n\t\n\t\treturn d * 1;\n\t};\n\t\n\t\n\t// Add the numeric 'deformatting' functions for sorting and search. This is done\n\t// in a function to provide an easy ability for the language options to add\n\t// additional methods if a non-period decimal place is used.\n\tfunction _addNumericSort ( decimalPlace ) {\n\t\t$.each(\n\t\t\t{\n\t\t\t\t// Plain numbers\n\t\t\t\t\"num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace );\n\t\t\t\t},\n\t\n\t\t\t\t// Formatted numbers\n\t\t\t\t\"num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_formatted_numeric );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric\n\t\t\t\t\"html-num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric, formatted\n\t\t\t\t\"html-num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );\n\t\t\t\t}\n\t\t\t},\n\t\t\tfunction ( key, fn ) {\n\t\t\t\t// Add the ordering method\n\t\t\t\t_ext.type.order[ key+decimalPlace+'-pre' ] = fn;\n\t\n\t\t\t\t// For HTML types add a search formatter that will strip the HTML\n\t\t\t\tif ( key.match(/^html\\-/) ) {\n\t\t\t\t\t_ext.type.search[ key+decimalPlace ] = _ext.type.search.html;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\t\n\t\n\t// Default sort methods\n\t$.extend( _ext.type.order, {\n\t\t// Dates\n\t\t\"date-pre\": function ( d ) {\n\t\t\treturn Date.parse( d ) || -Infinity;\n\t\t},\n\t\n\t\t// html\n\t\t\"html-pre\": function ( a ) {\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ta.replace ?\n\t\t\t\t\ta.replace( /<.*?>/g, \"\" ).toLowerCase() :\n\t\t\t\t\ta+'';\n\t\t},\n\t\n\t\t// string\n\t\t\"string-pre\": function ( a ) {\n\t\t\t// This is a little complex, but faster than always calling toString,\n\t\t\t// http://jsperf.com/tostring-v-check\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ttypeof a === 'string' ?\n\t\t\t\t\ta.toLowerCase() :\n\t\t\t\t\t! a.toString ?\n\t\t\t\t\t\t'' :\n\t\t\t\t\t\ta.toString();\n\t\t},\n\t\n\t\t// string-asc and -desc are retained only for compatibility with the old\n\t\t// sort methods\n\t\t\"string-asc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t},\n\t\n\t\t\"string-desc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t}\n\t} );\n\t\n\t\n\t// Numeric sorting types - order doesn't matter here\n\t_addNumericSort( '' );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\theader: {\n\t\t\t_: function ( settings, cell, column, classes ) {\n\t\t\t\t// No additional mark-up required\n\t\t\t\t// Attach a sort listener to update on sort - note that using the\n\t\t\t\t// `DT` namespace will allow the event to be removed automatically\n\t\t\t\t// on destroy, while the `dt` namespaced event is the one we are\n\t\t\t\t// listening for\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) { // need to check this this is the host\n\t\t\t\t\t\treturn;               // table, not a nested one\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tcolumn.sSortingClass +' '+\n\t\t\t\t\t\t\tclasses.sSortAsc +' '+\n\t\t\t\t\t\t\tclasses.sSortDesc\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t},\n\t\n\t\t\tjqueryui: function ( settings, cell, column, classes ) {\n\t\t\t\t$('<div/>')\n\t\t\t\t\t.addClass( classes.sSortJUIWrapper )\n\t\t\t\t\t.append( cell.contents() )\n\t\t\t\t\t.append( $('<span/>')\n\t\t\t\t\t\t.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo( cell );\n\t\n\t\t\t\t// Attach a sort listener to update on sort\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.find( 'span.'+classes.sSortIcon )\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tclasses.sSortJUIAsc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDesc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUI +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIAscAllowed +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDescAllowed\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortJUIAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortJUIDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClassJUI\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t/*\n\t * Public helper functions. These aren't used internally by DataTables, or\n\t * called by any of the options passed into DataTables, but they can be used\n\t * externally by developers working with DataTables. They are helper functions\n\t * to make working with DataTables a little bit easier.\n\t */\n\t\n\tvar __htmlEscapeEntities = function ( d ) {\n\t\treturn typeof d === 'string' ?\n\t\t\td.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;') :\n\t\t\td;\n\t};\n\t\n\t/**\n\t * Helpers for `columns.render`.\n\t *\n\t * The options defined here can be used with the `columns.render` initialisation\n\t * option to provide a display renderer. The following functions are defined:\n\t *\n\t * * `number` - Will format numeric data (defined by `columns.data`) for\n\t *   display, retaining the original unformatted data for sorting and filtering.\n\t *   It takes 5 parameters:\n\t *   * `string` - Thousands grouping separator\n\t *   * `string` - Decimal point indicator\n\t *   * `integer` - Number of decimal points to show\n\t *   * `string` (optional) - Prefix.\n\t *   * `string` (optional) - Postfix (/suffix).\n\t * * `text` - Escape HTML to help prevent XSS attacks. It has no optional\n\t *   parameters.\n\t *\n\t * @example\n\t *   // Column definition using the number renderer\n\t *   {\n\t *     data: \"salary\",\n\t *     render: $.fn.dataTable.render.number( '\\'', '.', 0, '$' )\n\t *   }\n\t *\n\t * @namespace\n\t */\n\tDataTable.render = {\n\t\tnumber: function ( thousands, decimal, precision, prefix, postfix ) {\n\t\t\treturn {\n\t\t\t\tdisplay: function ( d ) {\n\t\t\t\t\tif ( typeof d !== 'number' && typeof d !== 'string' ) {\n\t\t\t\t\t\treturn d;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar negative = d < 0 ? '-' : '';\n\t\t\t\t\tvar flo = parseFloat( d );\n\t\n\t\t\t\t\t// If NaN then there isn't much formatting that we can do - just\n\t\t\t\t\t// return immediately, escaping any HTML (this was supposed to\n\t\t\t\t\t// be a number after all)\n\t\t\t\t\tif ( isNaN( flo ) ) {\n\t\t\t\t\t\treturn __htmlEscapeEntities( d );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tflo = flo.toFixed( precision );\n\t\t\t\t\td = Math.abs( flo );\n\t\n\t\t\t\t\tvar intPart = parseInt( d, 10 );\n\t\t\t\t\tvar floatPart = precision ?\n\t\t\t\t\t\tdecimal+(d - intPart).toFixed( precision ).substring( 2 ):\n\t\t\t\t\t\t'';\n\t\n\t\t\t\t\treturn negative + (prefix||'') +\n\t\t\t\t\t\tintPart.toString().replace(\n\t\t\t\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g, thousands\n\t\t\t\t\t\t) +\n\t\t\t\t\t\tfloatPart +\n\t\t\t\t\t\t(postfix||'');\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\ttext: function () {\n\t\t\treturn {\n\t\t\t\tdisplay: __htmlEscapeEntities\n\t\t\t};\n\t\t}\n\t};\n\t\n\t\n\t/*\n\t * This is really a good bit rubbish this method of exposing the internal methods\n\t * publicly... - To be fixed in 2.0 using methods on the prototype\n\t */\n\t\n\t\n\t/**\n\t * Create a wrapper function for exporting an internal functions to an external API.\n\t *  @param {string} fn API function name\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#internal\n\t */\n\tfunction _fnExternApiFunc (fn)\n\t{\n\t\treturn function() {\n\t\t\tvar args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(\n\t\t\t\tArray.prototype.slice.call(arguments)\n\t\t\t);\n\t\t\treturn DataTable.ext.internal[fn].apply( this, args );\n\t\t};\n\t}\n\t\n\t\n\t/**\n\t * Reference to internal functions for use by plug-in developers. Note that\n\t * these methods are references to internal functions and are considered to be\n\t * private. If you use these methods, be aware that they are liable to change\n\t * between versions.\n\t *  @namespace\n\t */\n\t$.extend( DataTable.ext.internal, {\n\t\t_fnExternApiFunc: _fnExternApiFunc,\n\t\t_fnBuildAjax: _fnBuildAjax,\n\t\t_fnAjaxUpdate: _fnAjaxUpdate,\n\t\t_fnAjaxParameters: _fnAjaxParameters,\n\t\t_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,\n\t\t_fnAjaxDataSrc: _fnAjaxDataSrc,\n\t\t_fnAddColumn: _fnAddColumn,\n\t\t_fnColumnOptions: _fnColumnOptions,\n\t\t_fnAdjustColumnSizing: _fnAdjustColumnSizing,\n\t\t_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,\n\t\t_fnColumnIndexToVisible: _fnColumnIndexToVisible,\n\t\t_fnVisbleColumns: _fnVisbleColumns,\n\t\t_fnGetColumns: _fnGetColumns,\n\t\t_fnColumnTypes: _fnColumnTypes,\n\t\t_fnApplyColumnDefs: _fnApplyColumnDefs,\n\t\t_fnHungarianMap: _fnHungarianMap,\n\t\t_fnCamelToHungarian: _fnCamelToHungarian,\n\t\t_fnLanguageCompat: _fnLanguageCompat,\n\t\t_fnBrowserDetect: _fnBrowserDetect,\n\t\t_fnAddData: _fnAddData,\n\t\t_fnAddTr: _fnAddTr,\n\t\t_fnNodeToDataIndex: _fnNodeToDataIndex,\n\t\t_fnNodeToColumnIndex: _fnNodeToColumnIndex,\n\t\t_fnGetCellData: _fnGetCellData,\n\t\t_fnSetCellData: _fnSetCellData,\n\t\t_fnSplitObjNotation: _fnSplitObjNotation,\n\t\t_fnGetObjectDataFn: _fnGetObjectDataFn,\n\t\t_fnSetObjectDataFn: _fnSetObjectDataFn,\n\t\t_fnGetDataMaster: _fnGetDataMaster,\n\t\t_fnClearTable: _fnClearTable,\n\t\t_fnDeleteIndex: _fnDeleteIndex,\n\t\t_fnInvalidate: _fnInvalidate,\n\t\t_fnGetRowElements: _fnGetRowElements,\n\t\t_fnCreateTr: _fnCreateTr,\n\t\t_fnBuildHead: _fnBuildHead,\n\t\t_fnDrawHead: _fnDrawHead,\n\t\t_fnDraw: _fnDraw,\n\t\t_fnReDraw: _fnReDraw,\n\t\t_fnAddOptionsHtml: _fnAddOptionsHtml,\n\t\t_fnDetectHeader: _fnDetectHeader,\n\t\t_fnGetUniqueThs: _fnGetUniqueThs,\n\t\t_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,\n\t\t_fnFilterComplete: _fnFilterComplete,\n\t\t_fnFilterCustom: _fnFilterCustom,\n\t\t_fnFilterColumn: _fnFilterColumn,\n\t\t_fnFilter: _fnFilter,\n\t\t_fnFilterCreateSearch: _fnFilterCreateSearch,\n\t\t_fnEscapeRegex: _fnEscapeRegex,\n\t\t_fnFilterData: _fnFilterData,\n\t\t_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,\n\t\t_fnUpdateInfo: _fnUpdateInfo,\n\t\t_fnInfoMacros: _fnInfoMacros,\n\t\t_fnInitialise: _fnInitialise,\n\t\t_fnInitComplete: _fnInitComplete,\n\t\t_fnLengthChange: _fnLengthChange,\n\t\t_fnFeatureHtmlLength: _fnFeatureHtmlLength,\n\t\t_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,\n\t\t_fnPageChange: _fnPageChange,\n\t\t_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,\n\t\t_fnProcessingDisplay: _fnProcessingDisplay,\n\t\t_fnFeatureHtmlTable: _fnFeatureHtmlTable,\n\t\t_fnScrollDraw: _fnScrollDraw,\n\t\t_fnApplyToChildren: _fnApplyToChildren,\n\t\t_fnCalculateColumnWidths: _fnCalculateColumnWidths,\n\t\t_fnThrottle: _fnThrottle,\n\t\t_fnConvertToWidth: _fnConvertToWidth,\n\t\t_fnGetWidestNode: _fnGetWidestNode,\n\t\t_fnGetMaxLenString: _fnGetMaxLenString,\n\t\t_fnStringToCss: _fnStringToCss,\n\t\t_fnSortFlatten: _fnSortFlatten,\n\t\t_fnSort: _fnSort,\n\t\t_fnSortAria: _fnSortAria,\n\t\t_fnSortListener: _fnSortListener,\n\t\t_fnSortAttachListener: _fnSortAttachListener,\n\t\t_fnSortingClasses: _fnSortingClasses,\n\t\t_fnSortData: _fnSortData,\n\t\t_fnSaveState: _fnSaveState,\n\t\t_fnLoadState: _fnLoadState,\n\t\t_fnSettingsFromNode: _fnSettingsFromNode,\n\t\t_fnLog: _fnLog,\n\t\t_fnMap: _fnMap,\n\t\t_fnBindAction: _fnBindAction,\n\t\t_fnCallbackReg: _fnCallbackReg,\n\t\t_fnCallbackFire: _fnCallbackFire,\n\t\t_fnLengthOverflow: _fnLengthOverflow,\n\t\t_fnRenderer: _fnRenderer,\n\t\t_fnDataSource: _fnDataSource,\n\t\t_fnRowAttributes: _fnRowAttributes,\n\t\t_fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant\n\t\t                                // in 1.10, so this dead-end function is\n\t\t                                // added to prevent errors\n\t} );\n\t\n\n\t// jQuery access\n\t$.fn.dataTable = DataTable;\n\n\t// Provide access to the host jQuery object (circular reference)\n\tDataTable.$ = $;\n\n\t// Legacy aliases\n\t$.fn.dataTableSettings = DataTable.settings;\n\t$.fn.dataTableExt = DataTable.ext;\n\n\t// With a capital `D` we return a DataTables API instance rather than a\n\t// jQuery object\n\t$.fn.DataTable = function ( opts ) {\n\t\treturn $(this).dataTable( opts ).api();\n\t};\n\n\t// All properties that are available to $.fn.dataTable should also be\n\t// available on $.fn.DataTable\n\t$.each( DataTable, function ( prop, val ) {\n\t\t$.fn.DataTable[ prop ] = val;\n\t} );\n\n\n\t// Information about events fired by DataTables - for documentation.\n\t/**\n\t * Draw event, fired whenever the table is redrawn on the page, at the same\n\t * point as fnDrawCallback. This may be useful for binding events or\n\t * performing calculations when the table is altered at all.\n\t *  @name DataTable#draw.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Search event, fired when the searching applied to the table (using the\n\t * built-in global search, or column filters) is altered.\n\t *  @name DataTable#search.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page change event, fired when the paging of the table is altered.\n\t *  @name DataTable#page.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Order event, fired when the ordering applied to the table is altered.\n\t *  @name DataTable#order.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * DataTables initialisation complete event, fired when the table is fully\n\t * drawn, including Ajax data loaded, if Ajax data is required.\n\t *  @name DataTable#init.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The JSON object request from the server - only\n\t *    present if client-side Ajax sourced data is used</li></ol>\n\t */\n\n\t/**\n\t * State save event, fired when the table has changed state a new state save\n\t * is required. This event allows modification of the state saving object\n\t * prior to actually doing the save, including addition or other state\n\t * properties (for plug-ins) or modification of a DataTables core property.\n\t *  @name DataTable#stateSaveParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The state information to be saved\n\t */\n\n\t/**\n\t * State load event, fired when the table is loading state from the stored\n\t * data, but prior to the settings object being modified by the saved state\n\t * - allowing modification of the saved state is required or loading of\n\t * state for a plug-in.\n\t *  @name DataTable#stateLoadParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * State loaded event, fired when state has been loaded from stored data and\n\t * the settings object has been modified by the loaded data.\n\t *  @name DataTable#stateLoaded.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * Processing event, fired when DataTables is doing some kind of processing\n\t * (be it, order, searcg or anything else). It can be used to indicate to\n\t * the end user that there is something happening, or that something has\n\t * finished.\n\t *  @name DataTable#processing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {boolean} bShow Flag for if DataTables is doing processing or not\n\t */\n\n\t/**\n\t * Ajax (XHR) event, fired whenever an Ajax request is completed from a\n\t * request to made to the server for new data. This event is called before\n\t * DataTables processed the returned data, so it can also be used to pre-\n\t * process the data returned from the server, if needed.\n\t *\n\t * Note that this trigger is called in `fnServerData`, if you override\n\t * `fnServerData` and which to use this event, you need to trigger it in you\n\t * success function.\n\t *  @name DataTable#xhr.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {object} json JSON returned from the server\n\t *\n\t *  @example\n\t *     // Use a custom property returned from the server in another DOM element\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       $('#status').html( json.status );\n\t *     } );\n\t *\n\t *  @example\n\t *     // Pre-process the data returned from the server\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {\n\t *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;\n\t *       }\n\t *       // Note no return - manipulate the data directly in the JSON object.\n\t *     } );\n\t */\n\n\t/**\n\t * Destroy event, fired when the DataTable is destroyed by calling fnDestroy\n\t * or passing the bDestroy:true parameter in the initialisation object. This\n\t * can be used to remove bound events, added DOM nodes, etc.\n\t *  @name DataTable#destroy.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page length change event, fired when number of records to show on each\n\t * page (the length) is changed.\n\t *  @name DataTable#length.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {integer} len New length\n\t */\n\n\t/**\n\t * Column sizing has changed.\n\t *  @name DataTable#column-sizing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Column visibility has changed.\n\t *  @name DataTable#column-visibility.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {int} column Column index\n\t *  @param {bool} vis `false` if column now hidden, or `true` if visible\n\t */\n\n\treturn $.fn.dataTable;\n}));\n\n\n"
  },
  {
    "path": "www/partial/about-help.html",
    "content": "<div class=\"mdl-cell mdl-cell--12-col mdl-card mdl-shadow--4dp\">\n    <div class=\"mdl-card__title\">\n        <h2 class=\"mdl-card__title-text\">About & Help</h2>\n    </div>\n\n    <div class=\"mdl-card__supporting-text\">\n        <h5><i class=\"material-icons\">bug_report</i> Bugs? Feedback?</h5>\n        <p>Please, fell free to write me an issue on the <a href=\"https://github.com/friimaind?tab=repositories\">Github project page</a>.</p>\n        \n        <hr />\n        \n        <h5><i class=\"material-icons\">help_outline</i> Help</h5>        \n        <p>If you get here you need help to find the credential for your Pi-hole. It's very easy!</p>\n        <p>On the App setting page you need to insert the <strong>IP of your Pi-hole</strong> (for example http://192.168.1.2) or the <strong>hostname</strong> (for example http://mypyhole.local). Note that you can also specify a <strong>custom port</strong> with this format http://192.168.1.2:99 and obviously you can use <strong>https</strong>.</p>\n        <p>The <strong>token string</strong> is required for access the Pi-hole's API and extract charts, table etc.<br />These credentials are <strong>saved locally</strong> on your smartphone.</p>\n        <p>To obtain the token string you can access to the admin web page of your Pi-hole and <strong>scan the QR code</strong> with your smartphone:</p>\n        <ul>\n            <li>Connect to your Pi-hole with a computer: http://RASPBERRY_IP/admin</li>\n            <li>Login and go to Settings</li>\n            <li>On the API tab click on \"Show API token\". It will open a new page with the QR code</li>\n            <li>On your smartphone click on the QR code scan icon near the token field</li>\n        </ul>\n        <p><em>Please note:</em> \"Show API token\" function is present on Pi-hole >= 2.5 Web Interface Version.</p>\n        <p>You can even obtain the token string with a manual operation: the token string is inside your Raspberry, I suggest you to use a PC and paste it inside Google Keep or any other shared app with your smartphone.</p>\n        <ul>\n            <li>Connect to your Pi-hole with SSH.<br /><pre class=\"language-markup\"><code>ssh pi@RASPBERRY_IP</code></pre></li>\n            <li>Look at the configuration file<br /><pre class=\"language-markup\"><code>less /etc/pihole/setupVars.conf</code></pre></li>\n            <li>The token is the long string after the <strong>WEBPASSWORD=</strong></li>\n        </ul>\n        \n        <hr />\n        \n        <h5><i class=\"material-icons\">android</i> About this app</h5>\n        <p>First of all: <strong>thank you</strong> for trying this app!</p>\n        <p>I'm <a href=\"https://blog.friimaind.it\">Massimiliano Monaro</a> and I developed this app as a playground to learn Apache Cordova.</p>\n        <p>I am not affiliated to Pi-hole team, this is an unofficial app.</p>\n        <p>It would not have been possible to develop it without the help of some great tools:</p>\n        <ul>\n            <li><a href=\"https://pi-hole.net\">Pi-hole</a>: the main protagonist, it saves my daily web browsing.</li>\n            <li><a href=\"https://cordova.apache.org\">Apache Cordova</a>: this great framework gave me the opportunity to use my favorite languages to develop this native app.</li>\n            <li><a href=\"https://jquery.com\">jQuery</a>: 90% of the app is made with this library.</li>\n            <li><a href=\"https://gionkunz.github.io/chartist-js\">Chartist JS</a>: all charts is made with this wonderful library.</li>\n            <li><a href=\"https://getmdl.io\">MDL</a>: this library helped me to create the graphic interface of the app.</li>\n            <li><a href=\"https://datatables.net\">DataTables</a>: the Query Log page is handled by this jQuery plugin.</li>\n            <li><a href=\"http://hammerjs.github.io\">Hammer.js</a>: the library to recognize touch gestures.</li>\n        </ul>\n        <p>Lastly, I would like to thank my <strong>girlfriend Elisa</strong> who pushes me to accomplish things I love and my former colleague and friend <a href=\"https://melodycode.com/\">Daniele Simonin</a> for his technical help.</p>\n        <p>On Github you can find the <a href=\"https://github.com/friimaind/pi-hole-droid/blob/master/PRIVACY.MD\">Privacy Policy</a>.</p>\n    </div>   \n</div>"
  },
  {
    "path": "www/partial/app-settings.html",
    "content": "<div class=\"mdl-cell mdl-cell--12-col mdl-card mdl-shadow--4dp\">\n    <div class=\"mdl-card__title\">\n        <h2 class=\"mdl-card__title-text\">Settings</h2>\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">vpn_key</i>\n    </div>\n\n    <div class=\"mdl-card__supporting-text\">\n        <p>Please insert here your Pi-hole settings.</p>\n        <p>To obtain the token you can <strong>scan your Pi-hole's QR code</strong> from the admin web page. Click on the icon near the token field.</p>\n        <p>Need help? <a href=\"#/\" id=\"go_to_help\">Go to the Help page</a></p>\n        <form id=\"form_settings\" class=\"fullwidth\" method=\"POST\">\n            <div class=\"mdl-textfield mdl-js-textfield mdl-textfield--floating-label\">\n                <input class=\"mdl-textfield__input\" type=\"url\" id=\"pihole_host\">\n                <label class=\"mdl-textfield__label\" for=\"pihole_host\">Pi-hole's IP or hostname</label>                \n            </div>\n            <div class=\"mdl-textfield mdl-js-textfield mdl-textfield--floating-label\">\n                <input class=\"mdl-textfield__input\" type=\"text\" id=\"pihole_token\">\n                <label class=\"mdl-textfield__label\" for=\"pihole_token\">Pi-hole's token string</label>\n                <img id=\"qrcode_scan\" src=\"img/qrcode-scan.svg\" />\n            </div>\n            \n            <button type=\"submit\" class=\"mdl-button mdl-js-button mdl-button--raised mdl-button--accent\">                                \n                Save                \n            </button>\n        </form>\n    </div>\n\n    <dialog class=\"mdl-dialog\">\n        <h4 class=\"mdl-dialog__title\"><i class=\"material-icons mdl-color-text--red\">warning</i> Uhm...</h4>\n        <div class=\"mdl-dialog__content\">\n            <p>I'm sorry but I <strong>cannot connect</strong> to your Pi-hole.</p>\n            <p>Please insert a valid url (http://IP_OR_HOSTNAME) and the correct token.</p>\n        </div>\n        <div class=\"mdl-dialog__actions\">\n            <button type=\"button\" class=\"mdl-button close\">OK</button>\n        </div>\n    </dialog>\n</div>"
  },
  {
    "path": "www/partial/dashboard.html",
    "content": "<div class=\"centered-element\">\n    <div id=\"ads_blocked_today\" class=\"pihole-card pihole-card-floating mdl-card mdl-shadow--2dp bg-aqua\">\n        <div class=\"mdl-card__title mdl-card--expand\">\n            <h2><i class=\"material-icons loading\">refresh</i></h2>\n        </div>    \n        <div class=\"mdl-card__actions mdl-card--border\">\n            DNS Queries Blocked Today\n\n            <div class=\"mdl-layout-spacer\"></div>\n            <i class=\"material-icons\">today</i>\n        </div>\n    </div>\n\n    <div id=\"dns_queries_today\" class=\"pihole-card pihole-card-floating mdl-card mdl-shadow--2dp bg-green\">\n        <div class=\"mdl-card__title mdl-card--expand\">\n            <h2><i class=\"material-icons loading\">refresh</i></h2>\n        </div>\n        <div class=\"mdl-card__actions mdl-card--border\">\n            DNS Queries Today\n\n            <div class=\"mdl-layout-spacer\"></div>\n            <i class=\"material-icons\">public</i>\n        </div>\n    </div>\n\n    <div id=\"ads_percentage_today\" class=\"pihole-card pihole-card-floating mdl-card mdl-shadow--2dp bg-yellow\">\n        <div class=\"mdl-card__title mdl-card--expand\">\n            <h2><i class=\"material-icons loading\">refresh</i></h2>\n        </div>\n        <div class=\"mdl-card__actions mdl-card--border\">\n            Of Today's Queries Were Blocked\n\n            <div class=\"mdl-layout-spacer\"></div>\n            <i class=\"material-icons\">block</i>\n        </div>\n    </div>\n\n    <div id=\"domains_being_blocked\" class=\"pihole-card pihole-card-floating mdl-card mdl-shadow--2dp bg-red\">\n        <div class=\"mdl-card__title mdl-card--expand\">\n            <h2><i class=\"material-icons loading\">refresh</i></h2>\n        </div>\n        <div class=\"mdl-card__actions mdl-card--border\">\n            Domains Being Blocked\n\n            <div class=\"mdl-layout-spacer\"></div>\n            <i class=\"material-icons\">list</i>\n        </div>\n    </div>\n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Query types\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card__title mdl-card--expand\">        \n        <div class=\"ct-chart ct-chart-query-types\"><i class=\"material-icons loading\">refresh</i></div>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Forward destinations\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">forward</i>\n    </div>\n    <div class=\"mdl-card__title mdl-card--expand\">\n        <div class=\"ct-chart ct-chart-forward-destinations\"><i class=\"material-icons loading\">refresh</i></div>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Top domains\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card--expand\">        \n        <table class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth\">\n            <thead>\n                <tr>\n                    <th class=\"mdl-data-table__cell--non-numeric fullwidth\">Domain</th>\n                    <th class=\"fullwidth\">Hit</th>\n                </tr>\n            </thead>\n            <tbody id=\"tbody-table-top-queries\">\n                <tr>\n                    <td colspan=\"2\">\n                        <p class=\"mdl-typography--text-center\">\n                            <i class=\"material-icons loading\">refresh</i>\n                        </p>\n                    </td>\n                </tr>\n            </tbody>\n        </table>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Top advertisers\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card--expand\">\n        <table class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth\">\n            <thead>\n                <tr>\n                    <th class=\"mdl-data-table__cell--non-numeric fullwidth\">Domain</th>\n                    <th class=\"fullwidth\">Hit</th>\n                </tr>\n            </thead>\n            <tbody id=\"tbody-table-top-ads\">\n                <tr>\n                    <td colspan=\"2\">\n                        <p class=\"mdl-typography--text-center\">\n                            <i class=\"material-icons loading\">refresh</i>\n                        </p>\n                    </td>\n                </tr>\n            </tbody>\n        </table>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Top clients\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card--expand\">\n        <table class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth\">\n            <thead>\n                <tr>\n                    <th class=\"mdl-data-table__cell--non-numeric fullwidth\">Client</th>\n                    <th class=\"fullwidth\">Hit</th>\n                </tr>\n            </thead>\n            <tbody id=\"tbody-table-top-clients\">\n                <tr>\n                    <td colspan=\"2\">\n                        <p class=\"mdl-typography--text-center\">\n                            <i class=\"material-icons loading\">refresh</i>\n                        </p>\n                    </td>\n                </tr>\n            </tbody>\n            </tbody>\n        </table>\n    </div>    \n</div>\n\n<div class=\"pihole-card mdl-card mdl-shadow--2dp bg-white\">\n    <div class=\"mdl-card__actions mdl-card--border\">\n        Recent items\n        <div class=\"mdl-layout-spacer\"></div>\n        <i class=\"material-icons\">dns</i>\n    </div>\n    <div class=\"mdl-card--expand\">\n        <p class=\"please-rotate mdl-typography--text-center\">\n            <span class=\"mdl-chip mdl-chip--contact\">\n                <span class=\"mdl-chip__contact mdl-color--indigo mdl-color-text--white material-icons\">rotate_left</span>\n                <span class=\"mdl-chip__text\">Please rotate your device</span>\n            </span>\n        </p>\n        <table class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth force-landscape\">            \n            <thead>\n                <tr>\n                    <th class=\"mdl-data-table__cell--non-numeric fullwidth\">Time</th>\n                    <th>Domain</th>\n                    <th>IP</th>\n                </tr>\n            </thead>\n            <tbody id=\"tbody-table-recent-items\">\n                <tr>\n                    <td colspan=\"3\">\n                        <p class=\"mdl-typography--text-center\">\n                            <i class=\"material-icons loading\">refresh</i>\n                        </p>\n                    </td>\n                </tr>\n            </tbody>            \n        </table>\n    </div>    \n</div>"
  },
  {
    "path": "www/partial/query-log.html",
    "content": "<p class=\"please-rotate mdl-typography--text-center\">\n    <span class=\"mdl-chip mdl-chip--contact\">\n        <span class=\"mdl-chip__contact mdl-color--indigo mdl-color-text--white material-icons\">rotate_left</span>\n        <span class=\"mdl-chip__text\">Please rotate your device</span>\n    </span>\n</p>\n\n<div class=\"force-landscape\">\n    <p class=\"mdl-typography--text-center\">\n        <span class=\"mdl-chip mdl-chip--contact mdl-please-wait\">\n            <span class=\"mdl-chip__contact mdl-color--indigo mdl-color-text--white\"><i class=\"material-icons loading\">refresh</i></span>\n            <span class=\"mdl-chip__text\">Please wait, there are a lot of data to be processed.</span>\n        </span>\n    </p>\n    \n    <table id=\"query-log-table\" class=\"mdl-data-table mdl-js-data-table mdl-shadow--2dp fullwidth\" cellspacing=\"0\" width=\"100%\"></table>\n</div>"
  }
]