Initial import

This commit is contained in:
Anders Englöf Ytterström 2025-05-03 18:48:38 +02:00
commit 9f6fb1a2c5
32 changed files with 2330 additions and 0 deletions

66
2008.ie-valign.css Normal file
View file

@ -0,0 +1,66 @@
/* @group valignfix */
/* ***************************************
valignfix, by Anders Ytterström @ madr.se
**************************************** */
/*
HTML fixture:
.valign
%div
%div
%h1
%h2
%img
*/
/* @group ie8, ff, opera, safari
===================================== */
body > div {
display:table;
}
*.valign {
display:table-row;
}
*.valign > * {
width:50%;
display:table-cell;
vertical-align:middle;
}
/* @end ie8, ff, opera, safari
===================================== */
/* @group ie6,ie7
===================================== */
/*
use this in CC file.
Works only in standards mode.
*/
* html *.valign,
*+html *.valign {
position:relative;
overflow:auto;
}
* html *.valign div,
*+html *.valign div {
position:absolute;
top:50%;
}
* html *.valign div div,
*+html *.valign div div {
position:relative;
top:-50%;
}
* html *.valign div div *,
*+html *.valign div div * {
position:static;
top:0;
}
* html *.valign img,
*+html *.valign img {
float:right;
}
/* @end ie6, ie7
===================================== */
/* ****************************************
/valignfix, by Anders Ytterström @ madr.se
**************************************** */
/* @end valignfix */

View file

@ -0,0 +1,4 @@
<?php
$subject = "=?UTF-8?B?" . base64_encode($subject) . "?=";
// mail( ... )

View file

@ -0,0 +1,67 @@
/*!
light-weight click listener, v 1.0
Copyright (c) 2010 by madr <http://madr.se>
Licensed under the MIT license: http://en.wikipedia.org/wiki/MIT_License
*/
/*
Usage:
Alter the below snippet for your needs and put the modified snippet in a js-file or a <script> and add it to your document. If your webapp depends on libraries or other resources to load, you better keep that in mind.
*/
(function(document, undefined) {
function investigate(elm){
/*
Change the content of this function
to suit your web application.
*/
/*
EXAMPLE 0: do nothing until jQuery (or other libraries) is loaded.
if (typeof window.jQuery == 'undefined') { return false; }
*/
/*
EXAMPLE 1: look for element type
if (elm.nodeName == 'A') {
// do stuff ...
return true;
}
*/
/*
EXAMPLE 2: look for id or other property
if (elm.id == 'modal-window-opener') {
// do stuff ...
return true;
}
*/
/*
EXAMPLE 3: sniffing a classname
if (elm.className.match(/read-more/)) {
// do stuff ...
return true;
}
*/
return false; // default
}
function clicklistener(evt){
var event = evt || window.event,
elm = event.target || window.srcElement,
magic_did_happen = investigate(elm);
if (magic_did_happen) {
if (window.event) { window.eventReturnValue = false; }
else { evt.preventDefault(); }
return false;
}
}
if (document.attachEvent) {
document.attachEvent('onclick', clicklistener);
} else {
document.addEventListener('click', clicklistener, false);
}
})(document);

View file

