@@ -87,6 +87,12 @@ public class AppMessage extends IdentifiableBase implements AppTemplateEntity, H | |||
.toArray(NameAndValue[]::new); | |||
} | |||
public NameAndValue[] getMessagesWithPrefix (String prefix) { | |||
return Arrays.stream(getMessages()) | |||
.filter(m -> m.getName().startsWith(prefix)) | |||
.toArray(NameAndValue[]::new); | |||
} | |||
public boolean hasMessage(String name) { return !empty(getMessage(name)); } | |||
@ECSearchable @ECField(index=50) @Column(nullable=false) | |||
@@ -28,7 +28,8 @@ import static org.cobbzilla.util.string.StringUtil.splitAndTrim; | |||
@Slf4j | |||
public class FilterAppMessagesResource { | |||
public static final String PARAM_FILTER_MESSAGE = "find"; | |||
public static final String PARAM_FILTER = "find"; | |||
public static final String FILTER_PREFIX = "prefix:"; | |||
private final Account account; | |||
private final BubbleApp app; | |||
@@ -47,11 +48,13 @@ public class FilterAppMessagesResource { | |||
public AppMessage find(@Context ContainerRequest ctx, | |||
@PathParam("locale") String locale) { | |||
final Map<String, String> params = queryParams(ctx.getRequestUri().getQuery()); | |||
final String filter = params.get(PARAM_FILTER_MESSAGE); | |||
final String filter = params.get(PARAM_FILTER); | |||
final String cacheKey = app.getUuid() + ":" + locale + ":" + filter; | |||
return singleMessageCache.computeIfAbsent(cacheKey, k -> { | |||
final AppMessage messages = appMessageDAO.findByAccountAndAppAndLocale(account.getUuid(), app.getUuid(), locale); | |||
return new AppMessage().setMessages(messages.getMessages(splitAndTrim(filter, ","))); | |||
return filter.startsWith(FILTER_PREFIX) | |||
? new AppMessage().setMessages(messages.getMessagesWithPrefix(filter.substring(FILTER_PREFIX.length()))) | |||
: new AppMessage().setMessages(messages.getMessages(splitAndTrim(filter, ","))); | |||
}); | |||
} | |||
@@ -1,6 +1,7 @@ | |||
{{JS_PREFIX}}_load_messages = function (messages, set_func) { | |||
const requestOptions = { method: 'GET' }; | |||
fetch('/__bubble/api/filter/messages/{{BUBBLE_REQUEST_ID}}/{{BUBBLE_APP_NAME}}/{{ACCOUNT_LOCALE}}?find='+messages.join(","), requestOptions) | |||
const find = Array.isArray(messages) ? messages.join(",") : 'prefix:' + messages; | |||
fetch('/__bubble/api/filter/messages/{{BUBBLE_REQUEST_ID}}/{{BUBBLE_APP_NAME}}/{{ACCOUNT_LOCALE}}?find='+find, requestOptions) | |||
.then(response => response.json()) | |||
.then(appMessages => { | |||
const map = {}; | |||
@@ -20,6 +21,10 @@ if (typeof {{PAGE_PREFIX}}_icon_status === 'undefined') { | |||
let {{PAGE_PREFIX}}_icon_status = []; | |||
{{PAGE_PREFIX}}_msg_or_default = function (messages, msg, def) { | |||
return msg in messages ? messages[msg] : def; | |||
} | |||
{{PAGE_PREFIX}}_log = function (data) { | |||
const logData = JSON.stringify(data); | |||
const requestOptions = { | |||
@@ -1,4 +1,6 @@ | |||
let {{JS_PREFIX}}_blocked_users = null; | |||
let {{JS_PREFIX}}_blocked_keywords = null; | |||
let {{JS_PREFIX}}_blocked_links = null; | |||
const {{JS_PREFIX}}_request_id = '{{BUBBLE_REQUEST_ID}}'; | |||
let {{JS_PREFIX}}_unblocked_users_needs_refresh = false; | |||
@@ -23,6 +25,13 @@ const {{JS_PREFIX}}_create_block_img = function(size) { | |||
return img; | |||
} | |||
const {{JS_PREFIX}}_create_unblock_img = function(size) { | |||
const img = document.createElement('img'); | |||
img.src = '/__bubble/api/filter/assets/{{BUBBLE_REQUEST_ID}}/UserBlocker/unblock-icon?raw=true'; | |||
img.width = typeof size !== 'undefined' ? size : 16; | |||
return img; | |||
} | |||
const {{JS_PREFIX}}_stop_refreshing_blocks = function(e) { | |||
if ({{JS_PREFIX}}_interval !== null) { | |||
window.clearInterval({{JS_PREFIX}}_interval); | |||
@@ -31,6 +40,7 @@ const {{JS_PREFIX}}_stop_refreshing_blocks = function(e) { | |||
} | |||
const {{JS_PREFIX}}_refresh_blocks = function(e) { | |||
{{PAGE_PREFIX}}_log('_refresh_blocks!'); | |||
{{JS_PREFIX}}_last_applied = Date.now(); | |||
{{JS_PREFIX}}_stop_refreshing_blocks(); | |||
{{JS_PREFIX}}_apply_blocks({{JS_PREFIX}}_blocked_users); | |||
{{JS_PREFIX}}_interval = window.setInterval(function () { | |||
@@ -46,10 +56,21 @@ function {{JS_PREFIX}}_fetch_blocks (do_apply) { | |||
.then(resp => resp.json()) | |||
.then(data => { | |||
const blocked_users = []; | |||
const blocked_keywords = []; | |||
const blocked_links = []; | |||
for (let i=0; i<data.length; i++) { | |||
blocked_users.push(data[i]); | |||
let token = data[i]; | |||
if (token.startsWith('kw:')) { | |||
blocked_keywords.push(token); | |||
} else if (token.startsWith('link:')) { | |||
blocked_links.push(token); | |||
} else { | |||
blocked_users.push(token); | |||
} | |||
} | |||
{{JS_PREFIX}}_blocked_users = blocked_users; | |||
{{JS_PREFIX}}_blocked_keywords = blocked_keywords; | |||
{{JS_PREFIX}}_blocked_links = blocked_links; | |||
{{JS_PREFIX}}_refresh_blocks(); | |||
}); | |||
} | |||
@@ -64,13 +85,16 @@ function {{JS_PREFIX}}_handleVisibilityChange() { | |||
} | |||
} | |||
document.addEventListener("visibilitychange", {{JS_PREFIX}}_handleVisibilityChange, false); | |||
document.addEventListener("click", function (ev) { | |||
function {{JS_PREFIX}}_check_stale_refresher(ev) { | |||
if ({{JS_PREFIX}}_last_applied === null || Date.now() - {{JS_PREFIX}}_last_applied > 2*{{JS_PREFIX}}_idle_interval) { | |||
{{PAGE_PREFIX}}_log('document.click forcing refresh'); | |||
{{PAGE_PREFIX}}_log('check_stale_refresher forcing refresh upon document event.type='+ev.type); | |||
{{JS_PREFIX}}_refresh_blocks(); | |||
} | |||
}, false); | |||
} | |||
document.addEventListener("visibilitychange", {{JS_PREFIX}}_handleVisibilityChange, false); | |||
document.addEventListener("click", {{JS_PREFIX}}_check_stale_refresher, false); | |||
document.addEventListener("scroll", {{JS_PREFIX}}_check_stale_refresher, false); | |||
function {{JS_PREFIX}}_update_user (author, do_block) { | |||
{{JS_PREFIX}}_apply_blocks({{JS_PREFIX}}_blocked_users); | |||
@@ -101,7 +125,7 @@ function {{JS_PREFIX}}_unblock_user (author) { | |||
let {{JS_PREFIX}}_app_details = false; | |||
function {{JS_PREFIX}}_create_unblock_control(authorName) { | |||
const imgHolder = {{JS_PREFIX}}_create_block_img(); | |||
const imgHolder = {{JS_PREFIX}}_create_unblock_img(); | |||
const blockSpan = document.createElement('span'); | |||
const unblockLink = document.createElement('a'); | |||
unblockLink.addEventListener("click", function (e) { | |||
@@ -135,6 +159,7 @@ function {{JS_PREFIX}}_hide_app_details() { | |||
function {{JS_PREFIX}}_show_app_details() { | |||
{{PAGE_PREFIX}}_log('show_app_details called'); | |||
{{JS_PREFIX}}_refresh_blocks(); | |||
const detailsDivId = '{{JS_PREFIX}}_detailsDiv'; | |||
let detailsDiv = document.getElementById(detailsDivId); | |||
let blocks = {{JS_PREFIX}}_blocked_users; | |||
@@ -169,17 +194,19 @@ function {{JS_PREFIX}}_show_app_details() { | |||
window.location.reload(); | |||
return false; | |||
}); | |||
const refreshMessage = 'refreshPage' in {{JS_PREFIX}}_messages | |||
? {{JS_PREFIX}}_messages['refreshPage'] | |||
: 'refresh' | |||
const refreshMessage = {{PAGE_PREFIX}}_msg_or_default({{JS_PREFIX}}_messages, 'web_refreshPage', 'refresh'); | |||
refreshControl.appendChild(document.createTextNode(refreshMessage)); | |||
detailsDiv.appendChild(refreshControl); | |||
detailsDiv.appendChild(document.createElement('hr')); | |||
} | |||
const usersHeaderText = {{PAGE_PREFIX}}_msg_or_default({{JS_PREFIX}}_messages, 'web_blockedUsers', 'Users'); | |||
const usersHeader = document.createElement('strong'); | |||
usersHeader.appendChild(document.createTextNode(usersHeaderText)); | |||
detailsDiv.appendChild(usersHeader); | |||
detailsDiv.appendChild(document.createElement('hr')); | |||
if (blocks === null || blocks.length === 0) { | |||
const emptyMessage = 'noUsersBlocked' in {{JS_PREFIX}}_messages | |||
? {{JS_PREFIX}}_messages['noUsersBlocked'] | |||
: '(empty)' | |||
const emptyMessage = {{PAGE_PREFIX}}_msg_or_default({{JS_PREFIX}}_messages, 'web_noUsersBlocked', '(empty)'); | |||
const entryDiv = document.createElement('div'); | |||
const entryText = document.createTextNode(emptyMessage); | |||
entryDiv.appendChild(entryText); | |||
@@ -214,7 +241,7 @@ function {{JS_PREFIX}}_toggle_app_details(ev) { | |||
link: {{JS_PREFIX}}_toggle_app_details, | |||
icon: 'icon', | |||
onReady: function () { | |||
{{JS_PREFIX}}_load_messages(['noUsersBlocked'], function (messages) { | |||
{{JS_PREFIX}}_load_messages('web_', function (messages) { | |||
{{JS_PREFIX}}_messages = messages; | |||
}) | |||
{{JS_PREFIX}}_fetch_blocks(); | |||
@@ -10,6 +10,27 @@ function {{JS_PREFIX}}_getElementsByXPath(xpath, parent) { | |||
const {{JS_PREFIX}}_site_host = location.protocol + '//' + window.location.hostname + '/'; | |||
const {{JS_PREFIX}}_mobile = window.location.hostname === "m.facebook.com"; | |||
const {{JS_PREFIX}}_appendChild = Element.prototype.appendChild; | |||
Element.prototype.appendChild = function() { | |||
try { | |||
if (arguments[0].tagName) { | |||
if ({{JS_PREFIX}}_mobile && arguments[0].tagName.toUpperCase() === 'SECTION') { | |||
console.log('>>> intercepted appendChild for mobile article'); | |||
} else if ({{JS_PREFIX}}_mobile && arguments[0].tagName.toUpperCase() === 'DIV' && arguments[0].role && arguments[0].role === 'article') { | |||
console.log('>>> intercepted appendChild for desktop article'); | |||
} | |||
} | |||
} catch (e) { | |||
console.log('>>> error inspecting: e='+e); | |||
} | |||
try { | |||
{{JS_PREFIX}}_appendChild.apply(this, arguments); | |||
} catch (e) { | |||
console.log('>>> error calling document.appendChild: arg[0].tagName = '+arguments[0].tagName+' e='+e); | |||
} | |||
}; | |||
const log = {{PAGE_PREFIX}}_log; | |||
function {{JS_PREFIX}}_is_ad(article) { | |||
@@ -61,7 +82,8 @@ function {{JS_PREFIX}}_create_block_control(article, authorName) { | |||
return false; | |||
}); | |||
blockLink.appendChild(imgHolder); | |||
blockSpan.appendChild(blockLink) | |||
blockSpan.appendChild(document.createTextNode('\u00A0\u00A0')); | |||
blockSpan.appendChild(blockLink); | |||
blockSpan.id = 'blockSpan_'+{{JS_PREFIX}}_uuidv4(); | |||
return blockSpan; | |||
@@ -84,9 +106,68 @@ function {{JS_PREFIX}}_is_author_link(href) { | |||
return matches === null; | |||
} | |||
function {{JS_PREFIX}}_should_block(blocked_users, article) { | |||
const sitePrefix = {{JS_PREFIX}}_site_host; | |||
const mobile = {{JS_PREFIX}}_mobile; | |||
const log = {{PAGE_PREFIX}}_log; | |||
const authorLinks = Array.from(article.getElementsByTagName('a')) | |||
.filter(a => {{JS_PREFIX}}_is_author_link(a.href)) | |||
.filter(a => a.getElementsByTagName('svg').length === 0) | |||
.filter(a => mobile ? a.parentElement.tagName.toUpperCase() === 'STRONG' : a.getElementsByTagName('span').length === 1); | |||
for (let authIndex=0; authIndex<authorLinks.length; authIndex++) { | |||
const authorLink = authorLinks[authIndex]; | |||
let authorHref = authorLink.href; | |||
let authorName = authorHref.startsWith(sitePrefix) ? authorHref.substring(sitePrefix.length) : authorHref; | |||
const qPos = authorName.indexOf('?'); | |||
if (qPos !== -1) { | |||
authorName = authorName.substring(0, qPos); | |||
authorLink.href = sitePrefix + authorName; | |||
} | |||
if (authorName.endsWith('/')) authorName = authorName.substring(0, authorName.length-1); | |||
if (authorName === 'profile.php') { | |||
return true; | |||
} | |||
const authorDisplay = mobile | |||
? authorLink | |||
: authorLink.getElementsByTagName('span')[0]; | |||
const authorDisplayName = authorDisplay.innerHTML; | |||
if ({{JS_PREFIX}}_is_ad(article)) { | |||
log('removing ad ('+authorDisplayName+')'); | |||
return authorName == null ? true : authorName; | |||
} else if (blocked_users !== null && blocked_users.includes(authorName)) { | |||
return authorName == null ? true : authorName; | |||
} else { | |||
// have we visited this authorLink before? | |||
try { | |||
if (authorLink.id === "") { | |||
// log('VISITING author: ' + authorName + ' (' + authorDisplayName + ')'); | |||
authorLink.id = 'bubble_author_' + {{JS_PREFIX}}_uuidv4(); | |||
// log('assigned id='+authorLink.id+' for authorLink by '+authorName); | |||
} else if (authorDisplay.parentNode.innerHTML.indexOf('__bubble') !== -1) { | |||
// log('NOT RE-VISITING article node for author: ' + authorName + ' (' + authorDisplayName + '), display.inner='+authorDisplay.parentNode.innerHTML); | |||
continue; | |||
} else { | |||
// log('RE-VISITING article node for author: ' + authorName + ' (' + authorDisplayName + '), display.inner='+authorDisplay.parentNode.innerHTML); | |||
} | |||
let b = {{JS_PREFIX}}_create_block_control(article, authorName); | |||
// log('inserting span='+b.id+' for article by '+authorName); | |||
authorDisplay.parentNode.appendChild(b); | |||
} catch (e) { | |||
log('badness: '+e); | |||
} | |||
} | |||
} | |||
} | |||
function {{JS_PREFIX}}_apply_blocks(blocked_users) { | |||
const sitePrefix = {{JS_PREFIX}}_site_host; | |||
const mobile = {{JS_PREFIX}}_mobile; | |||
const log = {{PAGE_PREFIX}}_log; | |||
@@ -96,61 +177,9 @@ function {{JS_PREFIX}}_apply_blocks(blocked_users) { | |||
for (let i=0; i<articles.length; i++) { | |||
const article = articles[i]; | |||
const authorLinks = Array.from(article.getElementsByTagName('a')) | |||
.filter(a => {{JS_PREFIX}}_is_author_link(a.href)) | |||
.filter(a => a.getElementsByTagName('svg').length === 0) | |||
.filter(a => mobile ? a.parentElement.tagName.toUpperCase() === 'STRONG' : a.getElementsByTagName('span').length === 1); | |||
for (let authIndex=0; authIndex<authorLinks.length; authIndex++) { | |||
const authorLink = authorLinks[authIndex]; | |||
let authorHref = authorLink.href; | |||
let authorName = authorHref.startsWith(sitePrefix) ? authorHref.substring(sitePrefix.length) : authorHref; | |||
const qPos = authorName.indexOf('?'); | |||
if (qPos !== -1) { | |||
authorName = authorName.substring(0, qPos); | |||
authorLink.href = sitePrefix + authorName; | |||
} | |||
if (authorName.endsWith('/')) authorName = authorName.substring(0, authorName.length-1); | |||
if (authorName === 'profile.php') { | |||
{{JS_PREFIX}}_remove_article(article, null); | |||
break; | |||
} | |||
const authorDisplay = mobile | |||
? authorLink | |||
: authorLink.getElementsByTagName('span')[0]; | |||
const authorDisplayName = authorDisplay.innerHTML; | |||
if ({{JS_PREFIX}}_is_ad(article)) { | |||
log('removing ad ('+authorDisplayName+')'); | |||
{{JS_PREFIX}}_remove_article(article, authorName); | |||
break; | |||
} else if (blocked_users !== null && blocked_users.includes(authorName)) { | |||
{{JS_PREFIX}}_remove_article(article, authorName); | |||
break; | |||
} else { | |||
// have we visited this authorLink before? | |||
try { | |||
if (authorLink.id === "") { | |||
// log('VISITING author: ' + authorName + ' (' + authorDisplayName + ')'); | |||
authorLink.id = 'bubble_author_' + {{JS_PREFIX}}_uuidv4(); | |||
// log('assigned id='+authorLink.id+' for authorLink by '+authorName); | |||
} else if (authorDisplay.parentNode.innerHTML.indexOf('__bubble') !== -1) { | |||
// log('NOT RE-VISITING article node for author: ' + authorName + ' (' + authorDisplayName + '), display.inner='+authorDisplay.parentNode.innerHTML); | |||
continue; | |||
} else { | |||
// log('RE-VISITING article node for author: ' + authorName + ' (' + authorDisplayName + '), display.inner='+authorDisplay.parentNode.innerHTML); | |||
} | |||
let b = {{JS_PREFIX}}_create_block_control(article, authorName); | |||
// log('inserting span='+b.id+' for article by '+authorName); | |||
authorDisplay.parentNode.appendChild(b); | |||
} catch (e) { | |||
log('badness: '+e); | |||
} | |||
} | |||
const authorName = {{JS_PREFIX}}_should_block(blocked_users, article); | |||
if (authorName) { | |||
{{JS_PREFIX}}_remove_article(article, authorName === true ? null : authorName); | |||
} | |||
} | |||
} |
@@ -27,9 +27,8 @@ | |||
"messages": [ | |||
{"name": "name", "value": "Shadow Ban"}, | |||
{"name": "icon", "value": "classpath:models/apps/user_block/shadowban-icon.svg"}, | |||
{"name": "unblock-icon", "value": "classpath:models/apps/user_block/shadowban-unblock-icon.svg"}, | |||
{"name": "summary", "value": "User Blocker"}, | |||
{"name": "noUsersBlocked", "value": "(empty)"}, | |||
{"name": "refreshPage", "value": "refresh"}, | |||
{"name": "description", "value": "Throw the garbage to the curb!"}, | |||
{"name": "view.blocked_users", "value": "Manage Blocked Users"}, | |||
{"name": "field.key", "value": "Username"}, | |||
@@ -37,7 +36,17 @@ | |||
{"name": "field.ctime", "value": "Created"}, | |||
{"name": "action.enable", "value": "Enforce Block"}, | |||
{"name": "action.disable", "value": "Disable Block"}, | |||
{"name": "action.delete", "value": "Delete Block"} | |||
{"name": "action.delete", "value": "Delete Block"}, | |||
{"name": "web_blockedUsers", "value": "Users"}, | |||
{"name": "web_noUsersBlocked", "value": "(empty)"}, | |||
{"name": "web_blockedKeywords", "value": "Keywords"}, | |||
{"name": "web_noKeywordsBlocked", "value": "(empty)"}, | |||
{"name": "web_addKeyword", "value": "Add"}, | |||
{"name": "web_blockedCategories", "value": "Categories"}, | |||
{"name": "web_cat_us_news", "value": "US News Media"}, | |||
{"name": "web_cat_us_politics", "value": "US Politics"}, | |||
{"name": "web_refreshPage", "value": "refresh"} | |||
] | |||
}] | |||
} |
@@ -0,0 +1,18 @@ | |||
[{ | |||
"name": "UserBlocker", | |||
"children": { | |||
"AppData": [{ | |||
"site": "Facebook", | |||
"template": true, | |||
"matcher": "FBMatcher", | |||
"key": "cat~us_news", | |||
"value": "https://raw.githubusercontent.com/getbubblenow/bubble-filter-lists/master/sites_us_news.txt" | |||
}, { | |||
"site": "Facebook", | |||
"template": true, | |||
"matcher": "FBMatcher", | |||
"key": "cat~us_politics", | |||
"value": "https://raw.githubusercontent.com/getbubblenow/bubble-filter-lists/master/us_politics.txt" | |||
}] | |||
} | |||
}] |
@@ -0,0 +1,336 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:xlink="http://www.w3.org/1999/xlink" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
width="48.000000px" | |||
height="48.000000px" | |||
id="svg6361" | |||
sodipodi:version="0.32" | |||
inkscape:version="0.46" | |||
sodipodi:docbase="/home/jimmac/gfx/ximian/tango-icon-theme/scalable/actions" | |||
sodipodi:docname="process-stop.svg" | |||
inkscape:output_extension="org.inkscape.output.svg.inkscape"> | |||
<defs | |||
id="defs3"> | |||
<inkscape:perspective | |||
sodipodi:type="inkscape:persp3d" | |||
inkscape:vp_x="0 : 24 : 1" | |||
inkscape:vp_y="0 : 1000 : 0" | |||
inkscape:vp_z="48 : 24 : 1" | |||
inkscape:persp3d-origin="24 : 16 : 1" | |||
id="perspective52" /> | |||
<linearGradient | |||
id="linearGradient2256"> | |||
<stop | |||
style="stop-color:#565656;stop-opacity:1;" | |||
offset="0" | |||
id="stop2258" /> | |||
<stop | |||
style="stop-color:#bcbcbc;stop-opacity:1;" | |||
offset="1" | |||
id="stop2260" /> | |||
</linearGradient> | |||
<linearGradient | |||
inkscape:collect="always" | |||
id="linearGradient2248"> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:1;" | |||
offset="0" | |||
id="stop2250" /> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:0;" | |||
offset="1" | |||
id="stop2252" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient9647"> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:1;" | |||
offset="0" | |||
id="stop9649" /> | |||
<stop | |||
style="stop-color:#dbdbdb;stop-opacity:1;" | |||
offset="1" | |||
id="stop9651" /> | |||
</linearGradient> | |||
<linearGradient | |||
inkscape:collect="always" | |||
id="linearGradient21644"> | |||
<stop | |||
style="stop-color:#000000;stop-opacity:1;" | |||
offset="0" | |||
id="stop21646" /> | |||
<stop | |||
style="stop-color:#000000;stop-opacity:0;" | |||
offset="1" | |||
id="stop21648" /> | |||
</linearGradient> | |||
<radialGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient21644" | |||
id="radialGradient21650" | |||
cx="25.125" | |||
cy="36.75" | |||
fx="25.125" | |||
fy="36.75" | |||
r="15.75" | |||
gradientTransform="matrix(1.000000,0.000000,0.000000,0.595238,-2.300678e-15,14.87500)" | |||
gradientUnits="userSpaceOnUse" /> | |||
<linearGradient | |||
inkscape:collect="always" | |||
id="linearGradient7895"> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:1;" | |||
offset="0" | |||
id="stop7897" /> | |||
<stop | |||
style="stop-color:#ffffff;stop-opacity:0;" | |||
offset="1" | |||
id="stop7899" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient4981"> | |||
<stop | |||
style="stop-color:#444444;stop-opacity:1;" | |||
offset="0" | |||
id="stop4983" /> | |||
<stop | |||
style="stop-color:#3b3b3b;stop-opacity:1.0000000;" | |||
offset="1.0000000" | |||
id="stop4985" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient15762" | |||
inkscape:collect="always"> | |||
<stop | |||
id="stop15764" | |||
offset="0" | |||
style="stop-color:#ffffff;stop-opacity:1;" /> | |||
<stop | |||
id="stop15766" | |||
offset="1" | |||
style="stop-color:#ffffff;stop-opacity:0;" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient14236"> | |||
<stop | |||
id="stop14238" | |||
offset="0.0000000" | |||
style="stop-color:#797979;stop-opacity:1.0000000;" /> | |||
<stop | |||
id="stop14240" | |||
offset="1.0000000" | |||
style="stop-color:#363636;stop-opacity:1.0000000;" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient11780"> | |||
<stop | |||
style="stop-color:#b1b1b1;stop-opacity:1.0000000;" | |||
offset="0.0000000" | |||
id="stop11782" /> | |||
<stop | |||
style="stop-color:#606060;stop-opacity:1.0000000;" | |||
offset="1.0000000" | |||
id="stop11784" /> | |||
</linearGradient> | |||
<linearGradient | |||
id="linearGradient11014"> | |||
<stop | |||
style="stop-color:#383838;stop-opacity:1.0000000;" | |||
offset="0.0000000" | |||
id="stop11016" /> | |||
<stop | |||
style="stop-color:#424242;stop-opacity:1.0000000;" | |||
offset="0.0000000" | |||
id="stop13245" /> | |||
<stop | |||
style="stop-color:#4c4c4c;stop-opacity:1.0000000;" | |||
offset="1.0000000" | |||
id="stop11018" /> | |||
</linearGradient> | |||
<linearGradient | |||
y2="9.6507530" | |||
x2="9.8940229" | |||
y1="5.3855424" | |||
x1="5.7365270" | |||
gradientTransform="matrix(-1.000000,0.000000,0.000000,-1.000000,31.72170,31.29079)" | |||
gradientUnits="userSpaceOnUse" | |||
id="linearGradient15772" | |||
xlink:href="#linearGradient15762" | |||
inkscape:collect="always" /> | |||
<linearGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient11780" | |||
id="linearGradient2057" | |||
x1="15.737001" | |||
y1="12.503600" | |||
x2="53.570126" | |||
y2="47.374317" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="translate(0.000000,-2.000000)" /> | |||
<linearGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient4981" | |||
id="linearGradient4987" | |||
x1="23.995985" | |||
y1="20.105337" | |||
x2="41.047836" | |||
y2="37.959785" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="translate(0.000000,-2.000000)" /> | |||
<linearGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient7895" | |||
id="linearGradient7901" | |||
x1="15.578875" | |||
y1="16.285088" | |||
x2="32.166405" | |||
y2="28.394291" | |||
gradientUnits="userSpaceOnUse" /> | |||
<radialGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient9647" | |||
id="radialGradient2239" | |||
cx="24.30225" | |||
cy="33.30225" | |||
fx="24.30225" | |||
fy="33.30225" | |||
r="12.30225" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="matrix(1.693981,-5.775714e-16,5.775714e-16,1.693981,-16.86529,-25.11111)" /> | |||
<linearGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient4981" | |||
id="linearGradient2243" | |||
gradientUnits="userSpaceOnUse" | |||
x1="23.995985" | |||
y1="20.105337" | |||
x2="41.047836" | |||
y2="37.959785" | |||
gradientTransform="matrix(0.988373,0.000000,0.000000,0.988373,0.279002,0.278984)" /> | |||
<radialGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient2248" | |||
id="radialGradient2254" | |||
cx="16.75" | |||
cy="10.666344" | |||
fx="16.75" | |||
fy="10.666344" | |||
r="21.25" | |||
gradientTransform="matrix(4.154957,-2.979206e-24,3.255657e-24,3.198723,-52.84553,-23.50921)" | |||
gradientUnits="userSpaceOnUse" /> | |||
<linearGradient | |||
inkscape:collect="always" | |||
xlink:href="#linearGradient2256" | |||
id="linearGradient2262" | |||
x1="21.75" | |||
y1="15.80225" | |||
x2="24.30225" | |||
y2="35.05225" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="translate(0.000000,-2.000000)" /> | |||
</defs> | |||
<sodipodi:namedview | |||
inkscape:guide-bbox="true" | |||
showguides="true" | |||
id="base" | |||
pagecolor="#ffffff" | |||
bordercolor="#666666" | |||
borderopacity="0.15294118" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="4" | |||
inkscape:cx="0.007276" | |||
inkscape:cy="7.0544576" | |||
inkscape:current-layer="layer1" | |||
showgrid="false" | |||
inkscape:grid-bbox="true" | |||
inkscape:document-units="px" | |||
inkscape:window-width="786" | |||
inkscape:window-height="688" | |||
inkscape:window-x="488" | |||
inkscape:window-y="160" | |||
inkscape:showpageshadow="false" /> | |||
<metadata | |||
id="metadata4"> | |||
<rdf:RDF> | |||
<cc:Work | |||
rdf:about=""> | |||
<dc:format>image/svg+xml</dc:format> | |||
<dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
<dc:title>Stop</dc:title> | |||
<dc:date>2005-10-16</dc:date> | |||
<dc:creator> | |||
<cc:Agent> | |||
<dc:title>Andreas Nilsson</dc:title> | |||
</cc:Agent> | |||
</dc:creator> | |||
<dc:subject> | |||
<rdf:Bag> | |||
<rdf:li>stop</rdf:li> | |||
<rdf:li>halt</rdf:li> | |||
<rdf:li>error</rdf:li> | |||
</rdf:Bag> | |||
</dc:subject> | |||
<cc:license | |||
rdf:resource="http://creativecommons.org/licenses/publicdomain/" /> | |||
<dc:contributor> | |||
<cc:Agent> | |||
<dc:title>Jakub Steiner</dc:title> | |||
</cc:Agent> | |||
</dc:contributor> | |||
</cc:Work> | |||
<cc:License | |||
rdf:about="http://creativecommons.org/licenses/publicdomain/"> | |||
<cc:permits | |||
rdf:resource="http://creativecommons.org/ns#Reproduction" /> | |||
<cc:permits | |||
rdf:resource="http://creativecommons.org/ns#Distribution" /> | |||
<cc:permits | |||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /> | |||
</cc:License> | |||
</rdf:RDF> | |||
</metadata> | |||
<g | |||
id="layer1" | |||
inkscape:label="Layer 1" | |||
inkscape:groupmode="layer"> | |||
<path | |||
sodipodi:type="arc" | |||
style="opacity:0.63068183;color:#000000;fill:url(#radialGradient21650);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" | |||
id="path21642" | |||
sodipodi:cx="25.125" | |||
sodipodi:cy="36.75" | |||
sodipodi:rx="15.75" | |||
sodipodi:ry="9.375" | |||
d="M 40.875 36.75 A 15.75 9.375 0 1 1 9.375,36.75 A 15.75 9.375 0 1 1 40.875 36.75 z" | |||
transform="matrix(1.173803,0.000000,0.000000,0.600000,-5.265866,19.57500)" /> | |||
<path | |||
style="fill:url(#linearGradient4987);fill-opacity:1;fill-rule:evenodd;stroke:#2c2c2c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |||
d="M 15.591006,0.4919213 L 32.676311,0.4919213 L 45.497585,13.586385 L 45.497585,31.48003 L 32.848986,43.496929 L 15.418649,43.496929 L 2.4943857,30.658264 L 2.4943857,13.464078 L 15.591006,0.4919213 z " | |||
id="path9480" | |||
sodipodi:nodetypes="ccccccccc" /> | |||
<path | |||
style="opacity:0.81318683;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2057);stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" | |||
d="M 16.020655,1.5003424 L 32.248563,1.5003424 L 44.496456,13.922717 L 44.496456,31.037001 L 32.638472,42.48783 L 15.870253,42.48783 L 3.5090792,30.208718 L 3.5090792,13.84561 L 16.020655,1.5003424 z " | |||
id="path9482" | |||
sodipodi:nodetypes="ccccccccc" /> | |||
<path | |||
style="opacity:0.28977272;fill:url(#radialGradient2254);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |||
d="M 15.6875,0.75 L 2.75,13.5625 L 2.75,30.5625 L 5.6875,33.46875 C 22.450041,33.526299 22.164665,20.450067 45.25,21.59375 L 45.25,13.6875 L 32.5625,0.75 L 15.6875,0.75 z " | |||
id="path2241" | |||
sodipodi:nodetypes="cccccccc" /> | |||
<path | |||
style="fill:url(#radialGradient2239);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2262);stroke-width:0.99999958;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |||
d="M 16.767175,10.5 L 12.5,14.767175 L 20.035075,22.30225 L 12.5,29.837325 L 16.767175,34.104501 L 24.30225,26.569425 L 31.837325,34.104501 L 36.104501,29.837325 L 28.569425,22.30225 L 36.104501,14.767175 L 31.837325,10.5 L 24.30225,18.035075 L 16.767175,10.5 z " | |||
id="path2787" /> | |||
</g> | |||
</svg> |