Social Share Privacy is a jQuery plugin that lets you add social share buttons to your website that don't allow the social sites to track your users. The buttons are first disabled and a user needs to click them to enable them. So in order to e.g. like a site on facebook with these social share buttons a user needs to click two times. But in return for this extra click a user can only be tracked be this third party sites when he decides to enable the buttons. Using the settings menu a user can also permanently enable a social share button.
Supported share services:
- Buffer
- Delicious
- Disqus
- Facebook Like/Recommend
- Facebook Share
- Flattr
- Google+
- Hacker News
- Linked in
- Stumble Upon
- Tumblr
Note that Tumblr and email are just normal links and thus always enabled.
This is a fork of socialSharePrivacy by Heise. In this fork the service support
was made extensible, some services where added and some bugs fixed. It has some
incompatible changes, though (consolidated option names, use of the boolean values
true
and false
instead of the strings "on"
and "off"
etc.).
The original can be found here: http://www.heise.de/extras/socialshareprivacy/
The Delicious support was heavily inspired by the delicious button jQuery plugin:
http://code.google.com/p/delicious-button/
The style for this button was atually copied and only slightly adapted from this plugin.
- Dependencies
- How to use
- Methods
- Events
- Options
- Global Options
- Common Service Options
- Custom Services
- Helper Functions
- Build.sh
- Known Issues
- License
The jQuery cookies plugin is needed in order to enable services permanently. However, you can plug in you own replacement to store this options differently (e.g. via ajax in the user profile or in the browsers local store). For an example that stores the perma options in HTML5 local storage instead of cookies see the file localstorage.js.
<html>
<head>
…
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.socialshareprivacy.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('.share').socialSharePrivacy();
});
</script>
…
</head>
<body>
…
<div class="share"></div>
…
</body>
</html>
You only need to include the JavaScript files of the services you want to use. I recommend to pack all needed files into one using a JavaScript packer/compressor. The included pack.sh script can do that for you, if you've got uglifyjs and uglifycss installed.
However, for your convenience I provide these precompiled versions of the scripts:
- jquery.socialshareprivacy.min.js 1
- jquery.socialshareprivacy.min.autoload.js 2
- jquery.socialshareprivacy.min.de.js 3
- jquery.socialshareprivacy.min.es.js 3
- jquery.socialshareprivacy.min.fr.js 3
- jquery.socialshareprivacy.min.it.js 3
- jquery.socialshareprivacy.min.nl.js 3
- jquery.socialshareprivacy.min.pl.js 3
- jquery.socialshareprivacy.min.pt.js 3
- jquery.socialshareprivacy.min.ru.js 3
- jquery.socialshareprivacy.min.css
1 This file contains all JavaScripts except the jquery.socialshareprivacy.localstorage.js
module and the translations.
2 This file contains the same as 1, but it also automatically initializes elements with the attribute data-social-share-privacy="true"
set.
3 These files contain only translation strings and have to be included in addition to jquery.socialshareprivacy.min.js
.
You can also asynchronously load the buttons if you use the jquery.socialshareprivacy.min.autoload.js
script:
<html>
<head>
…
<script type="text/javascript" src="jquery.js"></script>
…
</head>
<body>
…
<div data-social-share-privacy="true"></div>
…
<div data-social-share-privacy="true"></div>
…
<script type="text/javascript">
(function () {
var s = document.createElement('script');
var t = document.getElementsByTagName('script')[0];
s.type = 'text/javascript';
s.async = true;
s.src = 'jquery.socialshareprivacy.min.autoload.js';
t.parentNode.insertBefore(s, t);
})();
</script>
</body>
</html>
.socialSharePrivacy([options])
Add social share buttons to all elements in the set. Returns this
.
.socialSharePrivacy("destroy")
Remove all social share buttons. This will return all elements in the set back
to their pre-init state. Returns this
.
.socialSharePrivacy("disable", [service_name])
Disable the named service or disable all services if no service_name
is given.
Returns this
.
.socialSharePrivacy("disabled", [service_name])
Returns true
if the given service is disabled, false
otherwise. If
service_name
is not given then it will return an object that maps
service names to their disabled-value.
.socialSharePrivacy("enable", [service_name])
Enable the named service or enable all services if no service_name
is given.
Returns this
.
.socialSharePrivacy("enabled", [service_name])
Returns true
if the given service is enabled, false
otherwise. If
service_name
is not given then it will return an object that maps
service names to their enabled-value.
.socialSharePrivacy("option", option_name, [value])
Get or set an option. If no value
is specified it will act as a getter.
Returns this
when acting as setter.
.socialSharePrivacy("options", [options])
Get or set all options. If no options
are specified it will act as a getter.
Returns this
when acting as setter.
.socialSharePrivacy("toggle", [service_name])
Toggle the named service or toggle all services if no service_name
is given.
Returns this
.
This event is emitted after the socialSharePrivacy
method created a Social
Share privacy widget. The event object will have an options
attribute holding
the option object of the initialized widget.
This event is emitted before a Social Share Privacy widget is destroyed.
This event is emitted after a certain service was disabled. The event object
will have a serviceName
property, holding the name of the service that was
disabled, and an isClick
property, wich is true
if a click by a user caused
this event (false
if it was disabled via JavaScript).
This event is emitted after a certain service was enabled. The event object
will have a serviceName
property, holding the name of the service that was
enabled, and an isClick
property, wich is true
if a click by a user caused
this event (false
if it was enabled via JavaScript).
Options can be set globally via $.fn.socialSharePrivacy.settings
, via an
options object passed to the socialSharePrivacy
function or via data-*
attributes of the share element. If options are defined in more than one way
the data-*
attributes will overwrite the options from the passed options
object and the options from passed options object will overwrite the
globally defined options.
In order to pass the options as data-*
attributes simply prepend data-
to
all option names. For the language option you can also use the standard lang
attribute. If you want to set an option of an service just use a data-*
attribute that includes dots (.
) as if it where a JavaScript property
expression:
<div class="share"
lang="de"
data-uri="http://example.com/"
data-image="http://example.com/image.png"
data-services.tumblr.type="photo"
data-order="facebook twitter tumblr"></div>
If you want you can combine all options of a service and pass a JSON string as attribute value:
<div class="share"
lang="de"
data-uri="http://example.com/"
data-image="http://example.com/image.png"
data-services.tumblr='{"type":"photo"}'
data-order="facebook twitter tumblr"></div>
You can also do this for all services:
<div class="share"
lang="de"
data-uri="http://example.com/"
data-image="http://example.com/image.png"
data-services='{"tumblr":{"type":"photo"}}'
data-order="facebook twitter tumblr"></div>
Or even all options at once:
<div class="share"
data-options='{
"language" : "de",
"uri" : "http://example.com/",
"image" : "http://example.com/image.png",
"services" : {
"tumblr" : {
"type" : "photo"
}
},
"order" : ["facebook", "twitter", "tumblr"]
}'></div>
Actually these aren't JSON objects but JavaScript expressions. This way
you can pass JavaScript code that will evaluate the option values when the
socialSharePrivacy
function is called. You can even pass a whole new
service implementation inline, if you want:
<div class="share"
data-options="{
language : document.documentElement.lang,
title : document.title,
services : {
my_inline_service : {
status : true,
dummy_line_img : 'dummy.png',
dummy_alt : 'DISABLED',
display_name : 'My Inline Service',
txt_info : 'Click to enable.',
perma_option : true,
button : function (options, uri, settings) {
return $('<div>ENABLED</div>');
}
}
}
}"></div>
The main advantage of using the data-*
attributes is, that you can easily
render several different share elements on your webserver and then initialize
them with one single JavaScript function call (no need for uniqe element IDs
and separate JavaScript calls for each element).
NOTE: When passing service options via data-*
attributes all option
values (except the common service options) are treated as strings. If you
need to pass values of other types (numbers, booleans, arrays or functions)
you need to use the JavaScript object syntax.
Set these options like this:
$.fn.socialSharePrivacy.settings.title = "Title of the thing to share.";
…
Or like this:
<script type="application/x-social-share-privacy-settings">
{
path_prefix: "/socialshareprivacy",
css_path: "socialshareprivacy.css",
…
}
</script>
The version using script
tags uses again JavaScript expressions to enable
inline service definitions.
Option | Default Value | Description |
---|---|---|
info_link | http://panzi.github.io/SocialSharePrivacy/ | The link of the i-icon that links users to more information about this. |
info_link_target | The target attribute of the info link. Possible values are _blank ,
_self , _parent , _top or a frame name. |
|
txt_settings | Settings | The text of the settings icon. |
txt_help | [Text] | Tooltip text of the settings menu. |
settings_perma | [Text] | Headline of the settings menu. |
layout | line | Possible values: line or box |
set_perma_option | function (service_name, settings) | Function that stores the perma setting of the service specified by service_name. |
del_perma_option | function (service_name, settings) | Function that removes the perma setting of the service specified by service_name. |
get_perma_options | function (settings) | Function that gets the perma setting of all services in an object where the keys are the service names and the values are boolean. Services that are missing are assumed as false. |
get_perma_option | function (service_name, settings) | Function that gets the perma setting of the service specified by service_name.
Returns a boolean value. Only one of the two functions get_perma_options and get_perma_option need to be implemented. In that case the respective other needs to be set to null. |
perma_option | true (if the jQuery cookies plugin is installed) | Give users the posibility to permanently enable services. (Boolean) |
cookie_path | / | |
cookie_domain | document.location.hostname |
|
cookie_expires | 365 | Days until the cookie expires. |
path_prefix | Prefix to all paths (css_path, dummy_line_img, dummy_box_img) | |
css_path | socialshareprivacy/socialshareprivacy.css | |
language | en | |
uri | [Function] | URI of the thing to share that is passed on to the share services. The default function
uses the value of the first link element with the rel attribute
canonical or the first meta element with the property
attribute og:url it can find or location.href if there are no such
elements. (Function or string) |
title | The title to pass to any share service that want's one. | |
description | The description to pass to any share service that want's one. | |
image | Image URL to pass to any share service that want's one. | |
embed | HTML embed code to pass to any share service that want's one. | |
ignore_fragment | true | Ignore the #fragment part of the url. (Boolean) |
Option | Default Value | Description |
---|---|---|
status | true | Enable/disable this service. (Boolean) |
class_name | [service specific] | The HTML class of the share button wrapper. Per default it is the key of the
service as it is registered in jQuery.fn.socialSharePrivacy.settings.services . |
button_class | HTML class of the share button. Per default the same as class_name. | |
dummy_line_img | Placeholder image for deactivated button in line layout. |
|
dummy_box_img | Placeholder image for deactivated button in box layout. |
|
dummy_alt | [Text] | Alt text of the placeholder image. |
txt_info | [Text] | Help text for deactivated button. |
txt_off | [Text] | Status text if button is deactivated. |
txt_on | [Text] | Status text if button is activated. |
perma_option | true | Give users the posibility to permanently enable this service. (Boolean) |
display_name | [Text] | Name of the service. |
referrer_track | A string that is appended to the URI for this service, so you can track from where your users are coming. | |
language | Override the global language just for this service. | |
path_prefix | Override the global path_prefix just for this service. |
See also: official documentation
Example:
$(document).ready(function () {
$('#share').socialSharePrivacy({
services: {
buffer: {
text : 'Some descriptive text...'
}
}
});
});
Option | Default Value | Description |
---|---|---|
text | jQuery.fn.socialSharePrivacy.getTitle | Tweet text (excluding the URL). It will be truncated to 120 characters, leaving place for 20 characters for the shortened URL. (Function or string) |
via | Twitter username (without the leading @ ). (Function or string) |
|
picture | jQuery.fn.socialSharePrivacy.getImage | URL of image that represents the thing to share. (Function or string) |
See also: official documentation
Example:
$(document).ready(function () {
$('#share').socialSharePrivacy({
services: {
delicious: {
title : 'Bookmark title'
}
}
});
});
Option | Default Value | Description |
---|---|---|
title | jQuery.fn.socialSharePrivacy.getTitle | Title of the new bookmark. (Function or string) |
See also: official documentation
WARNING: This is a hack. Using this Disqus button will break any usage of the comment count code as shown on the linked page above. This button does of course not interfere with the main Disqus widget.
Example:
$(document).ready(function () {
$('#share').socialSharePrivacy({
services: {
disqus: {
shortname : 'myforumshortname',
count : 'reactions'
}
}
});
});
Option | Default Value | Description |
---|---|---|
shortname | Your Disqus forum shortname. If an empty string is given it tries to use
window.disqus_shortname . (String) |
|
count | comments | What count to show. Possible values: comments or reactions |
onclick | Function to call when the Disqus button was clicked. (Function or String) |
Option | Default Value | Description |
---|---|---|
subject | jQuery.fn.socialSharePrivacy.getTitle | Subject of the new email. (Function or string) |
body | [Function] | Body of the new email. (Function or string) |
Note that facebook only supports certain languages and requires the region suffix (e.g.
en_US
). The facebook service ensures that only supported language strings are sent
to facebook, because otherwise facebook fails to render anything.
See also: official documentation
Example:
$(document).ready(function () {
$('#share').socialSharePrivacy({
services: {
facebook: {
action : 'recommend',
colorscheme : 'dark'
}
}
});
});
Option | Default Value | Description |
---|---|---|
action | like | Possible values: like or recommend |
colorscheme | light | Possible values: light or dark |
font | Possible values: arial , lucida grande , segoe ui , tahoma ,
trebuchet ms or verdana |
There are no Facebook Share specific options.
See also: official documentation
See also: official documentation
Example:
$(document).ready(function () {
$('#share').socialSharePrivacy({
services: {
flattr: {
uid : 'yourflattrid',
category : 'Text'
}
}
});
});
Option | Default Value | Description |
---|---|---|
title | jQuery.fn.socialSharePrivacy.getTitle | Title of the thing to share. (Function or string) |
description | jQuery.fn.socialSharePrivacy.getDescription | Description of the thing to share. (Function or string) |
uid | Flattr username. | |
category | Possible values: text , images , video , audio ,
software , people or rest |
|
tags | Multiple tags are seperated by a comma , . Only alpha characters are supported in tags. |
|
popout | When set to 0 no popout will appear when the Flattr button is hovered. |
|
hidden | When set to 1 your content will not be publicly listed on Flattr. |
There are no Google+ specific options.
See also: official documentation
See also: HNSearch API documentation
Option | Default Value | Description |
---|---|---|
title | jQuery.fn.socialSharePrivacy.getTitle | Title of the news to share. (Function or string) |
See also: official documentation
Option | Default Value | Description |
---|---|---|
title | jQuery.fn.socialSharePrivacy.getTitle | Title of the thing to share. (Function or string) |
description | jQuery.fn.socialSharePrivacy.getDescription | Description of the thing to share. (Function or string) |
media | jQuery.fn.socialSharePrivacy.getImage | URL of image that represents the thing to share. (Function or string) |
See also: official documentation
Option | Default Value | Description |
---|---|---|
onsuccess | Name of a callback function that shall invoked when the link was successfully shared. The shared url will be passed as a parameter. (String) | |
onerror | Name of a callback function that shall invoked if link sharing failed. The shared url will be passed as a parameter. (String) | |
showzero | false | Even show count and no placeholder if there are zero shares. (Boolean) |
See also: official documentation
Example:
$(document).ready(function () {
$('#share').socialSharePrivacy({
services: {
reddit: {
newwindow : false,
bgcolor : '#ffff00'
}
}
});
});
Option | Default Value | Description |
---|---|---|
title | jQuery.fn.socialSharePrivacy.getTitle | Title of the thing to share. (Function or string) |
target | A cummunity to target. | |
newwindow | 1 | Opens reddit in a new window when set to 1 . Set this option to an empty string or
anything that evaluates to false to open reddit in the same window. |
bgcolor | transparent | HTML color. |
bordercolor | HTML color. |
There are no Stumble Upon specific options.
See also: official documentation
See also: official documentation
Example:
$(document).ready(function () {
$('#share').socialSharePrivacy({
services: {
tumblr: {
type : 'photo',
photo : 'http://example.com/example.png'
}
}
});
});
Option | Default Value | Description |
---|---|---|
type | link | Possible values: link , quote , photo or video |
name | jQuery.fn.socialSharePrivacy.getTitle | Title of the thing to share. (Function or string) This option is only defined for the type link . |
description | jQuery.fn.socialSharePrivacy.getDescription | Description of the thing to share. (Function or string) This option is only defined for the type link . |
quote | [Function] | Quote to share. (Function or string) This option is only defined for the type quote . |
photo | jQuery.fn.socialSharePrivacy.getImage | Image URL of the thing to share. (Function or string) This option is only defined for the type photo . |
clickthrou | [Function] | The URL to where you get when you click the image. Per default it's the
shared URI including the referrer_track. (Function or string) This option is only defined for the type photo . |
embed | jQuery.fn.socialSharePrivacy.getEmbed | Embed code of the thing to share. (Function or string) This option is only defined for the type video . |
caption | jQuery.fn.socialSharePrivacy.getDescription | Caption of the thing to share. (Function or string) This option is only defined for the types photo and video . |
See also: official documentation
Example:
$(document).ready(function () {
$('#share').socialSharePrivacy({
services: {
twitter: {
hashtags : 'win'
}
}
});
});
Option | Default Value | Description |
---|---|---|
text | jQuery.fn.socialSharePrivacy.getTitle | Tweet text (excluding the URL). It will be truncated to 120 characters, leaving place for 20 characters for the shortened URL. (Function or string) |
via | Twitter username (without the leading @ ). |
|
related | Twitter username (without the leading @ ). |
|
hashtags | Hashtag to add to the tweet (without the leading # ). |
|
dnt | true | Do not tailor. |
There are no XING specific options.
Note that the view counter will not work unless the XING button is enabled by the user.
See also: official documentation
(function ($, undefined) {
$.fn.socialSharePrivacy.settings.services.myservice = {
/* default values for common service options... */
'button': function (options, uri, settings) {
return $('<iframe scrolling="no" frameborder="0" allowtransparency="true"></iframe>').attr(
'src', 'http://myservice.example/?' + $.param({
url: uri + options.referrer_track
});
}
};
})(jQuery);
Some helper functions that might be handy to use in your custom service.
Build an absolute url using a base url.
The provided base url has to be a valid absolute url. It will not be validated!
If no base url is given the documents base url/location is used.
Schemes that behave other than http might not work.
This function tries to support file:
-urls, but might fail in some cases.
email:
-urls aren't supported at all (don't make sense anyway).
Abbreviate at last blank before length and add "\u2026"
(…, horizontal ellipsis).
The length is the number of UTF-8 encoded bytes, not the number of unicode code
points, because twitters 140 "characters" are actually bytes.
Escapes text so it can be used safely in HTML strings.
Character | Replacement |
---|---|
< |
< |
> |
> |
& |
& |
" |
" |
' |
' |
Format a number to be displayed in a typical number bubble. It will
abbreviate numbers bigger than 9999 using the K
suffix, rounding the
number to the closest thousand and it inserts thousands delimeter
characters.
Example:
$.fn.socialSharePrivacy.formatNumber(1234) => "1,234"
$.fn.socialSharePrivacy.formatNumber(12345) => "12K"
$.fn.socialSharePrivacy.formatNumber(1234567) => "1,235K"
Lookup title of shared thing in several places:
settings.title
, which may be a string or a function with the same parameters.$('meta[name="DC.title"]').attr('content') + ' - ' + $('meta[name="DC.creator"]').attr('content')
$('meta[name="DC.title"]').attr('content')
$('meta[property="og:title"]').attr('content')
$('title').text()
The element of the share button is passed as this
.
Lookup image URL of shared thing in several places:
settings.image
, which may be a string or a function with the same parameters.$('meta[property="image"], meta[property="og:image"], meta[property="og:image:url"], ' +
'meta[name="twitter:image"], link[rel="image_src"], itemscope *[itemprop="image"]').
first().attr('content'
/'src'
/'href')
$('img').filter(':visible').filter(function () { return $(this).parents('.social_share_privacy_area').length === 0; })
, using the image with the biggest area.$('link[rel~="shortcut"][rel~="icon"]').attr('href')
'http://www.google.com/s2/favicons?'+$.param({domain:location.hostname})
The element of the share button is passed as this
.
Lookup image URL of shared thing in several places:
settings.embed
, which may be a string or a function with the same parameters.
If there is no embed code found it will construct it's own embed code. For this it
first searches for a meta element with the name twitter:player
and use it's
content as the src
of an iframe element. If meta tags with the names
twitter:player:width
and twitter:player:height
are found they are used for the
width and height attributes of the iframe. If no twitter:player
meta elements is
found the url of the current page will be used as the iframe src
(uri + options.referrer_track
).
The element of the share button is passed as this
.
Lookup description of shared thing in several places:
settings.description
, which may be a string or a function with the same parameters.$('meta[name="twitter:description"]').attr('content')
$('meta[itemprop="description"]').attr('content')
$('meta[name="description"]').attr('content')
$('article, p').first().text()
$('body').text()
If not defined in settings.description
the found text is truncated at 3500 bytes.
The element of the share button is passed as this
.
You can use build.sh
to pack the modules and languages you want. This requires
uglifyjs and
uglifycss to be installed.
Example:
./build.sh -m twitter,facebook,gplus -l de,fr
This generates these files:
build/jquery.socialshareprivacy.min.js
build/jquery.socialshareprivacy.min.autoload.js
build/jquery.socialshareprivacy.min.de.js
build/jquery.socialshareprivacy.min.fr.js
build/jquery.socialshareprivacy.min.css
These files then contain only the JavaScript/CSS code for Twitter, Facebook and Google+.
jquery.socialshareprivacy.min.de.js
and jquery.socialshareprivacy.min.fr.js
only
contain translation strings, so you need to include them after jquery.socialshareprivacy.min.js
in your HTML document.
Usage:
./build.sh [options]
Options:
-h Print this help message.
-m <modules> Comma separated list of JavaScript modules to pack. Possible values:
all, none, buffer, delicious, disqus, facebook, flattr,
gplus, hackernews, linkedin, mail, pinterest, reddit,
stumbleupon, tumblr, twitter, xing
default: all
-l <languages> Comma separated list of languages to pack. Possible values:
all, none, de, es, fr, nl, pl, pt, ru
default: all
-a <enabled> Autoload. Possible values: on, off (default: on)
-c <enabled> Pack stylesheets. Possible values: on, off (default: on)
-i <enabled> Pack images. Possible values: on, off (default: on)
-p <path> Prefix to stylesheet and dummy image paths. (empty per default)
-s <path> Stylesheet path in the generated JavaScript file.
default: stylesheets/jquery.socialshareprivacy.min.css
-o <directory> Output directory. (default: build)
In Internet Explorer <= 8 the Disqus widget doesn't work the first time you enable it. You have to disable and then enable it again. I could not figure out what might cause this.
It is recommended to declare a compatibility mode of Internet Explorer >= 9. E.g. add this to the head of your HTML documents:
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
Internet Explorer <= 7 is not supported.
Most of this plugin is licensed under the MIT license:
Copyright (c) 2012 Mathias Panzenböck
Copyright (c) 2011 Hilko Holweg, Sebastian Hilbig, Nicolas Heiringhoff,
Juergen Schmidt, Heise Zeitschriften Verlag GmbH & Co. KG, http://www.heise.de
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The file stylesheets/jquery.socialshareprivacy.delicious.css
is licensed under
the Apache License, Version 2.0:
Copyright (c) 2012 Mathias Panzenböck
Copyright (c) 2010 [Mike @ moretechtips.net]
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
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.