Commit 78157af4 authored by addyosmani's avatar addyosmani

trying to re-add sammy todo app as git decided it should be a submodule last time

parent 4320f1ce
sammyjs @ 166eb403
Subproject commit 166eb4038d1b3c0842c824e5090fb282b03135c3
This version/changes copyright 2011, Addy Osmani
Original multi-list/multi-todo/non todo standard version copyright 2010, Brandon Aaron
\ No newline at end of file
body { margin: 0; padding: 0; font-family: Helvetica; color: #444; }
#surface { position: relative; margin: 0 auto; width: 600px; }
h1 { position: relative; top: 18px; z-index: 2; margin: 0; padding: 0; width: 100%; height: 1.2em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 25px; font-weight: normal; }
#lists { position: absolute; top: 50px; left: 400px; z-index: 2; }
dl { margin: 0; padding: 0; color: #555; }
dt { margin: 0 0 5px 0; padding: 0; font-size: 20px; font-weight: normal; }
dd { margin: 0 0 5px 15px; padding: 0; font-size: 17px; cursor: pointer; }
#page { float: left; position: relative; z-index: 1; width: 400px; height: 600px; }
#page { }
h2 { position: absolute; top: 56px; left: 77px; margin: 0; font-size: 30px; width: 275px; height: 1.2em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: normal; }
/*ul { position: absolute; top: 116px; left: 80px; margin: 0; padding: 0; width: 275px; list-style: none; }*/
li { position: relative; margin: 0 0 0 25px; padding: 0; font-size: 20px; line-height: 27px; }
p { position: absolute; top: 116px; left: 80px; margin: 0; padding: 0; width: 275px; font-size: 20px; line-height: 27px; }
[contenteditable]:hover { outline: 1px dotted #999; }
.new { opacity: .25; cursor: pointer; }
.new:hover { opacity: .75; }
.trashcan { position: absolute; top: 63px; left: 57px; width: 25px; height: 25px; cursor: pointer; background: url(assets/destroy.png) no-repeat; }
.trashcan:hover { opacity: .75; }
li .trashcan { float: right;
left: 95%;
top: 15px; }
#page:hover .trashcan { display: inline-block; }
/*todos*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-weight: inherit;
font-style: inherit;
font-size: 100%;
font-family: inherit;
vertical-align: baseline;
}
body {
line-height: 1;
color: black;
background: white;
}
ol, ul {
list-style: none;
}
a img {
border: none;
}
html {
background: #eeeeee;
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.4em;
background: #eeeeee;
color: #333333;
}
#todoapp {
width: 480px;
margin: 0 auto 40px;
background: white;
padding: 20px;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
}
#todoapp h1 {
font-size: 36px;
font-weight: bold;
text-align: center;
padding: 20px 0 30px 0;
line-height: 1;
}
#create-todo {
position: relative;
}
#create-todo input {
width: 466px;
font-size: 24px;
font-family: inherit;
line-height: 1.4em;
border: 0;
outline: none;
padding: 6px;
border: 1px solid #999999;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
}
#create-todo input::-webkit-input-placeholder {
font-style: italic;
}
#create-todo span {
position: absolute;
z-index: 999;
width: 170px;
left: 50%;
margin-left: -85px;
}
#todo-list {
margin-top: 10px;
}
#todo-list li {
padding: 12px 20px 11px 0;
position: relative;
font-size: 24px;
line-height: 1.1em;
border-bottom: 1px solid #cccccc;
}
#todo-list li:after {
content: "\0020";
display: block;
height: 0;
clear: both;
overflow: hidden;
visibility: hidden;
}
#todo-list li.editing {
padding: 0;
border-bottom: 0;
}
#todo-list .editing .display,
#todo-list .edit {
display: none;
}
#todo-list .editing .edit {
display: block;
}
#todo-list .editing input {
width: 444px;
font-size: 24px;
font-family: inherit;
margin: 0;
line-height: 1.6em;
border: 0;
outline: none;
padding: 10px 7px 0px 27px;
border: 1px solid #999999;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
}
#todo-list .check {
position: relative;
top: 9px;
margin: 0 10px 0 7px;
float: left;
}
#todo-list .done .todo-content {
text-decoration: line-through;
color: #777777;
}
#todo-list .todo-destroy {
position: absolute;
right: 5px;
top: 14px;
display: none;
cursor: pointer;
width: 20px;
height: 20px;
background: url(destroy.png) no-repeat 0 0;
}
#todo-list li:hover .todo-destroy {
display: block;
}
#todo-list .todo-destroy:hover {
background-position: 0 -20px;
}
#todo-stats {
*zoom: 1;
margin-top: 10px;
color: #777777;
}
#todo-stats:after {
content: "\0020";
display: block;
height: 0;
clear: both;
overflow: hidden;
visibility: hidden;
}
#todo-stats .todo-count {
float: left;
}
#todo-stats .todo-count .number {
font-weight: bold;
color: #333333;
}
#todo-stats .todo-clear {
float: right;
}
#todo-stats .todo-clear a {
color: #777777;
font-size: 12px;
}
#todo-stats .todo-clear a:visited {
color: #777777;
}
#todo-stats .todo-clear a:hover {
color: #336699;
}
#instructions {
width: 520px;
margin: 10px auto;
color: #777777;
text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
text-align: center;
}
#instructions a {
color: #336699;
}
#credits {
width: 520px;
margin: 30px auto;
color: #999;
text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
text-align: center;
}
#credits a {
color: #888;
}
/*
* François 'cahnory' Germain
*/
.ui-tooltip, .ui-tooltip-top, .ui-tooltip-right, .ui-tooltip-bottom, .ui-tooltip-left {
color:#ffffff;
cursor:normal;
display:-moz-inline-stack;
display:inline-block;
font-size:12px;
font-family:arial;
padding:.5em 1em;
position:relative;
text-align:center;
text-shadow:0 -1px 1px #111111;
-webkit-border-top-left-radius:4px ;
-webkit-border-top-right-radius:4px ;
-webkit-border-bottom-right-radius:4px ;
-webkit-border-bottom-left-radius:4px ;
-khtml-border-top-left-radius:4px ;
-khtml-border-top-right-radius:4px ;
-khtml-border-bottom-right-radius:4px ;
-khtml-border-bottom-left-radius:4px ;
-moz-border-radius-topleft:4px ;
-moz-border-radius-topright:4px ;
-moz-border-radius-bottomright:4px ;
-moz-border-radius-bottomleft:4px ;
border-top-left-radius:4px ;
border-top-right-radius:4px ;
border-bottom-right-radius:4px ;
border-bottom-left-radius:4px ;
-o-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
-moz-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
-khtml-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
-webkit-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
background-color:#3b3b3b;
background-image:-moz-linear-gradient(top,#555555,#222222);
background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#555555),color-stop(1,#222222));
filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#555555,EndColorStr=#222222);
-ms-filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#555555,EndColorStr=#222222);
}
.ui-tooltip:after, .ui-tooltip-top:after, .ui-tooltip-right:after, .ui-tooltip-bottom:after, .ui-tooltip-left:after {
content:"\25B8";
display:block;
font-size:2em;
height:0;
line-height:0;
position:absolute;
}
.ui-tooltip:after, .ui-tooltip-bottom:after {
color:#2a2a2a;
bottom:0;
left:1px;
text-align:center;
text-shadow:1px 0 2px #000000;
-o-transform:rotate(90deg);
-moz-transform:rotate(90deg);
-khtml-transform:rotate(90deg);
-webkit-transform:rotate(90deg);
width:100%;
}
.ui-tooltip-top:after {
bottom:auto;
color:#4f4f4f;
left:-2px;
top:0;
text-align:center;
text-shadow:none;
-o-transform:rotate(-90deg);
-moz-transform:rotate(-90deg);
-khtml-transform:rotate(-90deg);
-webkit-transform:rotate(-90deg);
width:100%;
}
.ui-tooltip-right:after {
color:#222222;
right:-0.375em;
top:50%;
margin-top:-.05em;
text-shadow:0 1px 2px #000000;
-o-transform:rotate(0);
-moz-transform:rotate(0);
-khtml-transform:rotate(0);
-webkit-transform:rotate(0);
}
.ui-tooltip-left:after {
color:#222222;
left:-0.375em;
top:50%;
margin-top:.1em;
text-shadow:0 -1px 2px #000000;
-o-transform:rotate(180deg);
-moz-transform:rotate(180deg);
-khtml-transform:rotate(180deg);
-webkit-transform:rotate(180deg);
}
/* new additions - cleanup required*/
/* line 109 */
#todoapp #todo-stats {
*zoom: 1;
margin-top: 10px;
color: #555555;
-moz-border-radius-bottomleft: 5px;
-webkit-border-bottom-left-radius: 5px;
-o-border-bottom-left-radius: 5px;
-ms-border-bottom-left-radius: 5px;
-khtml-border-bottom-left-radius: 5px;
border-bottom-left-radius: 5px;
-moz-border-radius-bottomright: 5px;
-webkit-border-bottom-right-radius: 5px;
-o-border-bottom-right-radius: 5px;
-ms-border-bottom-right-radius: 5px;
-khtml-border-bottom-right-radius: 5px;
border-bottom-right-radius: 5px;
background: #f4fce8;
border-top: 1px solid #ededed;
padding: 0 20px;
line-height: 36px;
}
/* line 22, /opt/ree/lib/ruby/gems/1.8/gems/compass-0.10.5/frameworks/compass/stylesheets/compass/utilities/general/_clearfix.scss */
#todoapp #todo-stats:after {
content: "\0020";
display: block;
height: 0;
clear: both;
overflow: hidden;
visibility: hidden;
}
/* line 118 */
#todoapp #todo-stats .todo-count {
float: left;
}
/* line 120 */
#todoapp #todo-stats .todo-count .number {
font-weight: bold;
color: #555555;
}
/* line 123 */
#todoapp #todo-stats .todo-clear {
float: right;
}
/* line 125 */
#todoapp #todo-stats .todo-clear a {
display: block;
line-height: 20px;
text-decoration: none;
-moz-border-radius: 12px;
-webkit-border-radius: 12px;
-o-border-radius: 12px;
-ms-border-radius: 12px;
-khtml-border-radius: 12px;
border-radius: 12px;
background: rgba(0, 0, 0, 0.1);
color: #555555;
font-size: 11px;
margin-top: 8px;
padding: 0 10px 1px;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
}
/* line 136 */
#todoapp #todo-stats .todo-clear a:hover {
background: rgba(0, 0, 0, 0.15);
-moz-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-o-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
}
/* line 139 */
#todoapp #todo-stats .todo-clear a:active {
position: relative;
top: 1px;
}
#todos { display:block}
(function($) {
var app = $.sammy(function() {
this.use(Sammy.Template);
this.notFound = function(verb, path) {
this.runRoute('get', '#/404');
};
this.get('#/404', function() {
this.partial('templates/404.template', {}, function(html) {
$('#todo-list').html(html);
});
});
this.get('#/list/:id', function() {
var list = Lists.get(this.params['id']);
if (list) {
this.partial('templates/todolist.template', {
list: list,
todos: Todos.filter('listId', list.id)
}, function(html) {
$('#todo-list').html(html);
});
} else {
this.notFound();
}
});
// events
this.bind('run', function(e, data) {
var context = this;
var title = localStorage.getItem('title') || "Todo";
$('h1').text(title);
if(Lists._data.length <=0){
var list = Lists.create({ name: 'My new list' });
//app.trigger('updateLists');
}
$('#new-todo').keydown(function(e) {
if (e.keyCode == 13){
var todoContent = $(this).val();
var todo = Todos.create({ name: todoContent, done: false, listId: parseInt($('h2').attr('data-id'), 10) });
context.partial('templates/_todo.template', todo, function(html) {
//$(html).insertAfter('#todo-list li:last');
var q = $(html);
console.log(q);
$('#todo-list').append(q);
});
$(this).val('');
}
});
/*
$('#lists')
.delegate('dd[data-id]', 'click', function() {
context.redirect('#/list/'+$(this).attr('data-id'));
app.trigger('updateList');
});*/
$('.trashcan')
.live('click', function() {
var $this = $(this);
app.trigger('delete', {
type: $this.attr('data-type'),
id: $this.attr('data-id')
});
});
//new
$('.check')
.live('click', function() {
var $this = $(this),
$li = $this.parents('li').toggleClass('done'),
isDone = $li.is('.done');
app.trigger('mark' + (isDone ? 'Done' : 'Undone'), { id: $li.attr('data-id') });
});
/*
$('.checkbox')
.live('click', function() {
var $this = $(this),
$li = $this.parents('li').toggleClass('done'),
isDone = $li.is('.done');
app.trigger('mark' + (isDone ? 'Done' : 'Undone'), { id: $li.attr('data-id') });
});*/
$('[contenteditable]')
.live('focus', function() {
// store the current value
$.data(this, 'prevValue', $(this).text());
})
.live('blur', function() {
var $this = $(this),
// grab the, likely, modified value
text = $.trim($this.text());
if (!text) {
// restore the previous value if text is empty
$this.text($.data(this, 'prevValue'));
} else {
if ($this.is('h1')) {
// it is the title
localStorage.setItem('title', text);
} else {
// save it
app.trigger('save', {
type: $this.attr('data-type'),
id: $this.attr('data-id'),
name: text
});
}
}
})
.live('keypress', function(event) {
// save on enter
if (event.which === 13) {
this.blur();
return false;
}
});
if (!localStorage.getItem('initialized')) {
// create first list and todo
var listId = Lists.create({
name: 'My first list'
}).id;
Todos.create({
name: 'My first todo',
done: false,
listId: listId
});
localStorage.setItem('initialized', 'yup');
this.redirect('#/list/'+listId);
} else {
var lastViewedOrFirstList = localStorage.getItem('lastviewed') || '#/list/' + Lists.first().id;
this.redirect(lastViewedOrFirstList);
}
//app.trigger('updateLists');
});
/*save the route as the lastviewed item*/
this.bind('route-found', function(e, data) {
localStorage.setItem('lastviewed', document.location.hash);
});
this.bind('save', function(e, data) {
var model = data.type == 'todo' ? Todos : Lists;
model.update(data.id, { name: data.name });
//if (data.type == 'list') {
//app.trigger('updateLists');
// }
});
/*marking the selected item as done*/
this.bind('markDone', function(e, data) {
Todos.update(data.id, { done: true });
});
/*mark the todo with the selected id as not done*/
this.bind('markUndone', function(e, data) {
Todos.update(data.id, { done: false });
});
this.bind('delete', function(e, data) {
//if (confirm('Are you sure you want to delete this ' + data.type + '?')) {
var model = data.type == 'list' ? Lists : Todos;
model.destroy(data.id);
if (data.type == 'list') {
var list = Lists.first();
if (list) {
this.redirect('#/list/'+list.id);
} else {
// create first list and todo
var listId = Lists.create({
name: 'Initial list'
}).id;
Todos.create({
name: 'A sample todo item',
done: false,
listId: listId
});
this.redirect('#/list/'+listId);
}
//app.trigger('updateLists');
} else {
// delete the todo from the view
$('li[data-id=' + data.id + ']').remove();
}
// }
});
/*
this.bind('updateLists', function(e, data) {
var selected = parseInt(location.hash.substr(location.hash.lastIndexOf('/')+1), 10);
this.partial('templates/_lists.template', {
lists: Lists.getAll(),
selected: selected
}, function(html) {
$('#lists').html(html);
});
});*/
});
// lists model
Lists = Object.create(Model);
Lists.name = 'lists';
Lists.init();
// todos model
Todos = Object.create(Model);
Todos.name = 'todos';
Todos.init();
$(function() { app.run(); });
})(jQuery);
\ No newline at end of file
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<font id="handfont" horiz-adv-x="1046" >
<font-face font-family="handfont" font-weight="500" font-stretch="normal" units-per-em="2048" panose-1="2 0 6 3 0 0 0 0 0 0" ascent="1638" descent="-410" x-height="686" cap-height="1477" bbox="-49.5 -397 1689.65 1644.25" underline-thickness="102" underline-position="-256" unicode-range="U+0020-U+2022"/>
<missing-glyph horiz-adv-x="770" />
<glyph glyph-name=".notdef" horiz-adv-x="770" />
<glyph glyph-name=".null" horiz-adv-x="0" />
<glyph glyph-name="nonmarkingreturn" horiz-adv-x="682" />
<glyph glyph-name="space" unicode=" " horiz-adv-x="770" />
<glyph glyph-bame="tab" unicode="&#x09;" horiz-adv-x="770" />
<glyph glyph-bame="uni00A0" unicode="&#xa0;" horiz-adv-x="770" />
<glyph glyph-name="exclam" unicode="!" horiz-adv-x="684" d="M227 0q-88 25 -61 100q20 61 84 88q12 4 22 9q61 27 105 -33q43 -57 6 -105q-23 -57 -94 -67q-35 -6 -62 8zM285 354q-55 57 -29 201q23 111 23 135q-4 39 12 178q2 23 2 39l20 129q-2 23 9 160q2 25 2 43l22 195q0 6 2 12q-4 63 58 96q68 35 112 -18q14 -70 -16 -226 q-14 -68 -17 -106q-14 -96 -47 -471q-10 -45 -8 -189q2 -94 -18 -147q-14 -47 -86 -41q-25 0 -41 10z" />
<glyph glyph-name="quotedbl" unicode="&#x22;" horiz-adv-x="757" d="M293 1122q-88 16 -98 138l-11 145q-2 6 -2 12q-37 72 23 131q53 53 108 23q23 -10 39 -35q25 -295 25 -336q-2 -45 -58 -70q-14 -8 -26 -8zM516 1137q-78 6 -82 86v131q-2 20 -10 37q-35 154 0 200q23 33 74 35q68 -25 92 -153q20 -96 22 -107q2 -127 -6 -156 q-18 -81 -90 -73z" />
<glyph glyph-name="numbersign" unicode="#" horiz-adv-x="1525" d="M676 -98q-86 37 -37 143l68 131q8 18 10 34.5t41 94.5q33 63 -13 66q-14 2 -38 -2q-76 18 -101 -66l-31 -119q-6 -10 -10 -18q27 -66 -39 -113q-57 -41 -100 -16q-29 16 -25 63q-4 37 39 144q33 84 13 114q-31 6 -142 -16q-111 -25 -145 27q-6 10 -12 22q6 82 131 96 l145 15h4q88 -18 123 84l37 137q4 6 6 10q-10 2 -123 0q-115 -4 -121 60q-2 16 2 36q37 51 158 52q100 -2 127 4q47 49 98 194q23 70 41 105q8 72 76 80q63 8 94 -37q29 -45 -20 -101l-80 -153q-23 -53 -6 -80q174 -35 186 113q14 20 47 120q33 96 92 109q12 2 27 2 q80 -33 31 -147l-51 -115q-2 -8 -4 -14q-27 -53 10 -56l125 21q59 0 69 -47q10 -88 -110 -111l-166 -23q-78 -74 -94 -233q31 -10 139 2q109 14 137 -35q8 -16 10 -37q-29 -74 -157 -77q-104 -4 -107 -5q-94 8 -115 -32q-10 -16 -10 -45q-18 -23 -55 -131q-16 -53 -37 -80 l-43 -119q-33 -59 -94 -51zM846 520q4 16 51 125q29 66 21 100q-6 -2 -95 3q-47 2 -65 -15q-14 -27 -58 -162l-14 -45q31 -27 135 -12q15 4 25 6z" />
<glyph glyph-name="dollar" unicode="$" horiz-adv-x="1021" d="M301 -119q-63 27 -63 129q0 106 -7 127q-4 14 -12 27q-86 111 -78 198q6 55 60 80l59 -36q10 -2 14 14q2 12 -2 37q6 197 17 307q8 86 -31 278l-4 27q33 59 41 197q6 76 14 114q6 61 66 68q61 8 90 -41q12 -20 12 -45q-37 -111 21 -107q18 0 47 13q16 23 22 125 q6 111 56 129q20 8 53 2q76 -29 59 -142l-16 -118v-17q2 -25 57 -108q59 -92 21 -135q-12 -14 -35 -27q-72 -4 -72 -103l2 -135q-2 -23 -8 -37q8 -43 80 -102q76 -63 88 -111l4 -16q39 -129 -59 -250q-47 -57 -109 -88q-2 -160 -92 -164q-25 -2 -53 11q-25 14 -41 73 q-12 41 -43 43q-16 0 -39 -8q-14 -18 -21 -113q-6 -90 -55 -98q-18 -4 -43 2zM494 256q33 86 36 285v37q16 51 -41 100q-39 35 -45 43q-20 -16 -20 -191v-49q2 -8 -8 -129q-8 -111 35 -110q16 0 43 14zM694 354q37 33 13 109q-12 41 -27 37q-12 -6 -8 -62l-2 -96 q4 -21 24 12zM543 819q12 254 14 293q-94 12 -117 -74q-10 -41 0 -86q4 -59 56 -110q27 -27 47 -23z" />
<glyph glyph-name="percent" unicode="%" horiz-adv-x="1396" d="M375 0q-131 31 0 221l117 180q14 27 22 48q-98 -68 -240 22q-12 6 -22 14q-100 129 -59 312q25 137 126 194q25 14 54 23q129 33 239 -76q31 -31 54 -68q25 -20 28 -112q2 -43 13 -49q47 57 182 266l55 82q51 53 123 37q68 -16 72 -84q10 -70 -68 -148q-76 -74 -94 -106 q-18 -31 -146 -197l-43 -59l-147 -207l-4 -8q-25 -33 -135 -209l-27 -41q-8 -66 -100 -35zM467 616q59 25 43 111q-14 74 -61 90q-31 12 -60 -18q-55 -41 -47 -119q6 -76 66 -82q16 -4 38 2l11 8zM881 -4q-98 -4 -162 133q-29 166 72 309q59 90 170 105q59 6 106 -17 q109 -18 154 -155q6 -20 10 -41l-25 -181q-18 -76 -84 -106q-81 -65 -241 -47zM985 162q117 45 37 160q-6 63 -68 28q-57 -33 -75 -88q-4 -12 -5 -24q-23 -61 33 -84q39 -17 78 8z" />
<glyph glyph-name="ampersand" unicode="&#x26;" horiz-adv-x="1089" d="M768 -55q-41 0 -94 59q-51 55 -84 53q-25 -2 -55 -28q-164 -39 -308 14q-84 29 -73 174l8 84q18 125 153 289q-10 -12 50 57l-29 223q-4 61 6 113q66 223 168 311q162 117 258 70l20 -12q109 -100 54 -332q-59 -213 -166 -305q-86 -70 -96 -82q-61 -70 -9 -146l70 -153 q25 -39 51 -43q10 10 76 88q72 90 143 65q76 -43 15 -120l-58 -66q-70 -59 -67 -102q0 -18 8 -39q49 -61 27 -123q-14 -39 -60 -51zM410 164q92 -10 116 35q18 37 -28 86q-12 12 -52 106q-29 74 -55 43q-12 -12 -26 -43q-72 -131 -54 -217q8 -20 66 -10q25 4 33 0zM506 770 q111 68 156 207q88 190 30 242q-12 10 -33 14q-100 -31 -151 -189q-4 -16 -23 -73q-18 -61 -2 -152q7 -45 23 -49z" />
<glyph glyph-name="quotesingle" unicode="'" horiz-adv-x="579" d="M203 1032q-25 66 0 193q12 66 14 100l29 231q8 33 16 58q43 55 103 10q53 -41 47 -100q0 -6 -4 -15q-18 -51 -41 -217q-4 -33 -11 -57q-16 -123 -20 -135q-29 -100 -125 -72z" />
<glyph glyph-name="parenleft" unicode="(" horiz-adv-x="862" d="M559 -197q-8 -29 -135 23q-113 145 -158 293l-41 178q-4 31 -2 57q-12 37 -16 140q0 27 -4 49l2 190q25 248 33 289q4 27 10 51q57 188 80 236q8 16 14 30q98 166 227 228q74 31 105 -31q29 -59 -10 -111q-18 -25 -50 -32q-133 -96 -186 -252q-39 -106 -68 -365 q-4 -43 -8 -71q2 -231 13 -295q8 -55 22 -101q10 -127 76 -252q8 -25 72 -104q66 -84 32 -137q-2 -7 -8 -13z" />
<glyph glyph-name="parenright" unicode=")" horiz-adv-x="819" d="M283 -203q-61 59 2 144l88 110q41 57 33 109q61 270 34 741q-2 6 -2 12q-35 248 -71 344q-37 98 -101 164q-94 39 -73 109q16 55 77.5 71.5t110.5 -32.5q82 -80 141 -283q-2 8 13 -43q49 -225 51 -325q16 -201 14 -248q-2 -33 -8 -60q14 -197 -6 -336q-31 -293 -176 -440 q-90 -47 -127 -37z" />
<glyph glyph-name="asterisk" unicode="*" horiz-adv-x="1095" d="M408 594q-49 41 -23 143q20 74 21 97q16 94 2 100q-10 4 -37 -19q-90 -63 -150 -30q-16 8 -26 26q-27 55 38 103q59 45 70 57l45 45q12 20 -8 37q-72 88 -115 119q-57 45 -28 143q4 16 10 31q102 41 151 -12q12 -6 60 -64q39 -47 43 -12q2 12 2 31q10 125 16 145 q12 41 37 70q39 53 105 26q59 -23 59 -78q-2 -12 -6 -24q-29 -96 -2 -86q10 4 24 20q43 68 127 66q57 -2 92 -43q43 -74 -65 -160q-8 -6 -16 -10q-8 -8 -117 -98q-55 -47 -84 -89q37 -47 182 -196l92 -86q43 -51 13 -101q-49 -72 -127 -38q-41 18 -68 63q-6 4 -61 66 q-49 53 -78 38q-6 -14 -29 -133q-18 -94 -74 -133q-44 -22 -75 -14z" />
<glyph glyph-name="plus" unicode="+" horiz-adv-x="1236" d="M614 203q-74 4 -92 88q-6 31 0 63l19 209v25q-29 12 -133 18q-55 4 -86 15q-94 2 -140 63q-23 29 -20 64q-33 70 71 71q41 2 80 -8q133 -6 224 6q37 27 32 131q-6 80 4 111q-6 61 54 86q61 25 100 -25q2 -4 6 -8q74 -84 29 -227q4 -47 63 -23q76 31 88 31q10 2 19 -2 q76 -4 115 -64q18 -27 18 -55q-18 -82 -158 -131q-8 -2 -45 -14q-92 -6 -112 -21q-31 -23 -25 -78q-31 -240 -35 -280q-10 -2 -47 -31q-15 -14 -29 -14z" />
<glyph glyph-name="comma" unicode="," horiz-adv-x="546" d="M156 -231q-92 41 -52 143l64 139q8 27 10 49q-14 96 64 146q72 45 133 0q41 -29 51 -94q-61 -184 -76 -213q-49 -106 -125 -158q-57 -26 -69 -12z" />
<glyph glyph-name="hyphen" unicode="-" horiz-adv-x="1187" d="M322 537q-66 53 -64 116q2 31 27 56q82 47 272 67q78 8 115 15q186 18 256 -19q63 -33 80 -110q12 -41 -53.5 -84t-125.5 -25l-272 4q-66 -4 -119 -16l-88 -13q-16 1 -28 9z" />
<glyph glyph-name="period" unicode="." horiz-adv-x="468" d="M195 10q-63 27 -86 101q-27 82 43 118q27 43 104 25q88 -18 104 -92q6 -18 5 -39q-2 -98 -119 -113q-24 -2 -51 0z" />
<glyph glyph-name="slash" unicode="/" horiz-adv-x="1064" d="M190 25q-115 39 -16 190l72 107q158 264 172 286q29 55 51 105q23 37 131 243l31 56l98 215q35 59 76 90q102 20 129 -62q23 -74 -33 -141q-12 -16 -29 -27q-51 -74 -170 -307q-55 -111 -98 -176q-35 -68 -207 -358q-70 -117 -110 -203q-62 -45 -97 -18z" />
<glyph glyph-name="zero" unicode="0" horiz-adv-x="1652" d="M633 0q-203 10 -342 184q-92 117 -113 260q-61 469 82 781q96 180 303 243q135 41 271 13q203 -31 327 -181q31 -37 53 -79q100 -80 199 -279q4 -8 27 -57q109 -195 47 -422q-39 -147 -146 -250q-176 -176 -432 -207q-51 -8 -100 -6q-135 -6 -141 -4q-19 0 -35 4z M776 242q174 10 305 131q131 125 115 286q23 207 -235 263q-29 31 -37 125q-8 88 -47 112q-10 6 -27 10q-102 74 -227 37q-100 -31 -142 -119q-57 -123 -73 -385l-2 -47q4 -199 34 -276q39 -96 129 -127q84 -37 207 -10z" />
<glyph glyph-name="one" unicode="1" horiz-adv-x="765" d="M231 0q-63 51 -30 182q29 123 28 146l74 606l8 43l19 156q25 121 110 145q88 31 149.5 -36.5t26.5 -154.5q-27 -82 -61 -327l-39 -324l-8 -43q-6 -27 -19 -180q-8 -92 -34 -145q-102 -92 -197 -76q-15 2 -27 8z" />
<glyph glyph-name="two" unicode="2" horiz-adv-x="1228" d="M817 -14q-195 49 -397 30q-154 37 -201 146q-16 37 -16 80q37 109 172 250q121 129 160 184l83 133q53 102 21 166q-45 -8 -139 -70q-92 -61 -158 -49q-82 2 -115 72q-35 74 25 127q14 14 35 22q129 96 272 146q119 51 232 -2q78 -37 108 -115q96 -150 -18 -365 q-6 -8 -11 -16q-37 -111 -184 -260l-84 -84q-57 -70 19 -70q12 2 30 4q264 -29 389 -165q51 -78 7 -142q-45 -61 -132 -39q-41 5 -98 17z" />
<glyph glyph-name="three" unicode="3" horiz-adv-x="1251" d="M332 20q-94 37 -101 146q-4 63 27 117q59 66 156 36q102 -31 106 -30q27 -4 49 0q74 8 140 67q74 63 24 119l-135 123q-63 68 -86 133q-27 82 49 213q27 47 31 55q-49 14 -168 -6q-80 -12 -125 -2q-98 25 -109 123q-6 74 46 135q76 53 243 47q84 -4 107 -2 q195 -25 272 -63q41 -23 72 -51q82 -98 55 -209q-14 -70 -78 -113q-86 -49 -78 -108q4 -41 60 -68q223 -162 176 -330q-2 -4 -4 -10q-51 -123 -240 -248q-6 -4 -14 -10q-190 -80 -297 -84q-117 0 -139.5 6t-38.5 14z" />
<glyph glyph-name="four" unicode="4" horiz-adv-x="1228" d="M715 29q-61 68 -51 229l8 88q-2 12 10 133q12 113 -49 129q-27 8 -68 2l-248 8q-45 6 -81 17q-74 51 -50 168l29 127q2 12 2 22q43 221 129 348q70 74 166 13q74 -45 90 -121q23 -53 -31 -123q-57 -74 -63 -108q-2 -10 0 -23q8 -43 86 -57q88 -18 117 30q12 20 2 56 q4 14 12 153q8 141 88 189q96 45 174 -56q45 -57 51 -127q2 -45 -20 -204q-10 -68 -8 -115l-33 -344q-2 -20 -6 -39l-33 -309q-14 -78 -84 -95l-98 -20q-10 -2 -31 20q-6 7 -10 9z" />
<glyph glyph-name="five" unicode="5" horiz-adv-x="1269" d="M596 0q-203 14 -322 152q-25 27 -41 59q-25 76 31 145q49 59 113 39l139 -82q100 -47 184 -14q76 6 78 66q4 57 -53 92q-29 16 -61 14q-61 25 -189 4q-111 -16 -166 4q-80 25 -106 101q-25 76 28 131q72 133 70 329q-20 158 57 242q35 39 91 51q119 16 421 29 q160 -10 199 -102q47 -53 21 -127q-12 -33 -39 -50q-55 -82 -224 -63q283 -31 -77 8q-106 31 -127 -74l-21 -166l-2 -4q-4 -41 49 -49l111 -12q16 -4 24 -12q164 -43 250 -179q45 -72 51 -151q37 -133 -88 -250q-37 -35 -82 -59q-100 -68 -319 -72z" />
<glyph glyph-name="six" unicode="6" horiz-adv-x="1118" d="M541 0q-188 16 -262 82q-23 18 -39 41q-53 78 -47 246q2 92 2 118q20 184 94 457q82 213 180 309q104 119 238 195q88 29 163 -41q43 -41 54 -96q16 -55 -84 -137q-12 -10 -15 -13q-170 -115 -233 -266l-43 -100q-12 -49 47 -52q8 -2 16 -2q145 -53 250 -172 q109 -117 64 -311q-4 -12 -6 -22q-31 -102 -189 -177l-74 -32q-16 -8 -94 -21q-12 -4 -22 -6zM516 223q72 23 96 101q27 82 -37 120q-16 10 -38 15q-72 57 -84 -72q-2 -35 0 -74q-12 -102 43 -96q10 2 20 6z" />
<glyph glyph-name="seven" unicode="7" horiz-adv-x="1181" d="M449 0q-100 -23 -125 94q-18 90 16 168q27 104 137 389q6 16 12 29l144 326q4 16 61.5 122.5t14.5 128.5l-234 -22q-68 -2 -125 10q-80 16 -133 82q-59 76 4 135q41 53 182 47q131 -6 170 2l211 35q102 8 172 -33q125 -53 95 -256q-25 -125 -142 -346q-70 -133 -96 -198 q-23 -39 -86 -215q-23 -66 -43 -107q-70 -262 -82 -346q-102 -70 -153 -45z" />
<glyph glyph-name="eight" unicode="8" horiz-adv-x="1355" d="M565 -23q-180 8 -315 144q-106 61 -129 178q-16 86 29 158q31 84 151 190l82 74q-18 41 -107 172q-53 78 -73 137q-68 123 -19 285q27 90 84 147q131 125 262 127q150 16 263 -102q109 -111 94 -252q29 -18 96 35q82 66 123 65q35 0 63 -30q76 -70 -10 -191 q-29 -41 -72 -76q-47 -49 -247 -233q-45 -41 -76 -72q16 -55 100 -162q92 -117 101 -196v-17q25 -152 -109 -278q-51 -47 -113 -76q-113 -31 -145 -31q-17 0 -33 4zM623 211q82 35 67 143q-12 94 -80 140q-23 16 -47 18q-256 -209 -76 -289l72 -28q31 -7 64 16zM664 1010 q98 68 116 106q16 31 -63 4q-74 -18 -137 54q-61 70 -27 133q-68 35 -98 -58q-31 -94 4 -180q10 -31 30 -47q18 -96 72 -98q39 -2 74 57l16 16zM1028 1298z" />
<glyph glyph-name="nine" unicode="9" horiz-adv-x="1230" d="M598 0q-119 10 -121 133q0 84 47 160q45 100 111 348l24 111q6 57 -34 55q-20 0 -52 -14q-168 -23 -294 88q-49 41 -80 94q-82 141 -43 307q6 20 14 41q57 131 180 193q59 27 119 28q178 53 397 -47q174 -104 199 -299l-64 -297q-27 -203 -141 -553l-72 -215 q-27 -68 -63 -108l-98 -27q-17 0 -29 2zM549 1049q111 61 139 102q20 29 29 72q-31 66 -127 77q-104 12 -146 -57q-4 -10 -8 -18q-39 -53 -12 -129q29 -76 90 -62q17 5 35 15z" />
<glyph glyph-name="colon" unicode=":" horiz-adv-x="468" d="M186 6q-35 -2 -67 45q-12 18 -19 27q-14 68 31 115q18 18 43 22q55 10 100 -41q25 -29 27 -61q18 -70 -47 -105l-16 -8q-17 -2 -52 6zM281 635q-55 -4 -70 43q-45 20 -31 80q6 31 27 49q43 59 100 18q8 -6 15 -14q47 -14 69 -70q20 -57 -20 -84q-65 -30 -90 -22z" />
<glyph glyph-name="semicolon" unicode=";" horiz-adv-x="555" d="M188 -186q-51 14 -57 59q-6 35 27 59q57 31 37 109q-6 23 -19 43q-29 43 6 94q27 35 64 29q47 -2 98 -70q4 -6 6 -8q59 -92 8 -209q-2 -4 -6 -8q-43 -82 -119 -98q-12 -2 -24 -2q-11 0 -21 2zM317 590q-33 -2 -77 43q-16 18 -27 26q-16 27 12 80q18 31 21 47q47 47 114 5 q20 -10 33 -29q49 -41 33 -107q-8 -29 -33 -47q-31 -20 -76 -18z" />
<glyph glyph-name="less" unicode="&#x3c;" horiz-adv-x="905" d="M682 0q-16 10 -84 76q-29 27 -53 41q-31 14 -113 82q-51 43 -92 55l-184 92q-31 63 -4 133q18 43 53 53q23 23 51 99q2 10 6 18q66 51 125 189l62 104q16 20 32 31q6 29 54 98q16 25 26 43q33 57 94 2q80 -53 -26 -186q37 45 -23 -27l-108 -155q-6 -10 -11 -21 q-66 -80 -110 -170q0 -16 -33 -72q-31 -53 23 -75l178 -123q111 -74 178 -129q66 -51 22 -133q-4 -10 -10 -19q-28 -22 -53 -6z" />
<glyph glyph-name="equal" unicode="=" horiz-adv-x="1083" d="M274 420q-53 -6 -59 43q-6 47 31 67q18 12 41 7q33 2 192 26q35 20 162 45l27 4l114 43q55 12 90 -28q47 -37 13 -95q-27 -39 -70 -40q-25 -6 -213 -43q-70 -23 -264 -37h-10q-38 0 -54 8zM387 731l-117 10q-53 14 -59 56q-43 31 -6 69.5t88 16.5l160 2q47 4 84 16 q25 4 112 39q51 20 88 18q55 -20 70 -73q12 -47 -27 -76q-76 -55 -252 -72q-51 -6 -65 -8q-64 0 -76 2z" />
<glyph glyph-name="greater" unicode="&#x3e;" horiz-adv-x="1077" d="M221 0q-59 4 -65 57q-4 55 47 82l8 4q96 90 252 265l143 155l72 76q37 51 -23 66l-178 135l-215 143q-37 51 14 100q23 25 56 31q43 -4 127 -82q55 -51 84 -63l260 -183l88 -55q70 -53 18 -102q-16 -39 -84 -74q-61 -31 -80 -59l-120 -107l-37 -43l-291 -317 q-49 -39 -76 -29z" />
<glyph glyph-name="question" unicode="?" horiz-adv-x="813" d="M332 0q-68 14 -74 88q-2 53 31 92q27 68 94 37q27 -12 45 -39q61 -70 29 -115q-6 -8 -19 -16q-57 -49 -86 -49q-10 -2 -20 2zM389 446q-61 14 -72 70q-10 47 35 82q102 156 135 297q2 63 -47 61q-49 -4 -80 -51q-8 -12 -10 -26l-26 -93q-16 -35 -45 -49q-53 -35 -103 13 q-31 29 -24 71q4 59 73 170l21 31q63 96 162 121q119 4 180 -90q80 -68 61 -187q-2 -14 -4 -26l-86 -189q-14 -20 -53 -116q-10 -25 -21 -41q-18 -36 -96 -48z" />
<glyph glyph-name="at" unicode="@" horiz-adv-x="1236" d="M479 0l-119 23q-16 4 -30 12q-59 23 -72 55q-61 29 -102 150q-16 104 -15 145q-2 156 49 287q12 45 54 141q16 41 63 125q16 29 84 121q68 84 133 121q43 43 131 67q59 18 179 0l88 -51q25 -20 36 -43q27 -33 80 -129q47 -100 41 -223q2 -129 -47 -281l-49 -98 q-14 -23 -33 -37q-94 -100 -168 -104h-12l-61 8q-6 2 -9 6l-79 80q-88 0 -121 16q-43 18 -129 94q-6 4 -11 9q-16 74 7 170q16 70 131 94q72 18 178 -45q86 -66 74 -123q-12 -84 10 -119l4 -8q45 -61 106 69q49 100 62 218q14 137 -47 237q-43 90 -119 113q-31 8 -59 0 q-111 -12 -199 -109q-59 -68 -92 -117q-74 -129 -103 -245q-16 -41 -32 -174q0 -143 14 -189l8 -20q25 -74 107 -109q4 -2 8 -2q66 -18 194 -14q133 12 219 49q12 6 64 45q45 37 82 14q49 -41 24 -102q-14 -41 -53 -53q-23 -16 -114 -45q-14 -4 -25 -9q-94 -20 -317 -22z M559 532q18 29 -14 41q-31 12 -31 -4q0 -8 18 -22l23 -17q2 0 4 2z" />
<glyph glyph-name="A" unicode="A" horiz-adv-x="1296" d="M205 -203q-88 -2 -72 105q6 33 21 65q8 20 98 307l22 68l41 180q10 33 23 58q43 166 68 237q37 186 139 490q6 10 39 116q23 70 59 101q23 57 88 39q55 -16 66 -68q2 -12 0 -25q49 -53 80 -192q2 -8 2 -12q18 -66 41 -228q4 -10 34 -147q10 -37 21 -64q4 -39 41 -190 q33 -135 43 -211l57 -203l8 -20l39 -113q10 -51 -37 -76q-119 -10 -149 97q-27 41 -53 159l-11 41q-2 61 -82 47q-84 -16 -88 -16q-72 -16 -305 -55q-16 -25 -45 -127q-8 -31 -18 -51q-45 -141 -49 -242q-16 -90 -111 -72q-6 2 -10 2zM580 502q115 14 237 45q41 25 14 112 q-16 59 -18 78q-37 125 -65 275q-4 12 -17 100q-6 47 -26 66q-33 -29 -58 -134q-15 -59 -29 -88l-94 -321q-14 -63 -24 -119q2 -29 55 -18q19 4 25 4z" />
<glyph glyph-name="B" unicode="B" horiz-adv-x="1327" d="M500 -14q-127 33 -187 75q-23 27 -108 95l-29 24q-20 55 -8 189v16q18 100 25 199q20 125 18 215q-6 35 12 131q6 31 8 51q16 127 21 418q10 37 78 98q20 16 30 29q49 29 168 78q53 37 168 12l17 -4q96 -49 145 -137l74 -132q10 -12 20 -22q68 -78 19 -195 q-6 -14 -13 -26q-8 -25 -63 -94q-31 -39 -35 -66q84 -47 156 -113q37 -31 88 -129q6 -12 12 -22q82 -164 31 -289q-49 -182 -240 -307q-104 -61 -180 -80q-75 -26 -227 -14zM684 168q106 35 236 147q53 70 84 240q-80 180 -193 238q-92 43 -215 4q-147 -41 -170 -54 q-8 -2 -16 -6q-8 -29 -15 -141q-2 -41 -8 -68l-22 -161q0 -31 8 -58q27 -12 45 -69q16 -53 53 -60h18q99 -39 195 -12zM518 987q84 14 170 72q119 94 96 194q-10 37 -73 160q-2 4 -2 8q-29 66 -127 21q-59 -27 -62 -27q-63 -39 -76 -164q0 12 -4 -34l-16 -218q-2 -29 35 -24 q-9 -2 59 12z" />
<glyph glyph-name="C" unicode="C" horiz-adv-x="1400" d="M520 4q-51 4 -151 66q-25 14 -41 22q-10 12 -74 105q-8 14 -18 24q-29 98 -43 164q-14 70 -3 250q27 129 66 248q10 51 72 153q47 57 168 172q47 35 137 109q80 55 162 70q84 25 182 4q63 -6 184 -56q92 -57 103 -151q-29 -76 -131 -62q-27 4 -54 17q-70 53 -143 65 q-98 16 -244 -82q-8 -6 -20 -14q-121 -88 -207 -260q-45 -96 -55 -234q-41 -182 36 -329q78 -90 156 -97q47 0 170 35l43 10q29 4 148 39q33 10 59 15q94 41 137 6q16 -12 19 -37q-4 -84 -103 -133q-6 -4 -10 -6q-25 -12 -166 -60l-291 -51q-23 -2 -41 -4q-24 0 -47 2z" />
<glyph glyph-name="D" unicode="D" horiz-adv-x="1359" d="M254 8q-72 35 -96 107q-2 8 -4 14q-12 35 32 70q43 37 41 71l21 201l31 326q18 231 22 260q2 10 0 104q-2 47 14 78q39 61 166 98q41 12 43 13q16 4 107 2q23 0 41 2q199 -14 325 -164l93 -137l75 -135q12 -27 17 -50q25 -43 41 -170q6 -147 -13 -202q-4 -16 -10 -31 q-35 -100 -121 -195q-33 -43 -129 -106q-31 -20 -166 -84q-37 -16 -61 -31q-156 -47 -373 -43q-78 0 -96 2zM606 205q72 16 164 53q111 47 186 117q72 51 86 153q18 76 7 269q-4 35 -52 135l-8 20l-92 136l-27 26q-53 57 -190 62q-55 2 -61 4q-74 4 -111 -56 q-16 -29 -12 -61q-8 -35 -23 -195q-4 -43 -10 -73q-45 -430 -51 -582q20 -35 108 -23q39 6 53 7q17 2 33 8z" />
<glyph glyph-name="E" unicode="E" horiz-adv-x="1220" d="M365 31q-104 29 -158 61q-45 39 -10 123q25 61 28 78q0 35 25 190q6 43 8 76l43 315q-2 23 8 150q2 10 2 18q8 29 15 146v10l-41 57q-12 27 0 50q41 61 143 125q135 4 199 22q129 35 295 29q119 -6 141 -51q2 -6 4 -15q10 -59 -37 -96q-25 -18 -53 -16l-238 -17 q-76 -10 -135 -37q-90 -4 -106 -69q-4 -18 0 -39q-25 -186 -27 -228q127 10 250 56q106 20 149 -6l13 -9q51 -31 26 -92q-14 -39 -49 -51q-25 -12 -119 -27q-29 -4 -49 -12l-196 -51q-18 -4 -35 -6q-16 -25 -25 -109q-2 -37 -10 -59l-37 -289v-6q14 -39 84 -4q39 18 49 20 q25 6 162 62q72 29 127 32q96 49 168 48q72 -49 78 -82q2 -12 -2 -27q-6 -51 -78 -80q-14 -6 -27 -8q-111 -16 -166 -47q-35 -2 -131 -45q-23 -10 -41 -15q-160 -59 -170 -63q-54 -20 -77 -12zM727 1460z" />
<glyph glyph-name="F" unicode="F" horiz-adv-x="1222" d="M242 8q-70 18 -43 148q0 2 2 12q16 39 26 168q25 188 19 309q-53 78 -29 139q49 41 41 156v8l-10 230q-2 23 -6 43q-2 29 -33 129q-8 29 -12 53q6 68 102 117l154 -39q10 -2 20 -2q170 -6 356 24q94 41 181 -12q53 -6 65 -59q8 -37 -14 -68q-37 -63 -162 -66 q-137 -16 -346 -18q-82 -4 -94 -8q-35 -14 -27 -60q-10 -31 -4 -125q2 -31 0 -53v-168q27 -39 117 -20q43 10 57 10q80 31 131 -10q47 -4 68 -53q20 -47 -17 -74q-102 -59 -163 -70q-27 -4 -189 -14l-33 -39q-12 -20 11 -35q-20 -18 -9 -72q6 -35 -4 -49q10 -35 2 -143 q-4 -37 0 -61q14 -41 -8 -130q-6 -31 -8 -49q-31 -55 -109 -53q-18 0 -32 4z" />
<glyph glyph-name="G" unicode="G" horiz-adv-x="1359" d="M582 16q-215 33 -373 238q-4 6 -10 14q-68 102 -68 189q-4 137 41 293l70 243l4 17q6 39 59 135l27 53q72 129 252 252l125 57q27 8 53 13l119 6q51 -2 77 -31q102 -41 201 -141q90 -96 31 -152q-70 -70 -133 -53q-27 4 -45 29l-64 88q-25 25 -53 32q-90 31 -203 -18 q-119 -61 -198 -168q-55 -84 -72 -160q-2 -14 -45 -121q-23 -55 -21 -98l-39 -203q-10 -96 15 -170q12 -45 80 -106q18 -16 28 -27q117 -84 201 -67q123 0 184 82q63 63 76 178q37 84 -113 76l-71 4h-2l-51 71q-16 31 -2 64q4 72 116 76h60q27 8 141 16q23 2 39 4 q78 16 156 -65q57 -20 16 -76q-27 -37 -62 -43q-16 -29 -16 -113q0 -57 -18 -86q12 -27 -25 -88q-16 -27 -20 -41q-96 -154 -252 -188q-133 -29 -215 -15z" />
<glyph glyph-name="H" unicode="H" horiz-adv-x="1230" d="M268 20q-12 6 -78 7q-51 0 -53 41q-2 6 0 14q-14 31 10 104q12 39 11 64q16 139 12 176q6 23 16 139q4 41 11 68q2 129 18 223q16 223 41 367q12 23 16 102q4 55 29 84q37 55 154 14q2 -2 10 -4q59 -35 18 -137l-14 -39q-23 -51 -43 -168q-16 -45 -23 -186q-2 -23 -4 -39 q-18 -61 62 -70l76 -4q63 -2 196 19l107 4q6 2 10 2q4 53 18 424q0 18 2 35q-4 113 23 147q12 16 29 27q63 25 118 -29q45 -43 33 -94q-8 -39 -26 -248q-6 -63 -15 -107q-8 -207 -12 -245l-14 -140q0 -18 4 -36q-10 -41 -11 -185q-10 -135 7 -254q-16 -33 -82 -33 q-41 0 -58 -8q-59 4 -78 66q-8 31 -2 59q0 -2 33 174q12 209 12 234q-59 6 -190 -8l-166 14l-29 4q-49 37 -73 0q-16 -25 -4 -61q-2 -35 -29 -344l-2 -111q-6 -27 -29 -39l-28 -27q-7 0 -13 4z" />
<glyph glyph-name="I" unicode="I" horiz-adv-x="1157" d="M510 -41q-16 12 -74 16q-45 6 -59 39l-148 39q-37 14 -57 43q-39 45 -4 92q23 29 57 29q139 -10 146 -10q23 0 41 4q12 29 22 137q2 18 6 35q10 55 21 199q6 18 18 123q2 16 4 28l27 225l8 39q27 182 27 254q-2 0 -178 -26q-6 0 -15 -2q-43 -12 -73 47l-23 43q14 6 8 30 q-4 18 19 25q33 31 129 43q20 2 32 4q29 14 142 33q27 4 45 10l235 17q6 2 13 2q102 -18 135 -78q29 -68 -70 -94q-23 -6 -45 -9q-147 -4 -149 -92q-45 -190 -45 -260l-25 -135q-2 -16 0 -33q-2 -59 -21 -201q-20 -29 -20 -104q0 -39 -6 -63l-12 -187v-4q102 -6 124 -14 q31 -10 52 -33q49 -53 -9 -107q-29 -27 -67 -32q-113 -29 -115 -31q-35 -12 -57 -35q-19 -10 -39 -6z" />
<glyph glyph-name="J" unicode="J" horiz-adv-x="1437" d="M535 8q-141 6 -248 82q-109 57 -119 172q20 115 72 133q20 6 41 -6q39 -12 67 -76q31 -63 62 -77q8 -4 18 -7q158 -72 244 -57q18 2 35 8q119 39 155 74q25 23 37 53q47 98 23 293q14 -109 -7 47q-8 23 -32 148q-6 27 -13 47q-16 117 -43 231l-26 178q-8 29 -21 49 q-37 14 -139 -2q-45 -8 -70 -6q-61 10 -77 70q-12 45 16 80q25 55 115 53q70 -2 84 0q51 2 206 37q35 2 136 47q72 33 120 29q78 -14 105 -70q12 -25 6 -51q-10 -53 -92 -74q-72 -18 -84 -24q-59 -6 -74 -80q-16 -74 -16 -76q-4 -27 10 -148q4 -29 4 -51q35 -176 39 -184 q2 -6 2 -12l41 -203q-2 -16 16 -129q8 -49 5 -82q10 -66 -39 -195q-74 -115 -140 -143q-8 -4 -16 -6q-141 -74 -272 -74q-96 -2 -131 2z" />
<glyph glyph-name="K" unicode="K" horiz-adv-x="1284" d="M1016 -96q-25 27 -60 119q-10 31 -20 49q-82 170 -145 237q-106 158 -230 205q-113 61 -192 29q-31 -35 -25 -144q2 -57 -2 -84l-8 -237q0 -14 -2 -29q-35 -39 -135 -37q-33 2 -45 2q-61 29 -43 127l10 49q25 152 37 400q-2 33 10 182v29q14 385 14 409l15 211q2 27 8 49 q20 66 88 80q41 10 78 -10q66 -27 73 -100q6 -51 -30 -88q-10 -41 -33 -222q-4 -20 -6 -38l-11 -199q33 6 72 82q20 39 31 53l102 193q70 123 82 184q59 94 135 82q10 -2 23 -8q80 -16 102 -109q6 -23 6 -47l-106 -104q-23 -25 -37 -52q-20 -27 -80 -137q-12 -25 -24 -43 q-143 -246 -146 -248q-4 -8 -10 -16q252 -104 358 -231q121 -135 224 -340l51 -132q8 -27 6 -51q-6 -47 -78 -65q-34 -8 -57 0z" />
<glyph glyph-name="L" unicode="L" horiz-adv-x="1222" d="M938 0l-231 49h-9q-102 18 -225 4q-47 -47 -176 -37q-2 0 -14 2q-70 0 -99 45q-16 27 -4 60q45 84 45 190q14 240 15 725l4 168q-2 6 -2 13l-13 133q2 35 19 61q45 63 127 47q57 -10 84 -55q31 -37 8 -123q-8 -31 -10 -45l-13 -201q0 -12 -4 -22l-14 -475l-2 -263 q2 -10 2 -20q27 -8 135 -10q23 0 41 -2q68 -2 281 -43l118 -17q33 -10 41 -34q8 -12 7 -37q-2 -10 20 -19q49 -27 4 -67q-43 -39 -84 -29q-35 0 -51 2z" />
<glyph glyph-name="M" unicode="M" horiz-adv-x="1589" d="M291 0q-14 6 -76 6q-53 0 -59 49q-8 35 16 119q14 47 12 76l21 237l28 265v8q2 25 25 237q6 49 8 88q6 23 29 160q4 29 10 51q33 72 131 47q27 -8 51 -22q45 -25 72 -117q8 -25 10 -35q29 -55 123 -151q47 -8 90 69q29 51 37 62q20 27 82 151q27 55 53 89q66 68 195 -29 q45 -47 76 -174q4 -12 4 -21l45 -223q2 -8 2 -16q10 -25 22 -127q4 -33 13 -56l32 -213q2 -4 35 -147q2 -10 4 -18l39 -154q12 -31 29 -53q41 -45 -4 -92q-37 -41 -80 -27q-41 -57 -90 12q-23 31 -29 62q-2 14 -49 235q-6 27 -10 49q-12 31 -29 146q-2 25 -6 43l-31 190v6 q-18 51 -41 203q-6 10 -16 82q-8 53 -35 51l-92 -139q-16 -20 -33 -35l-82 -131l-18 -43q-86 -53 -154 -29q-23 10 -39 31q-25 55 -123 174q-45 35 -55 -35l-12 -88v-4l-25 -239q-6 -43 -24 -316v-10l-11 -178q-4 -25 -8 -45q-18 -31 -53 -33q-6 0 -10 2z" />
<glyph glyph-name="N" unicode="N" horiz-adv-x="1318" d="M233 0q-66 8 -77 70q-8 35 6 67l35 279q31 217 32 241v13q23 150 31 192q20 199 43 295l2 96q8 41 39 62q68 53 141 18q31 -14 52 -45q37 -35 36 -125v-51q6 -27 50 -113q16 -31 22 -53q4 -8 86 -192q37 -98 49 -115q10 -16 23 -23q18 37 33 154l4 27l57 346q4 10 18 98 q8 49 31 76q35 66 146 53q70 -43 73 -106q2 -18 -4 -35q-51 -119 -57 -156q-2 -12 -4 -22q-20 -82 -29 -166l-53 -314q0 -4 -2 -6l-27 -182q-2 -111 -10 -199q16 -86 -33 -121q-16 -12 -39 -12q-88 -25 -147 37l-8 8q-43 55 -90 97q10 0 4 16q-10 29 0 39q0 78 -56 248 l-16 53q-47 127 -62 158q-4 4 -32 65q-18 37 -37 25q-45 -211 -49 -297q-20 -35 -21 -129q0 -45 -8 -72l-20 -227q-4 -27 -11 -49q-12 -20 -98 -21q-15 0 -23 -2z" />
<glyph glyph-name="O" unicode="O" horiz-adv-x="1425" d="M578 -2q-166 27 -224 51q-16 6 -30 14q-68 29 -113 123q-70 156 -72 244q-14 170 11 275q35 281 139 434q74 121 141 170q119 84 264 43q115 -23 162 -68q84 -82 135 -117q33 -16 84 -80q18 -23 31 -34q47 -101 65 -135q8 -14 43 -107q4 -16 11 -29q41 -160 4 -323 l-49 -135q-6 -14 -17 -27q-12 -39 -76 -119l-24 -31q-88 -78 -129 -96q-10 -4 -19 -8q-98 -45 -184 -43q-114 -4 -153 -2zM680 160q94 6 194 82q80 80 127 200q55 135 35 287l-47 166q-8 53 -71 43q-70 -10 -84 -6l-9 4q-53 4 -67 76q-12 66 -15 71q2 29 -45 52 q-51 23 -61 49q-47 12 -123 -58l-25 -22q-27 -29 -86 -137q-2 -6 -6 -13q-55 -123 -67 -194q-16 -78 -31 -189q-4 -162 10 -217q2 -10 6 -22q49 -111 99 -142q6 -4 10 -6q104 -51 256 -24z" />
<glyph glyph-name="P" unicode="P" horiz-adv-x="1204" d="M252 0q-102 45 -88 109q0 23 26 102q10 31 11 55q6 27 26 195q4 35 9 59l-33 115q-2 27 6 49q47 98 51 133q2 6 2 12q0 16 14 203q2 29 3 55q6 53 69 136q27 33 115 63q12 4 20 6q143 35 250 -12q125 -35 187 -106q61 -45 96 -134q18 -63 26 -168q-4 -33 -45 -153 q-61 -109 -235 -152q-23 -10 -123 -24q-14 -2 -25 -4q-14 -2 -170 -19q-25 -45 -28 -164q0 -35 -4 -55l-9 -166q-4 -25 -12 -45q6 -59 -82 -84q-16 -4 -39 -8h-8zM573 745q135 23 175 41q47 23 71 64q51 63 27 137q-14 43 -49 64q-88 61 -156 67q-72 12 -102 -65 q-6 -12 -9 -27q-4 -16 -41 -80q-20 -39 -20 -69l-12 -109q2 -25 20 -33z" />
<glyph glyph-name="Q" unicode="Q" horiz-adv-x="1452" d="M1094 -127q-49 6 -84 72q-37 68 -60 84q-27 4 -104 -21q-45 -14 -76 -8l-223 -2l-39 4l-117 45q-33 16 -57 39q-72 80 -113 262q-20 139 -18 176q2 6 2 15q0 152 22 249q25 137 58 197q29 88 118 211q82 100 218 154q147 68 264 14q94 -33 147 -104l49 -107q16 -45 6 -80 q-6 -20 -59 -49q-45 -23 -27 -47q6 -8 19 -19l98 -110q16 -20 25 -43q102 -190 106 -307v-21q2 -131 -49 -198q-4 -6 -43 -70q-41 -61 12 -94q92 -82 72 -172q-16 -76 -129 -70h-18zM764 141l78 29q41 25 8 68l-57 112q-18 51 -13 94q6 55 66 78q61 23 98 -20q31 -6 53 -68 q18 -49 39 -49q55 94 -14 274l-4 13q-39 90 -172 225l-72 76l-72 84q-25 35 -8 59q33 33 99 17q45 -10 65 -7q-16 66 -102 64q-37 -2 -66 -19q-131 -57 -239 -258q-92 -213 -93 -358q-6 -195 56 -330q57 -82 168 -94q102 -8 182 10z" />
<glyph glyph-name="R" unicode="R" horiz-adv-x="1241" d="M1008 -4q-90 -4 -113 90q-37 104 -158 195q-25 25 -129 96q-8 4 -14 8l-127 82q-55 43 -64 -47l-2 -51q-2 -20 -41 -226q-6 -33 -10 -59q-14 -59 -78 -76q-51 -14 -90 17q-63 6 -61 86q0 20 6 38q31 57 47 144q18 63 35 250q2 14 2 26q-47 45 -23 158q61 98 60 168l4 154 q-2 23 -4 41q-25 74 8 157q47 68 145 82q35 18 136 23q43 2 71 10q76 4 170 -29q98 -35 131 -98q59 -72 72 -217q0 -98 -51 -170q-33 -72 -127 -150q-16 -16 -96 -59q-37 -20 -54 -39l172 -127q94 -74 117 -106q8 -8 12 -19q-6 -20 0 -18l25 8q6 -2 8 -16q76 -88 90 -109 q10 -18 17 -35q49 -74 16 -135q-6 -10 -12 -18q-39 -47 -80 -33q-4 2 -10 4zM547 799q66 12 155 94q90 98 101 170q-16 72 -84 96q-14 6 -31 6q-115 14 -156 -39q-61 -51 -69 -153l-12 -129q0 -31 18 -49q31 -4 78 4z" />
<glyph glyph-name="S" unicode="S" horiz-adv-x="1245" d="M594 4q-139 20 -277 82q-74 27 -174 100q-55 49 -24 148q41 70 114 59q10 0 19 -4l92 -80q25 -18 51 -26q25 -12 168 -64q8 -2 19 -6q186 -18 305 20q51 20 -15 84l-30 31q-43 39 -201 146q-61 41 -100 75q-43 27 -125 121q-10 10 -17 19q-59 80 -65 92q-10 23 -15 45 q-43 129 -36 203l24 116q10 33 31 58q35 59 147 96l129 24q16 2 33 0q225 6 318 -102q61 -61 53 -147q-6 -49 -41 -80q-59 -45 -154 -13q-31 14 -41 72q-6 47 -24 62q-88 31 -189 8q-70 -14 -82 -88q-2 -20 0 -41q-2 -45 39 -146q4 -10 9 -18l79 -98q16 -16 31 -27 q18 -18 98 -70q16 -10 29 -20l182 -125q150 -111 179 -274l4 -43q-31 -86 -119 -134q-123 -53 -373 -59h-14q-23 0 -37 4z" />
<glyph glyph-name="T" unicode="T" horiz-adv-x="1497" d="M635 0q-59 2 -82 66q-12 37 0 71q12 27 16 121q4 39 13 66q14 125 18 258q20 330 21 368v45q20 125 -33 121q-14 0 -33 -8q-39 -2 -182 29q-47 8 -80 12q-131 8 -143 82q4 70 75 106q29 14 62 17q188 4 305 -8q59 -12 246 -13h57q41 -2 192 27q84 14 140 8q80 -55 90 -92 q4 -18 -2 -39q-47 -59 -187 -72q-244 -29 -254 -28q-41 -25 -40 -117q0 -45 -3 -62q-6 -23 -8 -122q-2 -25 -4 -45q-20 -121 -14 -189q-6 -272 -21 -397l-8 -125q-8 -31 -26 -51q-54 -35 -115 -29z" />
<glyph glyph-name="U" unicode="U" horiz-adv-x="1574" d="M385 2q-84 2 -129 68q-12 16 -18 34q-20 49 -25 185q-2 29 -4 47q-6 246 14 387q8 27 15 137q4 45 12 76q2 12 31 201q0 4 2 8q6 16 28 125q8 35 19 57q4 88 63 119q23 10 49 8q80 20 121 -57q14 -27 19 -56q-4 -29 -52 -122q-25 -47 -28 -84q-63 -217 -86 -633v-21 q-2 -168 -2 -180q4 -47 18 -84q45 -45 131 27q33 27 37 28q115 111 160 187q61 92 92 180q61 147 70 186q12 47 8 93l-2 370q0 20 2 41l35 98q25 49 75 48q74 29 113 -56q8 -16 12 -37q23 -143 2 -358q-33 -158 -18 -262l16 -193q8 -45 23 -82q14 -109 74 -159 q84 -39 106 -125q0 -80 -158 -56q-98 6 -172 132q-6 10 -30 88q-12 39 -31 53q-16 -16 -82 -117q-25 -37 -45 -59q-133 -154 -248 -207q-98 -37 -180 -37q-17 2 -37 2z" />
<glyph glyph-name="V" unicode="V" horiz-adv-x="1384" d="M537 0q-53 23 -78 117q0 2 -4 20q0 41 -39 158q-14 45 -19 78q-25 68 -41 172l-49 168q-59 174 -94 252l-70 96q-12 20 -14 43q-12 76 45 110q18 10 43 13q76 39 143 -37l11 -10q23 -25 28 -101q4 -53 23 -80q10 -25 45 -163q10 -41 20 -70q2 -20 37 -131q12 -39 15 -68 q10 -74 55 -172q39 14 61 90q16 55 31 74q49 100 78 174l78 141l104 177q74 117 92 166q6 8 33 77q23 61 72 64q133 2 129 -80q-4 -53 -60 -160q-14 -27 -22 -45q-39 -72 -141 -223q-82 -131 -131 -250q-6 -12 -62 -145l-8 -17q-8 -14 -66 -143q-16 -35 -30 -59 q-23 -31 -60 -146q-8 -18 -12 -33q-27 -76 -135 -57h-8z" />
<glyph glyph-name="W" unicode="W" horiz-adv-x="1812" d="M1161 6q-57 25 -98 123l-16 39q-12 25 -150 283l-18 36q-29 20 -58 -36q-31 -59 -43 -68l-86 -143q-12 -23 -20 -43q-10 -12 -25 -76q-12 -45 -39 -58q-35 -49 -100 -51q-47 0 -70 31q-35 33 -47 129q-2 27 -6 41l-66 211q-49 197 -79 377l-41 198q-4 18 -56 199 q-25 78 58 113q35 14 73 12q66 0 95 -59q14 -35 4 -68q4 -102 30 -223l21 -156l8 -35q25 -143 80 -348q8 -43 33 -45q18 -2 26 33l121 176q41 88 82 205q8 84 72 104q20 6 45 2q117 -31 113 -104q0 -16 -7 -33q-2 -55 45 -176q8 -18 13 -33q14 -18 61 -114q27 -51 53 -76 q25 37 54 155q8 33 14 54l53 198q6 12 37 131q12 39 25 66q10 57 84 178q23 37 34 62q27 115 189 61q57 -55 8 -137l-96 -137l-23 -43q-18 -39 -73 -220l-15 -43q-2 -25 -39 -178q-6 -25 -10 -45q4 14 -88 -340q6 -53 -63 -98q-43 -29 -46 -29q-20 -22 -53 -2z" />
<glyph glyph-name="X" unicode="X" horiz-adv-x="1372" d="M1022 25q-74 27 -111 135q-53 90 -110 231q-12 31 -84 168q-8 6 -31 74q-18 49 -45 37l-113 -168q-63 -90 -90 -156q4 -102 -65 -182q-16 -82 -123 -76q-20 2 -41 6q-68 14 -66 90q2 41 27 74q66 133 145 258q45 66 103 166l106 174q4 6 8 14q27 39 -20 123 q-12 23 -16 33q-23 49 -84 154q-10 25 -70 96q-37 45 -47 82q-8 63 39 96q29 18 61 12q104 23 144 -84l63 -131l4 -12l70 -139l12 -17l111 136l22 22l166 189q39 39 74 67q57 29 121 12l12 -4q53 -14 51 -73q-2 -39 -26 -62l-76 -90q-16 -14 -33 -27q-209 -225 -217 -235 q-43 -49 -76 -94q-51 -39 -8 -117l22 -43l74 -164q16 -25 62 -129q14 -33 28 -53q49 -109 121 -207q59 -29 45 -96q-6 -35 -35 -60l-59 -35q-25 -9 -45 5z" />
<glyph glyph-name="Y" unicode="Y" horiz-adv-x="1222" d="M287 0q-61 37 -76 94q-8 33 8 58q63 125 78 182l72 164l67 163q20 33 68 154q4 10 6 16q59 78 -2 146q-12 12 -27 24q-72 72 -166 256q-8 12 -12 21q-6 14 -78 121q-12 17 -20 31q-45 70 -21 137q14 35 47 49q106 35 156 -23l8 -12q8 -12 76 -168l68 -143q8 -14 18 -27 q49 -74 51 -76q41 -47 60 23l98 211q10 20 47 125q10 29 21 49q51 51 133 43q8 0 14 -2q63 16 98 -45q12 -20 13 -45q-10 -12 -5 -58q2 -23 -4 -32l-118 -113q-2 -4 -4 -6q-82 -141 -97 -178q-2 -8 -6 -15q-18 -33 -76 -174l-86 -166q-39 -96 -78 -155q-8 -33 -59 -131 q-25 -45 -33 -78q-43 -80 -63 -191q-4 -10 -17 -108q-8 -68 -43 -98q-55 -33 -106 -27q-6 2 -10 4z" />
<glyph glyph-name="Z" unicode="Z" horiz-adv-x="1402" d="M197 0q-47 25 -58 84q-4 20 2 33q-29 68 19 96q8 6 20 8q14 39 68 55q4 0 12 3q106 117 146 194l102 156l88 139l139 229l90 146q8 31 -28 31l-90 -9q-123 -31 -158 -51q-6 -4 -14 -8q-100 -39 -150 8q-49 25 -57 82q-4 31 12 53q29 41 133 56q29 4 41 6q160 33 309 51 q78 20 248 20q63 10 76 -73q2 -14 2 -33q33 -63 -64 -139q-41 -43 -129 -176q-29 -45 -51 -74l-194 -297q-18 -25 -101 -158q-14 -18 -94 -158q-6 -10 -10 -18q12 -35 98 -25q47 6 64 5q39 6 180 10q262 8 364 2q59 -35 39 -123q-2 -8 -6 -16q0 -72 -94 -72q-35 0 -66 10 q-78 14 -286 6q-41 -2 -72 -2l-270 -16q-39 -6 -74 -12q-23 -23 -98 -17q-39 2 -52 -6q-9 -12 -36 0z" />
<glyph glyph-name="bracketleft" unicode="[" horiz-adv-x="1144" d="M139 -135q10 10 25 127q10 74 22 110q0 41 29 222q8 53 10 88l43 276l62 275q6 37 6 69l35 221q4 55 0 101q10 106 104 135q53 16 117 0l295 -55q31 -4 55 -4q88 -12 82 -87q-4 -61 -55 -94q-29 -18 -58 -12q-43 -2 -270 27q-31 4 -53 6q-37 -88 -60 -324 q-16 -158 -36 -229q-8 -98 -35 -348q-2 -37 -51 -240q-35 -150 -19 -190q33 -8 201 10q172 20 194 -31q14 -31 -10 -86q-66 -106 -242 -106q-45 0 -84 8q-63 -12 -174 -15q-63 -47 -108 21q-37 53 -25 125z" />
<glyph glyph-name="backslash" unicode="\" horiz-adv-x="1101" d="M145 1421q41 92 109 27q14 -14 29 -35q14 -63 94 -209q27 -51 43 -86q78 -166 98 -203q27 -14 31 -90q0 -20 6 -22q4 -2 16 10l117 -219q43 -61 139 -256q8 -31 72 -121q59 -82 41 -129q0 -59 -41 -84l-8 -4q-72 -35 -148 88q14 41 -69 203q-8 14 -12 24 q-113 207 -132 256l-157 291q-178 324 -240 471q-13 57 12 88z" />
<glyph glyph-name="bracketright" unicode="]" horiz-adv-x="1124" d="M154 -154q37 82 141 72q25 -4 55 -10q162 -8 213 12q72 29 70 111q4 35 4 241q2 82 8 136q-4 51 27 202q10 61 10 99q-4 72 31 258q23 115 18 186q35 121 -74 166q-39 16 -86 14q-45 -6 -98 29q-27 18 -49 -14q-86 -25 -158 45q-61 61 -35 112q18 37 82 45l387 -20 l177 -29q80 -23 75 -112l-28 -377q-8 -61 -19 -115q-20 -68 -28 -264q-6 -100 -21 -162q-14 -319 -12 -365q0 -49 4 -96q27 -82 -12 -143q-31 -51 -37 -66q-43 -20 -135 -22q-51 -2 -93 -12q-164 -63 -307 -19q-49 -23 -88 25q-24 30 -22 73z" />
<glyph glyph-name="asciicircum" unicode="^" horiz-adv-x="2048" d="M264 1106q25 47 86 127l25 33l121 178q16 23 34 39q59 27 82 4q33 -33 45 -39q72 -94 207 -193q72 -35 88 -67q8 -18 6 -39q39 -80 -6 -115q-31 -23 -80 4q-41 18 -170 129q-78 66 -118 86l-129 -127q-20 -25 -37 -51q-61 -66 -86 -71q-18 -6 -74 -3q-31 10 -10 60 q14 33 16 45z" />
<glyph glyph-name="underscore" unicode="_" horiz-adv-x="1167" d="M-27 -31l107 25q29 2 82 -6l207 -2q209 6 297 0l356 -2h4q86 12 160 -27q59 -14 37 -49q-27 -37 -105 -37q-176 -16 -317 -2l-228 4h-262l-231 -6q-31 0 -55 4q-68 12 -74 55q-2 12 4 23q12 16 18 20z" />
<glyph glyph-name="grave" unicode="`" horiz-adv-x="481" d="M102 1468q-4 49 31 76q23 16 49 4q20 12 64 -10q6 -4 10 -4q8 -10 39 -70q8 -14 16 -24q20 -25 62 -117q8 -18 16 -33q-2 -2 4 -20q2 -8 -6 -8q-4 -2 -12 2q-47 -29 -60 -31q-10 0 -20 2q0 12 -21 12q-18 2 -22 19l-72 98q-6 10 -14 18q-6 12 -41 50q-19 18 -23 36z" />
<glyph glyph-name="a" unicode="a" horiz-adv-x="1140" d="M885 0q-119 37 -162 170q0 6 -2 12q0 47 -35 66q-37 16 -51 -37q-72 -104 -211 -174q-117 -33 -143 -33q-55 -4 -91 27q-70 66 -61 223l4 102q12 248 162 371q16 14 37 27q100 57 278 37q94 -4 131 -91q18 -45 9 -98l75 -199q20 -47 45 -84q2 -55 72 -131q59 -66 68 -104 q-41 -70 -72 -82q-24 -8 -53 -2zM393 201q113 113 168 262q29 82 -35 106q-51 20 -108 -18q-66 -33 -84 -154q-10 -82 -12 -92q2 -104 14 -123q18 -26 57 19z" />
<glyph glyph-name="b" unicode="b" horiz-adv-x="1058" d="M381 0q-14 4 -86 45q-47 27 -90 23q-57 47 -43 161q8 76 8 74q39 213 43 248q14 238 43 455q10 35 14 168q2 96 33 149q31 41 123 43q29 2 39 2q78 -45 41 -176q-68 -248 -92 -647q27 -10 139 -19q94 -6 139 -47q102 -66 117 -170q4 -31 -2 -61q-39 -143 -207 -209 l-61 -19l-115 -26q-25 0 -43 6zM516 215q51 -2 80 45q29 45 -14 59q-14 6 -39 5q-51 29 -101 -19q-43 -43 -16 -76q10 -12 33 -18q34 -14 57 4z" />
<glyph glyph-name="c" unicode="c" horiz-adv-x="880" d="M350 0q-100 23 -145 127q-8 20 -12 41q-33 139 36 289q14 72 121 161q41 33 45 35q176 61 262 -49q43 -49 35 -117q-4 -20 -12 -34q-57 -76 -135 -43q-31 12 -56 41q-109 -31 -112 -220q27 -72 108 -45l105 37q39 10 67 -4q51 -72 -59 -156q-43 -31 -84 -47 q-66 -26 -164 -16z" />
<glyph glyph-name="d" unicode="d" horiz-adv-x="1044" d="M788 -98q-78 16 -104 129l-29 123q-2 2 -2 4q-2 72 -28 104q-20 29 -43 -41q-37 -139 -193 -213q-16 -8 -33 -14q-117 8 -180 149q-16 37 -26 76q-23 254 90 379q59 76 202 72q43 -6 60 57l16 80q23 102 12 342q-6 197 19 303q8 100 123 76q35 -6 67 -23q45 -16 43 -108 q-2 -55 0 -72q8 -223 -22 -508q2 -111 53 -401q12 -70 18 -119q35 -166 41 -180q12 -39 29 -70q72 -98 -39 -133q-33 -10 -74 -12zM389 324q35 39 19 86q-14 37 -35 14q-10 -12 -17 -37q-23 -47 -12 -90q8 -41 45 27z" />
<glyph glyph-name="e" unicode="e" horiz-adv-x="1058" d="M520 766h21q127 4 200 -80q35 -41 43 -90q2 -119 -116 -186q-72 -43 -152 -37q-70 33 -92 -17q-18 -41 16 -90q29 -119 203 -76q10 2 19 7q49 47 131 36q78 -8 79 -65q0 -20 -8 -43q-94 -104 -323 -125q-221 43 -283 180q-86 158 12 400q117 194 250 186zM559 594 q-4 -2 -67 -14q-27 -47 14 -52q39 -4 63 25q19 23 -10 41z" />
<glyph glyph-name="f" unicode="f" horiz-adv-x="1060" d="M391 0q-68 -10 -104 53q-25 45 -6 92q0 8 32 119q33 115 -32 133q-12 4 -27 4q-78 -6 -102 72q-23 76 22 129q16 18 39 27q100 -25 121 -23q57 6 41 86l26 336q12 160 70 295q59 96 188 66q61 -14 109 -54q160 -113 160 -245q0 -8 -2 -19q-2 -72 -74 -100 q-76 -29 -123 26q-8 10 -14 23q-10 59 -51 102q-41 45 -48 -30v-19q-29 -193 -47 -434q27 -43 111 -29q94 16 127 4q20 -10 37 -28q76 -66 2 -137q-61 -57 -141 -58q-158 -2 -187 -65q-12 -29 -4 -72l-14 -143q-20 -94 -101 -119z" />
<glyph glyph-name="g" unicode="g" horiz-adv-x="1085" d="M469 -387q-158 20 -276 147q-59 57 -54 140q6 74 74 92q92 20 129 -94q4 -12 8 -29q90 -94 221 -88q96 -2 140 72q37 61 -2 129q-66 184 -88 229q-4 10 -11 20q-23 6 -123 -4q-98 -8 -135 47q-59 63 -73 207q-25 160 73 289q57 76 140 107q156 27 217 -54q14 -16 20 -39 q31 -45 8 -143q-18 -84 -4 -121q10 -23 6 -102q-2 -66 31 -101l49 -153q12 -29 31 -53q96 -135 45 -332q-47 -80 -209 -137q-6 -2 -14 -4q-121 -43 -203 -25zM545 528q12 55 -35 74q-37 14 -47 -14q-8 -20 8 -53q-33 -39 2 -60q35 -18 59 8q17 16 13 45z" />
<glyph glyph-name="h" unicode="h" horiz-adv-x="888" d="M594 -111q-47 43 -62 162q-8 68 -16 94q-33 127 -72 127q-20 0 -38 -49q-8 -72 -50 -108q-23 -23 -45 -8q-47 -45 -110 -7q-55 31 -56 88l25 101q6 10 12 22q18 45 37 199q4 45 12 76q29 440 33 592q-29 70 19 125q37 45 92 32q119 -2 110 -133q-2 -39 -16 -82 q-10 -57 -41 -405q-6 -61 -10 -109q-14 -100 33 -108q14 0 34 4q127 -39 185 -162q16 -37 24 -76l49 -160q18 -78 2 -139q-6 -68 -108 -76q-23 -2 -43 0z" />
<glyph glyph-name="i" unicode="i" horiz-adv-x="770" d="M326 0q-98 23 -70 182l6 31q0 43 31 188q12 53 14 91q2 78 76 104.5t125 -29.5q12 -12 18 -28q25 -49 -8 -140q-20 -59 -22 -88q-12 -33 -19 -151q-4 -66 -20 -97q-6 -41 -74 -61q-34 -10 -57 -2zM414 645q-72 6 -88.5 80t34.5 117q39 35 125 12q63 -16 76 -55 q49 -68 -31 -129q-39 -29 -79 -33q-6 -12 -37 8z" />
<glyph glyph-name="j" unicode="j" horiz-adv-x="1064" d="M426 -336q-172 35 -236 100q-10 10 -18 23q-51 39 -20 115q29 68 90 69q14 2 30 -4q43 -2 66 -57q20 -49 41 -57q14 -6 39 -3q174 -27 272 29q102 59 17 248q-4 10 -13 29q-31 49 -86 206l-4 13q-53 117 -14 225q8 27 24 49q31 68 113 39q68 -23 88 -78q-31 -176 10 -272 q92 -184 121 -287q35 -133 -43 -233q-25 -31 -57 -54q-147 -115 -264 -104q-105 0 -156 4zM713 909q-72 4 -80 86q-4 66 31 109q61 49 149 6q41 -20 59 -53q8 -84 -55 -131q-47 -35 -104 -17z" />
<glyph glyph-name="k" unicode="k" d="M199 14q-53 55 -17 164q35 111 37 137v15q6 29 51 317q10 63 21 113q-2 43 24 213q8 61 9 106q12 84 88 117q72 33 131 -16q98 -45 2 -195q-25 -80 -53 -307q-18 -57 6 -51q29 6 55 53q6 12 8 22q63 45 137 0q74 -43 60 -114q-2 -18 -15 -37q-78 -63 -92 -86 q-35 -57 45 -98q8 -12 82 -86q76 -72 72 -138q31 -59 -31 -104q-55 -39 -102 -14l-121 155q-27 29 -55 47q-43 66 -88 80q-39 12 -39 -55q-6 -18 -21 -127q-12 -106 -78 -123q-4 -2 -8 -2q-39 -20 -88 0q-12 6 -20 14z" />
<glyph glyph-name="l" unicode="l" horiz-adv-x="800" d="M313 0q-66 -16 -90 55q-20 55 6 97q39 158 62 485q27 150 35 367q-10 80 63 120q74 43 135 -6l13 -12q49 -47 24 -160q-14 -63 -16 -80q-16 -113 -47 -360l-35 -393q-2 -10 -2 -23q-4 -78 -80 -88q-19 -2 -68 -2z" />
<glyph glyph-name="m" unicode="m" horiz-adv-x="1433" d="M1124 -31q-100 -4 -129 109l-24 143l-21 94q-12 27 -37 -32q-10 -16 -65 -133q-53 -113 -129 -140q-61 -37 -123 13q-59 49 -35 118l10 154q-2 49 -18 61q-27 -74 -133 -227l-31 -47q-74 -41 -151 0q-80 43 -54 135q25 156 19 299q-18 104 22 172q37 59 109 29 q41 2 78 -62q27 -43 39 -45q18 -2 45 52q66 66 155 20q80 -39 90 -119q20 -72 56 -31l71 97q41 43 78 30q66 23 127 -45q49 -6 109 -165q20 -59 26 -72q57 -137 11 -318q16 -47 -43 -77q-29 -17 -52 -13z" />
<glyph glyph-name="n" unicode="n" horiz-adv-x="1107" d="M758 10q-47 57 -53 191q-4 78 -11 108q8 90 -37 105q-45 12 -84 -64q-29 -33 -77 -145q-23 -57 -47 -90q-12 -96 -115 -101q-53 -4 -107 23q-41 47 -20 168q18 111 10 151l14 240l9 43q27 61 98 80q78 16 100 -43q4 -14 6 -31l19 -94q12 -27 49 31q90 90 186 80 q51 -4 88 -48q70 -68 107 -239l12 -64q-6 -31 21 -149q25 -117 -23 -148q-16 -10 -43 -14l-69 -12q-21 2 -33 22z" />
<glyph glyph-name="o" unicode="o" d="M444 -2q-123 16 -217 195q-102 252 -10 446q4 6 8 14q20 86 158 125q135 45 283 -59q16 -12 32 -27q23 -27 66 -131q33 -84 82 -115q72 -141 18 -253q-10 -23 -26 -41q-63 -121 -224 -148q-43 -6 -86 -4zM543 182q80 8 102 94q16 72 -20 130q-31 16 -84 102 q-51 80 -92 78q-29 0 -64 -33q-47 -182 33 -344q27 -45 125 -27z" />
<glyph glyph-name="p" unicode="p" horiz-adv-x="1017" d="M242 -362q-113 33 -39 223q4 6 6 14l55 342l4 49q6 23 21 156q10 96 47 147q47 43 131 49q51 4 76 11q137 20 233 -62q18 -14 31 -30q72 -80 49 -183q-10 -43 -39 -75q-80 -137 -205 -191q-16 -8 -104 -25q-78 -12 -84 -63q-2 -16 2 -41q-8 -23 -18 -154 q-10 -113 -62 -151q-57 -30 -104 -16zM543 279q53 23 73 75q25 63 -47 74q-41 -4 -73 -68q-35 -68 0 -86q16 -5 47 5z" />
<glyph glyph-name="q" unicode="q" horiz-adv-x="1114" d="M680 -387q-160 76 -166 262q-16 35 -6 137q6 88 -37 111q-135 2 -225 115q-39 49 -56 106q-55 164 25 281q53 109 193 123q104 10 186 -43q72 -43 115 -173l18 -59q-2 -31 45 -78q47 -49 37 -86q-27 -35 -29 -131q-4 -94 -53 -129q-6 -29 29 -29q68 0 75 -2q20 -8 29 -26 q121 -55 111 -199q0 -12 -2 -26q-70 -147 -219 -154q-29 -20 -70 0zM754 -156q14 35 -23 82q-18 25 -18 2q0 -12 6 -34q8 -63 12 -70q11 -7 23 20zM451 342q29 72 12 141q-8 45 -41 49q-43 -25 -45 -104.5t45 -89.5q13 -2 29 4z" />
<glyph glyph-name="r" unicode="r" horiz-adv-x="978" d="M252 0q-80 33 -62 322v22q4 31 -2 188q-2 66 5 109q-12 82 59 119q66 37 121 -8q25 -18 35 -52l18 -125q16 -51 92 7q100 33 184 -7q72 -35 82 -116q12 -102 -63 -103l-105 15q-141 39 -174 -127q-14 -76 -10 -197q0 -45 -88 -55q-53 -4 -92 8z" />
<glyph glyph-name="s" unicode="s" d="M479 0q-174 25 -256 109q-61 20 -57 96q4 70 55 92q29 12 64 -2q152 -90 282 -76q117 6 -12 98q-41 29 -80 50q-123 100 -158 143q-16 20 -28 39q-53 55 -39 145q8 61 47 82q92 104 264 90q123 -10 189 -110q8 -14 16 -31q43 -55 -12 -121q-49 -61 -109 -47 q-33 -6 -90 43q-47 41 -72 23q37 -70 162 -148q41 -25 45 -29q172 -111 187 -264q2 -12 2 -24q-29 -109 -183 -142q-8 -2 -18 -4q-140 -22 -199 -12z" />
<glyph glyph-name="t" unicode="t" horiz-adv-x="1144" d="M381 25q-104 51 -49 219l47 397q2 18 2 39q20 111 10 137q-14 41 -72 19q-72 -27 -139 18q-66 43 -41 113q31 70 156 98q98 25 113 31q33 113 47 137q35 61 98 63q76 0 117 -104q2 -6 18 -47q18 -18 100 -19q68 0 95 -22q59 -23 75 -94q16 -80 -47 -105q-12 -6 -28 -8 q-25 -10 -131 -6q-100 4 -119 -45q-2 -8 -4 -19l-31 -254l-33 -288q-6 -18 -12 -129q-6 -106 -68 -125q-8 -2 -18 -4q-57 -16 -74 -11z" />
<glyph glyph-name="u" unicode="u" horiz-adv-x="1144" d="M815 -4q-63 -2 -141 76q-35 37 -49 47q-68 -86 -203 -115q-39 -8 -74 -8q-100 0 -147 100q-27 55 -19 117q4 213 49 375q41 106 109 98q25 -4 49 -24q59 -47 62 -103q0 -29 -21 -47q-39 -72 -37 -166q4 -70 41 -74q51 -16 96 97q23 57 52 163q23 86 80 91q51 4 71 -54 q10 -29 6 -63q-6 -63 49 -189q25 -59 35 -90q8 -39 74 -67.5t76 -55.5q8 -16 4 -36q18 -55 -70 -72q-51 -8 -92 0z" />
<glyph glyph-name="v" unicode="v" horiz-adv-x="1193" d="M436 0q-80 59 -135 215q-41 113 -53 139l-55 158q-29 102 24 170q74 63 164 4q76 -47 80 -121q0 -14 -2 -26q-23 -43 6 -131q23 -72 53 -68q23 4 45 57q139 203 197 340q12 86 88 105q72 18 113 -35q29 -35 20 -88q-16 -94 -115 -264q-33 -59 -49 -93l-131 -204 q-92 -131 -207 -158q-29 -8 -43 0z" />
<glyph glyph-name="w" unicode="w" horiz-adv-x="1519" d="M909 -49q-96 37 -131 178l-33 147l-96 -151q-51 -68 -112 -74q-88 -29 -142 96q-12 29 -20 60q-72 135 -158 360q-68 94 -51 183q14 82 108 92q106 0 152 -185q8 -14 43 -120q25 -82 55 -84q10 0 21 6q20 33 41 145q18 111 82 141q106 37 170 -51q43 -57 39 -131l75 -250 q39 18 101 158q43 96 65 129q25 76 99 96q84 25 126 -49l9 -16q20 -92 -66 -238q-59 -104 -69 -129q-76 -150 -101 -184q-49 -68 -112 -98q-14 2 -54 -23q-23 -14 -41 -8z" />
<glyph glyph-name="x" unicode="x" horiz-adv-x="1298" d="M260 -16q-84 12 -72 98q10 78 76 127q10 23 80 82q72 66 49 110q-8 16 -26 31l-74 160q-37 102 20 164q109 82 197 -62q41 -66 57 -141q55 -16 152 90q88 96 117 117q49 72 135 39q74 -27 88 -97q6 -27 -2 -53q-33 -74 -150 -162q-113 -86 -149 -133q-12 -41 51 -118 q70 -86 72 -136q33 -45 -9 -88q-43 -45 -92 -12q-61 14 -131 98q-53 68 -84 88q-80 -66 -213 -204q-69 -2 -92 2z" />
<glyph glyph-name="y" unicode="y" horiz-adv-x="1316" d="M301 -393q-174 10 -70 211q23 41 54 84q33 51 196 338q76 129 133 213q-18 82 -127 231q-84 117 -110 182q-43 59 16 125q55 61 121 43q37 -10 59 -49q10 -12 74 -139q59 -117 123 -133q10 14 74 147q49 100 104 133q88 25 139 -55q49 -80 11 -154q-12 -25 -33 -41 q-145 -240 -238 -378q-16 -31 -161 -242q-82 -121 -123 -209q-35 -45 -111 -207l-33 -63q-4 -35 -82 -37h-16z" />
<glyph glyph-name="z" unicode="z" horiz-adv-x="1605" d="M326 0q-166 39 -39 254q29 49 67 96q20 39 138 176q86 104 86 146q-53 10 -213 2q-61 -4 -93 4q-94 31 -88 115q6 72 76 106q53 27 115 4q293 2 424 -29q43 -10 80 -24q102 -109 -27 -256q-20 -25 -57 -62q-18 -35 -123 -141q-88 -88 -82 -123q145 25 459 6 q150 -8 231 -6q102 -47 74 -125q-23 -66 -101 -88q-47 -12 -94 0q-37 -2 -293 8q-238 10 -377 -51l-133 -14q-16 0 -30 2z" />
<glyph glyph-name="braceleft" unicode="{" horiz-adv-x="1126" d="M682 -203q-84 -2 -158 82q-76 90 -84 96q-12 14 -26 23q-41 66 -21 209q20 137 2 192q-6 20 -18 39q-20 20 -125 76q-96 51 -98 96q-2 33 32 72q37 84 144 78q66 -4 96 -39q61 14 35 104l-35 121q-6 37 2 60q-23 252 119 378q12 10 24 19q139 135 301 33q63 -61 21 -140 q-41 -72 -121 -71q-12 2 -27 4q-139 -29 -92 -303q2 -18 6 -37q82 -106 46 -223q-25 -76 -95 -117q-33 -33 -2 -111q33 -90 19 -129q-33 -127 0 -209q33 -84 127 -39q66 43 135 -4q66 -45 45 -108q-8 -29 -33 -51q-90 -95 -219 -101z" />
<glyph glyph-name="bar" unicode="|" horiz-adv-x="696" d="M199 -242q-100 152 -15 316q45 182 41 291q-2 16 -2 147q31 33 23 145q-6 88 6 123q-16 14 2 47t0 50l22 141q0 23 -4 39q29 141 27 272q2 172 51 184q12 4 31 -2q16 8 22 5q4 -4 43 14l80 -92q51 -74 23 -150q-57 -131 -78 -401q-10 -127 -16 -180q-4 -39 -31 -474 q-6 -119 -16 -208l2 -158q-6 -70 -66 -105q-67 -39 -145 -4z" />
<glyph glyph-name="braceright" unicode="}" horiz-adv-x="1286" d="M467 -276q-317 37 -285 192q4 16 11 33q45 88 151 57l139 -49q33 -8 58 -4q74 61 26 180l-63 148q-18 55 -10 96q2 25 38 137q35 106 -22 170q-39 113 57 297q78 145 76 141q41 78 -14 80l-137 -10q-84 4 -99 74q-33 113 146 159q20 4 47 11q117 53 207 -27 q53 -45 69 -117q39 -131 -18 -268q-18 -43 -43 -74q-72 -78 -49 -139q23 -70 135 -31l12 4q135 -6 188 -69q29 -35 17 -80q-18 -92 -135 -127l-152 -41q-6 -2 -14 -6q-96 -82 6 -291q4 -10 12 -25q39 -143 -53 -272q-25 -37 -59 -66q-92 -96 -209 -88z" />
<glyph glyph-name="asciitilde" unicode="~" d="M639 522q-74 -20 -133 62q-25 37 -33 75q-35 29 -88 -26t-76 -64q-8 -2 -16 -2q-57 -4 -90 54q-29 47 -2 88q80 104 186 147q72 43 145 -12q31 -25 48 -60q20 -78 71 -82q29 -4 58 25q156 76 165 -16q0 -4 3 -11q14 -27 -23 -84q-53 -59 -182 -86q-6 0 -33 -8z" />
<glyph glyph-name="quoteleft" unicode="&#x2018;" horiz-adv-x="419" d="M102 1534q29 61 86 31q4 -2 9 -6q29 -23 67 -107q8 -18 15 -31q51 -78 55 -94q12 -33 4 -61q-6 -4 -35 -49q-16 -29 -51 0q-68 39 -94 143q-68 86 -68 139q2 15 12 35z" />
<glyph glyph-name="quoteright" unicode="&#x2019;" horiz-adv-x="444" d="M82 1313q59 90 84 166q47 76 84 88q25 6 51 -2q45 23 66 -19q10 -18 4 -41q-16 -61 -101 -180q-37 -61 -141 -108q-63 12 -63 40q0 21 16 56z" />
<glyph glyph-name="quotedblleft" unicode="&#x201c;" horiz-adv-x="794" d="M240 1075q-86 31 -107 150q-10 63 8 114q14 100 90 174q61 59 123 50q164 -55 -47 -236q-4 -4 -14 -12q-16 -37 31 -111q41 -63 24 -88q-12 -18 -53 -31q-22 -16 -55 -10zM514 1098q-113 78 -53 321q-18 78 51 117q61 35 104 -2q25 -23 23 -66q-68 -201 -2 -276 q16 -18 39 -31q-29 -70 -137 -65q-9 2 -25 2z" />
<glyph glyph-name="quotedblright" unicode="&#x201d;" horiz-adv-x="856" d="M203 1106q-20 35 -15 135q8 106 -41 156q-4 2 -8 6q-2 96 66 94q61 -2 110 -67q35 -47 31 -95q23 -86 -12 -174q-39 -100 -131 -55zM543 1102q-80 16 -49 76l59 100q31 72 -45 113q-68 35 -53 106q10 55 57 68q41 10 80 -39q121 -92 133 -221q8 -76 -31 -142 q-51 -59 -131 -63q-10 0 -20 2z" />
<glyph glyph-name="bullet" unicode="&#x2022;" horiz-adv-x="708" d="M578 659q29 -102 -37 -202q-68 -106 -172 -80q-14 4 -27 10q-66 -6 -121 80q-68 109 -26 211q20 51 71 86q123 92 254 -35q31 -31 58 -70z" />
</font>
</defs></svg>
\ No newline at end of file
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Todo App</title>
<link rel="stylesheet" href="app.css" type="text/css" media="screen" charset="utf-8">
<script src="http://code.jquery.com/jquery-1.6.1.min.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/sammy.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/sammy.template.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/model.js" type="text/javascript" charset="utf-8"></script>
<script src="app.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
if (!'localStorage' in window) {
alert('Your browser does not support localStorage');
}
</script>
</head>
<body>
<div id="todoapp">
<div class="title">
<h1>Todos</h1>
</div>
<div class="content">
<div id="create-todo">
<input id="new-todo" placeholder="What needs to be done?"
type="text" />
<span class="ui-tooltip-top" style="display: none;">Press Enter to save this task</span>
</div>
<div id="todos">
<ul id="todo-list">
</ul>
</div>
<div id="todo-stats">
</div>
</div>
</div>
<div id="credits">
This version by
<br />
<a href="http://twitter.com/addyosmani">Addy Osmani</a>
<br />
based on some code by Brandon Aaron
</div>
</body>
</html>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
Model = {
name: 'model',
init: function() {
this._id = 0;
this._data = [];
this._deserialize();
return this;
},
create: function(attributes, save) {
attributes.id = this._newId();
var item = this._data[ (this._data.push(attributes)) - 1 ];
if (save !== false) {
this.save();
}
return this._clone(item);
},
first: function() {
return this._clone(this._data[0]);
},
last: function() {
return this._clone(_data[ this._data.length-1 ]);
},
get: function(id) {
return this._clone(this._get(id));
},
getAll: function() {
return this._clone(this._data);
},
filter: function(attribute, value) {
return this._clone(this._filter(attribute, value));
},
multiFilter: function(filters) {
return this._clone(this._multiFilter(filter));
},
update: function(id, attributes, save) {
var item = this._get(id) || false;
if (item) {
this._mixin(item, attributes);
if (save !== false) {
this.save();
}
}
return item;
},
destroy: function(id, save) {
this._data.splice(this._indexOf(id), 1);
if (save !== false) {
this.save();
}
return true;
},
destroyAll: function(save) {
this._data = [];
if (save !== false) {
this.save();
}
return true;
},
save: function() {
this._serialize();
return true;
},
_first: function() {
return this._data[0];
},
_last: function() {
return _data[ this._data.length-1 ];
},
_get: function(id) {
return this._filter('id', id)[0];
},
_filter: function(attribute, value) {
var items = [], key, item, undefValue = (typeof value == "undefined");
for (key in this._data) {
if (this._data.hasOwnProperty(key)) {
item = this._data[key];
if (undefValue || item[attribute] == value) {
items.push(item);
}
}
}
return items;
},
_multiFilter: function(filters) {
var items = [], key, attribute, item;
for (key in this._data) {
if (this._data.hasOwnProperty(key)) {
item = this._data[key];
for (attribute in filters) {
if (filters.hasOwnProperty(attribute)) {
if (filters[attribute] == item[attribute]) {
items.push(item);
}
}
}
}
}
return items;
},
_indexOf: function(id) {
return this._data.indexOf(this._get(id));
},
_serialize: function() {
var data = {
prevId: this._id,
data: this._data
};
localStorage[this.name] = JSON.stringify(data);
},
_deserialize: function() {
var data = localStorage[this.name];
if (data) {
data = JSON.parse(data);
this._id = data.prevId;
this._data = data.data;
}
},
_newId: function() {
return this._id++;
},
_mixin: function(to, from) {
for (var key in from) {
if (from.hasOwnProperty(key)) {
to[key] = from[key];
}
}
},
_clone: function(obj) {
var type = Object.prototype.toString.call(obj),
cloned = obj;
if (type == '[object Object]') {
cloned = {};
for (var key in obj) {
obj.hasOwnProperty(key) && (cloned[key] = this._clone(obj[key]));
}
} else if (type == '[object Array]') {
cloned = [];
for (var index = 0, length = obj.length; index < length; index++) {
cloned[index] = this._clone(obj[index]);
}
}
return cloned;
}
};
// http://javascript.crockford.com/prototypal.html
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
\ No newline at end of file
// name: sammy
// version: 0.5.1
(function($) {
var Sammy,
PATH_REPLACER = "([^\/]+)",
PATH_NAME_MATCHER = /:([\w\d]+)/g,
QUERY_STRING_MATCHER = /\?([^#]*)$/,
_decode = decodeURIComponent,
_routeWrapper = function(verb) {
return function(path, callback) { return this.route.apply(this, [verb, path, callback]); };
},
loggers = [];
// <tt>Sammy</tt> (also aliased as $.sammy) is not only the namespace for a
// number of prototypes, its also a top level method that allows for easy
// creation/management of <tt>Sammy.Application</tt> instances. There are a
// number of different forms for <tt>Sammy()</tt> but each returns an instance
// of <tt>Sammy.Application</tt>. When a new instance is created using
// <tt>Sammy</tt> it is added to an Object called <tt>Sammy.apps</tt>. This
// provides for an easy way to get at existing Sammy applications. Only one
// instance is allowed per <tt>element_selector</tt> so when calling
// <tt>Sammy('selector')</tt> multiple times, the first time will create
// the application and the following times will extend the application
// already added to that selector.
//
// === Example
//
// // returns the app at #main or a new app
// Sammy('#main')
//
// // equivilent to "new Sammy.Application", except appends to apps
// Sammy();
// Sammy(function() { ... });
//
// // extends the app at '#main' with function.
// Sammy('#main', function() { ... });
//
Sammy = function() {
var args = $.makeArray(arguments),
app, selector;
Sammy.apps = Sammy.apps || {};
if (args.length === 0 || args[0] && $.isFunction(args[0])) { // Sammy()
return Sammy.apply(Sammy, ['body'].concat(args));
} else if (typeof (selector = args.shift()) == 'string') { // Sammy('#main')
app = Sammy.apps[selector] || new Sammy.Application();
app.element_selector = selector;
if (args.length > 0) {
$.each(args, function(i, plugin) {
app.use(plugin);
});
}
// if the selector changes make sure the refrence in Sammy.apps changes
if (app.element_selector != selector) {
delete Sammy.apps[selector];
}
Sammy.apps[app.element_selector] = app;
return app;
}
};
Sammy.VERSION = '0.5.1';
// Add to the global logger pool. Takes a function that accepts an
// unknown number of arguments and should print them or send them somewhere
// The first argument is always a timestamp.
Sammy.addLogger = function(logger) {
loggers.push(logger);
};
// Sends a log message to each logger listed in the global
// loggers pool. Can take any number of arguments.
// Also prefixes the arguments with a timestamp.
Sammy.log = function() {
var args = $.makeArray(arguments);
args.unshift("[" + Date() + "]");
$.each(loggers, function(i, logger) {
logger.apply(Sammy, args);
});
};
if (typeof window.console != 'undefined') {
if ($.isFunction(console.log.apply)) {
Sammy.addLogger(function() {
window.console.log.apply(console, arguments);
});
} else {
Sammy.addLogger(function() {
window.console.log(arguments);
});
}
} else if (typeof console != 'undefined') {
Sammy.addLogger(function() {
console.log.apply(console, arguments);
});
}
// Sammy.Object is the base for all other Sammy classes. It provides some useful
// functionality, including cloning, iterating, etc.
Sammy.Object = function(obj) { // constructor
return $.extend(this, obj || {});
};
$.extend(Sammy.Object.prototype, {
// Returns a copy of the object with Functions removed.
toHash: function() {
var json = {};
$.each(this, function(k,v) {
if (!$.isFunction(v)) {
json[k] = v;
}
});
return json;
},
// Renders a simple HTML version of this Objects attributes.
// Does not render functions.
// For example. Given this Sammy.Object:
//
// var s = new Sammy.Object({first_name: 'Sammy', last_name: 'Davis Jr.'});
// s.toHTML() //=> '<strong>first_name</strong> Sammy<br /><strong>last_name</strong> Davis Jr.<br />'
//
toHTML: function() {
var display = "";
$.each(this, function(k, v) {
if (!$.isFunction(v)) {
display += "<strong>" + k + "</strong> " + v + "<br />";
}
});
return display;
},
// Generates a unique identifing string. Used for application namespaceing.
uuid: function() {
if (typeof this._uuid == 'undefined' || !this._uuid) {
this._uuid = (new Date()).getTime() + '-' + parseInt(Math.random() * 1000, 10);
}
return this._uuid;
},
// Returns an array of keys for this object. If <tt>attributes_only</tt>
// is true will not return keys that map to a <tt>function()</tt>
keys: function(attributes_only) {
var keys = [];
for (var property in this) {
if (!$.isFunction(this[property]) || !attributes_only) {
keys.push(property);
}
}
return keys;
},
// Checks if the object has a value at <tt>key</tt> and that the value is not empty
has: function(key) {
return this[key] && $.trim(this[key].toString()) != '';
},
// convenience method to join as many arguments as you want
// by the first argument - useful for making paths
join: function() {
var args = $.makeArray(arguments);
var delimiter = args.shift();
return args.join(delimiter);
},
// Shortcut to Sammy.log
log: function() {
Sammy.log.apply(Sammy, arguments);
},
// Returns a string representation of this object.
// if <tt>include_functions</tt> is true, it will also toString() the
// methods of this object. By default only prints the attributes.
toString: function(include_functions) {
var s = [];
$.each(this, function(k, v) {
if (!$.isFunction(v) || include_functions) {
s.push('"' + k + '": ' + v.toString());
}
});
return "Sammy.Object: {" + s.join(',') + "}";
}
});
// The HashLocationProxy is the default location proxy for all Sammy applications.
// A location proxy is a prototype that conforms to a simple interface. The purpose
// of a location proxy is to notify the Sammy.Application its bound to when the location
// or 'external state' changes. The HashLocationProxy considers the state to be
// changed when the 'hash' (window.location.hash / '#') changes. It does this in two
// different ways depending on what browser you are using. The newest browsers
// (IE, Safari > 4, FF >= 3.6) support a 'onhashchange' DOM event, thats fired whenever
// the location.hash changes. In this situation the HashLocationProxy just binds
// to this event and delegates it to the application. In the case of older browsers
// a poller is set up to track changes to the hash. Unlike Sammy 0.3 or earlier,
// the HashLocationProxy allows the poller to be a global object, eliminating the
// need for multiple pollers even when thier are multiple apps on the page.
Sammy.HashLocationProxy = function(app, run_interval_every) {
this.app = app;
// check for native hash support
if ('onhashchange' in window) {
Sammy.log('native hash change exists, using');
this.is_native = true;
} else {
Sammy.log('no native hash change, falling back to polling');
this.is_native = false;
this._startPolling(run_interval_every);
}
};
Sammy.HashLocationProxy.prototype = {
// bind the proxy events to the current app.
bind: function() {
var app = this.app;
$(window).bind('hashchange.' + this.app.eventNamespace(), function() {
app.trigger('location-changed');
});
},
// unbind the proxy events from the current app
unbind: function() {
$(window).die('hashchange.' + this.app.eventNamespace());
},
// get the current location from the hash.
getLocation: function() {
// Bypass the `window.location.hash` attribute. If a question mark
// appears in the hash IE6 will strip it and all of the following
// characters from `window.location.hash`.
var matches = window.location.toString().match(/^[^#]*(#.+)$/);
return matches ? matches[1] : '';
},
// set the current location to <tt>new_location</tt>
setLocation: function(new_location) {
return (window.location = new_location);
},
_startPolling: function(every) {
// set up interval
var proxy = this;
if (!Sammy.HashLocationProxy._interval) {
if (!every) { every = 10; }
var hashCheck = function() {
current_location = proxy.getLocation();
// Sammy.log('getLocation', current_location);
if (!Sammy.HashLocationProxy._last_location ||
current_location != Sammy.HashLocationProxy._last_location) {
setTimeout(function() {
$(window).trigger('hashchange');
}, 1);
}
Sammy.HashLocationProxy._last_location = current_location;
};
hashCheck();
Sammy.HashLocationProxy._interval = setInterval(hashCheck, every);
$(window).bind('beforeunload', function() {
clearInterval(Sammy.HashLocationProxy._interval);
});
}
}
};
// The DataLocationProxy is an optional location proxy prototype. As opposed to
// the <tt>HashLocationProxy</tt> it gets its location from a jQuery.data attribute
// tied to the application's element. You can set the name of the attribute by
// passing a string as the second argument to the constructor. The default attribute
// name is 'sammy-location'. To read more about location proxies, check out the
// documentation for <tt>Sammy.HashLocationProxy</tt>
Sammy.DataLocationProxy = function(app, data_name) {
this.app = app;
this.data_name = data_name || 'sammy-location';
};
Sammy.DataLocationProxy.prototype = {
bind: function() {
var proxy = this;
this.app.$element().bind('setData', function(e, key) {
if (key == proxy.data_name) {
proxy.app.trigger('location-changed');
}
});
},
unbind: function() {
this.app.$element().die('setData');
},
getLocation: function() {
return this.app.$element().data(this.data_name);
},
setLocation: function(new_location) {
return this.app.$element().data(this.data_name, new_location);
}
};
// Sammy.Application is the Base prototype for defining 'applications'.
// An 'application' is a collection of 'routes' and bound events that is
// attached to an element when <tt>run()</tt> is called.
// The only argument an 'app_function' is evaluated within the context of the application.
Sammy.Application = function(app_function) {
var app = this;
this.routes = {};
this.listeners = new Sammy.Object({});
this.arounds = [];
this.befores = [];
this.namespace = this.uuid();
this.context_prototype = function() { Sammy.EventContext.apply(this, arguments); };
this.context_prototype.prototype = new Sammy.EventContext();
if ($.isFunction(app_function)) {
app_function.apply(this, [this]);
}
// set the location proxy if not defined to the default (HashLocationProxy)
if (!this.location_proxy) {
this.location_proxy = new Sammy.HashLocationProxy(app, this.run_interval_every);
}
if (this.debug) {
this.bindToAllEvents(function(e, data) {
app.log(app.toString(), e.cleaned_type, data || {});
});
}
};
Sammy.Application.prototype = $.extend({}, Sammy.Object.prototype, {
// the four route verbs
ROUTE_VERBS: ['get','post','put','delete'],
// An array of the default events triggered by the
// application during its lifecycle
APP_EVENTS: ['run','unload','lookup-route','run-route','route-found','event-context-before','event-context-after','changed','error','check-form-submission','redirect'],
_last_route: null,
_running: false,
// Defines what element the application is bound to. Provide a selector
// (parseable by <tt>jQuery()</tt>) and this will be used by <tt>$element()</tt>
element_selector: 'body',
// When set to true, logs all of the default events using <tt>log()</tt>
debug: false,
// When set to true, and the error() handler is not overriden, will actually
// raise JS errors in routes (500) and when routes can't be found (404)
raise_errors: false,
// The time in milliseconds that the URL is queried for changes
run_interval_every: 50,
// The location proxy for the current app. By default this is set to a new
// <tt>Sammy.HashLocationProxy</tt> on initialization. However, you can set
// the location_proxy inside you're app function to give youre app a custom
// location mechanism
location_proxy: null,
// The default template engine to use when using <tt>partial()</tt> in an
// <tt>EventContext</tt>. <tt>template_engine</tt> can either be a string that
// corresponds to the name of a method/helper on EventContext or it can be a function
// that takes two arguments, the content of the unrendered partial and an optional
// JS object that contains interpolation data. Template engine is only called/refered
// to if the extension of the partial is null or unknown. See <tt>partial()</tt>
// for more information
template_engine: null,
// //=> Sammy.Application: body
toString: function() {
return 'Sammy.Application:' + this.element_selector;
},
// returns a jQuery object of the Applications bound element.
$element: function() {
return $(this.element_selector);
},
// <tt>use()</tt> is the entry point for including Sammy plugins.
// The first argument to use should be a function() that is evaluated
// in the context of the current application, just like the <tt>app_function</tt>
// argument to the <tt>Sammy.Application</tt> constructor.
//
// Any additional arguments are passed to the app function sequentially.
//
// For much more detail about plugins, check out:
// http://code.quirkey.com/sammy/doc/plugins.html
//
// === Example
//
// var MyPlugin = function(app, prepend) {
//
// this.helpers({
// myhelper: function(text) {
// alert(prepend + " " + text);
// }
// });
//
// };
//
// var app = $.sammy(function() {
//
// this.use(MyPlugin, 'This is my plugin');
//
// this.get('#/', function() {
// this.myhelper('and dont you forget it!');
// //=> Alerts: This is my plugin and dont you forget it!
// });
//
// });
//
use: function() {
// flatten the arguments
var args = $.makeArray(arguments);
var plugin = args.shift();
try {
args.unshift(this);
plugin.apply(this, args);
} catch(e) {
if (typeof plugin == 'undefined') {
this.error("Plugin Error: called use() but plugin is not defined", e);
} else if (!$.isFunction(plugin)) {
this.error("Plugin Error: called use() but '" + plugin.toString() + "' is not a function", e);
} else {
this.error("Plugin Error", e);
}
}
return this;
},
// <tt>route()</tt> is the main method for defining routes within an application.
// For great detail on routes, check out: http://code.quirkey.com/sammy/doc/routes.html
//
// This method also has aliases for each of the different verbs (eg. <tt>get()</tt>, <tt>post()</tt>, etc.)
//
// === Arguments
//
// +verb+:: A String in the set of ROUTE_VERBS or 'any'. 'any' will add routes for each
// of the ROUTE_VERBS. If only two arguments are passed,
// the first argument is the path, the second is the callback and the verb
// is assumed to be 'any'.
// +path+:: A Regexp or a String representing the path to match to invoke this verb.
// +callback+:: A Function that is called/evaluated whent the route is run see: <tt>runRoute()</tt>.
// It is also possible to pass a string as the callback, which is looked up as the name
// of a method on the application.
//
route: function(verb, path, callback) {
var app = this, param_names = [], add_route;
// if the method signature is just (path, callback)
// assume the verb is 'any'
if (!callback && $.isFunction(path)) {
path = verb;
callback = path;
verb = 'any';
}
verb = verb.toLowerCase(); // ensure verb is lower case
// if path is a string turn it into a regex
if (path.constructor == String) {
// Needs to be explicitly set because IE will maintain the index unless NULL is returned,
// which means that with two consecutive routes that contain params, the second set of params will not be found and end up in splat instead of params
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/RegExp/lastIndex
PATH_NAME_MATCHER.lastIndex = 0;
// find the names
while ((path_match = PATH_NAME_MATCHER.exec(path)) !== null) {
param_names.push(path_match[1]);
}
// replace with the path replacement
path = new RegExp("^" + path.replace(PATH_NAME_MATCHER, PATH_REPLACER) + "$");
}
// lookup callback
if (typeof callback == 'string') {
callback = app[callback];
}
add_route = function(with_verb) {
var r = {verb: with_verb, path: path, callback: callback, param_names: param_names};
// add route to routes array
app.routes[with_verb] = app.routes[with_verb] || [];
// place routes in order of definition
app.routes[with_verb].push(r);
};
if (verb === 'any') {
$.each(this.ROUTE_VERBS, function(i, v) { add_route(v); });
} else {
add_route(verb);
}
// return the app
return this;
},
// Alias for route('get', ...)
get: _routeWrapper('get'),
// Alias for route('post', ...)
post: _routeWrapper('post'),
// Alias for route('put', ...)
put: _routeWrapper('put'),
// Alias for route('delete', ...)
del: _routeWrapper('delete'),
// Alias for route('any', ...)
any: _routeWrapper('any'),
// <tt>mapRoutes</tt> takes an array of arrays, each array being passed to route()
// as arguments, this allows for mass definition of routes. Another benefit is
// this makes it possible/easier to load routes via remote JSON.
//
// === Example
//
// var app = $.sammy(function() {
//
// this.mapRoutes([
// ['get', '#/', function() { this.log('index'); }],
// // strings in callbacks are looked up as methods on the app
// ['post', '#/create', 'addUser'],
// // No verb assumes 'any' as the verb
// [/dowhatever/, function() { this.log(this.verb, this.path)}];
// ]);
// })
//
mapRoutes: function(route_array) {
var app = this;
$.each(route_array, function(i, route_args) {
app.route.apply(app, route_args);
});
return this;
},
// A unique event namespace defined per application.
// All events bound with <tt>bind()</tt> are automatically bound within this space.
eventNamespace: function() {
return ['sammy-app', this.namespace].join('-');
},
// Works just like <tt>jQuery.fn.bind()</tt> with a couple noteable differences.
//
// * It binds all events to the application element
// * All events are bound within the <tt>eventNamespace()</tt>
// * Events are not actually bound until the application is started with <tt>run()</tt>
// * callbacks are evaluated within the context of a Sammy.EventContext
//
// See http://code.quirkey.com/sammy/docs/events.html for more info.
//
bind: function(name, data, callback) {
var app = this;
// build the callback
// if the arity is 2, callback is the second argument
if (typeof callback == 'undefined') { callback = data; }
var listener_callback = function() {
// pull off the context from the arguments to the callback
var e, context, data;
e = arguments[0];
data = arguments[1];
if (data && data.context) {
context = data.context;
delete data.context;
} else {
context = new app.context_prototype(app, 'bind', e.type, data);
}
e.cleaned_type = e.type.replace(app.eventNamespace(), '');
callback.apply(context, [e, data]);
};
// it could be that the app element doesnt exist yet
// so attach to the listeners array and then run()
// will actually bind the event.
if (!this.listeners[name]) { this.listeners[name] = []; }
this.listeners[name].push(listener_callback);
if (this.isRunning()) {
// if the app is running
// *actually* bind the event to the app element
this._listen(name, listener_callback);
}
return this;
},
// Triggers custom events defined with <tt>bind()</tt>
//
// === Arguments
//
// +name+:: The name of the event. Automatically prefixed with the <tt>eventNamespace()</tt>
// +data+:: An optional Object that can be passed to the bound callback.
// +context+:: An optional context/Object in which to execute the bound callback.
// If no context is supplied a the context is a new <tt>Sammy.EventContext</tt>
//
trigger: function(name, data) {
this.$element().trigger([name, this.eventNamespace()].join('.'), [data]);
return this;
},
// Reruns the current route
refresh: function() {
this.last_location = null;
this.trigger('location-changed');
return this;
},
// Takes a single callback that is pushed on to a stack.
// Before any route is run, the callbacks are evaluated in order within
// the current <tt>Sammy.EventContext</tt>
//
// If any of the callbacks explicitly return false, execution of any
// further callbacks and the route itself is halted.
//
// You can also provide a set of options that will define when to run this
// before based on the route it proceeds.
//
// === Example
//
// var app = $.sammy(function() {
//
// // will run at #/route but not at #/
// this.before('#/route', function() {
// //...
// });
//
// // will run at #/ but not at #/route
// this.before({except: {path: '#/route'}}, function() {
// this.log('not before #/route');
// });
//
// this.get('#/', function() {});
//
// this.get('#/route', function() {});
//
// });
//
// See <tt>contextMatchesOptions()</tt> for a full list of supported options
//
before: function(options, callback) {
if ($.isFunction(options)) {
callback = options;
options = {};
}
this.befores.push([options, callback]);
return this;
},
// A shortcut for binding a callback to be run after a route is executed.
// After callbacks have no guarunteed order.
after: function(callback) {
return this.bind('event-context-after', callback);
},
// Adds an around filter to the application. around filters are functions
// that take a single argument <tt>callback</tt> which is the entire route
// execution path wrapped up in a closure. This means you can decide whether
// or not to proceed with execution by not invoking <tt>callback</tt> or,
// more usefuly wrapping callback inside the result of an asynchronous execution.
//
// === Example
//
// The most common use case for around() is calling a _possibly_ async function
// and executing the route within the functions callback:
//
// var app = $.sammy(function() {
//
// var current_user = false;
//
// function checkLoggedIn(callback) {
// // /session returns a JSON representation of the logged in user
// // or an empty object
// if (!current_user) {
// $.getJSON('/session', function(json) {
// if (json.login) {
// // show the user as logged in
// current_user = json;
// // execute the route path
// callback();
// } else {
// // show the user as not logged in
// current_user = false;
// // the context of aroundFilters is an EventContext
// this.redirect('#/login');
// }
// });
// } else {
// // execute the route path
// callback();
// }
// };
//
// this.around(checkLoggedIn);
//
// });
//
around: function(callback) {
this.arounds.push(callback);
return this;
},
// Returns a boolean of weather the current application is running.
isRunning: function() {
return this._running;
},
// Helpers extends the EventContext prototype specific to this app.
// This allows you to define app specific helper functions that can be used
// whenever you're inside of an event context (templates, routes, bind).
//
// === Example
//
// var app = $.sammy(function() {
//
// helpers({
// upcase: function(text) {
// return text.toString().toUpperCase();
// }
// });
//
// get('#/', function() { with(this) {
// // inside of this context I can use the helpers
// $('#main').html(upcase($('#main').text());
// }});
//
// });
//
//
// === Arguments
//
// +extensions+:: An object collection of functions to extend the context.
//
helpers: function(extensions) {
$.extend(this.context_prototype.prototype, extensions);
return this;
},
// Helper extends the event context just like <tt>helpers()</tt> but does it
// a single method at a time. This is especially useful for dynamically named
// helpers
//
// === Example
//
// // Trivial example that adds 3 helper methods to the context dynamically
// var app = $.sammy(function(app) {
//
// $.each([1,2,3], function(i, num) {
// app.helper('helper' + num, function() {
// this.log("I'm helper number " + num);
// });
// });
//
// this.get('#/', function() {
// this.helper2(); //=> I'm helper number 2
// });
// });
//
// === Arguments
//
// +name+:: The name of the method
// +method+:: The function to be added to the prototype at <tt>name</tt>
//
helper: function(name, method) {
this.context_prototype.prototype[name] = method;
return this;
},
// Actually starts the application's lifecycle. <tt>run()</tt> should be invoked
// within a document.ready block to ensure the DOM exists before binding events, etc.
//
// === Example
//
// var app = $.sammy(function() { ... }); // your application
// $(function() { // document.ready
// app.run();
// });
//
// === Arguments
//
// +start_url+:: "value", Optionally, a String can be passed which the App will redirect to
// after the events/routes have been bound.
run: function(start_url) {
if (this.isRunning()) { return false; }
var app = this;
// actually bind all the listeners
$.each(this.listeners.toHash(), function(name, callbacks) {
$.each(callbacks, function(i, listener_callback) {
app._listen(name, listener_callback);
});
});
this.trigger('run', {start_url: start_url});
this._running = true;
// set last location
this.last_location = null;
if (this.getLocation() == '' && typeof start_url != 'undefined') {
this.setLocation(start_url);
}
// check url
this._checkLocation();
this.location_proxy.bind();
this.bind('location-changed', function() {
app._checkLocation();
});
// bind to submit to capture post/put/delete routes
this.bind('submit', function(e) {
var returned = app._checkFormSubmission($(e.target).closest('form'));
return (returned === false) ? e.preventDefault() : false;
});
// bind unload to body unload
$(window).bind('beforeunload', function() {
app.unload();
});
// trigger html changed
return this.trigger('changed');
},
// The opposite of <tt>run()</tt>, un-binds all event listeners and intervals
// <tt>run()</tt> Automaticaly binds a <tt>onunload</tt> event to run this when
// the document is closed.
unload: function() {
if (!this.isRunning()) { return false; }
var app = this;
this.trigger('unload');
// clear interval
this.location_proxy.unbind();
// unbind form submits
this.$element().unbind('submit').removeClass(app.eventNamespace());
// unbind all events
$.each(this.listeners.toHash() , function(name, listeners) {
$.each(listeners, function(i, listener_callback) {
app._unlisten(name, listener_callback);
});
});
this._running = false;
return this;
},
// Will bind a single callback function to every event that is already
// being listened to in the app. This includes all the <tt>APP_EVENTS</tt>
// as well as any custom events defined with <tt>bind()</tt>.
//
// Used internally for debug logging.
bindToAllEvents: function(callback) {
var app = this;
// bind to the APP_EVENTS first
$.each(this.APP_EVENTS, function(i, e) {
app.bind(e, callback);
});
// next, bind to listener names (only if they dont exist in APP_EVENTS)
$.each(this.listeners.keys(true), function(i, name) {
if (app.APP_EVENTS.indexOf(name) == -1) {
app.bind(name, callback);
}
});
return this;
},
// Returns a copy of the given path with any query string after the hash
// removed.
routablePath: function(path) {
return path.replace(QUERY_STRING_MATCHER, '');
},
// Given a verb and a String path, will return either a route object or false
// if a matching route can be found within the current defined set.
lookupRoute: function(verb, path) {
var app = this, routed = false;
this.trigger('lookup-route', {verb: verb, path: path});
if (typeof this.routes[verb] != 'undefined') {
$.each(this.routes[verb], function(i, route) {
if (app.routablePath(path).match(route.path)) {
routed = route;
return false;
}
});
}
return routed;
},
// First, invokes <tt>lookupRoute()</tt> and if a route is found, parses the
// possible URL params and then invokes the route's callback within a new
// <tt>Sammy.EventContext</tt>. If the route can not be found, it calls
// <tt>notFound()</tt>. If <tt>raise_errors</tt> is set to <tt>true</tt> and
// the <tt>error()</tt> has not been overriden, it will throw an actual JS
// error.
//
// You probably will never have to call this directly.
//
// === Arguments
//
// +verb+:: A String for the verb.
// +path+:: A String path to lookup.
// +params+:: An Object of Params pulled from the URI or passed directly.
//
// === Returns
//
// Either returns the value returned by the route callback or raises a 404 Not Found error.
//
runRoute: function(verb, path, params) {
var app = this,
route = this.lookupRoute(verb, path),
context,
wrapped_route,
arounds,
around,
befores,
before,
callback_args,
final_returned;
this.log('runRoute', [verb, path].join(' '));
this.trigger('run-route', {verb: verb, path: path, params: params});
if (typeof params == 'undefined') { params = {}; }
$.extend(params, this._parseQueryString(path));
if (route) {
this.trigger('route-found', {route: route});
// pull out the params from the path
if ((path_params = route.path.exec(this.routablePath(path))) !== null) {
// first match is the full path
path_params.shift();
// for each of the matches
$.each(path_params, function(i, param) {
// if theres a matching param name
if (route.param_names[i]) {
// set the name to the match
params[route.param_names[i]] = _decode(param);
} else {
// initialize 'splat'
if (!params.splat) { params.splat = []; }
params.splat.push(_decode(param));
}
});
}
// set event context
context = new this.context_prototype(this, verb, path, params);
// ensure arrays
arounds = this.arounds.slice(0);
befores = this.befores.slice(0);
// set the callback args to the context + contents of the splat
callback_args = [context].concat(params.splat);
// wrap the route up with the before filters
wrapped_route = function() {
var returned;
while (befores.length > 0) {
before = befores.shift();
// check the options
if (app.contextMatchesOptions(context, before[0])) {
returned = before[1].apply(context, [context]);
if (returned === false) { return false; }
}
}
app.last_route = route;
context.trigger('event-context-before', {context: context});
returned = route.callback.apply(context, callback_args);
context.trigger('event-context-after', {context: context});
return returned;
};
$.each(arounds.reverse(), function(i, around) {
var last_wrapped_route = wrapped_route;
wrapped_route = function() { return around.apply(context, [last_wrapped_route]); };
});
try {
final_returned = wrapped_route();
} catch(e) {
this.error(['500 Error', verb, path].join(' '), e);
}
return final_returned;
} else {
return this.notFound(verb, path);
}
},
// Matches an object of options against an <tt>EventContext</tt> like object that
// contains <tt>path</tt> and <tt>verb</tt> attributes. Internally Sammy uses this
// for matching <tt>before()</tt> filters against specific options. You can set the
// object to _only_ match certain paths or verbs, or match all paths or verbs _except_
// those that match the options.
//
// === Example
//
// var app = $.sammy(),
// context = {verb: 'get', path: '#/mypath'};
//
// // match against a path string
// app.contextMatchesOptions(context, '#/mypath'); //=> true
// app.contextMatchesOptions(context, '#/otherpath'); //=> false
// // equivilent to
// app.contextMatchesOptions(context, {only: {path:'#/mypath'}}); //=> true
// app.contextMatchesOptions(context, {only: {path:'#/otherpath'}}); //=> false
// // match against a path regexp
// app.contextMatchesOptions(context, /path/); //=> true
// app.contextMatchesOptions(context, /^path/); //=> false
// // match only a verb
// app.contextMatchesOptions(context, {only: {verb:'get'}}); //=> true
// app.contextMatchesOptions(context, {only: {verb:'post'}}); //=> false
// // match all except a verb
// app.contextMatchesOptions(context, {except: {verb:'post'}}); //=> true
// app.contextMatchesOptions(context, {except: {verb:'get'}}); //=> false
// // match all except a path
// app.contextMatchesOptions(context, {except: {path:'#/otherpath'}}); //=> true
// app.contextMatchesOptions(context, {except: {path:'#/mypath'}}); //=> false
//
contextMatchesOptions: function(context, match_options, positive) {
// empty options always match
var options = match_options;
if (typeof options === 'undefined' || options == {}) {
return true;
}
if (typeof positive === 'undefined') {
positive = true;
}
// normalize options
if (typeof options === 'string' || $.isFunction(options.test)) {
options = {path: options};
}
if (options.only) {
return this.contextMatchesOptions(context, options.only, true);
} else if (options.except) {
return this.contextMatchesOptions(context, options.except, false);
}
var path_matched = true, verb_matched = true;
if (options.path) {
// wierd regexp test
if ($.isFunction(options.path.test)) {
path_matched = options.path.test(context.path);
} else {
path_matched = (options.path.toString() === context.path);
}
}
if (options.verb) {
verb_matched = options.verb === context.verb;
}
return positive ? (verb_matched && path_matched) : !(verb_matched && path_matched);
},
// Delegates to the <tt>location_proxy</tt> to get the current location.
// See <tt>Sammy.HashLocationProxy</tt> for more info on location proxies.
getLocation: function() {
return this.location_proxy.getLocation();
},
// Delegates to the <tt>location_proxy</tt> to set the current location.
// See <tt>Sammy.HashLocationProxy</tt> for more info on location proxies.
//
// === Arguments
//
// +new_location+:: A new location string (e.g. '#/')
//
setLocation: function(new_location) {
return this.location_proxy.setLocation(new_location);
},
// Swaps the content of <tt>$element()</tt> with <tt>content</tt>
// You can override this method to provide an alternate swap behavior
// for <tt>EventContext.partial()</tt>.
//
// === Example
//
// var app = $.sammy(function() {
//
// // implements a 'fade out'/'fade in'
// this.swap = function(content) {
// this.$element().hide('slow').html(content).show('slow');
// }
//
// get('#/', function() {
// this.partial('index.html.erb') // will fade out and in
// });
//
// });
//
swap: function(content) {
return this.$element().html(content);
},
// This thows a '404 Not Found' error by invoking <tt>error()</tt>.
// Override this method or <tt>error()</tt> to provide custom
// 404 behavior (i.e redirecting to / or showing a warning)
notFound: function(verb, path) {
var ret = this.error(['404 Not Found', verb, path].join(' '));
return (verb === 'get') ? ret : true;
},
// The base error handler takes a string <tt>message</tt> and an <tt>Error</tt>
// object. If <tt>raise_errors</tt> is set to <tt>true</tt> on the app level,
// this will re-throw the error to the browser. Otherwise it will send the error
// to <tt>log()</tt>. Override this method to provide custom error handling
// e.g logging to a server side component or displaying some feedback to the
// user.
error: function(message, original_error) {
if (!original_error) { original_error = new Error(); }
original_error.message = [message, original_error.message].join(' ');
this.trigger('error', {message: original_error.message, error: original_error});
if (this.raise_errors) {
throw(original_error);
} else {
this.log(original_error.message, original_error);
}
},
_checkLocation: function() {
var location, returned;
// get current location
location = this.getLocation();
// compare to see if hash has changed
if (location != this.last_location) {
// lookup route for current hash
returned = this.runRoute('get', location);
}
// reset last location
this.last_location = location;
return returned;
},
_checkFormSubmission: function(form) {
var $form, path, verb, params, returned;
this.trigger('check-form-submission', {form: form});
$form = $(form);
path = $form.attr('action');
verb = $.trim($form.attr('method').toString().toLowerCase());
if (!verb || verb == '') { verb = 'get'; }
this.log('_checkFormSubmission', $form, path, verb);
params = $.extend({}, this._parseFormParams($form), {'$form': $form});
returned = this.runRoute(verb, path, params);
return (typeof returned == 'undefined') ? false : returned;
},
_parseFormParams: function($form) {
var params = {};
$.each($form.serializeArray(), function(i, field) {
if (params[field.name]) {
if ($.isArray(params[field.name])) {
params[field.name].push(field.value);
} else {
params[field.name] = [params[field.name], field.value];
}
} else {
params[field.name] = field.value;
}
});
return params;
},
_parseQueryString: function(path) {
var query = {}, parts, pairs, pair, i;
parts = path.match(QUERY_STRING_MATCHER);
if (parts) {
pairs = parts[1].split('&');
for (i = 0; i < pairs.length; i += 1) {
pair = pairs[i].split('=');
query[pair[0]] = _decode(pair[1]);
}
}
return query;
},
_listen: function(name, callback) {
return this.$element().bind([name, this.eventNamespace()].join('.'), callback);
},
_unlisten: function(name, callback) {
return this.$element().unbind([name, this.eventNamespace()].join('.'), callback);
}
});
// <tt>Sammy.EventContext</tt> objects are created every time a route is run or a
// bound event is triggered. The callbacks for these events are evaluated within a <tt>Sammy.EventContext</tt>
// This within these callbacks the special methods of <tt>EventContext</tt> are available.
//
// === Example
//
// $.sammy(function() { with(this) {
// // The context here is this Sammy.Application
// get('#/:name', function() { with(this) {
// // The context here is a new Sammy.EventContext
// if (params['name'] == 'sammy') {
// partial('name.html.erb', {name: 'Sammy'});
// } else {
// redirect('#/somewhere-else')
// }
// }});
// }});
//
// Initialize a new EventContext
//
// === Arguments
//
// +app+:: The <tt>Sammy.Application</tt> this event is called within.
// +verb+:: The verb invoked to run this context/route.
// +path+:: The string path invoked to run this context/route.
// +params+:: An Object of optional params to pass to the context. Is converted
// to a <tt>Sammy.Object</tt>.
Sammy.EventContext = function(app, verb, path, params) {
this.app = app;
this.verb = verb;
this.path = path;
this.params = new Sammy.Object(params);
};
Sammy.EventContext.prototype = $.extend({}, Sammy.Object.prototype, {
// A shortcut to the app's <tt>$element()</tt>
$element: function() {
return this.app.$element();
},
// Used for rendering remote templates or documents within the current application/DOM.
// By default Sammy and <tt>partial()</tt> know nothing about how your templates
// should be interpeted/rendered. This is easy to change, though. <tt>partial()</tt> looks
// for a method in <tt>EventContext</tt> that matches the extension of the file you're
// fetching (e.g. 'myfile.template' will look for a template() method, 'myfile.haml' => haml(), etc.)
// If no matching render method is found it just takes the file contents as is.
//
// If you're templates have different (or no) extensions, and you want to render them all
// through the same engine, you can set the default/fallback template engine on the app level
// by setting <tt>app.template_engine</tt> to the name of the engine or a <tt>function() {}</tt>
//
// === Caching
//
// If you use the <tt>Sammy.Cache</tt> plugin, remote requests will be automatically cached unless
// you explicitly set <tt>cache_partials</tt> to <tt>false</tt>
//
// === Example
//
// There are a couple different ways to use <tt>partial()</tt>:
//
// partial('doc.html');
// //=> Replaces $element() with the contents of doc.html
//
// use(Sammy.Template);
// //=> includes the template() method
// partial('doc.template', {name: 'Sammy'});
// //=> Replaces $element() with the contents of doc.template run through <tt>template()</tt>
//
// partial('doc.html', function(data) {
// // data is the contents of the template.
// $('.other-selector').html(data);
// });
//
// === Iteration/Arrays
//
// If the data object passed to <tt>partial()</tt> is an Array, <tt>partial()</tt>
// will itterate over each element in data calling the callback with the
// results of interpolation and the index of the element in the array.
//
// use(Sammy.Template);
// // item.template => "<li>I'm an item named <%= name %></li>"
// partial('item.template', [{name: "Item 1"}, {name: "Item 2"}])
// //=> Replaces $element() with:
// // <li>I'm an item named Item 1</li><li>I'm an item named Item 2</li>
// partial('item.template', [{name: "Item 1"}, {name: "Item 2"}], function(rendered, i) {
// rendered; //=> <li>I'm an item named Item 1</li> // for each element in the Array
// i; // the 0 based index of the itteration
// });
//
partial: function(path, data, callback) {
var file_data,
wrapped_callback,
engine,
data_array,
cache_key = 'partial:' + path,
context = this;
// engine setup
if ((engine = path.match(/\.([^\.]+)$/))) { engine = engine[1]; }
// set the engine to the default template engine if no match is found
if ((!engine || !$.isFunction(context[engine])) && this.app.template_engine) {
engine = this.app.template_engine;
}
if (engine && !$.isFunction(engine) && $.isFunction(context[engine])) {
engine = context[engine];
}
if (!callback && $.isFunction(data)) {
// callback is in the data position
callback = data;
data = {};
}
data_array = ($.isArray(data) ? data : [data || {}]);
wrapped_callback = function(response) {
var new_content = response,
all_content = "";
$.each(data_array, function(i, idata) {
// extend the data object with the context
$.extend(idata, context);
if ($.isFunction(engine)) {
new_content = engine.apply(context, [response, idata]);
}
// collect the content
all_content += new_content;
// if callback exists call it for each iteration
if (callback) {
// return the result of the callback
// (you can bail the loop by returning false)
return callback.apply(context, [new_content, i]);
}
});
if (!callback) { context.swap(all_content); }
context.trigger('changed');
};
if (this.app.cache_partials && this.cache(cache_key)) {
// try to load the template from the cache
wrapped_callback.apply(context, [this.cache(cache_key)]);
} else {
// the template wasnt cached, we need to fetch it
$.get(path, function(response) {
if (context.app.cache_partials) { context.cache(cache_key, response); }
wrapped_callback.apply(context, [response]);
});
}
},
// Changes the location of the current window. If <tt>to</tt> begins with
// '#' it only changes the document's hash. If passed more than 1 argument
// redirect will join them together with forward slashes.
//
// === Example
//
// redirect('#/other/route');
// // equivilent to
// redirect('#', 'other', 'route');
//
redirect: function() {
var to, args = $.makeArray(arguments),
current_location = this.app.getLocation();
if (args.length > 1) {
args.unshift('/');
to = this.join.apply(this, args);
} else {
to = args[0];
}
this.trigger('redirect', {to: to});
this.app.last_location = this.path;
this.app.setLocation(to);
if (current_location == to) {
this.app.trigger('location-changed');
}
},
// Triggers events on <tt>app</tt> within the current context.
trigger: function(name, data) {
if (typeof data == 'undefined') { data = {}; }
if (!data.context) { data.context = this; }
return this.app.trigger(name, data);
},
// A shortcut to app's <tt>eventNamespace()</tt>
eventNamespace: function() {
return this.app.eventNamespace();
},
// A shortcut to app's <tt>swap()</tt>
swap: function(contents) {
return this.app.swap(contents);
},
// Raises a possible <tt>notFound()</tt> error for the current path.
notFound: function() {
return this.app.notFound(this.verb, this.path);
},
// //=> Sammy.EventContext: get #/ {}
toString: function() {
return "Sammy.EventContext: " + [this.verb, this.path, this.params].join(' ');
}
});
// An alias to Sammy
$.sammy = window.Sammy = Sammy;
})(jQuery);
\ No newline at end of file
(function($) {
// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed
// adapted from: http://ejohn.org/blog/javascript-micro-templating/
// originally $.srender by Greg Borenstein http://ideasfordozens.com in Feb 2009
// modified for Sammy by Aaron Quint for caching templates by name
var srender_cache = {};
var srender = function(name, template, data) {
// target is an optional element; if provided, the result will be inserted into it
// otherwise the result will simply be returned to the caller
if (srender_cache[name]) {
fn = srender_cache[name];
} else {
if (typeof template == 'undefined') {
// was a cache check, return false
return false;
}
// Generate a reusable function that will serve as a template
// generator (and which will be cached).
fn = srender_cache[name] = new Function("obj",
"var p=[],print=function(){p.push.apply(p,arguments);};" +
// Introduce the data as local variables using with(){}
"with(obj){p.push(\"" +
// Convert the template into pure JavaScript
template
.replace(/[\r\t\n]/g, " ")
.replace(/\"/g, '\\"')
.split("<%").join("\t")
.replace(/((^|%>)[^\t]*)/g, "$1\r")
.replace(/\t=(.*?)%>/g, "\",$1,\"")
.split("\t").join("\");")
.split("%>").join("p.push(\"")
.split("\r").join("")
+ "\");}return p.join('');");
}
if (typeof data != 'undefined') {
return fn(data);
} else {
return fn;
}
};
Sammy = Sammy || {};
// <tt>Sammy.Template</tt> is a simple plugin that provides a way to create
// and render client side templates. The rendering code is based on John Resig's
// quick templates and Greg Borenstien's srender plugin.
// This is also a great template/boilerplate for Sammy plugins.
//
// Templates use <% %> tags to denote embedded javascript.
//
// === Examples
//
// Here is an example template (user.template):
//
// <div class="user">
// <div class="user-name"><%= user.name %></div>
// <% if (user.photo_url) { %>
// <div class="photo"><img src="<%= user.photo_url %>" /></div>
// <% } %>
// </div>
//
// Given that is a publicly accesible file, you would render it like:
//
// $.sammy(function() {
// // include the plugin
// this.use(Sammy.Template);
//
// this.get('#/', function() {
// // the template is rendered in the current context.
// this.user = {name: 'Aaron Quint'};
// // partial calls template() because of the file extension
// this.partial('user.template');
// })
// });
//
// You can also pass a second argument to use() that will alias the template
// method and therefore allow you to use a different extension for template files
// in <tt>partial()</tt>
//
// // alias to 'tpl'
// this.use(Sammy.Template, 'tpl');
//
// // now .tpl files will be run through srender
// this.get('#/', function() {
// this.partial('myfile.tpl');
// });
//
Sammy.Template = function(app, method_alias) {
// *Helper:* Uses simple templating to parse ERB like templates.
//
// === Arguments
//
// +template+:: A String template. '<% %>' tags are evaluated as Javascript and replaced with the elements in data.
// +data+:: An Object containing the replacement values for the template.
// data is extended with the <tt>EventContext</tt> allowing you to call its methods within the template.
// +name+:: An optional String name to cache the template.
//
var template = function(template, data, name) {
// use name for caching
if (typeof name == 'undefined') name = template;
return srender(name, template, $.extend({}, this, data));
};
// set the default method name/extension
if (!method_alias) method_alias = 'template';
// create the helper at the method alias
app.helper(method_alias, template);
};
})(jQuery);
\ No newline at end of file
# Sammy's Todos
This is a demo todo list app built on top of Sammy.js.
Original base code: [Brandon Aaron](http://brandonaaron.net). This version, refactored and rewritten: Addy Osmani
\ No newline at end of file
<h2>What?!</h2>
<p>Try clicking on one of your lists to the right.</p>
\ No newline at end of file
<li data-type="todo" data-id="<%= id %>" class="<%= done ? 'done' : '' %>">
<div class="todo">
<div class="display">
<input class="check" type="checkbox" <%= done ? 'checked' : '' %>/>
<span class="trashcan" data-type="todo" data-id="<%= id %>"></span>
<span contenteditable="true" data-type="todo" data-id="<%= id %>" class="todo-item"><%= name %></span>
</div>
</div>
</li>
<h2 data-type="list" data-id="<%= list.id %>"></h2>
<% $.each(todos, function(index, todo) { %>
<li data-type="todo" data-id="<%= todo.id %>" class="<%= todo.done ? 'done' : '' %>">
<div class="todo">
<div class="display">
<input class="check" type="checkbox" <%= todo.done ? 'checked' : '' %>/>
<span class="trashcan" data-type="todo" data-id="<%= todo.id %>"></span><span contenteditable="true" data-type="todo" data-id="<%= todo.id %>" class="todo-item"><%= todo.name %></span>
</div>
</div>
</li>
<% }); %>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment