Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions examples/edcon/Makefile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
XMLSECTOOL=xmlsectool
KEYSTORE=
KEY=1
KEYPASSWORD=
SIGNATURE_ALGORITHM=rsa-sha256

help:
# Needs a target, example: $$ make EntryToken.canonicalized.xml
#
# Let's say you have a TokenScript "EntryToken.xml"
#- to validate and canonicalize, add 'canonicalized' in the filename
@echo $$ make EntryToken.canonicalized.xml
# - to sign, use tsml as file extension:
@echo $$ make EntryToken.tsml

%.canonicalized.xml : %.xml
# xmlsectool canonicalises automatically when needed, but leaving an xml:base attribute which creates trouble later.
# xmlstarlet does it neatly
# XML Canonicalization
xmlstarlet c14n $^ > $@
# xmlsectool validates too, albeit adding xml:base with breaks schema. Example:
# JVMOPTS=-Djavax.xml.accessExternalDTD=all /opt/xmlsectool-2.0.0/xmlsectool.sh --validateSchema --xsd --schemaDirectory ../../schema --inFile $^
# XML Validation
# if INVALID, run validation again with xmllint to get meaningful error
# then delete the canonicalized file
-xmlstarlet val --xsd http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@ || (mv $@ $@.INVALID; xmllint --noout --schema http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@.INVALID)

%.tsml: %.canonicalized.xml
ifeq (,$(KEYSTORE))
@echo ---------------- Keystore missing. Try this ----------------
@echo $$ make KEYSTORE=shong.wang.p12 KEYPASSWORD=shong.wang $@
@echo replace it with your .p12 file and your password
rm $^
else
$(XMLSECTOOL) --sign --keyInfoKeyName 'Shong Wang' --digest SHA-256 --signatureAlgorithm http://www.w3.org/2001/04/xmldsig-more#$(SIGNATURE_ALGORITHM) --inFile $^ --outFile $@ --keystore $(KEYSTORE) --keystoreType PKCS12 --key $(KEY) --keyPassword $(KEYPASSWORD) --signaturePosition LAST
# removing the canonicalized created for validation
rm $^
endif
46 changes: 46 additions & 0 deletions examples/edcon/shared.css
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
.tbml-count {
font-family: "SourceSansPro";
font-weight: bolder;
font-size: 21px;
color: rgb(117, 185, 67);
}
.tbml-category {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 21px;
color: rgb(67, 67, 67);
}
.tbml-venue {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(67, 67, 67);
}
.tbml-date {
font-family: "SourceSansPro";
font-weight: bold;
font-size: 14px;
color: rgb(112, 112, 112);
margin-left: 7px;
margin-right: 7px;
}
.tbml-time {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(112, 112, 112);
}
html {
}
body {
padding: 0px;
margin: 0px;
}
div {
margin: 0px;
padding: 0px;
}
.data-icon {
height:16px;
vertical-align: middle
}
145 changes: 145 additions & 0 deletions examples/edcon/unicon.en.shtml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
<script type="text/javascript">
(function() {
'use strict'

function GeneralizedTime(generalizedTime) {
this.rawData = generalizedTime;
}

GeneralizedTime.prototype.getYear = function () {
return parseInt(this.rawData.substring(0, 4), 10);
}

GeneralizedTime.prototype.getMonth = function () {
return parseInt(this.rawData.substring(4, 6), 10) - 1;
}

GeneralizedTime.prototype.getDay = function () {
return parseInt(this.rawData.substring(6, 8), 10)
},

GeneralizedTime.prototype.getHours = function () {
return parseInt(this.rawData.substring(8, 10), 10)
},

GeneralizedTime.prototype.getMinutes = function () {
var minutes = parseInt(this.rawData.substring(10, 12), 10)
if (minutes) return minutes
return 0
},

GeneralizedTime.prototype.getSeconds = function () {
var seconds = parseInt(this.rawData.substring(12, 14), 10)
if (seconds) return seconds
return 0
},

GeneralizedTime.prototype.getMilliseconds = function () {
var startIdx
if (time.indexOf('.') !== -1) {
startIdx = this.rawData.indexOf('.') + 1
} else if (time.indexOf(',') !== -1) {
startIdx = this.rawData.indexOf(',') + 1
} else {
return 0
}

var stopIdx = time.length - 1
var fraction = '0' + '.' + time.substring(startIdx, stopIdx)
var ms = parseFloat(fraction) * 1000
return ms
},

GeneralizedTime.prototype.getTimeZone = function () {
let time = this.rawData;
var length = time.length
var symbolIdx
if (time.charAt(length - 1 ) === 'Z') return 0
if (time.indexOf('+') !== -1) {
symbolIdx = time.indexOf('+')
} else if (time.indexOf('-') !== -1) {
symbolIdx = time.indexOf('-')
} else {
return NaN
}

var minutes = time.substring(symbolIdx + 2)
var hours = time.substring(symbolIdx + 1, symbolIdx + 2)
var one = (time.charAt(symbolIdx) === '+') ? 1 : -1

var intHr = one * parseInt(hours, 10) * 60 * 60 * 1000
var intMin = one * parseInt(minutes, 10) * 60 * 1000
var ms = minutes ? intHr + intMin : intHr
return ms
}

if (typeof exports === 'object') {
module.exports = GeneralizedTime
} else if (typeof define === 'function' &amp;&amp; define.amd) {
define(GeneralizedTime)
} else {
window.GeneralizedTime = GeneralizedTime
}
}())
</script>
<script type="text/javascript"><![CDATA[
class Token {
constructor(tokenInstance) {
this.props = tokenInstance
}

formatGeneralizedTimeToDate(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleDateString()
}
formatGeneralizedTimeToTime(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})
}

render() {
let time;
let date;
if (this.props.time == null) {
time = ""
date = ""
} else {
time = this.formatGeneralizedTimeToTime(this.props.time.generalizedTime)
date = this.props.time == null ? "": this.formatGeneralizedTimeToDate(this.props.time.generalizedTime)
}
let redeemedMessage = "";
//might not have loaded so only set if actually loaded
if(this.props.redeemed === "1") {
redeemedMessage = "(Redeemed)"
} else if(this.props.redeemed === "0") {
redeemedMessage = "(Not redeemed)"
}
return `<div>
<div>
<span class="tbml-count">x${this.props._count}</span>
<span class="tbml-category">${this.props.category}</span>
<span class="tbml-category">${redeemedMessage}</span>
</div>
<div>
<span class="tbml-venue">${this.props.venue}</span>
</div>
<div style="margin: 0px; padding:0px; clear: both; height: 6px">
&nbsp;
</div>
<div>
<img src="data:image/png;base64,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" class="data-icon"/>
<span class="tbml-date">${date}</span>
</div>
<div>
<span class="tbml-time">${time}, &nbsp;${this.props.locality}</span>
</div>
</div>`;
}
}

web3.tokens.dataChanged = (oldTokens, updatedTokens) => {
const currentTokenInstance = web3.tokens.data.currentInstance;
document.getElementById('root').innerHTML = new Token(currentTokenInstance).render();
};
]]></script>
<div id="root"></div>
137 changes: 137 additions & 0 deletions examples/edcon/unicon.xml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE token [
<!ENTITY unicon.en SYSTEM "unicon.en.shtml">
<!ENTITY style SYSTEM "shared.css">
]>
<ts:token xmlns:ts="http://tokenscript.org/2019/10/tokenscript"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xsi:schemaLocation="http://tokenscript.org/2019/10/tokenscript http://tokenscript.org/2019/10/tokenscript.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
custodian="false"
>
<ts:name>
<ts:plurals xml:lang="en">
<ts:string quantity="one">Ticket</ts:string>
<ts:string quantity="other">Tickets</ts:string>
</ts:plurals>
</ts:name>

<ts:contract name="unicon" interface="erc721">
<ts:address network="100">0xF6b8DD8Ba9996bEaE6Ad0eE3481F1E9cF080A9eB</ts:address>
</ts:contract>

<ts:origins>
<!-- Define the contract which holds the token that the user will use -->
<ts:ethereum contract="unicon">
</ts:ethereum>
</ts:origins>

<ts:cards>
<ts:token-card>
<style type="text/css">&style;</style>
<ts:view-iconified xml:lang="en">
&unicon.en;
</ts:view-iconified>
<ts:view xml:lang="en">
&unicon.en;
</ts:view>
</ts:token-card>
</ts:cards>

<ts:attribute-types>

<ts:attribute-type id="time" syntax="1.3.6.1.4.1.1466.115.121.1.24">
<ts:name>
<ts:string xml:lang="en">Time</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000" as="utf8">
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<!-- TODO get location & venue, if only one then remove this attribute and hardcode it into the UI -->
<ts:attribute-type id="locality" oid="2.5.4.7" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">City</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000FF00000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="venue" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zhangzhongnan928 if you know the location, let me know

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBC,
They haven't paid to the venue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is
Vienna University of Economics and Business
Welthandelspl. 1, 1020 Wien, Austria

<ts:string xml:lang="en">Venue</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000FF000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Blockchain Plaza, Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="category" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">Cat</ts:string>
<ts:string xml:lang="zh">等级</ts:string>
<ts:string xml:lang="es">Cat</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000000000000000000000FF00000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">A</ts:value>
</ts:option>
<ts:option key="2">
<ts:value xml:lang="en">B</ts:value>
</ts:option>
<ts:option key="3">
<ts:value xml:lang="en">C</ts:value>
</ts:option>
<ts:option key="4">
<ts:value xml:lang="en">D</ts:value>
</ts:option>
<ts:option key="5">
<ts:value xml:lang="en">E</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="numero" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>№</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000000000000000000000FFFF00" as="uint"/>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="redeemed" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>Redeemed</ts:string>
</ts:name>
<ts:origins>
<ts:ethereum function="redeemed" contract="unicon" as="bool">
<ts:data>
<ts:uint256 ref="tokenId"/>
</ts:data>
</ts:ethereum>
</ts:origins>
</ts:attribute-type>

</ts:attribute-types>
</ts:token>
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions examples/edcon/Makefile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
XMLSECTOOL=xmlsectool
KEYSTORE=
KEY=1
KEYPASSWORD=
SIGNATURE_ALGORITHM=rsa-sha256

help:
# Needs a target, example: $$ make EntryToken.canonicalized.xml
#
# Let's say you have a TokenScript "EntryToken.xml"
#- to validate and canonicalize, add 'canonicalized' in the filename
@echo $$ make EntryToken.canonicalized.xml
# - to sign, use tsml as file extension:
@echo $$ make EntryToken.tsml