@ -0,0 +1,96 @@
/*jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, curly:true, browser:true, indent:2, maxerr:50 */
/*!
front.js
(c) 2011 Anders Ytterström
front.js may be freely distributed under the MIT license.
TODO: pushState support
*/
/*
USAGE: A route is defined by a path (could be a simple string or a regexp) and a callback (a function).
// static routes
front("books", displayBooks);
front("talks", displayTalks);
front("comments", displayComments);
// dynamic routes
front(/book:[\d+]$/, displayBookDetail);
front(/talk:[\d+]$/, displayTalkDetail);
front(/comment:[\d]$/, displayCommentDetail);
The frontcontroller should be executed when all dependencies are in place and the routes are configured.
front.run(); // defaults to location.hash -> http://example.com
front.run("book:12"); // goto book 12 -> http://example.com#!book:12
location.hash is altered everytime front.run is executed.
*/
(function (global) {
"use strict";
var i, _regexps = [], _statics = [];
function addRoute(path, callback) {
if (typeof path !== "string") { // regexp
_regexps.push([ path, callback ]);
} else {
_statics.push([ path, callback ]);
}
return true;
}
function dispatch(path) {
// set path
if (typeof path === "undefined") {
path = location.hash || "";
path = path.replace(/^#/, '').replace(/^!/, '');
}
// cleanup
var action, args;
// static routes lookup
i = _statics.length;
while (i--) {
if (_statics[i][0] === path) {
action = _statics[i][1];
break;
}
}
// regexp routes lookup unless a static action was defined.
if (typeof action !== "function") {
i = _regexps.length;
while (i--) {
args = args = path.match(_regexps[i][0]);
if (args) {
action = _regexps[i][1];
break;
}
}
}
// execute action and update hash unless the action is still undefined
if (typeof action === "function") {
if (args instanceof Array) {
args.shift();
if (args.length === 1) { args = args[0]; }
}
action(args);
path = (path.length ? '#!': '') + path;
if (location.hash !== path) {
location.hash = path;
}
}
return false; // for click events.
}
global.front = addRoute;
global.front.run = dispatch;
})(this);

14
2011.js.hex2rgb.js Normal file
View file

@ -0,0 +1,14 @@
function hex2rgb(hex, opacity) {
var rgb = hex.replace('#', '').match(/(.{2})/g);
var i = 3;
while (i--) {
rgb[i] = parseInt(rgb[i], 16);
}
if (typeof opacity == 'undefined') {
return 'rgb(' + rgb.join(', ') + ')';
}
return 'rgba(' + rgb.join(', ') + ', ' + opacity + ')';
};

View file

@ -0,0 +1,17 @@
function adate(daysFromNow) {
var date, datestr, mm, dd;
datestr = new Date().getTime();
if (!!daysFromNow) {
datestr += (1000 * 60 * 60 * 24 * daysFromNow);
}
date = new Date(datestr);
mm = date.getMonth() + '';
if (mm.length == 1) {
mm = '0' + mm;
}
dd = date.getDate() + '';
if (dd.length == 1) {
dd = '0' + dd;
}
return date.getFullYear() + '-' + mm + '-' + dd;
}

View file

@ -0,0 +1,45 @@
# example use:
# rake favicons["../img/origin.png"]
#
# Output:
# ./apple-touch-icon-114x114-precomposed.png
# ./apple-touch-icon-114x114.png
# ./apple-touch-icon-57x57-precomposed.png
# ./apple-touch-icon-57x57.png
# ./apple-touch-icon-72x72-precomposed.png
# ./apple-touch-icon-72x72.png
# ./apple-touch-icon-precomposed.png
# ./apple-touch-icon.png
# ./favicon.ico
require "RMagick"
desc "Generates favicons and webapp icons"
task :favicons, :origin do |t, args|
name = "apple-touch-icon-%dx%d.png"
name_pre = "apple-touch-icon-%dx%d-precomposed.png"
FileList["*apple-touch-ico*.png"].each do |img|
File.delete img
end
FileList["*favicon.ico"].each do |img|
File.delete img
end
FileList[args.origin].each do |img|
puts "creating favicon.ico"
Magick::Image::read(img).first.resize(16, 16).write("favicon.ico")
[114, 57, 72].each do |size|
puts "creating %d * %d icons" % [size, size]
Magick::Image::read(img).first.resize(size, size).write(name % [size, size]).write(name_pre % [size, size])
end
puts "creating backward-compatible icons"
cp name_pre % [57, 57], "apple-touch-icon.png"
cp name_pre % [57, 57], "apple-touch-icon-precomposed.png"
end
end

View file

@ -0,0 +1,119 @@
#!/usr/bin/env ruby
require 'net/https'
require "rexml/document"
require "date"
require 'net/smtp'
# delicious
@username = "YOU"
@password = "secr3t"
# smtp settings, asuming gmail
@smtp_server = 'smtp.gmail.com'
@smtp_port = 587
@smtp_user = "YOU@gmail.com"
@smtp_passwd = "secr3t"
# outgoing mail
@mail_from = "YOU@gmail.com"
@mail_from_alias = "YOU"
@mail_subject = "Värt att uppmärksamma, vecka #{(Date.today.cweek)} ((tags: läsvärt))"
# posterous
@posterous_email = "YOU@posterous.com"
#######
def get_description
description = gets.chomp
return description
end
# found at: http://blog.jerodsanto.net/2009/02/a-simple-ruby-method-to-send-emai/
def send_email(to, opts={})
opts[:server] ||= 'localhost'
opts[:from] ||= @mail_from
opts[:from_alias] ||= @mail_from_alias
opts[:subject] ||= @mail_subject
opts[:body] ||= "test"
msg = <<END_OF_MESSAGE
From: #{opts[:from_alias]} <#{opts[:from]}>
To: <#{to}>
Subject: #{opts[:subject]}
#{opts[:body]}
END_OF_MESSAGE
# found at: http://stackoverflow.com/questions/1183743/ruby-getting-netsmtp-working-with-gmail
smtp = Net::SMTP.new @smtp_server, @smtp_port
smtp.enable_starttls
smtp.start(@smtp_server, @smtp_user, @smtp_passwd, :login)
smtp.send_message(msg, to, to)
smtp.finish
end
#######
begin
resp = href = "";
puts "From date, YYYY-MM-DD"
from_date = gets.chomp
puts "To date, YYYY-MM-DD"
to_date = gets.chomp
puts " "
url = "/v1/posts/all?fromdt=#{from_date}T00:00:00Z&todt=#{to_date}T23:59:59Z"
descriptions = []
http = Net::HTTP.new("api.del.icio.us", 443)
http.use_ssl = true
http.start do |http|
req = Net::HTTP::Get.new(url, {"User-Agent" =>
"juretta.com RubyLicious 0.2"} )
req.basic_auth(@username, @password)
response = http.request(req)
resp = response.body
end
# XML Document
doc = REXML::Document.new(resp)
#doc.root.elements.each do |elem|
# puts " \n"
# puts elem.attributes['description']
# puts "(" + elem.attributes['href'] + ")"
# puts " =>"
# descriptions.push(get_description)
#end
body_txt = "<markdown>\n"
i = 0
doc.root.elements.each do |elem|
if elem.attributes['extended'] != ''
body_txt += "* [" + elem.attributes['description'] + "]("+ elem.attributes['href'] + ") \n " +
elem.attributes['extended'] + "\n" #descriptions[i] + "\n"
#i = i + 1
end
end
body_txt += "</markdown>\n#end"
puts "\n\n"
puts body_txt
puts "\n\n"
#puts "Sending to posterous ... "
#send_email @posterous_email, :body => body_txt
#puts "Done."
#puts " "
rescue SocketError
raise "Host " + host + " nicht erreichbar"
rescue REXML::ParseException => e
print "error parsing XML " + e.to_s
end

View file

@ -0,0 +1,119 @@
#!/usr/bin/env ruby
require 'net/https'
require "rexml/document"
require "date"
require 'net/smtp'
# delicious
@username = "YOU"
@password = "secr3t"
# smtp settings, asuming gmail
@smtp_server = 'smtp.gmail.com'
@smtp_port = 587
@smtp_user = "YOU@gmail.com"
@smtp_passwd = "s3cr3t"
# outgoing mail
@mail_from = "YOU@gmail.com"
@mail_from_alias = "Name Surname"
@mail_subject = "Värt att uppmärksamma, vecka #{(Date.today.cweek)-1}"
# posterous
@posterous_email = "YOU@posterous.com"
#######
def get_description
description = gets.chomp
return description
end
# found at: http://blog.jerodsanto.net/2009/02/a-simple-ruby-method-to-send-emai/
def send_email(to, opts={})
opts[:server] ||= 'localhost'
opts[:from] ||= @mail_from
opts[:from_alias] ||= @mail_from_alias
opts[:subject] ||= @mail_subject
opts[:body] ||= "test"
msg = <<END_OF_MESSAGE
From: #{opts[:from_alias]} <#{opts[:from]}>
To: <#{to}>
Subject: #{opts[:subject]}
#{opts[:body]}
END_OF_MESSAGE
# found at: http://stackoverflow.com/questions/1183743/ruby-getting-netsmtp-working-with-gmail
smtp = Net::SMTP.new @smtp_server, @smtp_port
smtp.enable_starttls
smtp.start(@smtp_server, @smtp_user, @smtp_passwd, :login)
smtp.send_message(msg, to, to)
smtp.finish
end
#######
begin
resp = href = "";
puts "From date, YYYY-MM-DD"
from_date = gets.chomp
puts "To date, YYYY-MM-DD"
to_date = gets.chomp
puts " "
url = "/v1/posts/all?fromdt=#{from_date}T00:00:00Z&todt=#{to_date}T23:59:59Z"
descriptions = []
http = Net::HTTP.new("api.del.icio.us", 443)
http.use_ssl = true
http.start do |http|
req = Net::HTTP::Get.new(url, {"User-Agent" =>
"juretta.com RubyLicious 0.2"} )
req.basic_auth(@username, @password)
response = http.request(req)
resp = response.body
end
# XML Document
doc = REXML::Document.new(resp)
doc.root.elements.each do |elem|
puts " \n"
puts elem.attributes['description']
puts "(" + elem.attributes['href'] + ")"
puts " =>"
descriptions.push(get_description)
end
body_txt = "<markdown>\n"
i = 0
doc.root.elements.each do |elem|
if elem.attributes['extended'] != ''
body_txt += "* [" + elem.attributes['description'] + "]("+ elem.attributes['href'] + ") \n " +
descriptions[i] + "\n" #elem.attributes['extended'] + "\n"
i = i + 1
end
end
body_txt += "</markdown>\n#end"
puts "\n\n"
puts body_txt
puts "\n\n"
puts "Sending to posterous ... "
#send_email @posterous_email, :body => body_txt
puts "Done."
puts " "
rescue SocketError
raise "Host " + host + " nicht erreichbar"
rescue REXML::ParseException => e
print "error parsing XML " + e.to_s
end

291
2012.js.autocomplete.js Normal file
View file

@ -0,0 +1,291 @@
/*
By Anders Ytterström 2012.
Example use:
<script src="autocomplete.js"></script>
<script>
var values = ["Hansi", "Andre", "The Omen", "Marcus", "Prince Charles"],
callback = function (k) {
console.log(k);
};
autocomplete("bg", values, callback);
</script>
*/
/*jslint indent: 2, maxlen: 90, browser: true */
var autocomplete = function (id, values, callback) {
"use strict";
var autoCompleteTimer,
stopDefaultAction,
getPosition,
field,
initAutoComplete,
keydownAutoComplete,
generateDropdown,
autoComplete,
mouseoverDropdown,
mouseoutDropdown,
mousedownDropdown,
assignMouseListeners,
blurAutoComplete,
closeDropdown;
stopDefaultAction = function (event) {
event.returnValue = false;
if (typeof event.preventDefault !== "undefined") {
event.preventDefault();
}
return true;
};
getPosition = function (theElement) {
var positionX = 0,
positionY = 0;
while (theElement !== null) {
positionX += theElement.offsetLeft;
positionY += theElement.offsetTop;
theElement = theElement.offsetParent;
}
return [positionX, positionY];
};
initAutoComplete = function () {
field = document.getElementById(id);
field.setAttribute("autocomplete", "off");
if (window.attachEvent) {
field.attachEvent("onkeydown", keydownAutoComplete);
} else {
field.addEventListener("keydown", keydownAutoComplete);
}
field.onblur = function () {
blurAutoComplete();
};
};
keydownAutoComplete = function (event) {
var target = event.target || event.srcElement,
autoCompleteDropdown,
childLis,
selected,
i,
max,
inputRanges;
if (typeof event === "undefined") {
event = window.event;
}
switch (event.keyCode) {
case 9: // tab
case 13: // enter
case 16: // shift
case 17: // ctrl
case 18: // alt
case 20: // caps lock
case 27: // esc
case 33: // page up
case 34: // page down
case 35: // end
case 36: // home
case 37: // left arrow
case 39: // right arrow
break;
case 38: // up arrow
autoCompleteDropdown = document.getElementById("autoCompleteDropdown");
if (autoCompleteDropdown !== null) {
childLis = autoCompleteDropdown.childNodes;
selected = false;
for (i = 0, max = childLis.length; i < max; i += 1) {
if (childLis[i].className === "hover") {
selected = true;
if (i > 0) {
childLis[i].className = "";
childLis[i - 1].className = "hover";
target.value = childLis[i - 1].firstChild.nodeValue;
}
break;
}
}
if (!selected) {
childLis[0].className = "hover";
target.value = childLis[0].firstChild.nodeValue;
}
}
stopDefaultAction(event);
break;
case 40: // down arrow
autoCompleteDropdown = document.getElementById("autoCompleteDropdown");
if (autoCompleteDropdown !== null) {
childLis = autoCompleteDropdown.childNodes;
selected = false;
for (i = 0, max = childLis.length; i < max; i += 1) {
if (childLis[i].className === "hover") {
selected = true;
if (i < childLis.length - 1) {
childLis[i].className = "";
childLis[i + 1].className = "hover";
target.value = childLis[i + 1].firstChild.nodeValue;
}
break;
}
}
if (!selected) {
childLis[0].className = "hover";
target.value = childLis[0].firstChild.nodeValue;
}
}
stopDefaultAction(event);
break;
case 8: // backspace
case 46: // delete
if (typeof autoCompleteTimer !== "undefined") {
clearTimeout(autoCompleteTimer);
}
autoCompleteTimer = setTimeout(function () {
generateDropdown(false);
}, 500);
break;
default:
if (typeof autoCompleteTimer !== "undefined") {
clearTimeout(autoCompleteTimer);
}
target = event.target || event.srcElement;
inputRanges = "false";
if (typeof target.createTextRange !== "undefined"
|| typeof target.setSelectionRange !== "undefined") {
inputRanges = "true";
}
autoCompleteTimer = setTimeout(function () {
generateDropdown(inputRanges);
}, 500);
}
return true;
};
assignMouseListeners = function (e) {
e.onmouseover = function () {
mouseoverDropdown(this);
};
e.mouseout = function () {
mouseoutDropdown(this);
};
e.mousedown = function () {
mousedownDropdown(this);
};
};
generateDropdown = function (doAutoComplete) {
closeDropdown();
var input = document.getElementById(id),
newUl = document.createElement("div"),
newLi,
i,
max = values.length;
newUl.setAttribute("id", "autoCompleteDropdown");
newUl.autoCompleteInput = input;
newUl.style.position = "absolute";
newUl.style.left = getPosition(input)[0] + "px";
newUl.style.top = getPosition(input)[1] + input.offsetHeight - 2 + "px";
newUl.style.width = input.offsetWidth - 3 + "px";
for (i = 0; i < max; i += 1) {
if (values[i].indexOf(input.value) === 0) {
newLi = document.createElement("button");
newLi.innerHTML = values[i];
assignMouseListeners(newLi);
newUl.appendChild(newLi);
}
}
if (newUl.firstChild !== null) {
document.getElementsByTagName("body")[0].appendChild(newUl);
}
if (typeof doAutoComplete !== "undefined" && doAutoComplete) {
autoComplete();
}
return true;
};
autoComplete = function () {
var input = document.getElementById(id),
cursorMidway = false,
range,
originalValue,
autoCompleteDropdown;
if (typeof document.selection !== "undefined") {
range = document.selection.createRange();
if (range.move("character", 1) !== 0) {
cursorMidway = true;
}
} else if (typeof input.selectionStart !== "undefined"
&& input.selectionStart < input.value.length) {
cursorMidway = true;
}
originalValue = input.value;
autoCompleteDropdown = document.getElementById("autoCompleteDropdown");
if (autoCompleteDropdown !== null && !cursorMidway) {
autoCompleteDropdown.firstChild.className = "hover";
input.value = autoCompleteDropdown.firstChild.firstChild.nodeValue;
if (typeof input.createTextRange !== "undefined") {
range = input.createTextRange();
range.moveStart("character", originalValue.length);
range.select();
} else if (typeof input.setSelectionRange !== "undefined") {
input.setSelectionRange(originalValue.length, input.value.length);
}
if (autoCompleteDropdown.childNodes.length === 1) {
setTimeout(function () {
closeDropdown();
}, 10);
}
}
return true;
};
mouseoverDropdown = function (target) {
var childLis, i, max;
while (target.nodeName.toLowerCase() !== "button") {
target = target.parentNode;
}
childLis = target.parentNode.childNodes;
max = childLis.length;
for (i = 0; i < max; i += 1) {
childLis[i].className = "";
}
target.className = "hover";
return true;
};
mouseoutDropdown = function (target) {
while (target.nodeName.toLowerCase() !== "button") {
target = target.parentNode;
}
target.className = "";
return true;
};
mousedownDropdown = function (target) {
while (target.nodeName.toLowerCase() !== "button") {
target = target.parentNode;
}
target.parentNode.autoCompleteInput.value = target.firstChild.nodeValue;
closeDropdown();
return true;
};
blurAutoComplete = function () {
if (typeof autoCompleteTimer !== "undefined") {
clearTimeout(autoCompleteTimer);
}
closeDropdown();
callback(field.value);
return true;
};
closeDropdown = function () {
var autoCompleteDropdown = document.getElementById("autoCompleteDropdown");
if (autoCompleteDropdown !== null) {
autoCompleteDropdown.parentNode.removeChild(autoCompleteDropdown);
}
return true;
};
initAutoComplete();
};

8
2012.js.get-week.js Normal file
View file

@ -0,0 +1,8 @@
/**
* getWeek function, return current week number from a `Date` object.
*/
getWeek = function (date) {
var onejan = new Date(date.getFullYear(), 0, 1);
return Math.ceil((((date - onejan) / 86400000)
+ onejan.getDay()) / 7);
};

View file

@ -0,0 +1,97 @@
/*jslint devel:true, browser:true, indent:2, maxlen: 70 */
(function (window) {
"use strict";
var Condition, Listener, watcher;
// Requires window.matchMedia:
// https://developer.mozilla.org/en/DOM/window.matchMedia
if (typeof window.matchMedia === "undefined") { return; }
Condition = function (mq, callback) {
this.mq = window.matchMedia(mq);
this.callback = function () {
callback.call();
};
};
Condition.prototype.matches = function () {
return this.mq.matches;
};
Listener = function () {
this.callbacks = [];
this.cbLen = 0;
this.runned = 0;
};
Listener.prototype.waitFor = function (condition) {
this.callbacks.push(condition);
this.cbLen += 1;
};
Listener.prototype.walk = function () {
var toRun = [],
i = this.cbLen,
cb = this.callbacks;
while (i) {
i -= 1;
if (cb[i]) {
if (cb[i].matches()) {
toRun.push(i);
}
}
}
return toRun;
};
Listener.prototype.execute = function (toRun) {
var i = toRun.length;
while (i) {
i -= 1;
this.callbacks[toRun[i]].callback.call();
this.callbacks[toRun[i]] = '';
this.runned += 1;
}
};
Listener.prototype.investigate = function () {
var toRun;
toRun = this.walk();
if (toRun.length) { this.execute(toRun); }
if (this.runned === this.cbLen) {
window.onresize = "";
}
};
Listener.prototype.install = function () {
var callback, wait, that = this;
callback = function () {
that.investigate();
};
window.onresize = function () {
clearTimeout(wait);
wait = setTimeout(callback, 333);
};
this.investigate();
};
watcher = new Listener();
watcher.waitFor(new Condition(
"all and (min-width: 801px)",
function () {
console.log("load delicicous bookmarks (we have room!)");
}
));
watcher.waitFor(new Condition(
"all and (min-width: 1281px)",
function () {
console.log("load heavy pictures (we are on desktop!)");
}
));
watcher.install();
}(window));

10
2012.js.sprintf.js Normal file
View file

@ -0,0 +1,10 @@
/*
Thank you, almighty!
http://www.nczonline.net/blog/2011/10/11/simple-maintainable-templating-with-javascript/
*/
function sprintf(text){
var i=1, args=arguments;
return text.replace(/%s/g, function(pattern){
return (i < args.length) ? args[i++] : "";
});
}

View file

@ -0,0 +1,50 @@
'''
Example htmldump_config.py:
url = "http://localhost:5000"
login = "admin@adeprimo.se"
password = "app161770"
def pages_to_validate():
pages = [
# event registration
('event-start', '/events/start/'),
('event-form', '/events/create'),
('events', '/events'),
('event-edit', '/events/view/'),
return pages
'''
import mechanize
import re
from htmldump_config import pages_to_validate, url, login, password
url = url + "%s"
filepattern = "../static/htmldumps/%s.html"
print "creating fake browser env"
br = mechanize.Browser()
print "--- done"
print "logging in as admin"
br.open(url % "/login")
br.select_form(nr=0)
br["email"] = login
br["password"] = password
br.submit()
print "--- now logged in as %s" % login
def htmldump(name, doc):
with open(filepattern % name, "w") as f:
f.write(doc)
f.close()
def begin_download(pages):
for filename, url_path in pages:
print "downloading: %s" % url_path
print " to: %s.html" % filename
response = br.open(url % url_path)
htmldump(filename, response.read())
pages = pages_to_validate()
begin_download(pages)

View file

@ -0,0 +1,14 @@
/* vertical ruler using pseudo-elements */
@mixin columnseparator {
@extend .relative;
&:before {
content: '';
position: absolute;
top: 0;
width: 3px;
background: #eee;
left: 681px;
bottom: 0;
}
}

View file

@ -0,0 +1,18 @@
// folded box
@mixin folded ($size: 10px, $y: 30px, $background: $grey4) {
line-height: $y;
height: $y;
margin-left: ($size * -1);
text-indent: $size;
position: relative;
&:before {
border-left: $size solid $pagebg;
border-top: $size solid darken($background, 80%);
float: left;
content: '';
position: absolute;
bottom: ($size * -1);
left: 0;
}
}

View file

@ -0,0 +1,24 @@
#!/bin/bash
#
# usage: ./adp-new-vhost <name>
#
mampdir=/Applications/MAMP
confdir=$mampdir/conf/apache/extra/vhosts
codedir=~/Code
mampport=80
cat <<end > $confdir/$1.conf
<VirtualHost *:$mampport>
ServerName $1
DocumentRoot $codedir/$1
<Directory "$codedir/$1">
AllowOverride all
Options -Indexes
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
end
echo <passwd> | sudo -- sh -c "echo '127.0.0.1 $1' >> /etc/hosts"

View file

@ -0,0 +1,26 @@
#!/usr/bin/env python
import base64, re, argparse
parser = argparse.ArgumentParser(description='CSS-Embed PNG images as data-URIs')
parser.add_argument('files', metavar='file', nargs="+", type=str,
help='path to a css file')
img = re.compile("url\('?\"?(.*\.png)'?\"?\)")
repl = "url(data:image/png;base64,%s)"
cssfiles = parser.parse_args().files
if "swapcase" in dir(["a"]):
cssfiles = [cssfiles]
for cssfile in cssfiles:
css = open(cssfile, "r").read()
for image_path in img.findall(css):
data = base64.b64encode(open(image_path, "r").read())
pattern = "url\('?\"?%s'?\"?\)" % image_path
css = re.sub(re.compile(pattern), repl % data, css)
f = open(cssfile, "w")
f.write(css)
f.close()

100
2013.ruby.ftp-upload.rb Normal file
View file

@ -0,0 +1,100 @@
require "rubygems"
require 'net/ftp'
require 'stringio'
ftp = ""
username = ""
passwd = ""
root_dir = "../../../../"
current_rev_file = root_dir + "__CURRENT_VERSION__"
root_dir = ""
# new rev is either HEAD or a commit, set by ARGV
new_rev = ""
new_rev = ARGV.first unless ARGV.first != nil
cmd_newrev = "git show -s --format=\"%%h %%s (%%ar)\" %s" % new_rev
new_rev = `#{cmd_newrev}`
# old rev (current in production) are stored in a file.
old_rev = File.open(current_rev_file, "r").read
cmd = "git diff --name-status %s %s" % [old_rev.split(" ").first, new_rev.split(" ").first]
files = `#{cmd}`
# change to root
Dir.chdir root_dir
class Net::FTP
def puttextcontent(content, remotefile, &block)
f = StringIO.new(content)
begin
storlines("STOR " + remotefile, f, &block)
ensure
f.close
end
end
end
def chkdir(ftp, parents)
path = []
parents.each do |d|
parent_path = path.join("/")
path << d
unless ftp.list(parent_path).any? { |dir| dir.match(d) }
ftp.mkdir(path.join("/"))
puts "[chkdir] created dir: %s" % path.join("/")
end
end
end
def put_file(ftp, path)
parents = path.split("/")
parents.pop
chkdir ftp, parents
if path.match(".png")
ftp.putbinaryfile(path, path)
else
ftp.puttextfile(path, path)
end
puts "[put_file] %s" % path
end
puts "\nCurrent rev in Production: %s" % old_rev
puts " The new rev: %s\n" % new_rev
if old_rev == new_rev
puts "Everything is up to date, exiting"
exit
end
# list files to be changed in ftp prod
puts "files changed:", files, ""
# connect to ftp server
ftp = Net::FTP.new(ftp)
ftp.login username, passwd
remote = ftp.chdir root_dir
# make changes
files.each_line do |file|
flag, file = file.split("\t")
file.strip!
if flag == "A" || flag == "M"
put_file ftp, file
end
if flag == "D"
ftp.delete file
end
end
File.open(current_rev_file, "w").write(new_rev)
ftp.close

View file

@ -0,0 +1,40 @@
require "rubygems"
require 'living-validator'
require 'uri'
url = ARGV.first
files = ARGV.slice(1, 9999)
stop_at = files.length
i = 1
def colorize(text, color_code)
"\e[#{color_code}m#{text}\e[0m"
end
def red(text); colorize(text, 31); end
def green(text); colorize(text, 32); end
valid = true
files.each do |file|
puts '[%d/%d] %s%s:' % [i, stop_at, url, file]
i += 1
result = LivingValidator::Validator.check '%s%s' % [url, file]
unless result == false
if result.errorCount > 0
result.errors.each do |error|
puts red("%d:%d %s" % [error["lastLine"], error["lastColumn"], error["message"]])
end
valid = false
else
puts green "valid"
end
else
puts red("FAILED")
end
end
exit 1 unless valid == true
exit 0

View file

@ -0,0 +1,94 @@
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body { margin: 0; }
div { position: absolute; width: 20px; height: 20px; border-radius: 50%; background: red; }
</style>
<img src="mupp2.png" alt="" width="2500" height="2500">
<div hidden></div>
<script>
/*jslint browser: true */
(function () {
"use strict";
if (navigator.geolocation !== undefined) {
var Map,
map,
mapImg,
upperLeftBound = { lat: 63.184472, lng: 14.616544 },
lowerRightBound = { lat: 63.171043, lng: 14.646316 };
window.scrollTo(0, 0);
Map = function (x, y, upperLeftBounds, lowerRightBounds) {
this.dims = {x: x, y: y};
this.bounds = [upperLeftBounds, lowerRightBounds];
this.spot = document.getElementsByTagName("div")[0];
};
Map.prototype.convert = function (lat, lng) {
var MAP_WIDTH, MAP_HEIGHT, e, w, n, s, nsspan, ewspan, nspix, ewpix, x, y;
MAP_WIDTH = this.dims.x;
MAP_HEIGHT = this.dims.y;
e = this.bounds[1].lat;
w = this.bounds[0].lat;
n = this.bounds[0].lng;
s = this.bounds[1].lng;
nsspan = Math.abs(n - s);
ewspan = Math.abs(w - e);
nspix = MAP_HEIGHT / nsspan;
ewpix = MAP_WIDTH / ewspan;
x = (Math.abs(w - lat)) * ewpix;
y = (Math.abs(n - lng)) * nspix;
return {
top: parseInt(x, 10),
left: parseInt(y, 10)
};
};
Map.prototype.center = function (lat, lng) {
var lt,
tl = this.convert(lat, lng),
w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
lt = {
left: tl.left - (w / 2),
top: tl.top - (h / 2)
};
if (lt.left < 0) { lt.left = 0; }
if (lt.top < 0) { lt.top = 0; }
window.scrollTo(lt.left, lt.top);
};
Map.prototype.showPos = function (lat, lng) {
var pos = this.convert(lat, lng);
this.spot.hidden = false;
this.spot.style.top = pos.top - 10 + "px";
this.spot.style.left = pos.left - 10 + "px";
};
mapImg = document.getElementsByTagName("img")[0];
map = new Map(mapImg.width, mapImg.height, upperLeftBound, lowerRightBound);
// initial scroll for the map
navigator.geolocation.getCurrentPosition(function (position) {
map.center(position.coords.latitude, position.coords.longitude);
});
// update position on map
var watchID = navigator.geolocation.watchPosition(function (position) {
map.showPos(position.coords.latitude, position.coords.longitude);
});
}
}());
</script>

View file

@ -0,0 +1,143 @@
/*
The Following folder structure is required:
./
./dist
app.js
app.min.js
app.min.zipped.js
design.css
design.min.css
design.min.zipped.css
./src
./src/js
.src/js/core
.src/js/modules
init.js
design.less
./styleguide
./styleguide/template
index.html
section-1.html
section-2.html
section-3.html
section-5.html
*/
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
csslint: {
strict: {
src: ['dist/design.css']
}
},
compress: {
main: {
options: {
mode: 'gzip'
},
files: [
{
expand: true,
src: ['dist/app.min.js'],
dest: '',
ext: '.min.zipped.js'
},
{
expand: true,
src: ['dist/design.min.css'],
dest: '',
ext: '.min.zipped.css'
}
]
}
},
concat: {
dist: {
src: ['src/js/core/*.js', 'src/js/modules/*.js', 'src/js/init.js'],
dest: 'dist/app.js',
},
},
devserver: {
"options": {
"port": 8888
},
server: {}
},
htmllint: {
all: ["styleguide/*.html"]
},
jasmine: {
pivotal: {
src: ['src/js/*/*.js'],
options: {
specs: 'spec/*Spec.js',
helpers: 'spec/*Helper.js'
}
}
},
jslint: {
client: {
src: [
'src/js/*/*.js',
'src/js/*.js'
],
exclude: [],
}
},
kss: {
options: {
template: 'styleguide/template', // create this manually: `kss-node -i styleguide/template`
includeType: 'less'
},
files: {
src: ['src/less'],
dest: 'styleguide'
}
},
less: {
development: {
files: {
"dist": "src/less"
},
files: {
"dist/design.css": "src/less/design.less"
}
},
production: {
options: {
cleancss: true
},
files: {
"dist/design.min.css": "src/less/design.less"
}
}
},
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: {
src: 'dist/app.js',
dest: 'dist/app.min.js'
}
}
});
grunt.loadNpmTasks('grunt-contrib-compress');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-csslint');
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-devserver');
grunt.loadNpmTasks('grunt-html');
grunt.loadNpmTasks('grunt-jslint');
grunt.loadNpmTasks('grunt-kss');
grunt.registerTask('deploy', ['less:production', 'less:development', 'concat', 'uglify', 'compress', 'kss']);
grunt.registerTask('test', ['htmllint', 'csslint', 'jslint', 'jasmine']);
grunt.registerTask('default', ['test']);
};

