Rdflib.js, how to serialize the data into turtle (.ttl) format? - serialization

How can I serialize RDF in turtle using rdflib.js? There's not much documentation. I can use:
Serializer.statementsToN3(destination);
to serialize into the N3 format, but not much besides that. I've tried altering the aforementioned command to stuff like statementsToTtl/Turtle/TURTLE/TTL, but nothing seems to work.

Figured it out. Courtesy of this (secret) Github gist.
$rdf.serialize(undefined, source, undefined,` 'text/turtle', function(err, str){
// do whatever you want, the data is in the str variable.
})
This is the code from the aforementioned Github gist.
/**
* rdflib.js with node.js -- basic RDF API example.
* #author ckristo
*/
var fs = require('fs');
var $rdf = require('rdflib');
FOAF = $rdf.Namespace('http://xmlns.com/foaf/0.1/');
XSD = $rdf.Namespace('http://www.w3.org/2001/XMLSchema#');
// - create an empty store
var kb = new $rdf.IndexedFormula();
// - load RDF file
fs.readFile('foaf.rdf', function (err, data) {
if (err) { /* error handling */ }
// NOTE: to get rdflib.js' RDF/XML parser to work with node.js,
// see https://github.com/linkeddata/rdflib.js/issues/47
// - parse RDF/XML file
$rdf.parse(data.toString(), kb, 'foaf.rdf', 'application/rdf+xml', function(err, kb) {
if (err) { /* error handling */ }
var me = kb.sym('http://kindl.io/christoph/foaf.rdf#me');
// - add new properties
kb.add(me, FOAF('mbox'), kb.sym('mailto:e0828633#student.tuwien.ac.at'));
kb.add(me, FOAF('nick'), 'ckristo');
// - alter existing statement
kb.removeMany(me, FOAF('age'));
kb.add(me, FOAF('age'), kb.literal(25, null, XSD('integer')));
// - find some existing statements and iterate over them
var statements = kb.statementsMatching(me, FOAF('mbox'));
statements.forEach(function(statement) {
console.log(statement.object.uri);
});
// - delete some statements
kb.removeMany(me, FOAF('mbox'));
// - print modified RDF document
$rdf.serialize(undefined, kb, undefined, 'application/rdf+xml', function(err, str) {
console.log(str);
});
});
});

Related

Community Connector getData() Request only uses the first two schema fields, not all four

I am building a Community Connector between Google Data Studio and SpyFu.com, in order to funnel SEO information for a specific url into the GDS Dashboard.
However, My getData() request only contains the first two fields from my Schema. As you can see, I have four listed in the code. The result is only the first two fields in the schema are printed to GDS.
I've been through tutorials, official documentation, YouTube videos, looked this issue up on google and checked out the community resources on GitHub.
//Step Two: Define getConfig()
function getConfig(request) {
var cc = DataStudioApp.createCommunityConnector();
var config = cc.getConfig();
config.newInfo()
.setId('instructions')
.setText('Give me SpyFu information on the following domain:');
config.newTextInput()
.setId('domain')
.setName('Enter the domain to search')
.setHelpText('e.g. ebay.com')
.setPlaceholder('ebay.com');
config.newTextInput()
.setId('SECRET_KEY')
.setName('Enter your API Secret Key')
.setHelpText('e.g. A1B2C3D4')
.setPlaceholder('A1B2C3D4');
config.setDateRangeRequired(false);
return config.build();
}
//Step Three: Define getSchema()
function getFields(request) {
var cc = DataStudioApp.createCommunityConnector();
var fields = cc.getFields();
var types = cc.FieldType;
var aggregations = cc.AggregationType;
fields.newDimension()
.setId('Keyword')
.setName('Keywords')
.setDescription('The keywords most often attributed to this domain.')
.setType(types.TEXT);
fields.newMetric()
.setId('Rank')
.setName('Rankings')
.setDescription('The ranking of the target site keyword on the Google Search Page.')
.setType(types.NUMBER);
fields.newMetric()
.setId('Local_Monthly_Searches')
.setName('Local Searches per Month')
.setDescription('Number of times, locally, that people have searched for this term within in the last month.')
.setType(types.NUMBER);
fields.newMetric()
.setId('Global_Monthly_Searches')
.setName('Global Searches per Month')
.setDescription('Number of times, globally, that people have searched for this term within in the last month.')
.setType(types.NUMBER);
return fields;
}
function getSchema(request) {
var fields = getFields(request).build();
return { schema: fields };
}
//Step Four: Define getData()
function responseToRows(requestedFields, response, domain) {
// Transform parsed data and filter for requested fields
return response.map(function(Array) {
var row = [];
requestedFields.asArray().forEach(function (field) {
switch (field.getId()) {
case 'Keyword':
return row.push(Array.term);
case 'Rank':
return row.push(Array.position);
case 'Local_Monthly_Searches':
return row.push(Array.exact_local_monthly_search_volume);
case 'Global_Monthly_Searches':
return row.push(Array.exact_global_monthly_search_volume);
case 'domain':
return row.push(domain);
default:
return row.push('');
}
});
return { values: row };
});
}
function getData(request) {
console.log("Request from Data Studio");
console.log(request);
var requestedFieldIds = request.fields.map(function(field) {
return field.name;
});
var requestedFields = getFields().forIds(requestedFieldIds);
// Fetch data from API
var url = [
'https://www.spyfu.com/apis/url_api/organic_kws?q='
+ request.configParams.domain
+ '&r=20'
+ '&p=[1 TO 10]'
+ '&api_key='
+ request.configParams.SECRET_KEY,
];
try {
var response = UrlFetchApp.fetch(url.join(''));
} catch (e) {
DataStudioApp.createCommunityConnector()
.newUserError()
.setDebugText('Failed URL Fetch Attempt. Exception details: ' + e)
.setText('There was an error accessing this domain. Try again later, or file an issue if this error persists.')
.throwException();
}
console.log("Response from API");
console.log(response);
//Parse data from the API
try {
var parsedResponse = JSON.parse(response);
} catch (e) {
DataStudioApp.createCommunityConnector()
.newUserError()
.setDebugText('Error parsing the JSON data. Exception details: ' + e)
.setText('There was an error parsing the JSON data. Try again later, or file an issue if this error persists.')
.throwException();
}
var rows = responseToRows(requestedFields, parsedResponse);
return {
schema: requestedFields.build(),
rows: rows
};
}
I need the GDS to post four columns of data. They are, "Keyword", "Rank", "Local Monthly Searches" and "Global Monthly searches".
I cannot figure out how to create a "fixed schema" so that the system always prints these four columns of data at every request. The tutorials and various documentation say it's possible, but not how to do it. Please help!
The number of metrics initially called up by the Google Community Connector is handled from the front-end, via Google Data Studio.
The back-end system (the Connector) only initially posts the default dimension and default metric. Getting the rest of the schemas to post should be handled when you are building a report on Google Data Studio. Simply click on the data set, select "data" on the right-hand menu, scroll down to either Metrics or Dimensions, and pick the ones you wish to add to the current set.
Note that these are the fields you established earlier in the coding process, when you were setting up your schemas.
Here, you're filtering your defined schema for fields that are present on the request object received by getData().
var requestedFieldIds = request.fields.map(function(field) {
return field.name;
});
var requestedFields = getFields().forIds(requestedFieldIds);
The visualization in Google Data Studio that is the catalyst for the request will determine which fields are requested.

TYPO3 6.2 - how to create FileReference in frontend (FE)?

I have the hypothetical Zoo extension in which I've Animal model with photo field and FrontEnd (FE) plugin with typical CRUD actions. photo field is typical FAL's FileReference and it works perfectly in backend (BE) with common TCA IRRE config.
I'm able to successful upload the file to the storage, it's visible in the Filelist module, and I can use it in BE during my Animal editing, anyway I can't create FileReference within my FE plugin.
My current approach looks like this:
/**
* #param \Zoo\Zoo\Domain\Model\Animal $animal
*/
public function updateAction(\Zoo\Zoo\Domain\Model\Animal $animal) {
// It reads proper uploaded `photo` from form's $_FILES
$file = $this->getFromFILES('tx_zoo_animal', 'photo');
if ($file && is_array($file) && $file['error'] == 0) {
/** #type $storageRepository \TYPO3\CMS\Core\Resource\StorageRepository */
$storageRepository = GeneralUtility::makeInstance('\TYPO3\CMS\Core\Resource\StorageRepository');
$storage = $storageRepository->findByUid(5); // TODO: make target storage configurable
// This adds uploaded file to the storage perfectly
$fileObject = $storage->addFile($file['tmp_name'], $storage->getRootLevelFolder(), $file['name']);
// Here I stuck... below line doesn't work (throws Exception no. 1 :/)
// It's 'cause $fileObject is type of FileInterface and FileReference is required
$animal->addPhoto($fileObject);
}
$this->animalRepository->update($animal);
$this->redirect('list');
}
anyway attempt to create reference by this line throws exception:
$animal->addPhoto($fileObject);
How can I resolve this?
Checked: DataHandler approach (link) won't work also, as it's unavailable for FE users.
TL;DR
How to add FileReference to Animal model from existing (just created) FAL record?
You need to do several things. This issue on forge is where I got the info, and some stuff is taken out of Helmut Hummels frontend upload example (and the accompanying blogpost) which #derhansen already commented.
I'm not entirely sure if this is everything you need, so feel free to add things. This does not use a TypeConverter, which you should probably do. That would open further possibilities, for example it would be easily possible to implement deletion and replacement of file references.
You need to:
Create a FAL file reference object from the File object. This can be done using FALs resource factory.
Wrap it in a \TYPO3\CMS\Extbase\Domain\Model\FileReference (method ->setOriginalResource)
EDIT: This step is unnecessary as of TYPO3 6.2.11 and 7.2, you can directly use the class \TYPO3\CMS\Extbase\Domain\Model\FileReference.
But, because the extbase model misses a field ($uidLocal) in 6.2.10rc1, that won't work. You need to inherit from the extbase model, add that field, and fill it. Don't forget to add a mapping in TypoScript to map your own model to sys_file_reference.
config.tx_extbase.persistence.classes.Zoo\Zoo\Domain\Model\FileReference.mapping.tableName = sys_file_reference
The class would look like this (taken from the forge issue):
class FileReference extends \TYPO3\CMS\Extbase\Domain\Model\FileReference {
/**
* We need this property so that the Extbase persistence can properly persist the object
*
* #var integer
*/
protected $uidLocal;
/**
* #param \TYPO3\CMS\Core\Resource\ResourceInterface $originalResource
*/
public function setOriginalResource(\TYPO3\CMS\Core\Resource\ResourceInterface $originalResource) {
$this->originalResource = $originalResource;
$this->uidLocal = (int)$originalResource->getUid();
}
}
Add this to the TCA of the image field, in the config-section (adapt to your table and field names of course):
'foreign_match_fields' => array(
'fieldname' => 'photo',
'tablenames' => 'tx_zoo_domain_model_animal',
'table_local' => 'sys_file',
),
EDIT: Use \TYPO3\CMS\Extbase\Domain\Model\FileReference in this step if on TYPO3 6.2.11 or 7.2 or above.
So at the end add the created $fileRef instead of $fileObject
$fileRef = GeneralUtility::makeInstance('\Zoo\Zoo\Domain\Model\FileReference');
$fileRef->setOriginalResource($fileObject);
$animal->addPhoto($fileRef);
Don't tell anyone what you have done.
Here is the complete function to upload file in TYPO3 using FAL and create filereference
/**
* Function to upload file and create file reference
*
* #var array $fileData
* #var mixed $obj foreing model object
*
* #return void
*/
private function uploadAndCreateFileReference($fileData, $obj) {
$storageUid = 2;
$resourceFactory = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance();
//Adding file to storage
$storage = $resourceFactory->getStorageObject($storageUid);
if (!is_object($storage)) {
$storage = $resourceFactory->getDefaultStorage();
}
$file = $storage->addFile(
$fileData['tmp_name'],
$storage->getRootLevelFolder(),
$fileData['name']
);
//Creating file reference
$newId = uniqid('NEW_');
$data = [];
$data['sys_file_reference'][$newId] = [
'table_local' => 'sys_file',
'uid_local' => $file->getUid(),
'tablenames' => 'tx_imageupload_domain_model_upload', //foreign table name
'uid_foreign' => $obj->getUid(),
'fieldname' => 'image', //field name of foreign table
'pid' => $obj->getPid(),
];
$data['tx_imageupload_domain_model_upload'][$obj->getUid()] = [
'image' => $newId,
];
$dataHandler = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
'TYPO3\CMS\Core\DataHandling\DataHandler'
);
$dataHandler->start($data, []);
}
where $filedata =
$this->request->getArgument('file_input_field_name');
And
$obj = //Object of your model for which you are creating file
reference
This example does not deserve a beauty prize but it might help you. It works in 7.6.x
private function uploadLogo(){
$file['name'] = $_FILES['logo']['name'];
$file['type'] = $_FILES['logo']['type'];
$file['tmp_name'] = $_FILES['logo']['tmp_name'];
$file['size'] = $_FILES['logo']['size'];
// Store the image
$resourceFactory = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance();
$storage = $resourceFactory->getDefaultStorage();
$saveFolder = $storage->getFolder('logo-companies/');
$newFile = $storage->addFile(
$file['tmp_name'],
$saveFolder,
$file['name']
);
// remove earlier refereces
$GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_file_reference', 'uid_foreign = '. $this->getCurrentUserCompanyID());
$addressRecord = $this->getUserCompanyAddressRecord();
// Create new reference
$data = array(
'table_local' => 'sys_file',
'uid_local' => $newFile->getUid(),
'tablenames' => 'tt_address',
'uid_foreign' => $addressRecord['uid'],
'fieldname' => 'image',
'pid' => $addressRecord['pid']
);
$GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_file_reference', $data);
$newId = $GLOBALS['TYPO3_DB']->sql_insert_id();
$where = "tt_address.uid = ".$addressRecord['uid'];
$GLOBALS['TYPO3_DB']->exec_UPDATEquery('tt_address', $where, array('image' => $newId ));
}

Get pdf-attachments from Gmail as text

I searched around the web & Stack Overflow but didn't find a solution. What I try to do is the following: I get certain attachments via mail that I would like to have as (Plain) text for further processing. My script looks like this:
function MyFunction() {
var threads = GmailApp.search ('label:templabel');
var messages = GmailApp.getMessagesForThreads(threads);
for (i = 0; i < messages.length; ++i)
{
j = messages[i].length;
var messageBody = messages[i][0].getBody();
var messageSubject = messages [i][0].getSubject();
var attach = messages [i][0].getAttachments();
var attachcontent = attach.getContentAsString();
GmailApp.sendEmail("mail", messageSubject, "", {htmlBody: attachcontent});
}
}
Unfortunately this doesn't work. Does anybody here have an idea how I can do this? Is it even possible?
Thank you very much in advance.
Best, Phil
Edit: Updated for DriveApp, as DocsList deprecated.
I suggest breaking this down into two problems. The first is how to get a pdf attachment from an email, the second is how to convert that pdf to text.
As you've found out, getContentAsString() does not magically change a pdf attachment to plain text or html. We need to do something a little more complicated.
First, we'll get the attachment as a Blob, a utility class used by several Services to exchange data.
var blob = attachments[0].getAs(MimeType.PDF);
So with the second problem separated out, and maintaining the assumption that we're interested in only the first attachment of the first message of each thread labeled templabel, here is how myFunction() looks:
/**
* Get messages labeled 'templabel', and send myself the text contents of
* pdf attachments in new emails.
*/
function myFunction() {
var threads = GmailApp.search('label:templabel');
var threadsMessages = GmailApp.getMessagesForThreads(threads);
for (var thread = 0; thread < threadsMessages.length; ++thread) {
var message = threadsMessages[thread][0];
var messageBody = message.getBody();
var messageSubject = message.getSubject();
var attachments = message.getAttachments();
var blob = attachments[0].getAs(MimeType.PDF);
var filetext = pdfToText( blob, {keepTextfile: false} );
GmailApp.sendEmail(Session.getActiveUser().getEmail(), messageSubject, filetext);
}
}
We're relying on a helper function, pdfToText(), to convert our pdf blob into text, which we'll then send to ourselves as a plain text email. This helper function has a variety of options; by setting keepTextfile: false, we've elected to just have it return the text content of the PDF file to us, and leave no residual files in our Drive.
pdfToText()
This utility is available as a gist. Several examples are provided there.
A previous answer indicated that it was possible to use the Drive API's insert method to perform OCR, but it didn't provide code details. With the introduction of Advanced Google Services, the Drive API is easily accessible from Google Apps Script. You do need to switch on and enable the Drive API from the editor, under Resources > Advanced Google Services.
pdfToText() uses the Drive service to generate a Google Doc from the content of the PDF file. Unfortunately, this contains the "pictures" of each page in the document - not much we can do about that. It then uses the regular DocumentService to extract the document body as plain text.
/**
* See gist: https://gist.github.com/mogsdad/e6795e438615d252584f
*
* Convert pdf file (blob) to a text file on Drive, using built-in OCR.
* By default, the text file will be placed in the root folder, with the same
* name as source pdf (but extension 'txt'). Options:
* keepPdf (boolean, default false) Keep a copy of the original PDF file.
* keepGdoc (boolean, default false) Keep a copy of the OCR Google Doc file.
* keepTextfile (boolean, default true) Keep a copy of the text file.
* path (string, default blank) Folder path to store file(s) in.
* ocrLanguage (ISO 639-1 code) Default 'en'.
* textResult (boolean, default false) If true and keepTextfile true, return
* string of text content. If keepTextfile
* is false, text content is returned without
* regard to this option. Otherwise, return
* id of textfile.
*
* #param {blob} pdfFile Blob containing pdf file
* #param {object} options (Optional) Object specifying handling details
*
* #returns {string} id of text file (default) or text content
*/
function pdfToText ( pdfFile, options ) {
// Ensure Advanced Drive Service is enabled
try {
Drive.Files.list();
}
catch (e) {
throw new Error( "To use pdfToText(), first enable 'Drive API' in Resources > Advanced Google Services." );
}
// Set default options
options = options || {};
options.keepTextfile = options.hasOwnProperty("keepTextfile") ? options.keepTextfile : true;
// Prepare resource object for file creation
var parents = [];
if (options.path) {
parents.push( getDriveFolderFromPath (options.path) );
}
var pdfName = pdfFile.getName();
var resource = {
title: pdfName,
mimeType: pdfFile.getContentType(),
parents: parents
};
// Save PDF to Drive, if requested
if (options.keepPdf) {
var file = Drive.Files.insert(resource, pdfFile);
}
// Save PDF as GDOC
resource.title = pdfName.replace(/pdf$/, 'gdoc');
var insertOpts = {
ocr: true,
ocrLanguage: options.ocrLanguage || 'en'
}
var gdocFile = Drive.Files.insert(resource, pdfFile, insertOpts);
// Get text from GDOC
var gdocDoc = DocumentApp.openById(gdocFile.id);
var text = gdocDoc.getBody().getText();
// We're done using the Gdoc. Unless requested to keepGdoc, delete it.
if (!options.keepGdoc) {
Drive.Files.remove(gdocFile.id);
}
// Save text file, if requested
if (options.keepTextfile) {
resource.title = pdfName.replace(/pdf$/, 'txt');
resource.mimeType = MimeType.PLAIN_TEXT;
var textBlob = Utilities.newBlob(text, MimeType.PLAIN_TEXT, resource.title);
var textFile = Drive.Files.insert(resource, textBlob);
}
// Return result of conversion
if (!options.keepTextfile || options.textResult) {
return text;
}
else {
return textFile.id
}
}
The conversion to DriveApp is helped with this utility from Bruce McPherson:
// From: http://ramblings.mcpher.com/Home/excelquirks/gooscript/driveapppathfolder
function getDriveFolderFromPath (path) {
return (path || "/").split("/").reduce ( function(prev,current) {
if (prev && current) {
var fldrs = prev.getFoldersByName(current);
return fldrs.hasNext() ? fldrs.next() : null;
}
else {
return current ? null : prev;
}
},DriveApp.getRootFolder());
}

Fiddler: Programmatically add word to Query string

Please be kind, I'm new to Fiddler
My purpose:I want to use Fiddler as a Google search filter
Summary:
I'm tired of manually adding "dog" every time I use Google.I do not want the "dog" appearing in my search results.
For example:
//www.google.com/search?q=cat+-dog
//www.google.com/search?q=baseball+-dog
CODE:
dog replaced with -torrent-watch-download
// ==UserScript==
// #name Tamper with Google Results
// #namespace http://superuser.com/users/145045/krowe
// #version 0.1
// #description This just modifies google results to exclude certain things.
// #match http://*.google.com
// #match https://*.google.com
// #copyright 2014+, KRowe
// ==/UserScript==
function GM_main () {
window.onload = function () {
var targ = window.location;
if(targ && targ.href && targ.href.match('https?:\/\/www.google.com/.+#q=.+') && targ.href.search("/+-torrent/+-watch/+-download")==-1) {
targ.href = targ.href +"+-torrent+-watch+-download";
}
};
}
//-- This is a standard-ish utility function:
function addJS_Node(text, s_URL, funcToRun, runOnLoad) {
var D=document, scriptNode = D.createElement('script');
if(runOnLoad) scriptNode.addEventListener("load", runOnLoad, false);
scriptNode.type = "text/javascript";
if(text) scriptNode.textContent = text;
if(s_URL) scriptNode.src = s_URL;
if(funcToRun) scriptNode.textContent = '(' + funcToRun.toString() + ')()';
var targ = D.getElementsByTagName('head')[0] || D.body || D.documentElement;
targ.appendChild(scriptNode);
}
addJS_Node (null, null, GM_main);
At first I was going to go with Tampermonkey userscripts,Because I did not know about Fiddler
==================================================================================
Now,lets focus on Fiddler
Before Request:
I want Fiddler to add text at the end of Google Query string.
Someone suggested me to use
static function OnBeforeRequest(oSession: Session) {
if (oSession.uriContains("targetString")) {
var sText = "Enter a string to append to a URL";
oSession.fullUrl = oSession.fullUrl + sText;
}
}
Before Response:
This is where my problem lies
I totally love the HTML response,Now I just want to scrape/hide the word in the search box without changing the search results.How can it be done? Any Ideas?
http://i.stack.imgur.com/4mUSt.jpg
Can you guys please take the above information and fix the problem for me
Thank you
Basing on goal definition above, I believe you can achieve better results with your own free Google custom search engine service. In particular, because you have control over GCSE fine-tuning results, returned by regular Google search.
Links:
https://www.google.com/cse/all
https://developers.google.com/custom-search/docs/structured_search

Issue with BTC-e API in App Script, method parameter

I am trying to incorporate the BTC-e.com API in to a google docs spreadsheet.
The API documentation is here: https://btc-e.com/api/documentation
The method name is sent via POST parameter method.
As the URLFetchApp requires me to set the type of request as POST by a parameter method and I then have another parameter called method to be set as getInfo.
How can I go about setting the fetch method as POST and have the API parameter method as getInfo.
Below is the function this relates too. Also I am sure there a more issues in my work I am yet to find.
function inventory() {
var nonce=Number(SpreadsheetApp.getActiveSheet().getRange('K2').getValue());
var token=SpreadsheetApp.getActiveSheet().getRange('K1').getValue();
var tokenEndpoint = "https://btc-e.com/tapi";
var sign= 'TEMP'
var head = {
'Content-Type': 'application/x-www-form-urlencoded',
'Key': token,
'Sign': sign
}
var params = {
method : "POST",
method : "getInfo",
headers: head,
contentType: 'application/x-www-form-urlencoded',
method : "getInfo",
nonce: nonce
}
var request = UrlFetchApp.getRequest(tokenEndpoint, params);
var response = UrlFetchApp.fetch(tokenEndpoint, params);
var response2=String(response);
SpreadsheetApp.getActiveSheet().getRange('K2').setValue(nonce+1);
SpreadsheetApp.getActiveSheet().getRange('I16').setValue(response2);
SpreadsheetApp.getActiveSheet().getRange('I17').setValue(nonce);
}
This just yields the error
Attribute provided with invalid value: method
Thanks,
Steve
PS: First time posting, I tried to get the format correct.
I made the following Google JavaScript function to do POST access to BTC-e. You can find this function in action in the example spreadsheet I made to demonstrate the BTC-e API functions.
function btceHttpPost(keyPair, method, params, nonce) {
if (keyPair === undefined) {
return "{'error':'missing key pair'}"
}
if (params === undefined) {
params = '';
}
// Cleanup keypair, remove all \s (any whitespace)
var keyPair = keyPair.replace(/[\s]/g, '');
// Keypair example: "AFE730YV-S9A4FXBJ-NQ12HXS9-CA3S3MPM-CKQLU0PG,96a00f086824ddfddd9085a5c32b8a7b225657ae2fe9c4483b4c109fab6bf1a7"
keyPair = keyPair.split(',');
var pubKey = keyPair[0];
var privKey = keyPair[1];
// As specified on the BTC-e api (https://btc-e.com/api/documentation) the
// nonce POST parameter must be an incrementing integer (>0). The easiest
// implementation is the use of a timestamp (TS), so there is no need
// for persistant storage. Preferable, the resolution of the TS should be
// small enough the handle the desired call-frequency (a sleep of the TS
// resolution can fix this but I don't like such a waste). Another
// consideration is the sizeof the nonce supported by BTC-e. Experiments
// revealed this is a 32 bit unsigned number. The native JavaScript TS,
// stored in a float, can be 53 bits and has a resolution of 1 ms.
if (nonce === undefined)
// This time stamp counts amount of 200ms ticks starting from Jan 1st, 2014 UTC
// On 22 Mar 2041 01:17:39 UTC, it will overflow the 32 bits and will fail
// the nonce key for BTC-e
var nonce = Math.floor((Date.now() - Date.UTC(2014,0)) / 200);
// Construct payload message
var msg = 'nonce=' + nonce + '&method=' + method + params;
var msgSign = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512, msg, privKey);
// Convert encoded message from byte[] to hex string
for (var msgSignHex = [], i = 0; i < msgSign.length; i++) {
// Doing it nibble by nibble makes sure we keep leading zero's
msgSignHex.push(((msgSign[i] >>> 4) & 0xF).toString(16));
msgSignHex.push((msgSign[i] & 0xF).toString(16));
}
msgSignHex = msgSignHex.join('');
var httpHeaders = {'Key': pubKey, 'Sign': msgSignHex};
var fetchOptions = {'method': 'post', 'headers': httpHeaders, 'payload': msg};
var reponse = UrlFetchApp.fetch('https://btc-e.com/tapi', fetchOptions);
return reponse.getContentText();
};
The problem looks to be with your params object . You have method set thrice in the same object, which is a source of confusion.
Next, take a look at the documentation for UrlFetchApp.fetch() ( https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetch(String,Object) ) . The method can take a value of post, get, delete, put.
The getInfo should probably be appended to your URL to make it
var tokenEndpoint = "https://btc-e.com/tapi/getInfo"
Per the docs, you also have to put in more parameters to the request, nonce, api key etc. Use this as a starting point, revisit the documentation and get back to SO if you still have trouble