%.canonicalized.xml : %.xml
# xmlsectool canonicalises automatically when needed, but leaving an xml:base attribute which creates trouble later.
# xmlstarlet does it neatly
# XML Canonicalization
xmlstarlet c14n $^ > $@
# xmlsectool validates too, albeit adding xml:base with breaks schema. Example:
# JVMOPTS=-Djavax.xml.accessExternalDTD=all /opt/xmlsectool-2.0.0/xmlsectool.sh --validateSchema --xsd --schemaDirectory ../../schema --inFile $^
# XML Validation
# if INVALID, run validation again with xmllint to get meaningful error
# then delete the canonicalized file
-xmlstarlet val --xsd http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@ || (mv $@ $@.INVALID; xmllint --noout --schema http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@.INVALID)

%.tsml: %.canonicalized.xml
ifeq (,$(KEYSTORE))
@echo ---------------- Keystore missing. Try this ----------------
@echo $$ make KEYSTORE=shong.wang.p12 KEYPASSWORD=shong.wang $@
@echo replace it with your .p12 file and your password
rm $^
else
$(XMLSECTOOL) --sign --keyInfoKeyName 'Shong Wang' --digest SHA-256 --signatureAlgorithm http://www.w3.org/2001/04/xmldsig-more#$(SIGNATURE_ALGORITHM) --inFile $^ --outFile $@ --keystore $(KEYSTORE) --keystoreType PKCS12 --key $(KEY) --keyPassword $(KEYPASSWORD) --signaturePosition LAST
# removing the canonicalized created for validation
rm $^
endif
46 changes: 46 additions & 0 deletions examples/edcon/shared.css
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
.tbml-count {
font-family: "SourceSansPro";
font-weight: bolder;
font-size: 21px;
color: rgb(117, 185, 67);
}
.tbml-category {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 21px;
color: rgb(67, 67, 67);
}
.tbml-venue {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(67, 67, 67);
}
.tbml-date {
font-family: "SourceSansPro";
font-weight: bold;
font-size: 14px;
color: rgb(112, 112, 112);
margin-left: 7px;
margin-right: 7px;
}
.tbml-time {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(112, 112, 112);
}
html {
}
body {
padding: 0px;
margin: 0px;
}
div {
margin: 0px;
padding: 0px;
}
.data-icon {
height:16px;
vertical-align: middle
}
145 changes: 145 additions & 0 deletions examples/edcon/unicon.en.shtml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
<script type="text/javascript">
(function() {
'use strict'

function GeneralizedTime(generalizedTime) {
this.rawData = generalizedTime;
}

GeneralizedTime.prototype.getYear = function () {
return parseInt(this.rawData.substring(0, 4), 10);
}

GeneralizedTime.prototype.getMonth = function () {
return parseInt(this.rawData.substring(4, 6), 10) - 1;
}

GeneralizedTime.prototype.getDay = function () {
return parseInt(this.rawData.substring(6, 8), 10)
},

GeneralizedTime.prototype.getHours = function () {
return parseInt(this.rawData.substring(8, 10), 10)
},

GeneralizedTime.prototype.getMinutes = function () {
var minutes = parseInt(this.rawData.substring(10, 12), 10)
if (minutes) return minutes
return 0
},

GeneralizedTime.prototype.getSeconds = function () {
var seconds = parseInt(this.rawData.substring(12, 14), 10)
if (seconds) return seconds
return 0
},

GeneralizedTime.prototype.getMilliseconds = function () {
var startIdx
if (time.indexOf('.') !== -1) {
startIdx = this.rawData.indexOf('.') + 1
} else if (time.indexOf(',') !== -1) {
startIdx = this.rawData.indexOf(',') + 1
} else {
return 0
}

var stopIdx = time.length - 1
var fraction = '0' + '.' + time.substring(startIdx, stopIdx)
var ms = parseFloat(fraction) * 1000
return ms
},

GeneralizedTime.prototype.getTimeZone = function () {
let time = this.rawData;
var length = time.length
var symbolIdx
if (time.charAt(length - 1 ) === 'Z') return 0
if (time.indexOf('+') !== -1) {
symbolIdx = time.indexOf('+')
} else if (time.indexOf('-') !== -1) {
symbolIdx = time.indexOf('-')
} else {
return NaN
}

var minutes = time.substring(symbolIdx + 2)
var hours = time.substring(symbolIdx + 1, symbolIdx + 2)
var one = (time.charAt(symbolIdx) === '+') ? 1 : -1

var intHr = one * parseInt(hours, 10) * 60 * 60 * 1000
var intMin = one * parseInt(minutes, 10) * 60 * 1000
var ms = minutes ? intHr + intMin : intHr
return ms
}

if (typeof exports === 'object') {
module.exports = GeneralizedTime
} else if (typeof define === 'function' &amp;&amp; define.amd) {
define(GeneralizedTime)
} else {
window.GeneralizedTime = GeneralizedTime
}
}())
</script>
<script type="text/javascript"><![CDATA[
class Token {
constructor(tokenInstance) {
this.props = tokenInstance
}

formatGeneralizedTimeToDate(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleDateString()
}
formatGeneralizedTimeToTime(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})
}

render() {
let time;
let date;
if (this.props.time == null) {
time = ""
date = ""
} else {
time = this.formatGeneralizedTimeToTime(this.props.time.generalizedTime)
date = this.props.time == null ? "": this.formatGeneralizedTimeToDate(this.props.time.generalizedTime)
}
let redeemedMessage = "";
//might not have loaded so only set if actually loaded
if(this.props.redeemed === "1") {
redeemedMessage = "(Redeemed)"
} else if(this.props.redeemed === "0") {
redeemedMessage = "(Not redeemed)"
}
return `<div>
<div>
<span class="tbml-count">x${this.props._count}</span>
<span class="tbml-category">${this.props.category}</span>
<span class="tbml-category">${redeemedMessage}</span>
</div>
<div>
<span class="tbml-venue">${this.props.venue}</span>
</div>
<div style="margin: 0px; padding:0px; clear: both; height: 6px">
&nbsp;
</div>
<div>
<img src="data:image/png;base64,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" class="data-icon"/>
<span class="tbml-date">${date}</span>
</div>
<div>
<span class="tbml-time">${time}, &nbsp;${this.props.locality}</span>
</div>
</div>`;
}
}

web3.tokens.dataChanged = (oldTokens, updatedTokens) => {
const currentTokenInstance = web3.tokens.data.currentInstance;
document.getElementById('root').innerHTML = new Token(currentTokenInstance).render();
};
]]></script>
<div id="root"></div>
137 changes: 137 additions & 0 deletions examples/edcon/unicon.xml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE token [
<!ENTITY unicon.en SYSTEM "unicon.en.shtml">
<!ENTITY style SYSTEM "shared.css">
]>
<ts:token xmlns:ts="http://tokenscript.org/2019/10/tokenscript"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xsi:schemaLocation="http://tokenscript.org/2019/10/tokenscript http://tokenscript.org/2019/10/tokenscript.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
custodian="false"
>
<ts:name>
<ts:plurals xml:lang="en">
<ts:string quantity="one">Ticket</ts:string>
<ts:string quantity="other">Tickets</ts:string>
</ts:plurals>
</ts:name>

<ts:contract name="unicon" interface="erc721">
<ts:address network="100">0xF6b8DD8Ba9996bEaE6Ad0eE3481F1E9cF080A9eB</ts:address>
</ts:contract>

<ts:origins>
<!-- Define the contract which holds the token that the user will use -->
<ts:ethereum contract="unicon">
</ts:ethereum>
</ts:origins>

<ts:cards>
<ts:token-card>
<style type="text/css">&style;</style>
<ts:view-iconified xml:lang="en">
&unicon.en;
</ts:view-iconified>
<ts:view xml:lang="en">
&unicon.en;
</ts:view>
</ts:token-card>
</ts:cards>

<ts:attribute-types>

<ts:attribute-type id="time" syntax="1.3.6.1.4.1.1466.115.121.1.24">
<ts:name>
<ts:string xml:lang="en">Time</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000" as="utf8">
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<!-- TODO get location & venue, if only one then remove this attribute and hardcode it into the UI -->
<ts:attribute-type id="locality" oid="2.5.4.7" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">City</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000FF00000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="venue" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zhangzhongnan928 if you know the location, let me know

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBC,
They haven't paid to the venue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is
Vienna University of Economics and Business
Welthandelspl. 1, 1020 Wien, Austria

<ts:string xml:lang="en">Venue</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000FF000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Blockchain Plaza, Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="category" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">Cat</ts:string>
<ts:string xml:lang="zh">等级</ts:string>
<ts:string xml:lang="es">Cat</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000000000000000000000FF00000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">A</ts:value>
</ts:option>
<ts:option key="2">
<ts:value xml:lang="en">B</ts:value>
</ts:option>
<ts:option key="3">
<ts:value xml:lang="en">C</ts:value>
</ts:option>
<ts:option key="4">
<ts:value xml:lang="en">D</ts:value>
</ts:option>
<ts:option key="5">
<ts:value xml:lang="en">E</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="numero" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>№</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000000000000000000000FFFF00" as="uint"/>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="redeemed" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>Redeemed</ts:string>
</ts:name>
<ts:origins>
<ts:ethereum function="redeemed" contract="unicon" as="bool">
<ts:data>
<ts:uint256 ref="tokenId"/>
</ts:data>
</ts:ethereum>
</ts:origins>
</ts:attribute-type>

</ts:attribute-types>
</ts:token>
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions examples/edcon/Makefile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
XMLSECTOOL=xmlsectool
KEYSTORE=
KEY=1
KEYPASSWORD=
SIGNATURE_ALGORITHM=rsa-sha256

help:
# Needs a target, example: $$ make EntryToken.canonicalized.xml
#
# Let's say you have a TokenScript "EntryToken.xml"
#- to validate and canonicalize, add 'canonicalized' in the filename
@echo $$ make EntryToken.canonicalized.xml
# - to sign, use tsml as file extension:
@echo $$ make EntryToken.tsml

%.canonicalized.xml : %.xml
# xmlsectool canonicalises automatically when needed, but leaving an xml:base attribute which creates trouble later.
# xmlstarlet does it neatly
# XML Canonicalization
xmlstarlet c14n $^ > $@
# xmlsectool validates too, albeit adding xml:base with breaks schema. Example:
# JVMOPTS=-Djavax.xml.accessExternalDTD=all /opt/xmlsectool-2.0.0/xmlsectool.sh --validateSchema --xsd --schemaDirectory ../../schema --inFile $^
# XML Validation
# if INVALID, run validation again with xmllint to get meaningful error
# then delete the canonicalized file
-xmlstarlet val --xsd http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@ || (mv $@ $@.INVALID; xmllint --noout --schema http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@.INVALID)