View file

@ -0,0 +1,66 @@
/*jslint browser: true, indent: 4 */
/*
Example use of ScrollGuard: a simple, unobtrusive lazy loader.
Each time the user scrolled to the bottom of the page:
1. Look if there is content to load (lookForNextPage)
2. If new content, get content using Ajax (getNextPage)
3. Append the new content and do some polish (appencContent)
*/
(function (g) {
"use strict";
var lookForNextPage,
getNextPage,
appendContent;
if (g.ScrollGuard === undefined) {
throw new Error("scrollguard.js is required!");
}
appendContent = function (content) {
var body, rows, i, max, newContent, table;
body = document.createElement("div");
body.innerHTML = content;
newContent = document.createDocumentFragment();
rows = body.querySelectorAll(".main-c table tr");
for (i = 1, max = rows.length; i < max; i += 1) {
newContent.appendChild(rows[i]);
}
table = document.querySelector(".main-c table").tBodies[0];
table.replaceChild(newContent, table.querySelector("tr.pagination"));
};
lookForNextPage = function () {
var nextPage = document.getElementById("pager-next");
if (nextPage) {
getNextPage(nextPage.href);
}
};
getNextPage = function (href) {
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
if (request.readyState === 4) {
if (request.status === 200 || request.status === 304) {
appendContent(request.responseText);
}
}
};
request.open("GET", href, true);
request.send(null);
};
if (document.getElementById("pager-next")) {
g.ScrollGuard.add(lookForNextPage, -1);
g.ScrollGuard.start();
}
}(this));

