Behavior, Content, Money – 3 Things you should never give away for free!!!

BCmoney MobileTV

WordReference API – AJAX SDK & Widget

Posted by bcmoney on June 1, 2011 in JavaScript, JSON, Semantic Web, Web Services with 19 Comments


No Gravatar
Languages

Yesterday I wrote about the Google API shutdown. It seems that I was wrong in that post about Wordreference not having an API, just a few days earlier founder Michael Kellogg announced the introduction of the brand-spanking new Wordreference API.

Like a dunce I contacted Michael by email to learn about this new revelation without double-checking the site itself (I knew in the past they didn’t have one, as I had checked just a month or so before out of curiosity). It seems that the API was in-development for quite some time, but was rushed out the door on the news of the Google Translate API shutdown. I can easily say that nothing was lost in the final rush, the API is excellent! There are both HTML or JSON versions of the API currently supported and the RESTful URIs make the whole thing quite intuitive to work with.

Awesome! So, feeling a bit dejected earlier this week, yet today having newfound hope for the future of online Translations, I’ve decided to build an SDK and example Widget for the newly released WordReference Dictionary API. I wanted to show multiple ways of interacting with the Translation API (including JSONp, jQuery, YQL, Server Proxy, Cache, etc) all directly via JavaScript. Also, with the completed Widget example, I wanted to show how you can use the API to simulate a full-text translation in real-time, without there being a full-text machine translation feature supported by WordReference (which works on words or phrase lookup only, since it is primarily a dictionary, not a translation service). The only downside of this approach, is that it may result in ALOT of requests to the API.

The CSS presentation styling is extremely minimal, but in the near future I’d consider adding more CSS3 hip features like text-shadows, gradients, transitions/fades and rounded corners. In the meantime, we get this basic CSS:

#wordreference.widget { font-family:'American Typewriter',Verdana,Arial,serif; }
#wordreference.widget legend { background:url('../images/logo_s.jpg') no-repeat; height:32px; font-size:1.4em; padding-left:38px; }
#wordreference.widget a { text-decoration:none; }
#wordreference.widget img { border:0; }
#wordreference.widget optgroup { font-size:8pt }
#wordreference.widget #from { float:left; padding:10px }
#wordreference.widget #swap { float:left; padding:10px; vertical-align:middle; font-size:0.7em; }
#wordreference.widget #to { float:left; padding:10px }
#wordreference.widget #text, #wordreference.widget #translation { color:#000; }
#wordreference.widget .unclicked { color:#ccc; }
#wordreference.widget .clear { clear:both; }
#wordreference.widget .acknowledgement { font-size:0.8em; color:#ccc; }
#wordreference.widget .acknowledgement a { color:#cccccc; border-bottom:1px dotted #ccc; }

Most of the behavior and thus real action happens in the following JavaScript:

/**
 * wordreference
 *   Implements the WordReference API (version 0.8 - 2011-06-10)
 *
 * @license http://www.gnu.org/licenses/lgpl.html
 * @author bcmoney
 * @credit http://bcmoney.tv/blog  *unless otherwise noted*
 */
JSONP_METHOD = false; //set this to true when using JSONp
/*****************************************************************************/
/** utilities for domain and path retrieval, plus data validation checks    **/

/*
 * getDomain
 *   Pulls just the domain out of the specified URL
 * @param _url String  OPTIONAL Full URL to check the domain of (defaults to current URL)
 * @return String  split section of the URL representing the domain without protocols, paths, params or hashes (i.e. example.com)
 */