%.tsml: %.canonicalized.xml
ifeq (,$(KEYSTORE))
@echo ---------------- Keystore missing. Try this ----------------
@echo $$ make KEYSTORE=shong.wang.p12 KEYPASSWORD=shong.wang $@
@echo replace it with your .p12 file and your password
rm $^
else
$(XMLSECTOOL) --sign --keyInfoKeyName 'Shong Wang' --digest SHA-256 --signatureAlgorithm http://www.w3.org/2001/04/xmldsig-more#$(SIGNATURE_ALGORITHM) --inFile $^ --outFile $@ --keystore $(KEYSTORE) --keystoreType PKCS12 --key $(KEY) --keyPassword $(KEYPASSWORD) --signaturePosition LAST
# removing the canonicalized created for validation
rm $^
endif
46 changes: 46 additions & 0 deletions examples/edcon/shared.css
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
.tbml-count {
font-family: "SourceSansPro";
font-weight: bolder;
font-size: 21px;
color: rgb(117, 185, 67);
}
.tbml-category {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 21px;
color: rgb(67, 67, 67);
}
.tbml-venue {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(67, 67, 67);
}
.tbml-date {
font-family: "SourceSansPro";
font-weight: bold;
font-size: 14px;
color: rgb(112, 112, 112);
margin-left: 7px;
margin-right: 7px;
}
.tbml-time {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(112, 112, 112);
}
html {
}
body {
padding: 0px;
margin: 0px;
}
div {
margin: 0px;
padding: 0px;
}
.data-icon {
height:16px;
vertical-align: middle
}
145 changes: 145 additions & 0 deletions examples/edcon/unicon.en.shtml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
<script type="text/javascript">
(function() {
'use strict'

function GeneralizedTime(generalizedTime) {
this.rawData = generalizedTime;
}

GeneralizedTime.prototype.getYear = function () {
return parseInt(this.rawData.substring(0, 4), 10);
}

GeneralizedTime.prototype.getMonth = function () {
return parseInt(this.rawData.substring(4, 6), 10) - 1;
}

GeneralizedTime.prototype.getDay = function () {
return parseInt(this.rawData.substring(6, 8), 10)
},

GeneralizedTime.prototype.getHours = function () {
return parseInt(this.rawData.substring(8, 10), 10)
},

GeneralizedTime.prototype.getMinutes = function () {
var minutes = parseInt(this.rawData.substring(10, 12), 10)
if (minutes) return minutes
return 0
},

GeneralizedTime.prototype.getSeconds = function () {
var seconds = parseInt(this.rawData.substring(12, 14), 10)
if (seconds) return seconds
return 0
},

GeneralizedTime.prototype.getMilliseconds = function () {
var startIdx
if (time.indexOf('.') !== -1) {
startIdx = this.rawData.indexOf('.') + 1
} else if (time.indexOf(',') !== -1) {
startIdx = this.rawData.indexOf(',') + 1
} else {
return 0
}

var stopIdx = time.length - 1
var fraction = '0' + '.' + time.substring(startIdx, stopIdx)
var ms = parseFloat(fraction) * 1000
return ms
},

GeneralizedTime.prototype.getTimeZone = function () {
let time = this.rawData;
var length = time.length
var symbolIdx
if (time.charAt(length - 1 ) === 'Z') return 0
if (time.indexOf('+') !== -1) {
symbolIdx = time.indexOf('+')
} else if (time.indexOf('-') !== -1) {
symbolIdx = time.indexOf('-')
} else {
return NaN
}

var minutes = time.substring(symbolIdx + 2)
var hours = time.substring(symbolIdx + 1, symbolIdx + 2)
var one = (time.charAt(symbolIdx) === '+') ? 1 : -1

var intHr = one * parseInt(hours, 10) * 60 * 60 * 1000
var intMin = one * parseInt(minutes, 10) * 60 * 1000
var ms = minutes ? intHr + intMin : intHr
return ms
}

if (typeof exports === 'object') {
module.exports = GeneralizedTime
} else if (typeof define === 'function' &amp;&amp; define.amd) {
define(GeneralizedTime)
} else {
window.GeneralizedTime = GeneralizedTime
}
}())
</script>
<script type="text/javascript"><![CDATA[
class Token {
constructor(tokenInstance) {
this.props = tokenInstance
}

formatGeneralizedTimeToDate(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleDateString()
}
formatGeneralizedTimeToTime(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})
}

render() {
let time;
let date;
if (this.props.time == null) {
time = ""
date = ""
} else {
time = this.formatGeneralizedTimeToTime(this.props.time.generalizedTime)
date = this.props.time == null ? "": this.formatGeneralizedTimeToDate(this.props.time.generalizedTime)
}
let redeemedMessage = "";
//might not have loaded so only set if actually loaded
if(this.props.redeemed === "1") {
redeemedMessage = "(Redeemed)"
} else if(this.props.redeemed === "0") {
redeemedMessage = "(Not redeemed)"
}
return `<div>
<div>
<span class="tbml-count">x${this.props._count}</span>
<span class="tbml-category">${this.props.category}</span>
<span class="tbml-category">${redeemedMessage}</span>
</div>
<div>
<span class="tbml-venue">${this.props.venue}</span>
</div>
<div style="margin: 0px; padding:0px; clear: both; height: 6px">
&nbsp;
</div>
<div>
<img src="data:image/png;base64,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" class="data-icon"/>
<span class="tbml-date">${date}</span>
</div>
<div>
<span class="tbml-time">${time}, &nbsp;${this.props.locality}</span>
</div>
</div>`;
}
}

web3.tokens.dataChanged = (oldTokens, updatedTokens) => {
const currentTokenInstance = web3.tokens.data.currentInstance;
document.getElementById('root').innerHTML = new Token(currentTokenInstance).render();
};
]]></script>
<div id="root"></div>
137 changes: 137 additions & 0 deletions examples/edcon/unicon.xml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE token [
<!ENTITY unicon.en SYSTEM "unicon.en.shtml">
<!ENTITY style SYSTEM "shared.css">
]>
<ts:token xmlns:ts="http://tokenscript.org/2019/10/tokenscript"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xsi:schemaLocation="http://tokenscript.org/2019/10/tokenscript http://tokenscript.org/2019/10/tokenscript.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
custodian="false"
>
<ts:name>
<ts:plurals xml:lang="en">
<ts:string quantity="one">Ticket</ts:string>
<ts:string quantity="other">Tickets</ts:string>
</ts:plurals>
</ts:name>

<ts:contract name="unicon" interface="erc721">
<ts:address network="100">0xF6b8DD8Ba9996bEaE6Ad0eE3481F1E9cF080A9eB</ts:address>
</ts:contract>

<ts:origins>
<!-- Define the contract which holds the token that the user will use -->
<ts:ethereum contract="unicon">
</ts:ethereum>
</ts:origins>

<ts:cards>
<ts:token-card>
<style type="text/css">&style;</style>
<ts:view-iconified xml:lang="en">
&unicon.en;
</ts:view-iconified>
<ts:view xml:lang="en">
&unicon.en;
</ts:view>
</ts:token-card>
</ts:cards>

<ts:attribute-types>

<ts:attribute-type id="time" syntax="1.3.6.1.4.1.1466.115.121.1.24">
<ts:name>
<ts:string xml:lang="en">Time</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000" as="utf8">
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<!-- TODO get location & venue, if only one then remove this attribute and hardcode it into the UI -->
<ts:attribute-type id="locality" oid="2.5.4.7" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">City</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000FF00000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="venue" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zhangzhongnan928 if you know the location, let me know

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBC,
They haven't paid to the venue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is
Vienna University of Economics and Business
Welthandelspl. 1, 1020 Wien, Austria

<ts:string xml:lang="en">Venue</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000FF000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Blockchain Plaza, Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="category" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">Cat</ts:string>
<ts:string xml:lang="zh">等级</ts:string>
<ts:string xml:lang="es">Cat</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000000000000000000000FF00000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">A</ts:value>
</ts:option>
<ts:option key="2">
<ts:value xml:lang="en">B</ts:value>
</ts:option>
<ts:option key="3">
<ts:value xml:lang="en">C</ts:value>
</ts:option>
<ts:option key="4">
<ts:value xml:lang="en">D</ts:value>
</ts:option>
<ts:option key="5">
<ts:value xml:lang="en">E</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="numero" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>№</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000000000000000000000FFFF00" as="uint"/>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="redeemed" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>Redeemed</ts:string>
</ts:name>
<ts:origins>
<ts:ethereum function="redeemed" contract="unicon" as="bool">
<ts:data>
<ts:uint256 ref="tokenId"/>
</ts:data>
</ts:ethereum>
</ts:origins>
</ts:attribute-type>

</ts:attribute-types>
</ts:token>
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions examples/edcon/Makefile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
XMLSECTOOL=xmlsectool
KEYSTORE=
KEY=1
KEYPASSWORD=
SIGNATURE_ALGORITHM=rsa-sha256

help:
# Needs a target, example: $$ make EntryToken.canonicalized.xml
#
# Let's say you have a TokenScript "EntryToken.xml"
#- to validate and canonicalize, add 'canonicalized' in the filename
@echo $$ make EntryToken.canonicalized.xml
# - to sign, use tsml as file extension:
@echo $$ make EntryToken.tsml

%.canonicalized.xml : %.xml
# xmlsectool canonicalises automatically when needed, but leaving an xml:base attribute which creates trouble later.
# xmlstarlet does it neatly
# XML Canonicalization
xmlstarlet c14n $^ > $@
# xmlsectool validates too, albeit adding xml:base with breaks schema. Example:
# JVMOPTS=-Djavax.xml.accessExternalDTD=all /opt/xmlsectool-2.0.0/xmlsectool.sh --validateSchema --xsd --schemaDirectory ../../schema --inFile $^
# XML Validation
# if INVALID, run validation again with xmllint to get meaningful error
# then delete the canonicalized file
-xmlstarlet val --xsd http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@ || (mv $@ $@.INVALID; xmllint --noout --schema http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@.INVALID)