25
2015.js.pirate-speech.js Normal file
View file

@ -0,0 +1,25 @@
/* Kopiera och klistra in i Firebug eller Dev Tools, ändra sista raden. */
(function (str) {
"use strict";
var blacklist = ' aeiouyöäåAEIOUYÖÄÅ';
function ify(c) {
return c + "o" + c.toLowerCase();
}
function pirate(str) {
var chars = str.split(""),
i = chars.length;
while (i) {
i -= 1;
if (!blacklist.match(chars[i])) {
chars[i] = ify(chars[i]);
}
}
return chars.join("");
}
return pirate(str);
}("Det här ska jag säga"));

View file

@ -0,0 +1,113 @@
/*jslint browser: true, indent: 4 */
/*global updateCanvas: true */
(function (g) {
"use strict";
var lookForNextPage,
getNextPage,
appendContent,
loadManually,
manual,
loader,
working;
if (g.ScrollGuard === undefined) {
throw new Error("scrollguard.js is required!");
}
appendContent = function (content) {
var body, rows, i, max, newContent, table;
body = document.createElement("div");
body.innerHTML = content;
newContent = document.createDocumentFragment();
rows = body.querySelectorAll(".main-c table tr");
for (i = 1, max = rows.length; i < max; i += 1) {
newContent.appendChild(rows[i]);
}
table = document.querySelector(".main-c table").tBodies[0];
table.replaceChild(newContent, table.querySelector("tr.pagination"));
if (typeof(updateCanvas) === "function") {
updateCanvas();
}
loadManually();
};
loadManually = function () {
var button;
button = document.getElementById("load-manually");
if (button) {
if (!document.getElementById("pager-next")) {
button.parentNode.removeChild(button);
}
button.onclick = function () {
var nextPage = document.getElementById("pager-next");
if (nextPage) {
getNextPage(nextPage.href);
button.parentNode.replaceChild(loader.cloneNode(), button);
}
};
}
};
manual = function () {
var style, elm;
elm = document.getElementById("load-manually");
if (!elm) { return false; }
style = window.getComputedStyle(elm, null);
return style.getPropertyValue("display") !== "none";
};
lookForNextPage = function () {
if (!manual()) {
var nextPage = document.getElementById("pager-next");
if (nextPage) {
getNextPage(nextPage.href);
}
}
};
getNextPage = function (href) {
var request = new XMLHttpRequest();
if (working === true) {
return;
}
working = true;
request.onreadystatechange = function () {
if (request.readyState === 4) {
working = false;
if (request.status === 200 || request.status === 304) {
appendContent(request.responseText);
}
}
};
request.open("GET", href, true);
request.send(null);
};
loadManually();
loader = document.createElement("img");
loader.style.paddingTop = "14px";
loader.src = "/templates/wide/css/images/loader.gif";
if (document.getElementById("pager-next")) {
g.ScrollGuard.add(lookForNextPage, -1);
g.ScrollGuard.start();
}
}(this));

