-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 5ae5f06
Showing
23 changed files
with
1,307 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
<img src="/images/logo.png" width=25%> | ||
|
||
Sourcepoint's HTML5 OTT solution allows you to surface a Sourcepoint CMP message on devices such as Tizen and webOS for supported regulatory frameworks. | ||
|
||
# Table of Contents | ||
|
||
- [Implementation overview](#implementation-overview) | ||
- [Supported campaigns](#supported-campaigns) | ||
- [Resurface OTT message](#resurface-ott-message) | ||
- [Global Privacy Platform (GPP) Multi-State Privacy (MSPS) support](#global-privacy-platform-gpp-multi-state-privacy-msps-support) | ||
- [APIs](#apis) | ||
|
||
## Implementation overview | ||
|
||
Every implementation requires a bundle of scripts that must be added to your `index.html` file in order to surface the appropriate message configured in the Sourcepoint portal. | ||
|
||
- [Stub file(s)](#stub-files) | ||
- [Client configuration script](#client-configuration-script) | ||
- [URL to messaging library](#url-to-messaging-library) | ||
|
||
### Stub file(s) | ||
|
||
The first part implementation script(s) contains the IAB stub functions. The stub functions set up the IAB privacy string object `__tcfapi` (for GDPR TCF campaigns) or `__uspapi` (for U.S. Privacy (Legacy) campaigns), respectively. | ||
|
||
This makes it available on queue to be called and released when needed. It is important to have these stub file(s) in the first position to avoid errors and failure of service. | ||
|
||
> Note: There is no stub file when configuring a GDPR Standard campaign for your project. | ||
```javascript | ||
// GDPR TCF stub file. Example only. Please use stub file generated in Sourcepoint portal as it may have changed. | ||
<script type="text/javascript"> | ||
function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}!function(){for(var t,e,o=[],n=window,r=n;r;){try{if(r.frames.__tcfapiLocator){t=r;break}}catch(t){}if(r===n.top)break;r=n.parent}t||(function t(){var e=n.document,o=!!n.frames.__tcfapiLocator;if(!o)if(e.body){var r=e.createElement("iframe");r.style.cssText="display:none",r.name="__tcfapiLocator",e.body.appendChild(r)}else setTimeout(t,5);return!o}(),n.__tcfapi=function(){for(var t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];if(!n.length)return o;"setGdprApplies"===n[0]?n.length>3&&2===parseInt(n[1],10)&&"boolean"==typeof n[3]&&(e=n[3],"function"==typeof n[2]&&n[2]("set",!0)):"ping"===n[0]?"function"==typeof n[2]&&n[2]({gdprApplies:e,cmpLoaded:!1,cmpStatus:"stub"}):o.push(n)},n.addEventListener("message",(function(t){var e="string"==typeof t.data,o={};if(e)try{o=JSON.parse(t.data)}catch(t){}else o=t.data;var n="object"===_typeof(o)?o.__tcfapiCall:null;n&&window.__tcfapi(n.command,n.version,(function(o,r){var a={__tcfapiReturn:{returnValue:o,success:r,callId:n.callId}};t&&t.source&&t.source.postMessage&&t.source.postMessage(e?JSON.stringify(a):a,"*")}),n.parameter)}),!1))}(); | ||
</script> | ||
``` | ||
|
||
```javascript | ||
// US Privacy (Legacy) stub file. Example only. Please use stub file generated in Sourcepoint portal as it may have changed. | ||
<script> | ||
(function () { var e = false; var c = window; var t = document; function r() { if (!c.frames["__uspapiLocator"]) { if (t.body) { var a = t.body; var e = t.createElement("iframe"); e.style.cssText = "display:none"; e.name = "__uspapiLocator"; a.appendChild(e) } else { setTimeout(r, 5) } } } r(); function p() { var a = arguments; __uspapi.a = __uspapi.a || []; if (!a.length) { return __uspapi.a } else if (a[0] === "ping") { a[2]({ gdprAppliesGlobally: e, cmpLoaded: false }, true) } else { __uspapi.a.push([].slice.apply(a)) } } function l(t) { var r = typeof t.data === "string"; try { var a = r ? JSON.parse(t.data) : t.data; if (a.__cmpCall) { var n = a.__cmpCall; c.__uspapi(n.command, n.parameter, function (a, e) { var c = { __cmpReturn: { returnValue: a, success: e, callId: n.callId } }; t.source.postMessage(r ? JSON.stringify(c) : c, "*") }) } } catch (a) { } } if (typeof __uspapi !== "function") { c.__uspapi = p; __uspapi.msgHandler = l; c.addEventListener("message", l, false) } })(); | ||
</script> | ||
``` | ||
|
||
```javascript | ||
// US Multi-State Privacy stub file. Example only. Please use stub file generated in Sourcepoint portal as it may have changed. | ||
window.__gpp_addFrame=function(e){if(!window.frames[e])if(document.body){var t=document.createElement("iframe");t.style.cssText="display:none",t.name=e,document.body.appendChild(t)}else window.setTimeout(window.__gpp_addFrame,10,e)},window.__gpp_stub=function(){var e=arguments;if(__gpp.queue=__gpp.queue||[],__gpp.events=__gpp.events||[],!e.length||1==e.length&&"queue"==e[0])return __gpp.queue;if(1==e.length&&"events"==e[0])return __gpp.events;var t=e[0],p=e.length>1?e[1]:null,s=e.length>2?e[2]:null;if("ping"===t)p({gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:["2:tcfeuv2","5:tcfcav1","6:uspv1","7:usnatv1","8:uscav1","9:usvav1","10:uscov1","11:usutv1","12:usctv1"],cmpId:0,sectionList:[],applicableSections:[],gppString:"",parsedSections:{}},!0);else if("addEventListener"===t){"lastId"in __gpp||(__gpp.lastId=0),__gpp.lastId++;var n=__gpp.lastId;__gpp.events.push({id:n,callback:p,parameter:s}),p({eventName:"listenerRegistered",listenerId:n,data:!0,pingData:{gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:["2:tcfeuv2","5:tcfcav1","6:uspv1","7:usnatv1","8:uscav1","9:usvav1","10:uscov1","11:usutv1","12:usctv1"],cmpId:0,sectionList:[],applicableSections:[],gppString:"",parsedSections:{}}},!0)}else if("removeEventListener"===t){for(var a=!1,i=0;i<__gpp.events.length;i++)if(__gpp.events[i].id==s){__gpp.events.splice(i,1),a=!0;break}p({eventName:"listenerRemoved",listenerId:s,data:a,pingData:{gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:["2:tcfeuv2","5:tcfcav1","6:uspv1","7:usnatv1","8:uscav1","9:usvav1","10:uscov1","11:usutv1","12:usctv1"],cmpId:0,sectionList:[],applicableSections:[],gppString:"",parsedSections:{}}},!0)}else"hasSection"===t?p(!1,!0):"getSection"===t||"getField"===t?p(null,!0):__gpp.queue.push([].slice.apply(e))},window.__gpp_msghandler=function(e){var t="string"==typeof e.data;try{var p=t?JSON.parse(e.data):e.data}catch(e){p=null}if("object"==typeof p&&null!==p&&"__gppCall"in p){var s=p.__gppCall;window.__gpp(s.command,(function(p,n){var a={__gppReturn:{returnValue:p,success:n,callId:s.callId}};e.source.postMessage(t?JSON.stringify(a):a,"*")}),"parameter"in s?s.parameter:null,"version"in s?s.version:"1.1")}},"__gpp"in window&&"function"==typeof window.__gpp||(window.__gpp=window.__gpp_stub,window.addEventListener("message",window.__gpp_msghandler,!1),window.__gpp_addFrame("__gppLocator")); | ||
</script> | ||
``` | ||
|
||
### Client configuration script | ||
|
||
### URL to messaging library | ||
|
||
## Supported campaigns | ||
|
||
Campaign are surfaced on yout HTML5 device by adding campaign objects to your configuration | ||
|
||
The following Sourcepoint campaigns are supported via our HTML5 OTT solution: | ||
|
||
| **Config object** | **Campaign** | | ||
| ----------------- | ------------------------- | | ||
| `gdpr: {}` | GDPR TCF or GDPR Standard | | ||
| `ccpa: {}` | U.S. Privacy (Legacy) | | ||
|
||
> U.S. Multi-State Privacy campaigns are currently not supported for HTML5 OTT devices. If your organization needs to support the Global Privacy Platform (GPP) Multi-State Privacy (MSPS) framework, you will need to configure a U.S. Privacy (Legacy) campaign to do so. [Click here](#us-multi-state-privacy-campaign-support) for more information about this configuration. | ||
## Resurface OTT message | ||
|
||
The privacy manager JavaScript code is a snippet that is added to your project and allows an end-user to resurface a privacy manager. Using this link/button, end-users can directly manage their consent preferences on an ongoing basis without having to re-encounter your organization's first layer message. | ||
|
||
Load the OTT message on demand by [retrieving the OTT message ID](https://docs.sourcepoint.com/hc/en-us/articles/20806618675603-Resurface-OTT-message) from the Sourcepoint portal and pass it to the `loadNativeOtt` function. | ||
|
||
```javascript | ||
//GDPR | ||
window._sp_.gdpr.loadNativeOtt(GDPR_OTT_ID); | ||
|
||
//U.S. Privacy (Legacy) | ||
window._sp_.ccpa.loadNativeOtt(USP_LEGACY_OTT_ID); | ||
``` | ||
|
||
Attach the `loadNativeOtt` function to an event handler on your project. Most organizations who implement this function will attach it to `onclick` event of an element. | ||
|
||
```javascript | ||
//GDPR | ||
<button onclick="window._sp_.gdpr.loadNativeOtt(123456)">OTT GDPR</button> | ||
|
||
//U.S. Privacy (Legacy) | ||
<button onclick="window._sp_.ccpa.loadNativeOtt(987654)">OTT USP Legacy</button> | ||
``` | ||
|
||
## Global Privacy Platform (GPP) Multi-State Privacy (MSPS) support | ||
|
||
In the Sourcepoint portal, U.S. Multi-State Privacy campaigns are created to support the Global Privacy Platform (GPP) Multi-State Privacy (MSPS) framework. Currently, U.S. Multi-State Privacy campaigns are not supported in Sourcepoint's HTML5 OTT solution. | ||
|
||
If your organization wishes to support the Global Privacy Platform (GPP) Multi-State Privacy (MSPS) framework you will need to specifically configure a U.S. Privacy (Legacy) campaign to do so. | ||
|
||
> Once successfully, configured Sourcepoint will enable the Multi-State Privacy String (MSPS) alongside the U.S. Privacy String. The MSPS can be acessed via the [GPP API](https://sourcepoint-public-api.readme.io/reference/iab-global-privacy-platform-gpp-api).<br><br>Please be aware that this solution will only set the [U.S. National Privacy section of the MSPS](https://sourcepoint-public-api.readme.io/reference/us-national-privacy-section) and will not set values for sensitive data categories. | ||
Add the GPP stub file in addition to the U.S. Privacy - CCPA stub file to `index.html`. | ||
|
||
```javascript | ||
//Example only. Please use stub file generated in Sourcepoint portal as it may have changed. | ||
<script> | ||
window.__gpp_addFrame=function(e){if(!window.frames[e])if(document.body){var t=document.createElement("iframe");t.style.cssText="display:none",t.name=e,document.body.appendChild(t)}else window.setTimeout(window.__gpp_addFrame,10,e)},window.__gpp_stub=function(){var e=arguments;if(__gpp.queue=__gpp.queue||[],__gpp.events=__gpp.events||[],!e.length||1==e.length&&"queue"==e[0])return __gpp.queue;if(1==e.length&&"events"==e[0])return __gpp.events;var t=e[0],p=e.length>1?e[1]:null,s=e.length>2?e[2]:null;if("ping"===t)p({gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:["2:tcfeuv2","5:tcfcav1","6:uspv1","7:usnatv1","8:uscav1","9:usvav1","10:uscov1","11:usutv1","12:usctv1"],cmpId:0,sectionList:[],applicableSections:[],gppString:"",parsedSections:{}},!0);else if("addEventListener"===t){"lastId"in __gpp||(__gpp.lastId=0),__gpp.lastId++;var n=__gpp.lastId;__gpp.events.push({id:n,callback:p,parameter:s}),p({eventName:"listenerRegistered",listenerId:n,data:!0,pingData:{gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:["2:tcfeuv2","5:tcfcav1","6:uspv1","7:usnatv1","8:uscav1","9:usvav1","10:uscov1","11:usutv1","12:usctv1"],cmpId:0,sectionList:[],applicableSections:[],gppString:"",parsedSections:{}}},!0)}else if("removeEventListener"===t){for(var a=!1,i=0;i<__gpp.events.length;i++)if(__gpp.events[i].id==s){__gpp.events.splice(i,1),a=!0;break}p({eventName:"listenerRemoved",listenerId:s,data:a,pingData:{gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:["2:tcfeuv2","5:tcfcav1","6:uspv1","7:usnatv1","8:uscav1","9:usvav1","10:uscov1","11:usutv1","12:usctv1"],cmpId:0,sectionList:[],applicableSections:[],gppString:"",parsedSections:{}}},!0)}else"hasSection"===t?p(!1,!0):"getSection"===t||"getField"===t?p(null,!0):__gpp.queue.push([].slice.apply(e))},window.__gpp_msghandler=function(e){var t="string"==typeof e.data;try{var p=t?JSON.parse(e.data):e.data}catch(e){p=null}if("object"==typeof p&&null!==p&&"__gppCall"in p){var s=p.__gppCall;window.__gpp(s.command,(function(p,n){var a={__gppReturn:{returnValue:p,success:n,callId:s.callId}};e.source.postMessage(t?JSON.stringify(a):a,"*")}),"parameter"in s?s.parameter:null,"version"in s?s.version:"1.1")}},"__gpp"in window&&"function"==typeof window.__gpp||(window.__gpp=window.__gpp_stub,window.addEventListener("message",window.__gpp_msghandler,!1),window.__gpp_addFrame("__gppLocator")); | ||
</script> | ||
``` | ||
|
||
Add the `includeGppApi` parameter to the `ccpa` object in your client configuration and set one of the following flag(s) depending on your organization's use case. [Click here](docs/MSPS_signatories.md) for more information on each attribute, possible values, and examples for signatories and non-signatories of the MSPA. | ||
|
||
If `includeGppApi` is set to `true`, the following MSPA arguments will be set accordingly: | ||
|
||
- `MspaCoveredTransaction`: `"no"` | ||
- `MspaOptOutOptionMode`: `"na"` | ||
- `MspaServiceProviderMode`: `"na"` | ||
|
||
``` | ||
window._sp_queue = []; | ||
window._sp_ = { | ||
config: { | ||
accountId: 1584, | ||
baseEndpoint: 'https://cdn.privacy-mgmt.com', | ||
ccpa: { | ||
includeGppApi: true | ||
}, | ||
propertyHref: 'https://www.testdemo.com', | ||
``` | ||
|
||
Optionally, your organization can customize support for the MSPS by configuring the MSPA attributes as part of the GPP config. | ||
|
||
``` | ||
window._sp_queue = []; | ||
window._sp_ = { | ||
config: { | ||
accountId: 1584, | ||
baseEndpoint: 'https://cdn.privacy-mgmt.com', | ||
ccpa: { | ||
includeGppApi: { | ||
"MspaCoveredTransaction": "yes", | ||
"MspaOptOutOptionMode": "yes", | ||
"MspaServiceProviderMode": "no" | ||
} | ||
}, | ||
propertyHref: 'https://www.testdemo.com', | ||
``` | ||
|
||
## APIs | ||
|
||
Find comprehensive guides and documentation to help you start working with Sourcepoint's public APIs as quickly as possible for different regulatory frameworks in our [API Hub](https://sourcepoint-public-api.readme.io/reference/welcome-to-the-sourcepoint-api-hub). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
The IAB Tech Lab's Global Privacy Platform's (GPP) Multi-State Privacy String (MSPS) is a signal that notifies downstream partners that participating publishers have provided end-users with specific notice and choice over data processing activities on their properties. | ||
|
||
Your organization will need to configure the following attributes as part of the GPP config: | ||
|
||
| Attribute | Possible values | Description | | ||
| ------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `MspaCoveredTransaction` | `yes`<br> `no` | Publisher or Advertiser, as applicable, is a signatory to the IAB Multistate Service Provider Agreement (MSPA), as may be amended from time to time, and declares that the transaction is a “Covered Transaction” as defined in the MSPA.<br><br>The configured value for the flag will translate to the following in the MSPS:<br>`yes` = 1<br>`no` = 2 | | ||
| `MspaOptOutOptionMode` | `na`<br> `yes`<br> `no` | Publisher or Advertiser, as applicable, has enabled “Opt-Out Option Mode” for the “Covered Transaction,” as such terms are defined in the MSPA.<br><br>The configured value for the flag will translate to the following in the MSPS:<br>`na` = 0<br>`yes` = 1<br>`no` = 2 | | ||
| `MspaServiceProviderMode` | `na`<br> `yes`<br> `no` | Publisher or Advertiser, as applicable, has enabled “Service Provider Mode” for the “Covered Transaction,” as such terms are defined in the MSPA.<br><br>The configured value for the flag will translate to the following in the MSPS:<br>`na` = 0 <br> `yes` = 1 <br> `no` = 2 | | ||
|
||
Depending on whether your organization is a signatory of the Multi-State Privacy Agreement (MSPA), your organization will configure the attributes in the following ways: | ||
|
||
### Non-signatory of the MSPA | ||
|
||
For organizations who have not signed the MSPA and only want to listen for the MSPS. When setting the attributes thusly, the MSPA, as a contractual framework, does not cover your transactions. | ||
|
||
> Note: This is the default settings for these attributes. Non-signatories of the MSPA can also just set the `includeGppApi` parameter to `true` within the `ccpa` object and these attributes will default to this configuration. | ||
``` | ||
window._sp_queue = []; | ||
window._sp_ = { | ||
config: { | ||
accountId: 1584, | ||
baseEndpoint: 'https://cdn.privacy-mgmt.com', | ||
ccpa: { | ||
includeGppApi: { | ||
"MspaCoveredTransaction": "no", | ||
"MspaOptOutOptionMode": "na", | ||
"MspaServiceProviderMode": "na" | ||
} | ||
}, | ||
propertyHref: 'https://www.testdemo.com', | ||
``` | ||
|
||
### Signatory of the MSPA | ||
|
||
For transactions covered by the MSPA, signatories can choose to operate in [Opt-Out Option Mode or Service Provider Mode](https://www.iab.com/wp-content/uploads/2022/12/IAB_MSPA_Decision_Tree.pdf). | ||
|
||
``` | ||
window._sp_queue = []; | ||
window._sp_ = { | ||
config: { | ||
accountId: 1584, | ||
baseEndpoint: 'https://cdn.privacy-mgmt.com', | ||
ccpa: { | ||
includeGppApi: { | ||
"MspaCoveredTransaction": "yes", | ||
"MspaOptOutOptionMode": "yes", | ||
"MspaServiceProviderMode": "no" | ||
} | ||
}, | ||
propertyHref: 'https://www.testdemo.com', | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<widget xmlns:tizen="http://tizen.org/ns/widgets" xmlns="http://www.w3.org/ns/widgets" id="http://yourdomain/SourcepointCMP" version="1.2.0" viewmodes="maximized"> | ||
<access origin="*" subdomains="true"></access> | ||
<tizen:application id="dMsNuVOUiZ.SourcepointCMP" package="dMsNuVOUiZ" required_version="3.0" launch_mode="single"/> | ||
<content src="index.html"/> | ||
<feature name="http://tizen.org/feature/screen.size.all"/> | ||
<icon src="icon.png"/> | ||
<name>SourcepointCMP</name> | ||
<tizen:privilege name="http://tizen.org/privilege/fullscreen"/> | ||
<tizen:privilege name="http://tizen.org/privilege/internet"/> | ||
<tizen:privilege name="http://tizen.org/privilege/tv.inputdevice"/> | ||
<tizen:profile name="tv-samsung"/> | ||
</widget> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
* { | ||
font-family: Lucida Sans, Arial, Helvetica, sans-serif; | ||
} | ||
|
||
body { | ||
margin: 50px auto; | ||
background-color: #ffffff; | ||
} | ||
|
||
header h1 { | ||
font-size: 108px; | ||
margin: 0px; | ||
} | ||
|
||
header h2 { | ||
font-size: 54px; | ||
margin: 0px; | ||
color: #888; | ||
font-style: italic; | ||
} | ||
|
||
nav ul { | ||
list-style: none; | ||
padding: 20px; | ||
display: block; | ||
clear: right; | ||
background-color: #666; | ||
padding-left: 4px; | ||
height: 48px; | ||
} | ||
|
||
nav ul li { | ||
display: inline; | ||
padding: 0px 20px 5px 10px; | ||
border-right: 1px solid #ccc; | ||
} | ||
|
||
nav ul li a { | ||
color: #EFD3D3; | ||
text-decoration: none; | ||
font-size: 39px; | ||
font-weight: bold; | ||
} | ||
|
||
nav ul li a:hover { | ||
color: #fff; | ||
} | ||
|
||
article > header h1 { | ||
font-size: 60px; | ||
margin-left: 14px; | ||
} | ||
|
||
article > header h1 a { | ||
color: #993333; | ||
} | ||
|
||
article > header h1 img { | ||
vertical-align:middle; | ||
} | ||
|
||
article > section header h1 { | ||
font-size: 48px; | ||
} | ||
|
||
article p { | ||
clear: both; | ||
} | ||
|
||
footer p { | ||
text-align: center; | ||
font-size: 36px; | ||
color: #888; | ||
margin-top: 30px; | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.