function getDomain(_url) {
    var url = (!empty(_url)) ? _url : window.location.href;
    return url.split(//+/g)[1];
}

/*
 * getPath
 *   Lists the path of the specified URL
 * @param _url String  OPTIONAL Full URL to check the domain of (defaults to current URL)
 * @return String  pathname after the URL's domain
 */
function getPath(_url) {
    var url = (!empty(_url)) ? _url : window.location.href;
    a = document.createElement('a');
    a.href = url;
    path = a.pathname;
    document.removeChild(this.a);
    return path;
}

/* GUP
 *   Get Url Paramaters
 * USAGE:
 *  var param1Val = gup('param1');
 * @param name String  name of a query parameter to look for a value of in URL
 * @param _url String  OPTIONAL, full URL to check for parameters in (defaults to the current URL)
 * @author Justin Barlow
 * @license http://creativecommons.org/publicdomain/mark/1.0/
 * @credit http://www.netlobo.com/url_query_string_javascript.html
 */
function gup(name, _url) {
    var url = (!empty(_url)) ? _url : window.location.href;
    name = name.replace(/[[]/,"\[").replace(/[]]/,"\]");
    var regexS = "[\?&]"+name+"=([^&#]*)";
    var regex = new RegExp(regexS);
    var results = regex.exec(url);
    if(empty(results)) {
        return "";
    }
    else {
        return results[1];
    }
}

/*
 * empty
 *   Simulate PHP emptiness check
 * @param mixed_var  Any combination of Objects (i.e. Array, String, Int, Double etc)
 * @author Philippe Baumann, Kevin van Zonneveld, Marc Jansen, et. al
 * @license http://www.opensource.org/licenses/mit-license.php
 * @credit http://phpjs.org/functions/empty:392
 */
function empty (mixed_var) {
    var key;
    if (mixed_var === "" || mixed_var === 0 || mixed_var === "0" || mixed_var === null || mixed_var === false || typeof mixed_var === 'undefined') {
        return true;
    }
    if (typeof mixed_var == 'object') {
        for (key in mixed_var) {
            return false;
        }
        return true;
    }
    return false;
}

/*
 * nodeExists
 * @author p00ya
 * @credit http://stackoverflow.com/questions/1129209/check-if-json-keys-nodes-exist
 */
function nodeExists(p, a) {
    for (i in a) {
        var key = a[i];
        if (p[key] == null) {
            return '';
        }
        p = p[key];
    }
    return p;
}

/*
 * console
 *   Replace missing console (log, info, error, warn, etc) functions
 * @license http://developer.yahoo.com/yui/license.html
 * @author Patrick Donelan
 * @credit http://blog.patspam.com/2009/the-curse-of-consolelog
 */
if (!("console" in window) || !("firebug" in console)) {
    var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
    window.console = {};
    for (var i = 0, len = names.length; i < len; ++i) {
        window.console[names[i]] = function(){ };
    }
}

/************************************************************/
/* AJAX cross-browser helper utilities */
/************************************************************/
/*
 * loadDoc
 *   Loads a Document (i.e. JSON or HTML) into a Text string
 * @param docURL String  a link to the Document to load
 * @return responseText
 */
function loadDoc(docURL) {
    if (window.XMLHttpRequest) {		// FireFox, Opera, Chrome, Safari
        xhttp = new XMLHttpRequest();
    }
    else {								// Internet Explorer
        xhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xhttp.open("GET",docURL,false);
        xhttp.setRequestHeader("Content-type", "text/plain; charset=utf-8");//try to force response type
    xhttp.send();
    return xhttp.responseText;
}

/*
 * loadXMLDoc
 *   Loads an XML Document into an XML (DOM) Object
 * @param docURL String  a link to the XML Document to load
 * @return responseXML
 */
function loadXMLDoc(docURL) {
    if (window.XMLHttpRequest) {		// FireFox, Opera, Chrome, Safari
        xhttp = new XMLHttpRequest();
    }
    else {								// Internet Explorer
        xhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xhttp.open("GET",docURL,false);
    xhttp.send();
    return xhttp.responseXML;
}

/*
 * loadXMLString
 *   Loads an XML String into an XML (DOM) Object
 * @param txt String  text to the Document to load
 * @return responseText
 */
function loadXMLString(txt) {
    if (window.DOMParser) {		// FireFox, Opera, Chrome, Safari
        parser=new DOMParser();
        xmlDoc=parser.parseFromString(txt,"text/xml");
    }
    else { 						// Internet Explorer
        xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async = "false";
        xmlDoc.loadXML(txt);
    }
    return xmlDoc;
}

/************************************************************/	
    API = 'http://api.wordreference.com';  //base URL for the API request
    API_VERSION = '0.8';                   //leave blank '' for latest version
    API_KEY = '82972';                     //NOW REQUIRED... back off, get your own API Key or userID!
    API_FORMAT = 'json';                   //'json' for JSON response type, or, blank '' for HTML 
    CALLBACK = '?callback=displayTranslation';  //name of your callback function
var API_URL = API + '/' + API_VERSION + '/' + API_KEY + '/' + API_FORMAT + '/';
/************************************************************/	

/**
 * wordreferenceAPI
 *   call request to WordReference API with our input data
 * @param language String representing the four character translation code (i.e. "enfr" or "enja")
 * @param word String representing the word (term) to lookup a translation for
 */
function wordreferenceAPI(language, word) {
    var api_endpoint = API_URL + language + '/' + encodeURIComponent(word) + API_URL_CREDENTIALS; //DEBUG: console.log(api_enpoint);
    /******************************PROXY*******************************/
    json = loadDoc("proxy.php?url="+api_endpoint); /* using a server-side PROXY, 1 of 5 alternatives that may be used (JSONp, jQuery, YQL, Server-side PROXY, or Local CACHE), see "tests/basic.html" */
    displayTranslation(json);
}

/**
 * displayTranslation
 *   process translation results and output the response
 * @param json String  takes in a String of JSON and parses it into an accsesible Object (NOTE: may need to pass your JSON through JSON.stringify)
 */
function displayTranslation(json) {
    var wordreference = JSON.parse(json); //use default "json2.js" parser (just in case JSON object not available)
    var term = ''; var sense = '';     

    /* parse JSON response */
    try {
        if (nodeExists(wordreference, ["term0", "Entries"])) {
        alert(wordreference.length);
            term = wordreference.term0.Entries[0].FirstTranslation.term;
            sense = wordreference.term0.Entries[0].FirstTranslation.sense;
            console.info(term + ' ' + sense);
        }
        else if (nodeExists(wordreference, ["term0", "PrincipalTranslations"])) {
            term = wordreference.term0.PrincipalTranslations[0].FirstTranslation.term;
            sense = wordreference.term0.PrincipalTranslations[0].FirstTranslation.sense;
            console.info(term + ' ' + sense);
        }
        else if (wordreference.Note.indexOf("No translation was found") !== -1) {
            term = lookahead;
            console.warn(wordreference.Note);
        }
        else {
            console.log('ERROR: Invalid input characters or looked up a word with no entry');
        }
    }
    catch (err) {
        console.error('ERROR: ' + err.description);
    }
    document.getElementById('translation').value += term + ' ';
        if (JSONP_METHOD) { jsonp.removeScriptTag(); } //JSONP only... remove the added SCRIPT tag to ensure limited lifetime of injected JS code
}

/*****************************************************************************/
/**                                WIDGET                                    **/
/*****************************************************************************/
//Somewhat regrettable but necssary (for now) GLOBALs
var unclicked = true;   //boolean to register the first click on the textareas
var lookahead = '';     //placeholder for the letters typed so far (in current word)
var caret_position = 0; //current caret position

/**
 * swapTranslationLanguage
 *   Exchange the selected indexes and values of two HTML Form Select inputs
 * @param ele1 String  name of the first HTML Form DOM Element to swap
 * @param ele2 String  name of the second HTML Form DOM Element to swap
 * @return boolean  true if the value is identical to the placeholder text, false otherwise
 */
function swapTranslationLanguage(ele1,ele2) {
    var element1 = (!empty(document.getElementById(ele1))) ? document.getElementById(ele1) : document.getElementById("language_to");
    var element2 = (!empty(document.getElementById(ele2))) ? document.getElementById(ele2) : document.getElementById("language_from");
    var swapMem = element1.value;
    setFormSelectValue(ele1,element2.value);
    setFormSelectValue(ele2,swapMem);
}

/**
 * setFormSelectValue
 *   Set the value of an HTML Form DOM input element
 * @param ele Element  representing the HTML Form DOM Element to clear text of
 * @param txt String  placeholder text to check against Form's current text
 * @return boolean  true if the value is identical to the placeholder text, false otherwise
 */
function setFormSelectValue(ele,txt) {
    if(document.getElementsByName(ele)!=null && document.getElementsByName(ele)[0]!=null) {
        var swapMem = document.getElementsByName(ele)[0];
        for(index=0; index < swapMem.length; index++) {
            if(swapMem[index].value == txt) {
                swapMem.selectedIndex = index;
            }
        }
    }
}

/**
 * clearDefaultText
 *   Clear any placeholder text that was stuck into a form input by default
 * @param ele Element  representing the HTML Form DOM Element to clear text of
 * @param txt String  placeholder text to check against Form's current text
 * @return boolean  true if the value is identical to the placeholder text, false otherwise
 */
function clearDefaultText(ele, txt) {
    if (!empty(ele) && unclicked) {
        if (ele.value == txt) {
            ele.value='';
            return true;
        }
    }
}

/**
 * lookupTranslation
 *   Perform a real-time interactive Dictionary lookup on the typed word
 * @param from String
 * @param to String
 * @param text String
 * @return translated  String Translation for performing an update on the current Translation
 */
function lookupTranslation(from, to, text) {
    var txt = (!empty(text) && !empty(document.getElementById(text).value)) ? document.getElementById(text).value : 'default ';
//DEBUG:  console.log(caret_position + "n" + lookahead + "n" + from + "|" + to + "n" + text);
        word = txt.substring(caret_position+1, txt.lastIndexOf(' ')+1);
            fromLanguage = (!empty(from) && !empty(document.getElementById(from).value)) ? document.getElementById(from).value : "en";
            toLanguage = (!empty(to) && !empty(document.getElementById(to).value)) ? document.getElementById(to).value : "fr";
            lang = fromLanguage + toLanguage;
        translated = wordreferenceAPI(lang, word);
        lookahead = '';
    return translated;
}  

IE5 = (document.all) ? 1 : 0; // Must capture the event if it is NS6.0 and NS4.0+
if(!IE5) { document.captureEvents(Event.KEYPRESS); } 

/**
 * checkKeyPress
 *   Check whether or not a key that was pressed was SPACEBAR or ENTER
 * @param evt Event  runtime event giving access to each typed key
 * @return boolean  true if SPACEBAR or ENTER keys were pressed, false otherwise
 */
function checkKeyPress(evt) {
    evt = (evt) ? evt : ((event) ? event : null);
    pressedKey = !(IE5) ? (evt.charCode || evt.keyCode) : evt.keyCode; // Grab the ascii code of the key that was pressed
    if (String.fromCharCode(pressedKey) == ' ' || pressedKey == 32 || String.fromCharCode(pressedKey) == 'n' || pressedKey == 13) {
      self.focus(); // Display the key and its ASCII code
      lookupTranslation('language_from', 'language_to', 'text');
      caret_position++;
    }
    else if (pressedKey == 8 && (lookahead.substring(caret_position-1,caret_position) !== ' ')) {
       lookahead = lookahead.substring(0,caret_position-1);
       caret_position--;
       return false;
    }
    else {
      lookahead += String.fromCharCode(pressedKey);
      caret_position++;
      return false;
    }
}

The structure for the HTML is a plain and simple HTML5 skeleton (without any exciting new features) as follows:

<!DOCTYPE html>
<html>
<head>
  <title>WordReference AJAX SDK / Widget</title>
  <link rel="shortcut icon" href="favicon.ico" />
  <link rel="stylesheet" type="text/css" media="all" href="style/widget.css" />
</head>
<body>

Translate
<>
Translations © WordReference.com
</body> </html>

As you can see in the following demo, there are still a few bugs to be worked out on both the SDK end and the API end, but the premise is there so I’m releasing it anyway!


-or-

There were some small gotchas, as with the first-run of any API. Here are a few of the (very minor nitpicky things) I noticed:

  • Spanish-English dictionary (esen) – Not supported yet, but supposedly coming soon!
  • First Word – Queries like “Hello World” don’t seem to work properly as the API just grabs the first matched word (hello), thus each word should be called separately and its hard to tell when to do that, since other queries for popular sayings like “the cat’s meow” work fine … knowing me I could be doing something wrong like not encoding properly though, if there was a way to specify that you are looking for a full-term match not just partial that might quickly solve this one without needing too many server-side coding changes, something like &match=phrase as an optional additional URL parameter on each request?
  • Error/Status Codes – It would be helpful to see a brief error code and/or short status code explanation (i.e. “no definition available for that term”, “no match”, “not a known word”, “unable to decode”, etc… so we could double check encoding, punctuation, spelling/typos, but I can see how its hard to make that work, some kind of generic error message would work for now too).
  • RESTful APIs – nice and simple URLs, they did a great job here (might also make sense to add some mod_redirect magic to support a dash between dictionaries, i.e. en-fr)? Something like the following, but I suck at regular expressions so definitely not perfect:
    RewriteRule ^([A-Za-z]2)-([A-Za-z]2)/([A-Za-z]*)/?u=([^/.]+)$ /$1$2/$3?u=$4 [R]
  • Full text translations – probably not realistic, given the nature of the site being primarily a Dictionary for words and short phrases… not full paragraphs, documents or websites… ok, that’s a given, but one resource I have found very useful in my personal use of the site (dating back to 2003-2004 in my University days struggling to get through Spanish classes and brush-up on my French in University) is the automatic link to the forums you get when typing in full phrases on the WordReference site directly. (i.e. ) I wonder if there are any plans to provide at least some of those same links in the API (maybe via a totally separate API call like http://wordreference.com/suggestion/json/ but that might be already available via the forum software’s API if one exists?? Even better yet and less realistic, would be to be able to have users rate the responses and automatically return the highest rated response in the API. That would take lots of key-mashing to make happen, and probably not happening anytime in the near future

Last but not least, for those who prefer to not dig into any API code at all, there was already an official WordReference MINI translation widget/tool built by the WordReference team themselves, which can be embedded via a simple iFrame, here’s what it looks like when in use:

That would definitely be the easiest possible way to quickly include translations on your site or blog, and the really nice thing about it is that it already includes links to the user discussion forums for the incredibly helpful community suggestions and assistance threads around specific terms in a given language.

Summary

In closing, Mkellog has done an excellent job on version 0.8 of the WordReference API, so a tip of the hat for him! I hope he continues to develop it and considers a tiered models to support an even higher quality of service, such that Google Translate API won’t even be missed!

UPDATE (2011-06-10):
JSONp requests where a callback is specified don’t seem to be working right now, though I did see them working in the first week the API was released have been fixed. Also, I have noticed the widget is not working well in IE7 *seems to work fine now*, will take a look at that later (but maybe not because I hate IE in general). Seems to be working well in IE8+, Safari 4+, Opera 10+, Chrome 8+, FF 3.5+ and even on iPhone for me so far… please feel free to report bugs or inconsistencies in these or other browser versions though!

  1. MemodayMarch 21, 2012 - 8:28 pm #1

    Thank you so much for sharing this. I am trying to implement it with Oracle Apex, but I am confused and there is a lack for resources. My question is:

    According to Wordreference (WR), the JSON URL is:
    http://api.wordreference.com/{api_version}/{API_key}/json/{dictionary}/{term}

    In Apex REST Web Service Details, I have the following fields:

    URL: what should I put in there? Should I just put the above URL after adding my own API and that’s it?

    Also, in Apex, there is a field that is called “REST HTTP Headers”
    What should I put in there? Is it “{term}” or something else or can I simply ignore it?

    I assume the HTTP method is “Get”, right?

    Apex also asks for “REST Input Parameters” and it gives me 2 fields:

    Name: What should go here?
    Type: there is 2 options here ‘string and binary’. I think it is string.

    Sorry for all these questions, but I am newbie and trying to learn.

    By the way, do you have any idea how can this be used with Drupal?

    Thanks in advance.

    Reply
    • bcmoneyMarch 26, 2012 - 3:53 am #2

      I’m not too sure about Oracle Application Express (APEX) in particular, but I’m assuming you’ll need to do all the replacements first so that your URL looks something like:
      http://api.wordreference.com/0.8/516663/json/enfr/hello
      (but please replace ‘516663’ with your own key, that is just my public testing key and will have a limit on number of requests)

      Then pass it through the “apex_web_service.make_rest_request” method via the “p_url” parameter as per this document:
      http://docs.oracle.com/cd/E23903_01/doc/doc.41/e21676/apex_web_service.htm#BABGGBBH

      It is a GET request and the response type would definitely be string (JSON string to be exact, but they may not have a type for that) not boolean.

      Reply
  2. stream movies online freeDecember 5, 2012 - 8:31 am #3

    My brother suggested I would possibly like this website.

    He was totally right. This post actually made my day.
    You cann’t believe just how much time I had spent for this information! Thanks!

    Reply
    • bcmoneyDecember 21, 2012 - 3:12 am #4

      Sorry to hear you had trouble with them, have you tried calling them:
      http://chalkgaming.com/contactus.php

      Keep in mind they are probably only available 9am-5pm business hours (AST +04:00; Halifax Nova Scotia, Canada). If you call and they don’t answer, I’d be shocked as that is nothing like my experience with them, they were quite responsive. Another reliable local alternative I could recommend is SportsDirect, inc. which I know for sure will be responsive to new business inquiries.

      Chalk Gaming might be better for developers that are working for/with Enterprise clients, whereas SportsDirect is open to all business small-to-medium and bigger.

      Reply
  3. ShannonJanuary 6, 2013 - 9:46 am #5

    If someone wants to get updates on the newest technologies, they must pay a visit this site regularly. Sure way to be up to date all the time!

    Reply
  4. LaurenceJanuary 7, 2013 - 1:39 pm #6

    Amazing blog! Do you have any tips for aspiring writers?

    I’m hoping to start my own site soon but I’m a little lost on everything. Would you recommend starting with a free platform like WordPress or going for a paid option? There are so many choices out there that I’m completely overwhelmed .. Any suggestions? Thanks a lot!

    Reply
    • bcmoneyJanuary 9, 2013 - 9:24 am #7

      Start with a WordPress hosted account at:
      http://wordpress.com/

      From there depending on your usage frequency and requirements, you may want to host it yourself.

      Reply
  5. SpryskiwaczeApril 10, 2013 - 11:37 am #8

    Excellent blog post. I definitely appreciate this website.
    Stick with it!

    Reply
  6. brown bagsApril 13, 2013 - 11:20 am #9

    This article will hugely assist not just myself but also the average internet users for setting up a translation service on their own web site or even blogs, with a simple client-side method from start to end. Thanks!

    Reply
  7. RosariaLaughsAtCelebsWithoutMakeupApril 23, 2013 - 1:10 am #10

    Spot on with this write-up, I truly think this web site… needs a lot more attention. I’ll probably be back again to read more, thanks for the advice!

    Reply
  8. Alberto-ProjektowanieMay 25, 2013 - 9:27 am #11

    What’s up, yeah this article is really nice and I have learned lot of things from it concerning blogging and translation APIs. thanks.

    Reply
  9. MelissaSewardJune 9, 2013 - 2:36 pm #12

    I bet very soon this website will quickly rise to earn the fame and recognition it deserves among all blogging and website-building visitors, due to it’s nice articles, info and reviews

    Reply
  10. SaraJuly 16, 2013 - 11:42 pm #13

    hola,
    Debo admitir que antes no me interesaba mucho esteblog, sin embargo con los
    ultimos posts estoy visitandolo frecuentemente y me esta gustando mas.

    A seguir igual!

    Reply
  11. RonnyBJuly 17, 2013 - 6:00 am #14

    Hi, I do believe this is an excellent web site. I stumbledupon it ;) I may revisit yet
    again since I saved as a favorite it. Money and freedom is the greatest way to
    change, may you be rich and continue to guide others.

    Reply
  12. Jerald HavenerJuly 18, 2013 - 12:46 pm #15

    This is helpful!

    Reply
  13. Immigration Advice in IslingtonJuly 19, 2013 - 4:02 pm #16

    It’s actually a cool and useful piece of information. I am happy that you simply shared this helpful information with us. Please keep us informed like this. Thanks for sharing.

    Reply
  14. หนังสือพิมพ์July 31, 2013 - 6:15 am #17

    This blog was… how do you say it? EXTREMELY Relevant!! Finally I have found something which helped me do translations Japanese to English (then to Thai by myself). Hoping they get more improvements and add Thai dictionary. Thank you!

    Reply
  15. AlCooperSeptember 12, 2013 - 11:31 am #18

    I’ve loved reading this concise article and I’m always trying to find solid informative tutorials and information similar to this. This really is what I was looking for to help me use WordReference translations on my own site. Thanks!

    Reply
Leave a Reply

Posts with similar tags
Posts in similar categories

BC$ = Behavior, Content, Money

The goal of the BC$ project is to raise awareness and make changes with respect to the three pillars of information freedom - Behavior (pursuit of interests and passions), Content (sharing/exchanging ideas in various formats), Money (fairness and accessibility) - bringing to light the fact that:

1. We regularly hand over our browser histories, search histories and daily online activities to companies that want our money, or, to benefit from our use of their services with lucrative ad deals or sales of personal information.

2. We create and/or consume interesting content on their services, but we aren't adequately rewarded for our creative efforts or loyalty.

3. We pay money to be connected online (and possibly also over mobile), yet we lose both time and money by allowing companies to market to us with unsolicited advertisements, irrelevant product offers and unfairly structured service pricing plans.

  • Archives