116
2015.js.scrollguard.js Normal file
View file

@ -0,0 +1,116 @@
/*jslint browser: true, indent: 4 */
(function (g) {
"use strict";
var ScrollGuard,
started = false,
lock = false,
timer,
breakpoints = [],
getDocHeight,
getScrollTop;
// found at http://james.padolsey.com/javascript/
// get-document-height-cross-browser/
getDocHeight = function () {
return Math.max(
Math.max(document.body.scrollHeight,
document.documentElement.scrollHeight),
Math.max(document.body.offsetHeight,
document.documentElement.offsetHeight),
Math.max(document.body.clientHeight,
document.documentElement.clientHeight)
);
};
// found at http://stackoverflow.com/questions/871399/
// cross-browser-method-for-detecting-the-scrolltop-of-the-browser-g
getScrollTop = function () {
var b, d;
if (g.pageYOffset !== undefined) {
return g.pageYOffset;
}
b = document.body;
d = document.documentElement;
d = (d.clientHeight) ? d : b;
return d.scrollTop;
};
ScrollGuard = {
// from: a distance from top, given in pixels (required)
// to: a distance from top, given in pixels (optional)
//
// special cases:
// from = -1 will instead look if bottom of page
// is visible.
add: function (callback, from, to) {
var range;
if (from === -1) {
range = function (topPos) {
return getDocHeight() - topPos <= g.innerHeight;
};
} else {
if (to === undefined) {
range = function (topPos) {
return topPos >= from;
};
} else {
range = function (topPos) {
return topPos >= from && topPos <= to;
};
}
}
breakpoints.push({
within: range,
callback: callback
});
},
fire: function (pos) {
var max = breakpoints.length,
i,
bp;
lock = true;
for (i = 0; i < max; i += 1) {
bp = breakpoints[i];
if (bp.within(pos)) {
bp.callback();
}
}
lock = false;
},
start: function () {
if (started) { return; }
var callback = function () {
if (lock === false) {
clearTimeout(timer);
timer = setTimeout(function () {
ScrollGuard.fire(getScrollTop());
}, 100);
}
};
if (g.attachEvent) {
g.attachEvent('onscroll', callback);
} else {
g.addEventListener('scroll', callback, false);
}
started = true;
// initial call to catch initial scroll positions
callback();
}
};
g.ScrollGuard = ScrollGuard;
}(this));