%.tsml: %.canonicalized.xml
ifeq (,$(KEYSTORE))
@echo ---------------- Keystore missing. Try this ----------------
@echo $$ make KEYSTORE=shong.wang.p12 KEYPASSWORD=shong.wang $@
@echo replace it with your .p12 file and your password
rm $^
else
$(XMLSECTOOL) --sign --keyInfoKeyName 'Shong Wang' --digest SHA-256 --signatureAlgorithm http://www.w3.org/2001/04/xmldsig-more#$(SIGNATURE_ALGORITHM) --inFile $^ --outFile $@ --keystore $(KEYSTORE) --keystoreType PKCS12 --key $(KEY) --keyPassword $(KEYPASSWORD) --signaturePosition LAST
# removing the canonicalized created for validation
rm $^
endif
46 changes: 46 additions & 0 deletions examples/edcon/shared.css
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
.tbml-count {
font-family: "SourceSansPro";
font-weight: bolder;
font-size: 21px;
color: rgb(117, 185, 67);
}
.tbml-category {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 21px;
color: rgb(67, 67, 67);
}
.tbml-venue {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(67, 67, 67);
}
.tbml-date {
font-family: "SourceSansPro";
font-weight: bold;
font-size: 14px;
color: rgb(112, 112, 112);
margin-left: 7px;
margin-right: 7px;
}
.tbml-time {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(112, 112, 112);
}
html {
}
body {
padding: 0px;
margin: 0px;
}
div {
margin: 0px;
padding: 0px;
}
.data-icon {
height:16px;
vertical-align: middle
}
145 changes: 145 additions & 0 deletions examples/edcon/unicon.en.shtml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
<script type="text/javascript">
(function() {
'use strict'

function GeneralizedTime(generalizedTime) {
this.rawData = generalizedTime;
}

GeneralizedTime.prototype.getYear = function () {
return parseInt(this.rawData.substring(0, 4), 10);
}

GeneralizedTime.prototype.getMonth = function () {
return parseInt(this.rawData.substring(4, 6), 10) - 1;
}

GeneralizedTime.prototype.getDay = function () {
return parseInt(this.rawData.substring(6, 8), 10)
},

GeneralizedTime.prototype.getHours = function () {
return parseInt(this.rawData.substring(8, 10), 10)
},

GeneralizedTime.prototype.getMinutes = function () {
var minutes = parseInt(this.rawData.substring(10, 12), 10)
if (minutes) return minutes
return 0
},

GeneralizedTime.prototype.getSeconds = function () {
var seconds = parseInt(this.rawData.substring(12, 14), 10)
if (seconds) return seconds
return 0
},

GeneralizedTime.prototype.getMilliseconds = function () {
var startIdx
if (time.indexOf('.') !== -1) {
startIdx = this.rawData.indexOf('.') + 1
} else if (time.indexOf(',') !== -1) {
startIdx = this.rawData.indexOf(',') + 1
} else {
return 0
}

var stopIdx = time.length - 1
var fraction = '0' + '.' + time.substring(startIdx, stopIdx)
var ms = parseFloat(fraction) * 1000
return ms
},

GeneralizedTime.prototype.getTimeZone = function () {
let time = this.rawData;
var length = time.length
var symbolIdx
if (time.charAt(length - 1 ) === 'Z') return 0
if (time.indexOf('+') !== -1) {
symbolIdx = time.indexOf('+')
} else if (time.indexOf('-') !== -1) {
symbolIdx = time.indexOf('-')
} else {
return NaN
}

var minutes = time.substring(symbolIdx + 2)
var hours = time.substring(symbolIdx + 1, symbolIdx + 2)
var one = (time.charAt(symbolIdx) === '+') ? 1 : -1

var intHr = one * parseInt(hours, 10) * 60 * 60 * 1000
var intMin = one * parseInt(minutes, 10) * 60 * 1000
var ms = minutes ? intHr + intMin : intHr
return ms
}

if (typeof exports === 'object') {
module.exports = GeneralizedTime
} else if (typeof define === 'function' &amp;&amp; define.amd) {
define(GeneralizedTime)
} else {
window.GeneralizedTime = GeneralizedTime
}
}())
</script>
<script type="text/javascript"><![CDATA[
class Token {
constructor(tokenInstance) {
this.props = tokenInstance
}

formatGeneralizedTimeToDate(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleDateString()
}
formatGeneralizedTimeToTime(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})
}

render() {
let time;
let date;
if (this.props.time == null) {
time = ""
date = ""
} else {
time = this.formatGeneralizedTimeToTime(this.props.time.generalizedTime)
date = this.props.time == null ? "": this.formatGeneralizedTimeToDate(this.props.time.generalizedTime)
}
let redeemedMessage = "";
//might not have loaded so only set if actually loaded
if(this.props.redeemed === "1") {
redeemedMessage = "(Redeemed)"
} else if(this.props.redeemed === "0") {
redeemedMessage = "(Not redeemed)"
}
return `<div>
<div>
<span class="tbml-count">x${this.props._count}</span>
<span class="tbml-category">${this.props.category}</span>
<span class="tbml-category">${redeemedMessage}</span>
</div>
<div>
<span class="tbml-venue">${this.props.venue}</span>
</div>
<div style="margin: 0px; padding:0px; clear: both; height: 6px">
&nbsp;
</div>
<div>
<img src="data:image/png;base64,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" class="data-icon"/>
<span class="tbml-date">${date}</span>
</div>
<div>
<span class="tbml-time">${time}, &nbsp;${this.props.locality}</span>
</div>
</div>`;
}
}

web3.tokens.dataChanged = (oldTokens, updatedTokens) => {
const currentTokenInstance = web3.tokens.data.currentInstance;
document.getElementById('root').innerHTML = new Token(currentTokenInstance).render();
};
]]></script>
<div id="root"></div>
137 changes: 137 additions & 0 deletions examples/edcon/unicon.xml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE token [
<!ENTITY unicon.en SYSTEM "unicon.en.shtml">
<!ENTITY style SYSTEM "shared.css">
]>
<ts:token xmlns:ts="http://tokenscript.org/2019/10/tokenscript"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xsi:schemaLocation="http://tokenscript.org/2019/10/tokenscript http://tokenscript.org/2019/10/tokenscript.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
custodian="false"
>
<ts:name>
<ts:plurals xml:lang="en">
<ts:string quantity="one">Ticket</ts:string>
<ts:string quantity="other">Tickets</ts:string>
</ts:plurals>
</ts:name>

<ts:contract name="unicon" interface="erc721">
<ts:address network="100">0xF6b8DD8Ba9996bEaE6Ad0eE3481F1E9cF080A9eB</ts:address>
</ts:contract>

<ts:origins>
<!-- Define the contract which holds the token that the user will use -->
<ts:ethereum contract="unicon">
</ts:ethereum>
</ts:origins>

<ts:cards>
<ts:token-card>
<style type="text/css">&style;</style>
<ts:view-iconified xml:lang="en">
&unicon.en;
</ts:view-iconified>
<ts:view xml:lang="en">
&unicon.en;
</ts:view>
</ts:token-card>
</ts:cards>

<ts:attribute-types>

<ts:attribute-type id="time" syntax="1.3.6.1.4.1.1466.115.121.1.24">
<ts:name>
<ts:string xml:lang="en">Time</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000" as="utf8">
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<!-- TODO get location & venue, if only one then remove this attribute and hardcode it into the UI -->
<ts:attribute-type id="locality" oid="2.5.4.7" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">City</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000FF00000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="venue" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zhangzhongnan928 if you know the location, let me know

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBC,
They haven't paid to the venue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is
Vienna University of Economics and Business
Welthandelspl. 1, 1020 Wien, Austria

<ts:string xml:lang="en">Venue</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000FF000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Blockchain Plaza, Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="category" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">Cat</ts:string>
<ts:string xml:lang="zh">等级</ts:string>
<ts:string xml:lang="es">Cat</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000000000000000000000FF00000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">A</ts:value>
</ts:option>
<ts:option key="2">
<ts:value xml:lang="en">B</ts:value>
</ts:option>
<ts:option key="3">
<ts:value xml:lang="en">C</ts:value>
</ts:option>
<ts:option key="4">
<ts:value xml:lang="en">D</ts:value>
</ts:option>
<ts:option key="5">
<ts:value xml:lang="en">E</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="numero" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>№</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000000000000000000000FFFF00" as="uint"/>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="redeemed" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>Redeemed</ts:string>
</ts:name>
<ts:origins>
<ts:ethereum function="redeemed" contract="unicon" as="bool">
<ts:data>
<ts:uint256 ref="tokenId"/>
</ts:data>
</ts:ethereum>
</ts:origins>
</ts:attribute-type>

</ts:attribute-types>
</ts:token>
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions examples/edcon/Makefile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
XMLSECTOOL=xmlsectool
KEYSTORE=
KEY=1
KEYPASSWORD=
SIGNATURE_ALGORITHM=rsa-sha256

help:
# Needs a target, example: $$ make EntryToken.canonicalized.xml
#
# Let's say you have a TokenScript "EntryToken.xml"
#- to validate and canonicalize, add 'canonicalized' in the filename
@echo $$ make EntryToken.canonicalized.xml
# - to sign, use tsml as file extension:
@echo $$ make EntryToken.tsml

%.canonicalized.xml : %.xml
# xmlsectool canonicalises automatically when needed, but leaving an xml:base attribute which creates trouble later.
# xmlstarlet does it neatly
# XML Canonicalization
xmlstarlet c14n $^ > $@
# xmlsectool validates too, albeit adding xml:base with breaks schema. Example:
# JVMOPTS=-Djavax.xml.accessExternalDTD=all /opt/xmlsectool-2.0.0/xmlsectool.sh --validateSchema --xsd --schemaDirectory ../../schema --inFile $^
# XML Validation
# if INVALID, run validation again with xmllint to get meaningful error
# then delete the canonicalized file
-xmlstarlet val --xsd http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@ || (mv $@ $@.INVALID; xmllint --noout --schema http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@.INVALID)

