diff --git a/BulkAPISampleFiles/delete.csv b/BulkAPISampleFiles/delete.csv
new file mode 100644
index 0000000..9535358
--- /dev/null
+++ b/BulkAPISampleFiles/delete.csv
@@ -0,0 +1,5 @@
+Id
+003E000001DJOfxIAH
+003E000001DJOfyIAH
+003E000001DJOV4IAP
+003E000001DJOV5IAP
\ No newline at end of file
diff --git a/BulkAPISampleFiles/delete.xml b/BulkAPISampleFiles/delete.xml
new file mode 100644
index 0000000..e644728
--- /dev/null
+++ b/BulkAPISampleFiles/delete.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ 003E000001DJOfxIAH
+
+
+ 003E000001DJOfyIAH
+
+
+ 003E000001DJOV4IAP
+
+
+ 003E000001DJOV5IAP
+
+
\ No newline at end of file
diff --git a/BulkAPISampleFiles/insert.csv b/BulkAPISampleFiles/insert.csv
new file mode 100644
index 0000000..31cb26a
--- /dev/null
+++ b/BulkAPISampleFiles/insert.csv
@@ -0,0 +1,3 @@
+FirstName,LastName,Department,Birthdate,Description
+Tom,Jones,Marketing,1940-06-07Z,"Self-described as ""the top"" branding guru on the West Coast"
+Ian,Dury,R&D,,"World-renowned expert in fuzzy logic design. Influential in technology purchases."
\ No newline at end of file
diff --git a/BulkAPISampleFiles/insert.xml b/BulkAPISampleFiles/insert.xml
new file mode 100644
index 0000000..686ed5a
--- /dev/null
+++ b/BulkAPISampleFiles/insert.xml
@@ -0,0 +1,17 @@
+
+
+
+
+ Tom
+ Jones
+ Marketing
+ 1940-06-07Z
+ Self-described as "the top" branding guru on the West Coast
+
+
+ Ian
+ Dury
+ R&D
+ World-renowned expert in fuzzy logic design. Influential in technology purchases.
+
+
\ No newline at end of file
diff --git a/BulkAPISampleFiles/update.csv b/BulkAPISampleFiles/update.csv
new file mode 100644
index 0000000..230ef1a
--- /dev/null
+++ b/BulkAPISampleFiles/update.csv
@@ -0,0 +1,2 @@
+Id,Title
+003E000001CbzBi,Ninja
\ No newline at end of file
diff --git a/BulkAPISampleFiles/update.xml b/BulkAPISampleFiles/update.xml
new file mode 100644
index 0000000..8574c72
--- /dev/null
+++ b/BulkAPISampleFiles/update.xml
@@ -0,0 +1,8 @@
+
+
+
+
+ 003E000001CbzBi
+ Pirate
+
+
\ No newline at end of file
diff --git a/BulkAPISampleFiles/upsert.csv b/BulkAPISampleFiles/upsert.csv
new file mode 100644
index 0000000..5841c32
--- /dev/null
+++ b/BulkAPISampleFiles/upsert.csv
@@ -0,0 +1,2 @@
+Twitter_Handle__c,Title
+pattest7,Guru
\ No newline at end of file
diff --git a/BulkAPISampleFiles/upsert.xml b/BulkAPISampleFiles/upsert.xml
new file mode 100644
index 0000000..b942d57
--- /dev/null
+++ b/BulkAPISampleFiles/upsert.xml
@@ -0,0 +1,8 @@
+
+
+
+
+ pattest7
+ Pirate
+
+
\ No newline at end of file
diff --git a/BulkTK.md b/BulkTK.md
new file mode 100644
index 0000000..74217e4
--- /dev/null
+++ b/BulkTK.md
@@ -0,0 +1,121 @@
+BulkTK: Force.com Bulk API JavaScript Toolkit
+=============================================
+
+This minimal toolkit extends ForceTK to allow JavaScript in web pages to call the [Force.com Bulk API](https://www.salesforce.com/us/developer/docs/api_asynch/).
+
+Background
+==========
+
+The Force.com Bulk API allows asynchronous data access. BulkTK extends ForceTK with methods to create Bulk API jobs, add batches to them, monitor job status and retrieve job results. Control plane XML is parsed to JavaScript objects for ease of use, while data is returned verbatim.
+
+You should familiarize yourself with the [Force.com Bulk API documentation](https://www.salesforce.com/us/developer/docs/api_asynch/), since BulkTK is a relatively thin layer on the raw XML Bulk API.
+
+bulk.page is a simple Visualforce single page application to demonstrate BulkTK. Try it out in a sandbox or developer edition.
+
+Note that, just like ForceTK, BulkTK is unsupported and supplied as is. It is also currently in a very early stage of development. It appears to work well, but bugs cannot be ruled out, and the interface should not be considered stable.
+
+Example Usage
+=============
+
+You must create a ForceTK client first. On a Visualforce page, you would do:
+
+ var client = new forcetk.Client();
+ client.setSessionToken('{!$Api.Session_ID}');
+
+See the ForceTK documentation for authenticating from an external website, such as a Heroku app, or PhoneGap/Cordova.
+
+Create a job
+------------
+
+ // See https://www.salesforce.com/us/developer/docs/api_asynch/Content/asynch_api_reference_jobinfo.htm
+ // for details of the JobInfo structure
+
+ // Insert Contact records in CSV format
+ var job = {
+ operation : 'insert',
+ object : 'Contact',
+ contentType : 'CSV'
+ };
+
+ client.createJob(job, function(response) {
+ jobId = response.jobInfo.id;
+ console.log('Job created with id '+jobId+'\n');
+ }, function(jqXHR, textStatus, errorThrown) {
+ console.log('Error creating job', jqXHR.responseText);
+ });
+
+Add a batch of records to the job
+---------------------------------
+
+You can add multiple batches to the job; each batch can contain up to 10,000 records. See [batch size and limits](https://www.salesforce.com/us/developer/docs/api_asynch/Content/asynch_api_concepts_limits.htm#batch_size_title) for more details.
+
+ var csvData = "FirstName,LastName,Department,Birthdate,Description\n"+
+ "Tom,Jones,Marketing,1940-06-07Z,"Self-described as ""the top"" branding guru on the West Coast\n"+
+ "Ian,Dury,R&D,,"World-renowned expert in fuzzy logic design. Influential in technology purchases."\n";
+
+ client.addBatch(jobId, "text/csv; charset=UTF-8", csvData,
+ function(response){
+ console.log('Added batch '+response.batchInfo.id+'. State: '+response.batchInfo.state+'\n');
+ }, function(jqXHR, textStatus, errorThrown) {
+ console.log('Error adding batch', jqXHR.responseText);
+ });
+
+See BulkAPISampleFiles for sample CSV and XML data for different operations.
+
+Close the job
+-------------
+
+You must close the job to inform Salesforce that no more batches will be submitted for the job.
+
+ client.closeJob(jobId, function(response){
+ console.log('Job closed. State: '+response.jobInfo.state+'\n');
+ }, function(jqXHR, textStatus, errorThrown) {
+ console.log('Error closing job', jqXHR.responseText);
+ });
+
+Check batch status
+------------------
+
+ client.getBatchDetails(jobId, batchId, function(response){
+ console.log('Batch state: '+response.batchInfo.state+'\n');
+ }, function(jqXHR, textStatus, errorThrown) {
+ console.log('Error getting batch details', jqXHR.responseText);
+ });
+
+Get batch results
+-----------------
+
+Pass `true` as the `parseXML` parameter to get batch results for a query, false otherwise.
+
+ client.getBatchResult(jobId, batchId, false, function(response){
+ console.log('Batch result: '+response);
+ }, function(jqXHR, textStatus, errorThrown) {
+ console.log('Error getting batch result', jqXHR.responseText);
+ });
+
+Bulk query
+----------
+
+When adding a batch to a bulk query job, the `contentType` for the request must be either `text/csv` or `application/xml`, depending on the content type specified when the job was created. The actual SOQL statement supplied for the batch will be in plain text format.
+
+ var soql = 'SELECT Id, FirstName, LastName, Email FROM Contact';
+
+ client.addBatch(jobId, 'text/csv', soql, function(response){
+ console.log('Batch state: '+response.batchInfo.state+'\n');
+ }, function(jqXHR, textStatus, errorThrown) {
+ console.log('Error getting batch result', jqXHR.responseText);
+ });
+
+Getting bulk query results is a two step process. Call `getBatchResult()` with `parseXML` set to `true` to get a set of result IDs, then call `getBulkQueryResult()` to get the actual records for each result
+
+ client.getBatchResult(jobId, batchId, true, function(response){
+ response['result-list'].result.forEach(function(resultId){
+ client.getBulkQueryResult(jobId, batchId, resultId, function(response){
+ console.log('Batch result: '+response);
+ }, function(jqXHR, textStatus, errorThrown) {
+ console.log('Error getting bulk query results', jqXHR.responseText);
+ });
+ });
+ }, function(jqXHR, textStatus, errorThrown) {
+ console.log('Error getting batch result', jqXHR.responseText);
+ });
diff --git a/bulk.page b/bulk.page
new file mode 100644
index 0000000..ded3603
--- /dev/null
+++ b/bulk.page
@@ -0,0 +1,254 @@
+
+
+
+
+
+
1. Create a Bulk API job
+
+
+
+
+
+ External ID Field:
+
+
+
+
2. Select one or more CSV files to upload
+
+
+
+
+
2. Enter a SOQL Query
+
+
+
+
+
+
3. Close the Bulk API job
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bulktk.js b/bulktk.js
new file mode 100644
index 0000000..44c8447
--- /dev/null
+++ b/bulktk.js
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2015, salesforce.com, inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * BulkTK: JavaScript library to wrap Force.com Bulk API. Extends ForceTK.
+ * Dependencies:
+ * jquery - http://jquery.com/
+ * ForceTK - https://github.com/developerforce/Force.com-JavaScript-REST-Toolkit
+ * jxon - https://github.com/wireload/Ratatosk/blob/master/jxon.js
+ */
+
+forcetk.Client.prototype.xmlHeader = "\n";
+
+/*
+ * Low level utility function to call the Bulk API.
+ * @param path resource path
+ * @param parseXML set to true to parse XML response
+ * @param callback function to which response will be passed
+ * @param [error=null] function to which jqXHR will be passed in case of error
+ * @param [method="GET"] HTTP method for call
+ * @param [contentType=null] Content type of payload - e.g. 'application/xml; charset=UTF-8'
+ * @param [payload=null] payload for POST
+ * @param [parseXML=false] set to true to parse XML response
+ */
+forcetk.Client.prototype.bulkAjax = function(path, parseXML, callback, error, method, contentType, payload, retry) {
+ var that = this;
+ var url = this.instanceUrl + path;
+
+ if (this.debug) {
+ console.log('bulkAjax sending: ', payload);
+ }
+
+ return $.ajax({
+ type: method || "GET",
+ async: this.asyncAjax,
+ url: (this.proxyUrl !== null) ? this.proxyUrl: url,
+ contentType: method == "DELETE" ? null : contentType,
+ cache: false,
+ processData: false,
+ data: payload,
+ success: function(data, textStatus, jqXHR) {
+ var respContentType = jqXHR.getResponseHeader('Content-Type');
+ // Naughty Bulk API doesn't always set Content-Type!
+ if (parseXML &&
+ ((respContentType && respContentType.indexOf('application/xml') === 0) ||
+ data.indexOf('