61
2015.php.view-engine.php Normal file
View file

@ -0,0 +1,61 @@
<?php
/**
* view.php
*
* simple view class, template-based.
* @todo indent markup using tidy?
*
* $Rev$
* $Author$
* $Date$
*/
class view
{
protected $hasLayout;
private $file;
public function __construct( $file_path ) {
if(!file_exists($file_path)) {
throw new Exception('file ' . $file_path . ' does not exist!', 666);
} else {
$this->file = $file_path;
}
}
/**
* Compile the view
*
* @return $HTMLSource the compiled view
*/
public function compile($registry = false) {
if($registry === false){
$registry =& registry::getInstance();
}
$user =& user::getInstance();
foreach($registry as $k=>$v){
$$k = $v;
}
ob_start();
require $this->file;
$body = ob_get_clean();
(isset($contentType)) ? http_response::content($contentType) : http_response::content(CONTENT_TYPE);
$isFragment = isset($this->isFragment);
if(defined('LAYOUT') && !$isFragment){
ob_start();
require LAYOUT;
$body = ob_get_clean();
}
return $body;
}
public function isFragment() {
$this->isFragment = true;
}
function __toString() {
return __CLASS__;
}
}

View file

@ -0,0 +1,19 @@
'''
based on: http://24ways.org/2010/calculating-color-contrast/
accepts hex colors with 3 or 6 chars. hash-char is optional.
'''
def get_contrast_yiq(hex_color):
hex_color = hex_color.replace("#", "")
if len(hex_color) == 3:
hex_color = "".join([c + c for c in hex_color])
r = int(hex_color[0:2], 16)
g = int(hex_color[2:4], 16)
b = int(hex_color[4:6], 16)
yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000
if yiq >= 128:
return 'black'
return 'white'