%.tsml: %.canonicalized.xml
ifeq (,$(KEYSTORE))
@echo ---------------- Keystore missing. Try this ----------------
@echo $$ make KEYSTORE=shong.wang.p12 KEYPASSWORD=shong.wang $@
@echo replace it with your .p12 file and your password
rm $^
else
$(XMLSECTOOL) --sign --keyInfoKeyName 'Shong Wang' --digest SHA-256 --signatureAlgorithm http://www.w3.org/2001/04/xmldsig-more#$(SIGNATURE_ALGORITHM) --inFile $^ --outFile $@ --keystore $(KEYSTORE) --keystoreType PKCS12 --key $(KEY) --keyPassword $(KEYPASSWORD) --signaturePosition LAST
# removing the canonicalized created for validation
rm $^
endif
46 changes: 46 additions & 0 deletions examples/edcon/shared.css
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
.tbml-count {
font-family: "SourceSansPro";
font-weight: bolder;
font-size: 21px;
color: rgb(117, 185, 67);
}
.tbml-category {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 21px;
color: rgb(67, 67, 67);
}
.tbml-venue {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(67, 67, 67);
}
.tbml-date {
font-family: "SourceSansPro";
font-weight: bold;
font-size: 14px;
color: rgb(112, 112, 112);
margin-left: 7px;
margin-right: 7px;
}
.tbml-time {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(112, 112, 112);
}
html {
}
body {
padding: 0px;
margin: 0px;
}
div {
margin: 0px;
padding: 0px;
}
.data-icon {
height:16px;
vertical-align: middle
}
145 changes: 145 additions & 0 deletions examples/edcon/unicon.en.shtml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
<script type="text/javascript">
(function() {
'use strict'

function GeneralizedTime(generalizedTime) {
this.rawData = generalizedTime;
}

GeneralizedTime.prototype.getYear = function () {
return parseInt(this.rawData.substring(0, 4), 10);
}

GeneralizedTime.prototype.getMonth = function () {
return parseInt(this.rawData.substring(4, 6), 10) - 1;
}

GeneralizedTime.prototype.getDay = function () {
return parseInt(this.rawData.substring(6, 8), 10)
},

GeneralizedTime.prototype.getHours = function () {
return parseInt(this.rawData.substring(8, 10), 10)
},

GeneralizedTime.prototype.getMinutes = function () {
var minutes = parseInt(this.rawData.substring(10, 12), 10)
if (minutes) return minutes
return 0
},

GeneralizedTime.prototype.getSeconds = function () {
var seconds = parseInt(this.rawData.substring(12, 14), 10)
if (seconds) return seconds
return 0
},

GeneralizedTime.prototype.getMilliseconds = function () {
var startIdx
if (time.indexOf('.') !== -1) {
startIdx = this.rawData.indexOf('.') + 1
} else if (time.indexOf(',') !== -1) {
startIdx = this.rawData.indexOf(',') + 1
} else {
return 0
}

var stopIdx = time.length - 1
var fraction = '0' + '.' + time.substring(startIdx, stopIdx)
var ms = parseFloat(fraction) * 1000
return ms
},

GeneralizedTime.prototype.getTimeZone = function () {
let time = this.rawData;
var length = time.length
var symbolIdx
if (time.charAt(length - 1 ) === 'Z') return 0
if (time.indexOf('+') !== -1) {
symbolIdx = time.indexOf('+')
} else if (time.indexOf('-') !== -1) {
symbolIdx = time.indexOf('-')
} else {
return NaN
}

var minutes = time.substring(symbolIdx + 2)
var hours = time.substring(symbolIdx + 1, symbolIdx + 2)
var one = (time.charAt(symbolIdx) === '+') ? 1 : -1

var intHr = one * parseInt(hours, 10) * 60 * 60 * 1000
var intMin = one * parseInt(minutes, 10) * 60 * 1000
var ms = minutes ? intHr + intMin : intHr
return ms
}

if (typeof exports === 'object') {
module.exports = GeneralizedTime
} else if (typeof define === 'function' &amp;&amp; define.amd) {
define(GeneralizedTime)
} else {
window.GeneralizedTime = GeneralizedTime
}
}())
</script>
<script type="text/javascript"><![CDATA[
class Token {
constructor(tokenInstance) {
this.props = tokenInstance
}

formatGeneralizedTimeToDate(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleDateString()
}
formatGeneralizedTimeToTime(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})
}

render() {
let time;
let date;
if (this.props.time == null) {
time = ""
date = ""
} else {
time = this.formatGeneralizedTimeToTime(this.props.time.generalizedTime)
date = this.props.time == null ? "": this.formatGeneralizedTimeToDate(this.props.time.generalizedTime)
}
let redeemedMessage = "";
//might not have loaded so only set if actually loaded
if(this.props.redeemed === "1") {
redeemedMessage = "(Redeemed)"
} else if(this.props.redeemed === "0") {
redeemedMessage = "(Not redeemed)"
}
return `<div>
<div>
<span class="tbml-count">x${this.props._count}</span>
<span class="tbml-category">${this.props.category}</span>
<span class="tbml-category">${redeemedMessage}</span>
</div>
<div>
<span class="tbml-venue">${this.props.venue}</span>
</div>
<div style="margin: 0px; padding:0px; clear: both; height: 6px">
&nbsp;
</div>
<div>
<img src="data:image/png;base64,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" class="data-icon"/>
<span class="tbml-date">${date}</span>
</div>
<div>
<span class="tbml-time">${time}, &nbsp;${this.props.locality}</span>
</div>
</div>`;
}
}

web3.tokens.dataChanged = (oldTokens, updatedTokens) => {
const currentTokenInstance = web3.tokens.data.currentInstance;
document.getElementById('root').innerHTML = new Token(currentTokenInstance).render();
};
]]></script>
<div id="root"></div>
137 changes: 137 additions & 0 deletions examples/edcon/unicon.xml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE token [
<!ENTITY unicon.en SYSTEM "unicon.en.shtml">
<!ENTITY style SYSTEM "shared.css">
]>
<ts:token xmlns:ts="http://tokenscript.org/2019/10/tokenscript"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xsi:schemaLocation="http://tokenscript.org/2019/10/tokenscript http://tokenscript.org/2019/10/tokenscript.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
custodian="false"
>
<ts:name>
<ts:plurals xml:lang="en">
<ts:string quantity="one">Ticket</ts:string>
<ts:string quantity="other">Tickets</ts:string>
</ts:plurals>
</ts:name>

<ts:contract name="unicon" interface="erc721">
<ts:address network="100">0xF6b8DD8Ba9996bEaE6Ad0eE3481F1E9cF080A9eB</ts:address>
</ts:contract>

<ts:origins>
<!-- Define the contract which holds the token that the user will use -->
<ts:ethereum contract="unicon">
</ts:ethereum>
</ts:origins>

<ts:cards>
<ts:token-card>
<style type="text/css">&style;</style>
<ts:view-iconified xml:lang="en">
&unicon.en;
</ts:view-iconified>
<ts:view xml:lang="en">
&unicon.en;
</ts:view>
</ts:token-card>
</ts:cards>

<ts:attribute-types>

<ts:attribute-type id="time" syntax="1.3.6.1.4.1.1466.115.121.1.24">
<ts:name>
<ts:string xml:lang="en">Time</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000" as="utf8">
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<!-- TODO get location & venue, if only one then remove this attribute and hardcode it into the UI -->
<ts:attribute-type id="locality" oid="2.5.4.7" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">City</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000FF00000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="venue" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zhangzhongnan928 if you know the location, let me know

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBC,
They haven't paid to the venue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is
Vienna University of Economics and Business
Welthandelspl. 1, 1020 Wien, Austria

<ts:string xml:lang="en">Venue</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000FF000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Blockchain Plaza, Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="category" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">Cat</ts:string>
<ts:string xml:lang="zh">等级</ts:string>
<ts:string xml:lang="es">Cat</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000000000000000000000FF00000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">A</ts:value>
</ts:option>
<ts:option key="2">
<ts:value xml:lang="en">B</ts:value>
</ts:option>
<ts:option key="3">
<ts:value xml:lang="en">C</ts:value>
</ts:option>
<ts:option key="4">
<ts:value xml:lang="en">D</ts:value>
</ts:option>
<ts:option key="5">
<ts:value xml:lang="en">E</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="numero" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>№</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000000000000000000000FFFF00" as="uint"/>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="redeemed" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>Redeemed</ts:string>
</ts:name>
<ts:origins>
<ts:ethereum function="redeemed" contract="unicon" as="bool">
<ts:data>
<ts:uint256 ref="tokenId"/>
</ts:data>
</ts:ethereum>
</ts:origins>
</ts:attribute-type>

</ts:attribute-types>
</ts:token>
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions examples/edcon/Makefile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
XMLSECTOOL=xmlsectool
KEYSTORE=
KEY=1
KEYPASSWORD=
SIGNATURE_ALGORITHM=rsa-sha256

help:
# Needs a target, example: $$ make EntryToken.canonicalized.xml
#
# Let's say you have a TokenScript "EntryToken.xml"
#- to validate and canonicalize, add 'canonicalized' in the filename
@echo $$ make EntryToken.canonicalized.xml
# - to sign, use tsml as file extension:
@echo $$ make EntryToken.tsml

%.canonicalized.xml : %.xml
# xmlsectool canonicalises automatically when needed, but leaving an xml:base attribute which creates trouble later.
# xmlstarlet does it neatly
# XML Canonicalization
xmlstarlet c14n $^ > $@
# xmlsectool validates too, albeit adding xml:base with breaks schema. Example:
# JVMOPTS=-Djavax.xml.accessExternalDTD=all /opt/xmlsectool-2.0.0/xmlsectool.sh --validateSchema --xsd --schemaDirectory ../../schema --inFile $^
# XML Validation
# if INVALID, run validation again with xmllint to get meaningful error
# then delete the canonicalized file
-xmlstarlet val --xsd http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@ || (mv $@ $@.INVALID; xmllint --noout --schema http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@.INVALID)

%.tsml: %.canonicalized.xml
ifeq (,$(KEYSTORE))
@echo ---------------- Keystore missing. Try this ----------------
@echo $$ make KEYSTORE=shong.wang.p12 KEYPASSWORD=shong.wang $@
@echo replace it with your .p12 file and your password
rm $^
else
$(XMLSECTOOL) --sign --keyInfoKeyName 'Shong Wang' --digest SHA-256 --signatureAlgorithm http://www.w3.org/2001/04/xmldsig-more#$(SIGNATURE_ALGORITHM) --inFile $^ --outFile $@ --keystore $(KEYSTORE) --keystoreType PKCS12 --key $(KEY) --keyPassword $(KEYPASSWORD) --signaturePosition LAST
# removing the canonicalized created for validation
rm $^
endif
46 changes: 46 additions & 0 deletions examples/edcon/shared.css
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
.tbml-count {
font-family: "SourceSansPro";
font-weight: bolder;
font-size: 21px;
color: rgb(117, 185, 67);
}
.tbml-category {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 21px;
color: rgb(67, 67, 67);
}
.tbml-venue {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(67, 67, 67);
}
.tbml-date {
font-family: "SourceSansPro";
font-weight: bold;
font-size: 14px;
color: rgb(112, 112, 112);
margin-left: 7px;
margin-right: 7px;
}
.tbml-time {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(112, 112, 112);
}
html {
}
body {
padding: 0px;
margin: 0px;
}
div {
margin: 0px;
padding: 0px;
}
.data-icon {
height:16px;
vertical-align: middle
}
145 changes: 145 additions & 0 deletions examples/edcon/unicon.en.shtml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
<script type="text/javascript">
(function() {
'use strict'

function GeneralizedTime(generalizedTime) {
this.rawData = generalizedTime;
}

GeneralizedTime.prototype.getYear = function () {
return parseInt(this.rawData.substring(0, 4), 10);
}

GeneralizedTime.prototype.getMonth = function () {
return parseInt(this.rawData.substring(4, 6), 10) - 1;
}

GeneralizedTime.prototype.getDay = function () {
return parseInt(this.rawData.substring(6, 8), 10)
},

GeneralizedTime.prototype.getHours = function () {
return parseInt(this.rawData.substring(8, 10), 10)
},

GeneralizedTime.prototype.getMinutes = function () {
var minutes = parseInt(this.rawData.substring(10, 12), 10)
if (minutes) return minutes
return 0
},

GeneralizedTime.prototype.getSeconds = function () {
var seconds = parseInt(this.rawData.substring(12, 14), 10)
if (seconds) return seconds
return 0
},

GeneralizedTime.prototype.getMilliseconds = function () {
var startIdx
if (time.indexOf('.') !== -1) {
startIdx = this.rawData.indexOf('.') + 1
} else if (time.indexOf(',') !== -1) {
startIdx = this.rawData.indexOf(',') + 1
} else {
return 0
}

var stopIdx = time.length - 1
var fraction = '0' + '.' + time.substring(startIdx, stopIdx)
var ms = parseFloat(fraction) * 1000
return ms
},

GeneralizedTime.prototype.getTimeZone = function () {
let time = this.rawData;
var length = time.length
var symbolIdx
if (time.charAt(length - 1 ) === 'Z') return 0
if (time.indexOf('+') !== -1) {
symbolIdx = time.indexOf('+')
} else if (time.indexOf('-') !== -1) {
symbolIdx = time.indexOf('-')
} else {
return NaN
}

var minutes = time.substring(symbolIdx + 2)
var hours = time.substring(symbolIdx + 1, symbolIdx + 2)
var one = (time.charAt(symbolIdx) === '+') ? 1 : -1

var intHr = one * parseInt(hours, 10) * 60 * 60 * 1000
var intMin = one * parseInt(minutes, 10) * 60 * 1000
var ms = minutes ? intHr + intMin : intHr
return ms
}

if (typeof exports === 'object') {
module.exports = GeneralizedTime
} else if (typeof define === 'function' &amp;&amp; define.amd) {
define(GeneralizedTime)
} else {
window.GeneralizedTime = GeneralizedTime
}
}())
</script>
<script type="text/javascript"><![CDATA[
class Token {
constructor(tokenInstance) {
this.props = tokenInstance
}

formatGeneralizedTimeToDate(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleDateString()
}
formatGeneralizedTimeToTime(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})
}

render() {
let time;
let date;
if (this.props.time == null) {
time = ""
date = ""
} else {
time = this.formatGeneralizedTimeToTime(this.props.time.generalizedTime)
date = this.props.time == null ? "": this.formatGeneralizedTimeToDate(this.props.time.generalizedTime)
}
let redeemedMessage = "";
//might not have loaded so only set if actually loaded
if(this.props.redeemed === "1") {
redeemedMessage = "(Redeemed)"
} else if(this.props.redeemed === "0") {
redeemedMessage = "(Not redeemed)"
}
return `<div>
<div>
<span class="tbml-count">x${this.props._count}</span>
<span class="tbml-category">${this.props.category}</span>
<span class="tbml-category">${redeemedMessage}</span>
</div>
<div>
<span class="tbml-venue">${this.props.venue}</span>
</div>
<div style="margin: 0px; padding:0px; clear: both; height: 6px">
&nbsp;
</div>
<div>
<img src="data:image/png;base64,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" class="data-icon"/>
<span class="tbml-date">${date}</span>
</div>
<div>
<span class="tbml-time">${time}, &nbsp;${this.props.locality}</span>
</div>
</div>`;
}
}