293
2016.less.boilerplate.less Normal file
View file

@ -0,0 +1,293 @@
/*csslint box-model: false, box-sizing: false, universal-selector: false */
/*
All projects
should have nice
ASCII ART!
http://patorjk.com/software/taag/
*/
@bg: #fff;
@fg: #000;
.transform(@value) {
-webkit-transform: @value;
-moz-transform: @value;
-o-transform: @value;
-ms-transform: @value;
transform: @value;
}
/* ==========================================================================
Base
========================================================================== */
/*
Base
Normalisering av HTML-element, t ex inmatningsfält, knappar och länkar. Detta
avsnitt bör innehålla element- och attributselektorer som är enkla att stila
med hjälp av klasser. Klasser ska undvikas.
Låna så mycket som möjligt från
[normalise.css](https://github.com/necolas/normalize.css/blob/master/normalize.css).
Bastypografin sätts till *large* (ca 24px) med 1.25 radhöjd. Fonten **Open Sans** bäddas in från Google Web Fonts.
Fonten ändras med hjälp av media queries (blir mindre på små viewports).
Markup:
Normaliserad text som fyller ut en hel rad genom att
fler ord fylls på i det här stycket, även <a href="http://madr.se">länk läggs in</a> för att visa hur den ser ut.
<br>Detta är ett hårt radbryt.
Styleguide 1
*/
*, :before, :after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html {
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
background: @bg;
color: @fg;
font: normal large/1.25 sans-serif;
}
body, ul, p {
margin: 0;
}
fieldset {
margin: 0;
padding: 0;
border: 0;
}
legend {
display: none;
}
a {
text-decoration: none;
color: inherit;
}
a[href]:not([class]) {
color: blue;
text-decoration: underline;
}
em {
font-style: normal;
}
button,
input[type=submit] {
.user-select(text);
border: 0;
font: inherit;
line-height: 1;
cursor: pointer;
}
button::-moz-focus-inner,
input[type=submit]::-moz-focus-inner {
padding: 0;
border: 0;
}
input {
border: 0;
background: #fff;
padding: 0;
margin: 0;
line-height: 1;
font-size: inherit;
}
/* ==========================================================================
Template
========================================================================== */
/*
Mall
Innehåller kolumner, ett system för grids och containers fö övriga
designkomponenter. Detta avsnitt ska i strikt mening innehålla endast klasser.
Styleguide 2
*/
/* Float Helpers
========================================================================== */
/*
Layouthjälpare (floats)
Klasser som främst hanterar floats. Är i dagsläget ej anpassade till
följsam layout.
.pull-left - gör ett objekt float: left;
.pull-right - gör ett objekt float: right;
.line - får en behållare att rymma objekt med floats
.clear - får en behållare eller objekt att rensa floats
Markup:
<div class="line">
<div class="{$modifiers}">Text</div>
</div>
Styleguide 2.1
*/
.pull-left, .unit {
float: left;
}
.pull-right {
float: right;
}
.line:after {
content: "";
display: block;
clear: both;
}
.clear {
clear: both;
}
/* Columns
========================================================================== */
.page {
}
/* Grid
========================================================================== */
/*
Grid
Griden är baserad på YUI grids och är i skrivandets stund ej anpassad för
följsam layout.
Markup:
<div class="line">
<div class="unit size1of2">1/2</div>
<div class="unit size1of2">1/2</div>
</div>
<div class="line">
<div class="unit size1of3">1/3</div>
<div class="unit size2of2">2/3</div>
</div>
<div class="line">
<div class="unit size1of4">1/4</div>
<div class="unit size3of4">3/4</div>
</div>
<div class="line">
<div class="unit size1of5">1/5</div>
<div class="unit size4of5">4/5</div>
<div class="unit size3of5">3/5</div>
<div class="unit size2of5">2/5</div>
</div>
Styleguide 2.2
*/
.unit {
list-style: none;
padding: 0;
margin: 0;
}
.size1of5 { width: 20% }
.size1of4 { width: 25% }
.size1of3 { width: 33.3333% }
.size2of5 { width: 40% }
.size1of2 { width: 50% }
.size3of5 { width: 60% }
.size2of3 { width: 66.6666% }
.size3of4 { width: 75% }
.size4of5 { width: 80% }
.size1of7 { width: 14.2857% }
/* ==========================================================================
Core modules
========================================================================== */
/*
Kärnmoduler
Moduler som andra moduler är beroende av för att fungera korrekt, vilket gör
att dessa behöver komma först i The Cascade.
Detta avsnitt ska endast innehålla klasser och media queries, med få undantag.
Styleguide 3
*/
/* nav pattern */
.nav { list-style: none; padding: 0;}
.nav a, .nav strong { display: block; }
/* Headings
========================================================================== */
/*
Rubriker
Rubriker används för att skapa sektioner och avdelningar i designen.
.big - Överdrivet stor rubrik
.h1 - Dominant one-of-a-kind rubrik
.h2 - typisk sektionsrubrik
Markup:
<div class="{$modifiers}">En rubrik<br>med ett radbryt</div>
Styleguide 3.2
*/
h1, .h1 {
font-weight: normal;
text-align: center;
font-size: 1.66em;
}
/* ==========================================================================
Modules
========================================================================== */
/*
Moduler
Modulerna i detta asvnitt är isolerade och beror ej på andra moduler som ej är
kärnmoduler, detta för att enkelt kunna slå av och på CSS. Normalt sett så
är modulerna utökningar av kärnmoduler och behållare.
Avsnittet ska enbart innehålla klasser och media queries, med få undantag.
Styleguide 4
*/

View file

@ -0,0 +1,92 @@
"""
Podcast backup script
Parses an RSS feed from SOURCE_FILE and download all items to
DESTINATION_PATH. Downloads are done in parallel, for
PARALLEL_COUNT downloads at the time.
How to use
----------
1. Set DESTINATION_PATH. Make sure the folder exists on your
file system.
2. Save the source file (RSS or Atom) on your computer and
update SOURCE_FILE if needed.
3. Alter PARALLEL_COUNT for your needs. Higher number will
decrease total time for this script to be done, but will
increase net traffic.
4. Run script in a python intepreter, 3.7 is recommended.
This script was written by Anders Ytterström in October 2019.
If you find it useful, buy him a 🍺.
"""
import queue
import threading
import xml.etree.ElementTree as ET
from urllib.request import urlretrieve
DESTINATION_PATH = "D:\Asmodean\podcasts\inbox"
SOURCE_FILE = "D:\Kod\gists\src.xml"
PARALLEL_COUNT = 3
def download_file(url, target):
print(f"Downloading {target} <- {url}")
urlretrieve(url, f"{DESTINATION_PATH}\{target}.mp3")
def get_urls():
tree = ET.parse(SOURCE_FILE)
root = tree.getroot()
def f(item):
url = item.find("enclosure").attrib["url"]
filename = slugify(item.find("title").text)
return (url, filename)
return map(f, root.findall("./channel/item"))
def slugify(text):
return (
text.lower()
.replace(" ", "-")
.replace(":", "")
.replace("/", "-av-")
.replace("?", "")
)
def do_work(item):
download_file(*item)
if __name__ == "__main__":
def worker():
while True:
item = q.get()
if item is None:
break
do_work(item)
q.task_done()
q = queue.Queue()
threads = []
for i in range(PARALLEL_COUNT):
t = threading.Thread(target=worker)
t.start()
threads.append(t)
source = get_urls()
for item in source:
q.put(item)
# block until all tasks are done
q.join()
# stop workers
for i in range(PARALLEL_COUNT):
q.put(None)
for t in threads:
t.join()

71
2020.css.shame.css Normal file
View file

@ -0,0 +1,71 @@
acronym,
applet,
basefont,
big,
center,
dir,
font,
isindex,
menu,
noframes,
s,
strike,
tt,
u {
color: red !important;
font-weight: bold !important;
}
[rev],
[charset],
[shape],
[coords],
[longdesc],
link[target]
[nohref]
img[name]
archive object
classid object
codebase object
codetype object
declare object
standby object
valuetype param
type param
axis td and t
abbr td and t
scope td
align caption, iframe, img, input, object, legend, table, hr, div, h1, h2, h3, h4, h5, h6, p, col, colgroup, tbody, td, tfoot, th, thead and tr.
alink body
link body
vlink body
text body
background body
bgcolor table, tr, td, th and body.
border table and object.
cellpadding table
cellspacing table
char col, colgroup, tbody, td, tfoot, th, thead and tr.
charoff col, colgroup, tbody, td, tfoot, th, thead and tr.
clear br
compact dl, menu, ol and ul.
frame table
compact dl, menu, ol and ul.
frame table
frameborder iframe
hspace img and object.
vspace img and object.
marginheight iframe
marginwidth iframe
noshade hr
nowrap td and th
rules table
scrolling iframe
size hr
type li, ol and ul.
valign col, colgroup, tbody, td, tfoot, th, thead and tr
width hr, table, td, th, col, colgroup and pre.
br + br {
display: none;
}

View file

@ -0,0 +1,12 @@
# Males (B2: waist, C2: neck)
# Replace `height` with actual height
# for the imperial system, replace 30,3 with 36,76
=86,01 * Log10(B2 - C2) - 70,041 * log10(height) + 30,3
# Females (B2: waist, C2: neck, D2: hips)
# Replace `height` with actual height
# for the imperial system, replace 104,912 with 78,387
=163,205 * Log10(B2 + D2 - C2) - 97,684 * Log10(height) - 104,912
# ALL MEASUREMENTS SHOULD BE DONE IN METRIC, LIKE THE REST OF THE WORLD DOES IT.
# https://friendlybit.com/other/im-not-from-america/