web3.tokens.dataChanged = (oldTokens, updatedTokens) => {
const currentTokenInstance = web3.tokens.data.currentInstance;
document.getElementById('root').innerHTML = new Token(currentTokenInstance).render();
};
]]></script>
<div id="root"></div>
137 changes: 137 additions & 0 deletions examples/edcon/unicon.xml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE token [
<!ENTITY unicon.en SYSTEM "unicon.en.shtml">
<!ENTITY style SYSTEM "shared.css">
]>
<ts:token xmlns:ts="http://tokenscript.org/2019/10/tokenscript"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xsi:schemaLocation="http://tokenscript.org/2019/10/tokenscript http://tokenscript.org/2019/10/tokenscript.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
custodian="false"
>
<ts:name>
<ts:plurals xml:lang="en">
<ts:string quantity="one">Ticket</ts:string>
<ts:string quantity="other">Tickets</ts:string>
</ts:plurals>
</ts:name>

<ts:contract name="unicon" interface="erc721">
<ts:address network="100">0xF6b8DD8Ba9996bEaE6Ad0eE3481F1E9cF080A9eB</ts:address>
</ts:contract>

<ts:origins>
<!-- Define the contract which holds the token that the user will use -->
<ts:ethereum contract="unicon">
</ts:ethereum>
</ts:origins>

<ts:cards>
<ts:token-card>
<style type="text/css">&style;</style>
<ts:view-iconified xml:lang="en">
&unicon.en;
</ts:view-iconified>
<ts:view xml:lang="en">
&unicon.en;
</ts:view>
</ts:token-card>
</ts:cards>

<ts:attribute-types>

<ts:attribute-type id="time" syntax="1.3.6.1.4.1.1466.115.121.1.24">
<ts:name>
<ts:string xml:lang="en">Time</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000" as="utf8">
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<!-- TODO get location & venue, if only one then remove this attribute and hardcode it into the UI -->
<ts:attribute-type id="locality" oid="2.5.4.7" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">City</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000FF00000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="venue" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zhangzhongnan928 if you know the location, let me know

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBC,
They haven't paid to the venue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is
Vienna University of Economics and Business
Welthandelspl. 1, 1020 Wien, Austria

<ts:string xml:lang="en">Venue</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000FF000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Blockchain Plaza, Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="category" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">Cat</ts:string>
<ts:string xml:lang="zh">等级</ts:string>
<ts:string xml:lang="es">Cat</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000000000000000000000FF00000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">A</ts:value>
</ts:option>
<ts:option key="2">
<ts:value xml:lang="en">B</ts:value>
</ts:option>
<ts:option key="3">
<ts:value xml:lang="en">C</ts:value>
</ts:option>
<ts:option key="4">
<ts:value xml:lang="en">D</ts:value>
</ts:option>
<ts:option key="5">
<ts:value xml:lang="en">E</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="numero" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>№</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000000000000000000000FFFF00" as="uint"/>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="redeemed" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>Redeemed</ts:string>
</ts:name>
<ts:origins>
<ts:ethereum function="redeemed" contract="unicon" as="bool">
<ts:data>
<ts:uint256 ref="tokenId"/>
</ts:data>
</ts:ethereum>
</ts:origins>
</ts:attribute-type>

</ts:attribute-types>
</ts:token>
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions examples/edcon/Makefile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
XMLSECTOOL=xmlsectool
KEYSTORE=
KEY=1
KEYPASSWORD=
SIGNATURE_ALGORITHM=rsa-sha256

help:
# Needs a target, example: $$ make EntryToken.canonicalized.xml
#
# Let's say you have a TokenScript "EntryToken.xml"
#- to validate and canonicalize, add 'canonicalized' in the filename
@echo $$ make EntryToken.canonicalized.xml
# - to sign, use tsml as file extension:
@echo $$ make EntryToken.tsml

%.canonicalized.xml : %.xml
# xmlsectool canonicalises automatically when needed, but leaving an xml:base attribute which creates trouble later.
# xmlstarlet does it neatly
# XML Canonicalization
xmlstarlet c14n $^ > $@
# xmlsectool validates too, albeit adding xml:base with breaks schema. Example:
# JVMOPTS=-Djavax.xml.accessExternalDTD=all /opt/xmlsectool-2.0.0/xmlsectool.sh --validateSchema --xsd --schemaDirectory ../../schema --inFile $^
# XML Validation
# if INVALID, run validation again with xmllint to get meaningful error
# then delete the canonicalized file
-xmlstarlet val --xsd http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@ || (mv $@ $@.INVALID; xmllint --noout --schema http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@.INVALID)

%.tsml: %.canonicalized.xml
ifeq (,$(KEYSTORE))
@echo ---------------- Keystore missing. Try this ----------------
@echo $$ make KEYSTORE=shong.wang.p12 KEYPASSWORD=shong.wang $@
@echo replace it with your .p12 file and your password
rm $^
else
$(XMLSECTOOL) --sign --keyInfoKeyName 'Shong Wang' --digest SHA-256 --signatureAlgorithm http://www.w3.org/2001/04/xmldsig-more#$(SIGNATURE_ALGORITHM) --inFile $^ --outFile $@ --keystore $(KEYSTORE) --keystoreType PKCS12 --key $(KEY) --keyPassword $(KEYPASSWORD) --signaturePosition LAST
# removing the canonicalized created for validation
rm $^
endif
46 changes: 46 additions & 0 deletions examples/edcon/shared.css
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
.tbml-count {
font-family: "SourceSansPro";
font-weight: bolder;
font-size: 21px;
color: rgb(117, 185, 67);
}
.tbml-category {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 21px;
color: rgb(67, 67, 67);
}
.tbml-venue {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(67, 67, 67);
}
.tbml-date {
font-family: "SourceSansPro";
font-weight: bold;
font-size: 14px;
color: rgb(112, 112, 112);
margin-left: 7px;
margin-right: 7px;
}
.tbml-time {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(112, 112, 112);
}
html {
}
body {
padding: 0px;
margin: 0px;
}
div {
margin: 0px;
padding: 0px;
}
.data-icon {
height:16px;
vertical-align: middle
}
145 changes: 145 additions & 0 deletions examples/edcon/unicon.en.shtml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
<script type="text/javascript">
(function() {
'use strict'

function GeneralizedTime(generalizedTime) {
this.rawData = generalizedTime;
}

GeneralizedTime.prototype.getYear = function () {
return parseInt(this.rawData.substring(0, 4), 10);
}

GeneralizedTime.prototype.getMonth = function () {
return parseInt(this.rawData.substring(4, 6), 10) - 1;
}

GeneralizedTime.prototype.getDay = function () {
return parseInt(this.rawData.substring(6, 8), 10)
},

GeneralizedTime.prototype.getHours = function () {
return parseInt(this.rawData.substring(8, 10), 10)
},

GeneralizedTime.prototype.getMinutes = function () {
var minutes = parseInt(this.rawData.substring(10, 12), 10)
if (minutes) return minutes
return 0
},

GeneralizedTime.prototype.getSeconds = function () {
var seconds = parseInt(this.rawData.substring(12, 14), 10)
if (seconds) return seconds
return 0
},

GeneralizedTime.prototype.getMilliseconds = function () {
var startIdx
if (time.indexOf('.') !== -1) {
startIdx = this.rawData.indexOf('.') + 1
} else if (time.indexOf(',') !== -1) {
startIdx = this.rawData.indexOf(',') + 1
} else {
return 0
}

var stopIdx = time.length - 1
var fraction = '0' + '.' + time.substring(startIdx, stopIdx)
var ms = parseFloat(fraction) * 1000
return ms
},

GeneralizedTime.prototype.getTimeZone = function () {
let time = this.rawData;
var length = time.length
var symbolIdx
if (time.charAt(length - 1 ) === 'Z') return 0
if (time.indexOf('+') !== -1) {
symbolIdx = time.indexOf('+')
} else if (time.indexOf('-') !== -1) {
symbolIdx = time.indexOf('-')
} else {
return NaN
}

var minutes = time.substring(symbolIdx + 2)
var hours = time.substring(symbolIdx + 1, symbolIdx + 2)
var one = (time.charAt(symbolIdx) === '+') ? 1 : -1

var intHr = one * parseInt(hours, 10) * 60 * 60 * 1000
var intMin = one * parseInt(minutes, 10) * 60 * 1000
var ms = minutes ? intHr + intMin : intHr
return ms
}

if (typeof exports === 'object') {
module.exports = GeneralizedTime
} else if (typeof define === 'function' &amp;&amp; define.amd) {
define(GeneralizedTime)
} else {
window.GeneralizedTime = GeneralizedTime
}
}())
</script>
<script type="text/javascript"><![CDATA[
class Token {
constructor(tokenInstance) {
this.props = tokenInstance
}

formatGeneralizedTimeToDate(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleDateString()
}
formatGeneralizedTimeToTime(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})
}

render() {
let time;
let date;
if (this.props.time == null) {
time = ""
date = ""
} else {
time = this.formatGeneralizedTimeToTime(this.props.time.generalizedTime)
date = this.props.time == null ? "": this.formatGeneralizedTimeToDate(this.props.time.generalizedTime)
}
let redeemedMessage = "";
//might not have loaded so only set if actually loaded
if(this.props.redeemed === "1") {
redeemedMessage = "(Redeemed)"
} else if(this.props.redeemed === "0") {
redeemedMessage = "(Not redeemed)"
}
return `<div>
<div>
<span class="tbml-count">x${this.props._count}</span>
<span class="tbml-category">${this.props.category}</span>
<span class="tbml-category">${redeemedMessage}</span>
</div>
<div>
<span class="tbml-venue">${this.props.venue}</span>
</div>
<div style="margin: 0px; padding:0px; clear: both; height: 6px">
&nbsp;
</div>
<div>
<img src="data:image/png;base64,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" class="data-icon"/>
<span class="tbml-date">${date}</span>
</div>
<div>
<span class="tbml-time">${time}, &nbsp;${this.props.locality}</span>
</div>
</div>`;
}
}

web3.tokens.dataChanged = (oldTokens, updatedTokens) => {
const currentTokenInstance = web3.tokens.data.currentInstance;
document.getElementById('root').innerHTML = new Token(currentTokenInstance).render();
};
]]></script>
<div id="root"></div>
137 changes: 137 additions & 0 deletions examples/edcon/unicon.xml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE token [
<!ENTITY unicon.en SYSTEM "unicon.en.shtml">
<!ENTITY style SYSTEM "shared.css">
]>
<ts:token xmlns:ts="http://tokenscript.org/2019/10/tokenscript"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xsi:schemaLocation="http://tokenscript.org/2019/10/tokenscript http://tokenscript.org/2019/10/tokenscript.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
custodian="false"
>
<ts:name>
<ts:plurals xml:lang="en">
<ts:string quantity="one">Ticket</ts:string>
<ts:string quantity="other">Tickets</ts:string>
</ts:plurals>
</ts:name>

<ts:contract name="unicon" interface="erc721">
<ts:address network="100">0xF6b8DD8Ba9996bEaE6Ad0eE3481F1E9cF080A9eB</ts:address>
</ts:contract>

<ts:origins>
<!-- Define the contract which holds the token that the user will use -->
<ts:ethereum contract="unicon">
</ts:ethereum>
</ts:origins>

<ts:cards>
<ts:token-card>
<style type="text/css">&style;</style>
<ts:view-iconified xml:lang="en">
&unicon.en;
</ts:view-iconified>
<ts:view xml:lang="en">
&unicon.en;
</ts:view>
</ts:token-card>
</ts:cards>

<ts:attribute-types>

<ts:attribute-type id="time" syntax="1.3.6.1.4.1.1466.115.121.1.24">
<ts:name>
<ts:string xml:lang="en">Time</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000" as="utf8">
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<!-- TODO get location & venue, if only one then remove this attribute and hardcode it into the UI -->
<ts:attribute-type id="locality" oid="2.5.4.7" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">City</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000FF00000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="venue" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zhangzhongnan928 if you know the location, let me know

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBC,
They haven't paid to the venue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is
Vienna University of Economics and Business
Welthandelspl. 1, 1020 Wien, Austria

<ts:string xml:lang="en">Venue</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000FF000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Blockchain Plaza, Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="category" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">Cat</ts:string>
<ts:string xml:lang="zh">等级</ts:string>
<ts:string xml:lang="es">Cat</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000000000000000000000FF00000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">A</ts:value>
</ts:option>
<ts:option key="2">
<ts:value xml:lang="en">B</ts:value>
</ts:option>
<ts:option key="3">
<ts:value xml:lang="en">C</ts:value>
</ts:option>
<ts:option key="4">
<ts:value xml:lang="en">D</ts:value>
</ts:option>
<ts:option key="5">
<ts:value xml:lang="en">E</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="numero" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>№</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000000000000000000000FFFF00" as="uint"/>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="redeemed" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>Redeemed</ts:string>
</ts:name>
<ts:origins>
<ts:ethereum function="redeemed" contract="unicon" as="bool">
<ts:data>
<ts:uint256 ref="tokenId"/>
</ts:data>
</ts:ethereum>
</ts:origins>
</ts:attribute-type>

</ts:attribute-types>
</ts:token>
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions examples/edcon/Makefile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
XMLSECTOOL=xmlsectool
KEYSTORE=
KEY=1
KEYPASSWORD=
SIGNATURE_ALGORITHM=rsa-sha256

help:
# Needs a target, example: $$ make EntryToken.canonicalized.xml
#
# Let's say you have a TokenScript "EntryToken.xml"
#- to validate and canonicalize, add 'canonicalized' in the filename
@echo $$ make EntryToken.canonicalized.xml
# - to sign, use tsml as file extension:
@echo $$ make EntryToken.tsml

%.canonicalized.xml : %.xml
# xmlsectool canonicalises automatically when needed, but leaving an xml:base attribute which creates trouble later.
# xmlstarlet does it neatly
# XML Canonicalization
xmlstarlet c14n $^ > $@
# xmlsectool validates too, albeit adding xml:base with breaks schema. Example:
# JVMOPTS=-Djavax.xml.accessExternalDTD=all /opt/xmlsectool-2.0.0/xmlsectool.sh --validateSchema --xsd --schemaDirectory ../../schema --inFile $^
# XML Validation
# if INVALID, run validation again with xmllint to get meaningful error
# then delete the canonicalized file
-xmlstarlet val --xsd http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@ || (mv $@ $@.INVALID; xmllint --noout --schema http://tokenscript.org/2019/10/tokenscript/tokenscript.xsd $@.INVALID)

%.tsml: %.canonicalized.xml
ifeq (,$(KEYSTORE))
@echo ---------------- Keystore missing. Try this ----------------
@echo $$ make KEYSTORE=shong.wang.p12 KEYPASSWORD=shong.wang $@
@echo replace it with your .p12 file and your password
rm $^
else
$(XMLSECTOOL) --sign --keyInfoKeyName 'Shong Wang' --digest SHA-256 --signatureAlgorithm http://www.w3.org/2001/04/xmldsig-more#$(SIGNATURE_ALGORITHM) --inFile $^ --outFile $@ --keystore $(KEYSTORE) --keystoreType PKCS12 --key $(KEY) --keyPassword $(KEYPASSWORD) --signaturePosition LAST
# removing the canonicalized created for validation
rm $^
endif
46 changes: 46 additions & 0 deletions examples/edcon/shared.css
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
.tbml-count {
font-family: "SourceSansPro";
font-weight: bolder;
font-size: 21px;
color: rgb(117, 185, 67);
}
.tbml-category {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 21px;
color: rgb(67, 67, 67);
}
.tbml-venue {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(67, 67, 67);
}
.tbml-date {
font-family: "SourceSansPro";
font-weight: bold;
font-size: 14px;
color: rgb(112, 112, 112);
margin-left: 7px;
margin-right: 7px;
}
.tbml-time {
font-family: "SourceSansPro";
font-weight: lighter;
font-size: 16px;
color: rgb(112, 112, 112);
}
html {
}
body {
padding: 0px;
margin: 0px;
}
div {
margin: 0px;
padding: 0px;
}
.data-icon {
height:16px;
vertical-align: middle
}
145 changes: 145 additions & 0 deletions examples/edcon/unicon.en.shtml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
<script type="text/javascript">
(function() {
'use strict'

function GeneralizedTime(generalizedTime) {
this.rawData = generalizedTime;
}

GeneralizedTime.prototype.getYear = function () {
return parseInt(this.rawData.substring(0, 4), 10);
}

GeneralizedTime.prototype.getMonth = function () {
return parseInt(this.rawData.substring(4, 6), 10) - 1;
}

GeneralizedTime.prototype.getDay = function () {
return parseInt(this.rawData.substring(6, 8), 10)
},

GeneralizedTime.prototype.getHours = function () {
return parseInt(this.rawData.substring(8, 10), 10)
},

GeneralizedTime.prototype.getMinutes = function () {
var minutes = parseInt(this.rawData.substring(10, 12), 10)
if (minutes) return minutes
return 0
},

GeneralizedTime.prototype.getSeconds = function () {
var seconds = parseInt(this.rawData.substring(12, 14), 10)
if (seconds) return seconds
return 0
},

GeneralizedTime.prototype.getMilliseconds = function () {
var startIdx
if (time.indexOf('.') !== -1) {
startIdx = this.rawData.indexOf('.') + 1
} else if (time.indexOf(',') !== -1) {
startIdx = this.rawData.indexOf(',') + 1
} else {
return 0
}

var stopIdx = time.length - 1
var fraction = '0' + '.' + time.substring(startIdx, stopIdx)
var ms = parseFloat(fraction) * 1000
return ms
},

GeneralizedTime.prototype.getTimeZone = function () {
let time = this.rawData;
var length = time.length
var symbolIdx
if (time.charAt(length - 1 ) === 'Z') return 0
if (time.indexOf('+') !== -1) {
symbolIdx = time.indexOf('+')
} else if (time.indexOf('-') !== -1) {
symbolIdx = time.indexOf('-')
} else {
return NaN
}

var minutes = time.substring(symbolIdx + 2)
var hours = time.substring(symbolIdx + 1, symbolIdx + 2)
var one = (time.charAt(symbolIdx) === '+') ? 1 : -1

var intHr = one * parseInt(hours, 10) * 60 * 60 * 1000
var intMin = one * parseInt(minutes, 10) * 60 * 1000
var ms = minutes ? intHr + intMin : intHr
return ms
}

if (typeof exports === 'object') {
module.exports = GeneralizedTime
} else if (typeof define === 'function' &amp;&amp; define.amd) {
define(GeneralizedTime)
} else {
window.GeneralizedTime = GeneralizedTime
}
}())
</script>
<script type="text/javascript"><![CDATA[
class Token {
constructor(tokenInstance) {
this.props = tokenInstance
}

formatGeneralizedTimeToDate(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleDateString()
}
formatGeneralizedTimeToTime(str) {
const d = new GeneralizedTime(str)
return new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes(), d.getSeconds()).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})
}

render() {
let time;
let date;
if (this.props.time == null) {
time = ""
date = ""
} else {
time = this.formatGeneralizedTimeToTime(this.props.time.generalizedTime)
date = this.props.time == null ? "": this.formatGeneralizedTimeToDate(this.props.time.generalizedTime)
}
let redeemedMessage = "";
//might not have loaded so only set if actually loaded
if(this.props.redeemed === "1") {
redeemedMessage = "(Redeemed)"
} else if(this.props.redeemed === "0") {
redeemedMessage = "(Not redeemed)"
}
return `<div>
<div>
<span class="tbml-count">x${this.props._count}</span>
<span class="tbml-category">${this.props.category}</span>
<span class="tbml-category">${redeemedMessage}</span>
</div>
<div>
<span class="tbml-venue">${this.props.venue}</span>
</div>
<div style="margin: 0px; padding:0px; clear: both; height: 6px">
&nbsp;
</div>
<div>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADkAAAA5CAYAAACMGIOFAAAABGdBTUEAALGPC/xhBQAABw9JREFUaAXtWt1vFFUUP3d224JVqHyVXTSCjzYVBFMx/eTJJ1tQ+yA+iBLEIDGa+CBP4h+gMcYXYgR8sDxUacs/YD8DkgjWBB+lpHa3hbZQpNDdzs71nNmZ3Xvv3PlYk+IWd5LNnM/fPWdm7p1zzyyDEo8DYzMvW2buFAB/Gl17qtuSH/YylguD6b58c2t2yTwLHJqBwVj1mvih3qYt06F+nMeyw6mv0e4gAJs04rGjfc31F8P8RL0hMmE055xZOfNHDryRA9Th79jyaPpwmB/pM0vml+j/Cvo+Tmfio/gRPo2TH4832uNjHFF8XZuSknz9l/ltnEPSdaazBdAk8n40RiXZqbyfn4pP41McfvY6eUlJWjwb94Bw8Mo8RrZAtVN5vZcGXxuH3ts7cPc1Xp1ZuNVg5HLrRR/D4NfPNydviDIdvX8k3SHKGRi3+1rrx0WZjt4/dnMXWLk6UdffmhgUeR29/2J6O5iwXdRZsdhCzfrN13obWNaV21ezc/TWE8xa/iI7l3obF4ZqfESkwwLjJAo+l4QaxrKsn0UxY3wQ+X2iTEfjPPsKOG9XdEzhvWzWOoSxfiYpLAswj2znUOosxKo+udCy+W+D7h5Y2VFcDI7g814tOZQ5Y+Ejpgsxnwd/D/MaofyMzPz0Cbx7z+uMV72Mw87s3PSnBuP81VWfTGACvBPnJG8UbRiwCW6ws6IsxmFQ5H1pw567BbVhwUSBCSBinJ3JGUyazwHmBRXFhc+rtFZwxg7h1HumYIT5xT3zkMHEhdaE5Fh0CKb+rV9fe+L7YGS9tq8tMYQa+hWOzuFUBzKFJCm/kt6ThoUuysFwWVREehZLHUmh8pKyyOjwdXEUPbxUSUnG6hJphFgSYfBd+KfI+9GccclO5f38VHzG4IETh5+LR15SkvSCxTn7ERbKpo3E4PfH2NpvPKgagQHGCfSbzavYbJ7XGCoiGx/HcfxM4Oxj8UWvmGvZkpIkhIH25KnamthTRrzqhd2tyT09rXW3tciKsL8tcblmU3yHYbAX6Uy8YqJlCZ/GiRnxXTQuja81DBDaFU+AXqs6t7d+BhUz/Vqtv7C3Ycs91P7qb6HXnGT2kxNaHuq9AUq+k35A5SyvJFnOd6eU2Cp3spSrVc62kVfXruH0c1gTvotNqE1SQgxMfBwuV7UkvtM1tA6O3HnyPn9wnIP1LAd8lTsHVTL0oqf3oO411I0NLOrv4H6xCWslOU4Os4yx0wNtiT9cvKCz7Oxj2T00vSPDLXyv8VqlOEOR3ec5jB21nej+gQhxkvP4lZHUINo4W7liZUcUJg73YPENtNvjvCYK7tShQ5tjBYFCYDH5PsbV2Nu+9bqi8rCR5mTGsDrtBD3ukgBbhvIxPnqzoZigrCtweAFsu4KgQHjwChqb4LX5uGSpjouUZIzBpM5ZljGPzZoqwL6qUwLKxgLHzLydILJJL55qES2uiMXA+eZEH86mMzilis+bPOIUNX1lEQBVRjgJj1NRreqIJznpnQpKMnHwpiShy2AcFA/F5YqCzqxzaEoKHCf04EBbcp/OiRpecba8QdLFanI/vbRhCv0kHNGG+iy5O+mEKCOadhNBxTYudMzuseYyMdHX5FXz1KASZS6N+0lcA+SmWKSFxwVwgD3ghSXTNVTOTiI3FHEo61y4v0INQwwizckQjLJX/y+SLOlxpTlpxMyN4q0zWLUZdU5aBi4XzkEtjKhzUv0sYOXic35z0sUXz5HuJC0AXcNTp8FaXrCy1nXxZ2aWJruGU5P0SU8EdumuodTRzGxqwTT5hOSHPHa675DetRXPhEe4hC/6EU1xUDwUl+jjR0dK8rWx9AGsMN6xKzE90rb8N0tZ+ealmXpccqk9skbW5DnEXEt6slP1Dp7+6xUmR/FQXKqfjo+UZI4DfXANOeyPspLN0jJsxUopZErweN5OckXGi6daRIsrYjFQYxkX8NW9qA6i8D0KDztbtlzDgt5pQqlah0e9bedVe/BkE7aYj0uW6riQq5x3oSIYdyFN+IgE7kLUAajoxl1Ix30I3oWoxTnh0Gd63IWMB+1CetvCi3PCKqniIYdyP3QVT6Q5We6JhcVXSTLsCq0WfaSFh5KptD8AKu2PwMe60v4IvDzwUNsfuLdIBbU/MFTpm6YQ+hJW2L7tD8IVbIvkSrY/3ro0t26RZ6X2x3+x1apl1fM/7N14t5h1kdIVA5FXV4JxgD3gYfudSvujeBNWjKpUPCt2aR8ycOVOPuQLvmLDMVxyF7B3s84dAf/CsoDtod9cfrWdsY+/C/8HVfy/LmN347j8X8FmUoebjG3Aod3lV9sZc1GPq/ifIfhWlT5KPP4N9JQx0JLsoS9Ej1Jibi64qp7ub912rlCsdI2mDuKH3yN4u3eLc9R1WDVnnIMY61W6g5Qgxf0P/UFw0L/BhyIAAAAASUVORK5CYII=" class="data-icon"/>
<span class="tbml-date">${date}</span>
</div>
<div>
<span class="tbml-time">${time}, &nbsp;${this.props.locality}</span>
</div>
</div>`;
}
}

web3.tokens.dataChanged = (oldTokens, updatedTokens) => {
const currentTokenInstance = web3.tokens.data.currentInstance;
document.getElementById('root').innerHTML = new Token(currentTokenInstance).render();
};
]]></script>
<div id="root"></div>
137 changes: 137 additions & 0 deletions examples/edcon/unicon.xml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE token [
<!ENTITY unicon.en SYSTEM "unicon.en.shtml">
<!ENTITY style SYSTEM "shared.css">
]>
<ts:token xmlns:ts="http://tokenscript.org/2019/10/tokenscript"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xsi:schemaLocation="http://tokenscript.org/2019/10/tokenscript http://tokenscript.org/2019/10/tokenscript.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
custodian="false"
>
<ts:name>
<ts:plurals xml:lang="en">
<ts:string quantity="one">Ticket</ts:string>
<ts:string quantity="other">Tickets</ts:string>
</ts:plurals>
</ts:name>

<ts:contract name="unicon" interface="erc721">
<ts:address network="100">0xF6b8DD8Ba9996bEaE6Ad0eE3481F1E9cF080A9eB</ts:address>
</ts:contract>

<ts:origins>
<!-- Define the contract which holds the token that the user will use -->
<ts:ethereum contract="unicon">
</ts:ethereum>
</ts:origins>

<ts:cards>
<ts:token-card>
<style type="text/css">&style;</style>
<ts:view-iconified xml:lang="en">
&unicon.en;
</ts:view-iconified>
<ts:view xml:lang="en">
&unicon.en;
</ts:view>
</ts:token-card>
</ts:cards>

<ts:attribute-types>

<ts:attribute-type id="time" syntax="1.3.6.1.4.1.1466.115.121.1.24">
<ts:name>
<ts:string xml:lang="en">Time</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000" as="utf8">
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<!-- TODO get location & venue, if only one then remove this attribute and hardcode it into the UI -->
<ts:attribute-type id="locality" oid="2.5.4.7" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">City</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000FF00000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="venue" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zhangzhongnan928 if you know the location, let me know

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBC,
They haven't paid to the venue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is
Vienna University of Economics and Business
Welthandelspl. 1, 1020 Wien, Austria

<ts:string xml:lang="en">Venue</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000FF000000000000000000000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">Blockchain Plaza, Vienna</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="category" syntax="1.3.6.1.4.1.1466.115.121.1.15">
<ts:name>
<ts:string xml:lang="en">Cat</ts:string>
<ts:string xml:lang="zh">等级</ts:string>
<ts:string xml:lang="es">Cat</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="000000000000000000000000000000000000000000000000000000FF00000000" as="uint">
<ts:mapping>
<ts:option key="1">
<ts:value xml:lang="en">A</ts:value>
</ts:option>
<ts:option key="2">
<ts:value xml:lang="en">B</ts:value>
</ts:option>
<ts:option key="3">
<ts:value xml:lang="en">C</ts:value>
</ts:option>
<ts:option key="4">
<ts:value xml:lang="en">D</ts:value>
</ts:option>
<ts:option key="5">
<ts:value xml:lang="en">E</ts:value>
</ts:option>
</ts:mapping>
</ts:token-id>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="numero" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>№</ts:string>
</ts:name>
<ts:origins>
<ts:token-id bitmask="00000000000000000000000000000000000000000000000000000000FFFF00" as="uint"/>
</ts:origins>
</ts:attribute-type>

<ts:attribute-type id="redeemed" syntax="1.3.6.1.4.1.1466.115.121.1.27">
<ts:name>
<ts:string>Redeemed</ts:string>
</ts:name>
<ts:origins>
<ts:ethereum function="redeemed" contract="unicon" as="bool">
<ts:data>
<ts:uint256 ref="tokenId"/>
</ts:data>
</ts:ethereum>
</ts:origins>
</ts:attribute-type>

</ts:attribute-types>
</ts:token>