# HG changeset patch # User Mahlon E. Smith # Date 1423502401 28800 # Node ID 52d30e6014a04a0f61862b6bdfbee7eae034b2a0 Initial commit. Experimental cross-platform frontend for yubikey programming. diff -r 000000000000 -r 52d30e6014a0 Rakefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Rakefile Mon Feb 09 09:20:01 2015 -0800 @@ -0,0 +1,52 @@ +#!rake +# vim: set nosta noet ts=4 sw=4: + +require 'rake' +require 'pathname' + +BASEDIR = Pathname.new( __FILE__ ).expand_path.dirname.relative_path_from( Pathname.getwd ) +NODEWEBKIT = '/Applications/node-webkit.app/Contents/MacOS/node-webkit' + +manifest = File.read( __FILE__ ).split( /^__END__/, 2 ).last.split +manifest.each do |dep| + file dep +end + +######################################################################## +### T A S K S +######################################################################## + +task :default => [ :run ] + +desc "Run the application." +task :run do + sh NODEWEBKIT, BASEDIR.to_s +end + +desc "Package a node-webkit bundle." +task :build => manifest do + sh 'zip', '-r', 'app.nw', *manifest +end + + +######################################################################## +### M A N I F E S T +######################################################################## +__END__ +css/main.css +css/pure-min.css +html/main.html +img/yubi.png +js/can.jquery-2.1.1.js +js/jquery-2.1.1.js +js/main.js +js/startup.js +js/yubi.js +package.json +platform/osx/app.icns +platform/osx/Info.plist +yubi/darwin/bin/ykinfo +yubi/darwin/bin/ykpersonalize +yubi/darwin/lib/libyubikey.0.dylib +yubi/darwin/lib/libyubikey.a +yubi/darwin/lib/libyubikey.dylib diff -r 000000000000 -r 52d30e6014a0 css/main.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/css/main.css Mon Feb 09 09:20:01 2015 -0800 @@ -0,0 +1,5 @@ + +#main { margin-top: 20px } +table { margin-left: 20px } +.r { text-align: right; padding-right: 10px } + diff -r 000000000000 -r 52d30e6014a0 css/pure-min.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/css/pure-min.css Mon Feb 09 09:20:01 2015 -0800 @@ -0,0 +1,19 @@ +/*! +Pure v0.5.0 +Copyright 2014 Yahoo! Inc. All rights reserved. +Licensed under the BSD License. +https://github.com/yui/pure/blob/master/LICENSE.md +*/ +/*! +normalize.css v1.1.3 | MIT License | git.io/normalize +Copyright (c) Nicolas Gallagher and Jonathan Neal +*/ +/*! normalize.css v1.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}html,button,input,select,textarea{font-family:sans-serif}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}h2{font-size:1.5em;margin:.83em 0}h3{font-size:1.17em;margin:1em 0}h4{font-size:1em;margin:1.33em 0}h5{font-size:.83em;margin:1.67em 0}h6{font-size:.67em;margin:2.33em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:1em 40px}dfn{font-style:italic}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}p,pre{margin:1em 0}code,kbd,pre,samp{font-family:monospace,serif;_font-family:'courier new',monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:before,q:after{content:'';content:none}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,menu,ol,ul{margin:1em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0;white-space:normal;*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}.pure-g{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class *="pure-u"]{font-family:sans-serif}.pure-u-1,.pure-u-1-1,.pure-u-1-2,.pure-u-1-3,.pure-u-2-3,.pure-u-1-4,.pure-u-3-4,.pure-u-1-5,.pure-u-2-5,.pure-u-3-5,.pure-u-4-5,.pure-u-5-5,.pure-u-1-6,.pure-u-5-6,.pure-u-1-8,.pure-u-3-8,.pure-u-5-8,.pure-u-7-8,.pure-u-1-12,.pure-u-5-12,.pure-u-7-12,.pure-u-11-12,.pure-u-1-24,.pure-u-2-24,.pure-u-3-24,.pure-u-4-24,.pure-u-5-24,.pure-u-6-24,.pure-u-7-24,.pure-u-8-24,.pure-u-9-24,.pure-u-10-24,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%;*width:4.1357%}.pure-u-1-12,.pure-u-2-24{width:8.3333%;*width:8.3023%}.pure-u-1-8,.pure-u-3-24{width:12.5%;*width:12.469%}.pure-u-1-6,.pure-u-4-24{width:16.6667%;*width:16.6357%}.pure-u-1-5{width:20%;*width:19.969%}.pure-u-5-24{width:20.8333%;*width:20.8023%}.pure-u-1-4,.pure-u-6-24{width:25%;*width:24.969%}.pure-u-7-24{width:29.1667%;*width:29.1357%}.pure-u-1-3,.pure-u-8-24{width:33.3333%;*width:33.3023%}.pure-u-3-8,.pure-u-9-24{width:37.5%;*width:37.469%}.pure-u-2-5{width:40%;*width:39.969%}.pure-u-5-12,.pure-u-10-24{width:41.6667%;*width:41.6357%}.pure-u-11-24{width:45.8333%;*width:45.8023%}.pure-u-1-2,.pure-u-12-24{width:50%;*width:49.969%}.pure-u-13-24{width:54.1667%;*width:54.1357%}.pure-u-7-12,.pure-u-14-24{width:58.3333%;*width:58.3023%}.pure-u-3-5{width:60%;*width:59.969%}.pure-u-5-8,.pure-u-15-24{width:62.5%;*width:62.469%}.pure-u-2-3,.pure-u-16-24{width:66.6667%;*width:66.6357%}.pure-u-17-24{width:70.8333%;*width:70.8023%}.pure-u-3-4,.pure-u-18-24{width:75%;*width:74.969%}.pure-u-19-24{width:79.1667%;*width:79.1357%}.pure-u-4-5{width:80%;*width:79.969%}.pure-u-5-6,.pure-u-20-24{width:83.3333%;*width:83.3023%}.pure-u-7-8,.pure-u-21-24{width:87.5%;*width:87.469%}.pure-u-11-12,.pure-u-22-24{width:91.6667%;*width:91.6357%}.pure-u-23-24{width:95.8333%;*width:95.8023%}.pure-u-1,.pure-u-1-1,.pure-u-5-5,.pure-u-24-24{width:100%}.pure-button{display:inline-block;*display:inline;zoom:1;line-height:normal;white-space:nowrap;vertical-align:baseline;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button{font-family:inherit;font-size:100%;*font-size:90%;*overflow:visible;padding:.5em 1em;color:#444;color:rgba(0,0,0,.8);*color:#444;border:1px solid #999;border:0 rgba(0,0,0,0);background-color:#E6E6E6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:hover,.pure-button:focus{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0);background-image:-webkit-gradient(linear,0 0,0 100%,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-moz-linear-gradient(top,rgba(0,0,0,.05) 0,rgba(0,0,0,.1));background-image:-o-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset}.pure-button[disabled],.pure-button-disabled,.pure-button-disabled:hover,.pure-button-disabled:focus,.pure-button-disabled:active{border:0;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);filter:alpha(opacity=40);-khtml-opacity:.4;-moz-opacity:.4;opacity:.4;cursor:not-allowed;box-shadow:none}.pure-button-hidden{display:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=text]:focus,.pure-form input[type=password]:focus,.pure-form input[type=email]:focus,.pure-form input[type=url]:focus,.pure-form input[type=date]:focus,.pure-form input[type=month]:focus,.pure-form input[type=time]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=week]:focus,.pure-form input[type=number]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=color]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;outline:thin dotted \9;border-color:#129FEA}.pure-form input:not([type]):focus{outline:0;outline:thin dotted \9;border-color:#129FEA}.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus,.pure-form input[type=checkbox]:focus{outline:thin dotted #333;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=text][disabled],.pure-form input[type=password][disabled],.pure-form input[type=email][disabled],.pure-form input[type=url][disabled],.pure-form input[type=date][disabled],.pure-form input[type=month][disabled],.pure-form input[type=time][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=week][disabled],.pure-form input[type=number][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=color][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form textarea:focus:invalid,.pure-form select:focus:invalid{color:#b94a48;border-color:#ee5f5b}.pure-form input:focus:invalid:focus,.pure-form textarea:focus:invalid:focus,.pure-form select:focus:invalid:focus{border-color:#e9322d}.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus,.pure-form input[type=checkbox]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=text],.pure-form-stacked input[type=password],.pure-form-stacked input[type=email],.pure-form-stacked input[type=url],.pure-form-stacked input[type=date],.pure-form-stacked input[type=month],.pure-form-stacked input[type=time],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=week],.pure-form-stacked input[type=number],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=color],.pure-form-stacked select,.pure-form-stacked label,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned textarea,.pure-form-aligned select,.pure-form-aligned .pure-help-inline,.pure-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 10em}.pure-form input.pure-input-rounded,.pure-form .pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input{display:block;padding:10px;margin:0;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus{z-index:2}.pure-form .pure-group input:first-child{top:1px;border-radius:4px 4px 0 0}.pure-form .pure-group input:last-child{top:-2px;border-radius:0 0 4px 4px}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form .pure-help-inline,.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=text],.pure-group input[type=password],.pure-group input[type=email],.pure-group input[type=url],.pure-group input[type=date],.pure-group input[type=month],.pure-group input[type=time],.pure-group input[type=datetime],.pure-group input[type=datetime-local],.pure-group input[type=week],.pure-group input[type=number],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=color]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form .pure-help-inline,.pure-form-message-inline,.pure-form-message{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu ul{position:absolute;visibility:hidden}.pure-menu.pure-menu-open{visibility:visible;z-index:2;width:100%}.pure-menu ul{left:-10000px;list-style:none;margin:0;padding:0;top:-10000px;z-index:1}.pure-menu>ul{position:relative}.pure-menu-open>ul{left:0;top:0;visibility:visible}.pure-menu-open>ul:focus{outline:0}.pure-menu li{position:relative}.pure-menu a,.pure-menu .pure-menu-heading{display:block;color:inherit;line-height:1.5em;padding:5px 20px;text-decoration:none;white-space:nowrap}.pure-menu.pure-menu-horizontal>.pure-menu-heading{display:inline-block;*display:inline;zoom:1;margin:0;vertical-align:middle}.pure-menu.pure-menu-horizontal>ul{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu li a{padding:5px 20px}.pure-menu-can-have-children>.pure-menu-label:after{content:'\25B8';float:right;font-family:'Lucida Grande','Lucida Sans Unicode','DejaVu Sans',sans-serif;margin-right:-20px;margin-top:-1px}.pure-menu-can-have-children>.pure-menu-label{padding-right:30px}.pure-menu-separator{background-color:#dfdfdf;display:block;height:1px;font-size:0;margin:7px 2px;overflow:hidden}.pure-menu-hidden{display:none}.pure-menu-fixed{position:fixed;top:0;left:0;width:100%}.pure-menu-horizontal li{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu-horizontal li li{display:block}.pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label:after{content:"\25BE"}.pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label{padding-right:30px}.pure-menu-horizontal li.pure-menu-separator{height:50%;width:1px;margin:0 7px}.pure-menu-horizontal li li.pure-menu-separator{height:1px;width:auto;margin:7px 2px}.pure-menu.pure-menu-open,.pure-menu.pure-menu-horizontal li .pure-menu-children{background:#fff;border:1px solid #b7b7b7}.pure-menu.pure-menu-horizontal,.pure-menu.pure-menu-horizontal .pure-menu-heading{border:0}.pure-menu a{border:1px solid transparent;border-left:0;border-right:0}.pure-menu a,.pure-menu .pure-menu-can-have-children>li:after{color:#777}.pure-menu .pure-menu-can-have-children>li:hover:after{color:#fff}.pure-menu .pure-menu-open{background:#dedede}.pure-menu li a:hover,.pure-menu li a:focus{background:#eee}.pure-menu li.pure-menu-disabled a:hover,.pure-menu li.pure-menu-disabled a:focus{background:#fff;color:#bfbfbf}.pure-menu .pure-menu-disabled>a{background-image:none;border-color:transparent;cursor:default}.pure-menu .pure-menu-disabled>a,.pure-menu .pure-menu-can-have-children.pure-menu-disabled>a:after{color:#bfbfbf}.pure-menu .pure-menu-heading{color:#565d64;text-transform:uppercase;font-size:90%;margin-top:.5em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#dfdfdf}.pure-menu .pure-menu-selected a{color:#000}.pure-menu.pure-menu-open.pure-menu-fixed{border:0;border-bottom:1px solid #b7b7b7}.pure-paginator{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;list-style:none;margin:0;padding:0}.opera-only :-o-prefocus,.pure-paginator{word-spacing:-.43em}.pure-paginator li{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-paginator .pure-button{border-radius:0;padding:.8em 1.4em;vertical-align:top;height:1.1em}.pure-paginator .pure-button:focus,.pure-paginator .pure-button:active{outline-style:none}.pure-paginator .prev,.pure-paginator .next{color:#C0C1C3;text-shadow:0 -1px 0 rgba(0,0,0,.45)}.pure-paginator .prev{border-radius:2px 0 0 2px}.pure-paginator .next{border-radius:0 2px 2px 0}@media (max-width:480px){.pure-menu-horizontal{width:100%}.pure-menu-children li{display:block;border-bottom:1px solid #000}}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child td,.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0} + +/*! +Pure v0.5.0 +Copyright 2014 Yahoo! Inc. All rights reserved. +Licensed under the BSD License. +https://github.com/yui/pure/blob/master/LICENSE.md +*/ +@media screen and (min-width:35.5em){.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-1-2,.pure-u-sm-1-3,.pure-u-sm-2-3,.pure-u-sm-1-4,.pure-u-sm-3-4,.pure-u-sm-1-5,.pure-u-sm-2-5,.pure-u-sm-3-5,.pure-u-sm-4-5,.pure-u-sm-5-5,.pure-u-sm-1-6,.pure-u-sm-5-6,.pure-u-sm-1-8,.pure-u-sm-3-8,.pure-u-sm-5-8,.pure-u-sm-7-8,.pure-u-sm-1-12,.pure-u-sm-5-12,.pure-u-sm-7-12,.pure-u-sm-11-12,.pure-u-sm-1-24,.pure-u-sm-2-24,.pure-u-sm-3-24,.pure-u-sm-4-24,.pure-u-sm-5-24,.pure-u-sm-6-24,.pure-u-sm-7-24,.pure-u-sm-8-24,.pure-u-sm-9-24,.pure-u-sm-10-24,.pure-u-sm-11-24,.pure-u-sm-12-24,.pure-u-sm-13-24,.pure-u-sm-14-24,.pure-u-sm-15-24,.pure-u-sm-16-24,.pure-u-sm-17-24,.pure-u-sm-18-24,.pure-u-sm-19-24,.pure-u-sm-20-24,.pure-u-sm-21-24,.pure-u-sm-22-24,.pure-u-sm-23-24,.pure-u-sm-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-sm-1-24{width:4.1667%;*width:4.1357%}.pure-u-sm-1-12,.pure-u-sm-2-24{width:8.3333%;*width:8.3023%}.pure-u-sm-1-8,.pure-u-sm-3-24{width:12.5%;*width:12.469%}.pure-u-sm-1-6,.pure-u-sm-4-24{width:16.6667%;*width:16.6357%}.pure-u-sm-1-5{width:20%;*width:19.969%}.pure-u-sm-5-24{width:20.8333%;*width:20.8023%}.pure-u-sm-1-4,.pure-u-sm-6-24{width:25%;*width:24.969%}.pure-u-sm-7-24{width:29.1667%;*width:29.1357%}.pure-u-sm-1-3,.pure-u-sm-8-24{width:33.3333%;*width:33.3023%}.pure-u-sm-3-8,.pure-u-sm-9-24{width:37.5%;*width:37.469%}.pure-u-sm-2-5{width:40%;*width:39.969%}.pure-u-sm-5-12,.pure-u-sm-10-24{width:41.6667%;*width:41.6357%}.pure-u-sm-11-24{width:45.8333%;*width:45.8023%}.pure-u-sm-1-2,.pure-u-sm-12-24{width:50%;*width:49.969%}.pure-u-sm-13-24{width:54.1667%;*width:54.1357%}.pure-u-sm-7-12,.pure-u-sm-14-24{width:58.3333%;*width:58.3023%}.pure-u-sm-3-5{width:60%;*width:59.969%}.pure-u-sm-5-8,.pure-u-sm-15-24{width:62.5%;*width:62.469%}.pure-u-sm-2-3,.pure-u-sm-16-24{width:66.6667%;*width:66.6357%}.pure-u-sm-17-24{width:70.8333%;*width:70.8023%}.pure-u-sm-3-4,.pure-u-sm-18-24{width:75%;*width:74.969%}.pure-u-sm-19-24{width:79.1667%;*width:79.1357%}.pure-u-sm-4-5{width:80%;*width:79.969%}.pure-u-sm-5-6,.pure-u-sm-20-24{width:83.3333%;*width:83.3023%}.pure-u-sm-7-8,.pure-u-sm-21-24{width:87.5%;*width:87.469%}.pure-u-sm-11-12,.pure-u-sm-22-24{width:91.6667%;*width:91.6357%}.pure-u-sm-23-24{width:95.8333%;*width:95.8023%}.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-5-5,.pure-u-sm-24-24{width:100%}}@media screen and (min-width:48em){.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-1-2,.pure-u-md-1-3,.pure-u-md-2-3,.pure-u-md-1-4,.pure-u-md-3-4,.pure-u-md-1-5,.pure-u-md-2-5,.pure-u-md-3-5,.pure-u-md-4-5,.pure-u-md-5-5,.pure-u-md-1-6,.pure-u-md-5-6,.pure-u-md-1-8,.pure-u-md-3-8,.pure-u-md-5-8,.pure-u-md-7-8,.pure-u-md-1-12,.pure-u-md-5-12,.pure-u-md-7-12,.pure-u-md-11-12,.pure-u-md-1-24,.pure-u-md-2-24,.pure-u-md-3-24,.pure-u-md-4-24,.pure-u-md-5-24,.pure-u-md-6-24,.pure-u-md-7-24,.pure-u-md-8-24,.pure-u-md-9-24,.pure-u-md-10-24,.pure-u-md-11-24,.pure-u-md-12-24,.pure-u-md-13-24,.pure-u-md-14-24,.pure-u-md-15-24,.pure-u-md-16-24,.pure-u-md-17-24,.pure-u-md-18-24,.pure-u-md-19-24,.pure-u-md-20-24,.pure-u-md-21-24,.pure-u-md-22-24,.pure-u-md-23-24,.pure-u-md-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-md-1-24{width:4.1667%;*width:4.1357%}.pure-u-md-1-12,.pure-u-md-2-24{width:8.3333%;*width:8.3023%}.pure-u-md-1-8,.pure-u-md-3-24{width:12.5%;*width:12.469%}.pure-u-md-1-6,.pure-u-md-4-24{width:16.6667%;*width:16.6357%}.pure-u-md-1-5{width:20%;*width:19.969%}.pure-u-md-5-24{width:20.8333%;*width:20.8023%}.pure-u-md-1-4,.pure-u-md-6-24{width:25%;*width:24.969%}.pure-u-md-7-24{width:29.1667%;*width:29.1357%}.pure-u-md-1-3,.pure-u-md-8-24{width:33.3333%;*width:33.3023%}.pure-u-md-3-8,.pure-u-md-9-24{width:37.5%;*width:37.469%}.pure-u-md-2-5{width:40%;*width:39.969%}.pure-u-md-5-12,.pure-u-md-10-24{width:41.6667%;*width:41.6357%}.pure-u-md-11-24{width:45.8333%;*width:45.8023%}.pure-u-md-1-2,.pure-u-md-12-24{width:50%;*width:49.969%}.pure-u-md-13-24{width:54.1667%;*width:54.1357%}.pure-u-md-7-12,.pure-u-md-14-24{width:58.3333%;*width:58.3023%}.pure-u-md-3-5{width:60%;*width:59.969%}.pure-u-md-5-8,.pure-u-md-15-24{width:62.5%;*width:62.469%}.pure-u-md-2-3,.pure-u-md-16-24{width:66.6667%;*width:66.6357%}.pure-u-md-17-24{width:70.8333%;*width:70.8023%}.pure-u-md-3-4,.pure-u-md-18-24{width:75%;*width:74.969%}.pure-u-md-19-24{width:79.1667%;*width:79.1357%}.pure-u-md-4-5{width:80%;*width:79.969%}.pure-u-md-5-6,.pure-u-md-20-24{width:83.3333%;*width:83.3023%}.pure-u-md-7-8,.pure-u-md-21-24{width:87.5%;*width:87.469%}.pure-u-md-11-12,.pure-u-md-22-24{width:91.6667%;*width:91.6357%}.pure-u-md-23-24{width:95.8333%;*width:95.8023%}.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-5-5,.pure-u-md-24-24{width:100%}}@media screen and (min-width:64em){.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-1-2,.pure-u-lg-1-3,.pure-u-lg-2-3,.pure-u-lg-1-4,.pure-u-lg-3-4,.pure-u-lg-1-5,.pure-u-lg-2-5,.pure-u-lg-3-5,.pure-u-lg-4-5,.pure-u-lg-5-5,.pure-u-lg-1-6,.pure-u-lg-5-6,.pure-u-lg-1-8,.pure-u-lg-3-8,.pure-u-lg-5-8,.pure-u-lg-7-8,.pure-u-lg-1-12,.pure-u-lg-5-12,.pure-u-lg-7-12,.pure-u-lg-11-12,.pure-u-lg-1-24,.pure-u-lg-2-24,.pure-u-lg-3-24,.pure-u-lg-4-24,.pure-u-lg-5-24,.pure-u-lg-6-24,.pure-u-lg-7-24,.pure-u-lg-8-24,.pure-u-lg-9-24,.pure-u-lg-10-24,.pure-u-lg-11-24,.pure-u-lg-12-24,.pure-u-lg-13-24,.pure-u-lg-14-24,.pure-u-lg-15-24,.pure-u-lg-16-24,.pure-u-lg-17-24,.pure-u-lg-18-24,.pure-u-lg-19-24,.pure-u-lg-20-24,.pure-u-lg-21-24,.pure-u-lg-22-24,.pure-u-lg-23-24,.pure-u-lg-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-lg-1-24{width:4.1667%;*width:4.1357%}.pure-u-lg-1-12,.pure-u-lg-2-24{width:8.3333%;*width:8.3023%}.pure-u-lg-1-8,.pure-u-lg-3-24{width:12.5%;*width:12.469%}.pure-u-lg-1-6,.pure-u-lg-4-24{width:16.6667%;*width:16.6357%}.pure-u-lg-1-5{width:20%;*width:19.969%}.pure-u-lg-5-24{width:20.8333%;*width:20.8023%}.pure-u-lg-1-4,.pure-u-lg-6-24{width:25%;*width:24.969%}.pure-u-lg-7-24{width:29.1667%;*width:29.1357%}.pure-u-lg-1-3,.pure-u-lg-8-24{width:33.3333%;*width:33.3023%}.pure-u-lg-3-8,.pure-u-lg-9-24{width:37.5%;*width:37.469%}.pure-u-lg-2-5{width:40%;*width:39.969%}.pure-u-lg-5-12,.pure-u-lg-10-24{width:41.6667%;*width:41.6357%}.pure-u-lg-11-24{width:45.8333%;*width:45.8023%}.pure-u-lg-1-2,.pure-u-lg-12-24{width:50%;*width:49.969%}.pure-u-lg-13-24{width:54.1667%;*width:54.1357%}.pure-u-lg-7-12,.pure-u-lg-14-24{width:58.3333%;*width:58.3023%}.pure-u-lg-3-5{width:60%;*width:59.969%}.pure-u-lg-5-8,.pure-u-lg-15-24{width:62.5%;*width:62.469%}.pure-u-lg-2-3,.pure-u-lg-16-24{width:66.6667%;*width:66.6357%}.pure-u-lg-17-24{width:70.8333%;*width:70.8023%}.pure-u-lg-3-4,.pure-u-lg-18-24{width:75%;*width:74.969%}.pure-u-lg-19-24{width:79.1667%;*width:79.1357%}.pure-u-lg-4-5{width:80%;*width:79.969%}.pure-u-lg-5-6,.pure-u-lg-20-24{width:83.3333%;*width:83.3023%}.pure-u-lg-7-8,.pure-u-lg-21-24{width:87.5%;*width:87.469%}.pure-u-lg-11-12,.pure-u-lg-22-24{width:91.6667%;*width:91.6357%}.pure-u-lg-23-24{width:95.8333%;*width:95.8023%}.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-5-5,.pure-u-lg-24-24{width:100%}}@media screen and (min-width:80em){.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-1-2,.pure-u-xl-1-3,.pure-u-xl-2-3,.pure-u-xl-1-4,.pure-u-xl-3-4,.pure-u-xl-1-5,.pure-u-xl-2-5,.pure-u-xl-3-5,.pure-u-xl-4-5,.pure-u-xl-5-5,.pure-u-xl-1-6,.pure-u-xl-5-6,.pure-u-xl-1-8,.pure-u-xl-3-8,.pure-u-xl-5-8,.pure-u-xl-7-8,.pure-u-xl-1-12,.pure-u-xl-5-12,.pure-u-xl-7-12,.pure-u-xl-11-12,.pure-u-xl-1-24,.pure-u-xl-2-24,.pure-u-xl-3-24,.pure-u-xl-4-24,.pure-u-xl-5-24,.pure-u-xl-6-24,.pure-u-xl-7-24,.pure-u-xl-8-24,.pure-u-xl-9-24,.pure-u-xl-10-24,.pure-u-xl-11-24,.pure-u-xl-12-24,.pure-u-xl-13-24,.pure-u-xl-14-24,.pure-u-xl-15-24,.pure-u-xl-16-24,.pure-u-xl-17-24,.pure-u-xl-18-24,.pure-u-xl-19-24,.pure-u-xl-20-24,.pure-u-xl-21-24,.pure-u-xl-22-24,.pure-u-xl-23-24,.pure-u-xl-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-xl-1-24{width:4.1667%;*width:4.1357%}.pure-u-xl-1-12,.pure-u-xl-2-24{width:8.3333%;*width:8.3023%}.pure-u-xl-1-8,.pure-u-xl-3-24{width:12.5%;*width:12.469%}.pure-u-xl-1-6,.pure-u-xl-4-24{width:16.6667%;*width:16.6357%}.pure-u-xl-1-5{width:20%;*width:19.969%}.pure-u-xl-5-24{width:20.8333%;*width:20.8023%}.pure-u-xl-1-4,.pure-u-xl-6-24{width:25%;*width:24.969%}.pure-u-xl-7-24{width:29.1667%;*width:29.1357%}.pure-u-xl-1-3,.pure-u-xl-8-24{width:33.3333%;*width:33.3023%}.pure-u-xl-3-8,.pure-u-xl-9-24{width:37.5%;*width:37.469%}.pure-u-xl-2-5{width:40%;*width:39.969%}.pure-u-xl-5-12,.pure-u-xl-10-24{width:41.6667%;*width:41.6357%}.pure-u-xl-11-24{width:45.8333%;*width:45.8023%}.pure-u-xl-1-2,.pure-u-xl-12-24{width:50%;*width:49.969%}.pure-u-xl-13-24{width:54.1667%;*width:54.1357%}.pure-u-xl-7-12,.pure-u-xl-14-24{width:58.3333%;*width:58.3023%}.pure-u-xl-3-5{width:60%;*width:59.969%}.pure-u-xl-5-8,.pure-u-xl-15-24{width:62.5%;*width:62.469%}.pure-u-xl-2-3,.pure-u-xl-16-24{width:66.6667%;*width:66.6357%}.pure-u-xl-17-24{width:70.8333%;*width:70.8023%}.pure-u-xl-3-4,.pure-u-xl-18-24{width:75%;*width:74.969%}.pure-u-xl-19-24{width:79.1667%;*width:79.1357%}.pure-u-xl-4-5{width:80%;*width:79.969%}.pure-u-xl-5-6,.pure-u-xl-20-24{width:83.3333%;*width:83.3023%}.pure-u-xl-7-8,.pure-u-xl-21-24{width:87.5%;*width:87.469%}.pure-u-xl-11-12,.pure-u-xl-22-24{width:91.6667%;*width:91.6357%}.pure-u-xl-23-24{width:95.8333%;*width:95.8023%}.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-5-5,.pure-u-xl-24-24{width:100%}} diff -r 000000000000 -r 52d30e6014a0 html/main.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/html/main.html Mon Feb 09 09:20:01 2015 -0800 @@ -0,0 +1,56 @@ + + + + + Yubikey Programmer + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
 
+ + + + + + + + + + + + + + + + + + + + + +
Firmware version:
Serial:
Programmed counter:
Slot 1 status:
Slot 2 status:
+ + + diff -r 000000000000 -r 52d30e6014a0 img/yubi.png Binary file img/yubi.png has changed diff -r 000000000000 -r 52d30e6014a0 js/can.jquery-2.1.1.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/can.jquery-2.1.1.js Mon Feb 09 09:20:01 2015 -0800 @@ -0,0 +1,7219 @@ +/*! + * CanJS - 2.1.1 + * http://canjs.us/ + * Copyright (c) 2014 Bitovi + * Fri, 23 May 2014 15:47:45 GMT + * Licensed MIT + * Includes: can/construct/construct.js,can/map/map.js,can/list/list.js,can/compute/compute.js,can/model/model.js,can/view/view.js,can/control/control.js,can/route/route.js,can/control/route/route.js,can/view/ejs/ejs.js,can/map/backup/backup.js,can/util/object/object.js + * Download from: http://bitbuilder.herokuapp.com/can.custom.js?configuration=jquery&plugins=can%2Fconstruct%2Fconstruct.js&plugins=can%2Fmap%2Fmap.js&plugins=can%2Flist%2Flist.js&plugins=can%2Fcompute%2Fcompute.js&plugins=can%2Fmodel%2Fmodel.js&plugins=can%2Fview%2Fview.js&plugins=can%2Fcontrol%2Fcontrol.js&plugins=can%2Froute%2Froute.js&plugins=can%2Fcontrol%2Froute%2Froute.js&plugins=can%2Fview%2Fejs%2Fejs.js&plugins=can%2Fmap%2Fbackup%2Fbackup.js&plugins=can%2Futil%2Fobject%2Fobject.js + */ +(function(undefined) { + + // ## can/util/can.js + var __m5 = (function() { + + var can = window.can || {}; + if (typeof GLOBALCAN === 'undefined' || GLOBALCAN !== false) { + window.can = can; + } + + // An empty function useful for where you need a dummy callback. + can.k = function() {}; + + can.isDeferred = function(obj) { + var isFunction = this.isFunction; + // Returns `true` if something looks like a deferred. + return obj && isFunction(obj.then) && isFunction(obj.pipe); + }; + + var cid = 0; + can.cid = function(object, name) { + if (!object._cid) { + cid++; + object._cid = (name || '') + cid; + } + return object._cid; + }; + can.VERSION = '@EDGE'; + + can.simpleExtend = function(d, s) { + for (var prop in s) { + d[prop] = s[prop]; + } + return d; + }; + + can.frag = function(item) { + var frag; + if (!item || typeof item === "string") { + frag = can.buildFragment(item == null ? "" : "" + item, document.body); + // If we have an empty frag... + if (!frag.childNodes.length) { + frag.appendChild(document.createTextNode('')); + } + return frag; + } else if (item.nodeType === 11) { + return item; + } else if (typeof item.nodeType === "number") { + frag = document.createDocumentFragment(); + frag.appendChild(item); + return frag; + } else if (typeof item.length === "number") { + frag = document.createDocumentFragment(); + can.each(item, function(item) { + frag.appendChild(can.frag(item)); + }); + return frag; + } else { + frag = can.buildFragment("" + item, document.body); + // If we have an empty frag... + if (!frag.childNodes.length) { + frag.appendChild(document.createTextNode('')); + } + return frag; + } + }; + + // this is here in case can.compute hasn't loaded + can.__reading = function() {}; + + return can; + })(); + + // ## can/util/attr/attr.js + var __m6 = (function(can) { + + // Acts as a polyfill for setImmediate which only works in IE 10+. Needed to make + // the triggering of `attributes` event async. + var setImmediate = window.setImmediate || function(cb) { + return setTimeout(cb, 0); + }, + attr = { + // This property lets us know if the browser supports mutation observers. + // If they are supported then that will be setup in can/util/jquery and those native events will be used to inform observers of attribute changes. + // Otherwise this module handles triggering an `attributes` event on the element. + MutationObserver: window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver, + + + map: { + "class": "className", + "value": "value", + "innerText": "innerText", + "textContent": "textContent", + "checked": true, + "disabled": true, + "readonly": true, + "required": true, + // For the `src` attribute we are using a setter function to prevent values such as an empty string or null from being set. + // An `img` tag attempts to fetch the `src` when it is set, so we need to prevent that from happening by removing the attribute instead. + src: function(el, val) { + if (val == null || val === "") { + el.removeAttribute("src"); + return null; + } else { + el.setAttribute("src", val); + return val; + } + }, + style: function(el, val) { + return el.style.cssText = val || ""; + } + }, + // These are elements whos default value we should set. + defaultValue: ["input", "textarea"], + // ## attr.set + // Set the value an attribute on an element. + set: function(el, attrName, val) { + var oldValue; + // In order to later trigger an event we need to compare the new value to the old value, so here we go ahead and retrieve the old value for browsers that don't have native MutationObservers. + if (!attr.MutationObserver) { + oldValue = attr.get(el, attrName); + } + + var tagName = el.nodeName.toString() + .toLowerCase(), + prop = attr.map[attrName], + newValue; + + // Using the property of `attr.map`, go through and check if the property is a function, and if so call it. Then check if the property is `true`, and if so set the value to `true`, also making sure to set `defaultChecked` to `true` for elements of `attr.defaultValue`. We always set the value to true because for these boolean properties, setting them to false would be the same as removing the attribute. + // For all other attributes use `setAttribute` to set the new value. + if (typeof prop === "function") { + newValue = prop(el, val); + } else if (prop === true) { + newValue = el[attrName] = true; + + if (attrName === "checked" && el.type === "radio") { + if (can.inArray(tagName, attr.defaultValue) >= 0) { + el.defaultChecked = true; + } + } + + } else if (prop) { + newValue = el[prop] = val; + if (prop === "value" && can.inArray(tagName, attr.defaultValue) >= 0) { + el.defaultValue = val; + } + } else { + el.setAttribute(attrName, val); + newValue = val; + } + + // Now that the value has been set, for browsers without MutationObservers, check to see that value has changed and if so trigger the "attributes" event on the element. + if (!attr.MutationObserver && newValue !== oldValue) { + attr.trigger(el, attrName, oldValue); + } + }, + // ## attr.trigger + // Used to trigger an "attributes" event on an element. Checks to make sure that someone is listening for the event and then queues a function to be called asynchronously using `setImmediate. + trigger: function(el, attrName, oldValue) { + if (can.data(can.$(el), "canHasAttributesBindings")) { + return setImmediate(function() { + can.trigger(el, { + type: "attributes", + attributeName: attrName, + target: el, + oldValue: oldValue, + bubbles: false + }, []); + }); + } + }, + // ## attr.get + // Gets the value of an attribute. First checks to see if the property is a string on `attr.map` and if so returns the value from the element's property. Otherwise uses `getAttribute` to retrieve the value. + get: function(el, attrName) { + var prop = attr.map[attrName]; + if (typeof prop === "string" && el[prop]) { + return el[prop]; + } + + return el.getAttribute(attrName); + }, + // ## attr.remove + // Removes an attribute from an element. Works by using the `attr.map` to see if the attribute is a special type of property. If the property is a function then the fuction is called with `undefined` as the value. If the property is `true` then the attribute is set to false. If the property is a string then the attribute is set to an empty string. Otherwise `removeAttribute` is used. + // If the attribute previously had a value and the browser doesn't support MutationObservers we then trigger an "attributes" event. + remove: function(el, attrName) { + var oldValue; + if (!attr.MutationObserver) { + oldValue = attr.get(el, attrName); + } + + var setter = attr.map[attrName]; + if (typeof setter === "function") { + setter(el, undefined); + } + if (setter === true) { + el[attrName] = false; + } else if (typeof setter === "string") { + el[setter] = ""; + } else { + el.removeAttribute(attrName); + } + if (!attr.MutationObserver && oldValue != null) { + attr.trigger(el, attrName, oldValue); + } + + }, + // ## attr.has + // Checks if an element contains an attribute. + // For browsers that support `hasAttribute`, creates a function that calls hasAttribute, otherwise creates a function that uses `getAttribute` to check that the attribute is not null. + has: (function() { + var el = document.createElement('div'); + if (el.hasAttribute) { + return function(el, name) { + return el.hasAttribute(name); + }; + } else { + return function(el, name) { + return el.getAttribute(name) !== null; + }; + } + })() + }; + + return attr; + + })(__m5); + + // ## can/event/event.js + var __m7 = (function(can) { + // ## can.event.addEvent + // Adds a basic event listener to an object. + // This consists of storing a cache of event listeners on each object, + // that are iterated through later when events are dispatched. + + can.addEvent = function(event, handler) { + // Initialize event cache. + var allEvents = this.__bindEvents || (this.__bindEvents = {}), + eventList = allEvents[event] || (allEvents[event] = []); + + // Add the event + eventList.push({ + handler: handler, + name: event + }); + return this; + }; + + // ## can.event.listenTo + // Listens to an event without know how bind is implemented. + // The primary use for this is to listen to another's objects event while + // tracking events on the local object (similar to namespacing). + // The API was heavily influenced by BackboneJS: http://backbonejs.org/ + + can.listenTo = function(other, event, handler) { + // Initialize event cache + var idedEvents = this.__listenToEvents; + if (!idedEvents) { + idedEvents = this.__listenToEvents = {}; + } + + // Identify the other object + var otherId = can.cid(other); + var othersEvents = idedEvents[otherId]; + + // Create a local event cache + if (!othersEvents) { + othersEvents = idedEvents[otherId] = { + obj: other, + events: {} + }; + } + var eventsEvents = othersEvents.events[event]; + if (!eventsEvents) { + eventsEvents = othersEvents.events[event] = []; + } + + // Add the event, both locally and to the other object + eventsEvents.push(handler); + can.bind.call(other, event, handler); + }; + + // ## can.event.stopListening + // Stops listening for events on other objects + + can.stopListening = function(other, event, handler) { + var idedEvents = this.__listenToEvents, + iterIdedEvents = idedEvents, + i = 0; + if (!idedEvents) { + return this; + } + if (other) { + var othercid = can.cid(other); + (iterIdedEvents = {})[othercid] = idedEvents[othercid]; + // you might be trying to listen to something that is not there + if (!idedEvents[othercid]) { + return this; + } + } + + // Clean up events on the other object + for (var cid in iterIdedEvents) { + var othersEvents = iterIdedEvents[cid], + eventsEvents; + other = idedEvents[cid].obj; + + // Find the cache of events + if (!event) { + eventsEvents = othersEvents.events; + } else { + (eventsEvents = {})[event] = othersEvents.events[event]; + } + + // Unbind event handlers, both locally and on the other object + for (var eventName in eventsEvents) { + var handlers = eventsEvents[eventName] || []; + i = 0; + while (i < handlers.length) { + if (handler && handler === handlers[i] || !handler) { + can.unbind.call(other, eventName, handlers[i]); + handlers.splice(i, 1); + } else { + i++; + } + } + // no more handlers? + if (!handlers.length) { + delete othersEvents.events[eventName]; + } + } + if (can.isEmptyObject(othersEvents.events)) { + delete idedEvents[cid]; + } + } + return this; + }; + + // ## can.event.removeEvent + // Removes a basic event listener from an object. + // This removes event handlers from the cache of listened events. + + can.removeEvent = function(event, fn, __validate) { + if (!this.__bindEvents) { + return this; + } + var events = this.__bindEvents[event] || [], + i = 0, + ev, isFunction = typeof fn === 'function'; + while (i < events.length) { + ev = events[i]; + // Determine whether this event handler is "equivalent" to the one requested + // Generally this requires the same event/function, but a validation function + // can be included for extra conditions. This is used in some plugins like `can/event/namespace`. + if (__validate ? __validate(ev, event, fn) : isFunction && ev.handler === fn || !isFunction && (ev.cid === fn || !fn)) { + events.splice(i, 1); + } else { + i++; + } + } + return this; + }; + + // ## can.event.dispatch + // Dispatches/triggers a basic event on an object. + + can.dispatch = function(event, args) { + var events = this.__bindEvents; + if (!events) { + return; + } + + // Initialize the event object + if (typeof event === 'string') { + event = { + type: event + }; + } + + // Grab event listeners + var eventName = event.type, + handlers = (events[eventName] || []).slice(0); + + // Execute handlers listening for this event. + args = [event].concat(args || []); + for (var i = 0, len = handlers.length; i < len; i++) { + handlers[i].handler.apply(this, args); + } + + return event; + }; + + // ## can.event.one + // Adds a basic event listener that listens to an event once and only once. + + can.one = function(event, handler) { + // Unbind the listener after it has been executed + var one = function() { + can.unbind.call(this, event, one); + return handler.apply(this, arguments); + }; + + // Bind the altered listener + can.bind.call(this, event, one); + return this; + }; + + // ## can.event + // Create and export the `can.event` mixin + can.event = { + // Event method aliases + + on: function() { + if (arguments.length === 0 && can.Control && this instanceof can.Control) { + return can.Control.prototype.on.call(this); + } else { + return can.addEvent.apply(this, arguments); + } + }, + + + off: function() { + if (arguments.length === 0 && can.Control && this instanceof can.Control) { + return can.Control.prototype.off.call(this); + } else { + return can.removeEvent.apply(this, arguments); + } + }, + + + bind: can.addEvent, + + unbind: can.removeEvent, + + delegate: function(selector, event, handler) { + return can.addEvent.call(event, handler); + }, + + undelegate: function(selector, event, handler) { + return can.removeEvent.call(event, handler); + }, + + trigger: can.dispatch, + + // Normal can/event methods + one: can.one, + addEvent: can.addEvent, + removeEvent: can.removeEvent, + listenTo: can.listenTo, + stopListening: can.stopListening, + dispatch: can.dispatch + }; + + return can.event; + })(__m5); + + // ## can/util/array/each.js + var __m8 = (function(can) { + + // The following is from jQuery + var isArrayLike = function(obj) { + var length = obj.length; + return typeof arr !== "function" && + (length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj); + }; + + can.each = function(elements, callback, context) { + var i = 0, + key, + len, + item; + if (elements) { + if (isArrayLike(elements)) { + if (can.List && elements instanceof can.List) { + for (len = elements.attr("length"); i < len; i++) { + item = elements.attr(i); + if (callback.call(context || item, item, i, elements) === false) { + break; + } + } + } else { + for (len = elements.length; i < len; i++) { + item = elements[i]; + if (callback.call(context || item, item, i, elements) === false) { + break; + } + } + } + + } else if (typeof elements === "object") { + + if (can.Map && elements instanceof can.Map || elements === can.route) { + var keys = can.Map.keys(elements); + for (i = 0, len = keys.length; i < len; i++) { + key = keys[i]; + item = elements.attr(key); + if (callback.call(context || item, item, key, elements) === false) { + break; + } + } + } else { + for (key in elements) { + if (elements.hasOwnProperty(key) && callback.call(context || elements[key], elements[key], key, elements) === false) { + break; + } + } + } + + } + } + return elements; + }; + return can; + })(__m5); + + // ## can/util/inserted/inserted.js + var __m9 = (function(can) { + can.inserted = function(elems) { + // Turn the `elems` property into an array to prevent mutations from changing the looping. + elems = can.makeArray(elems); + var inDocument = false, + // Gets the `doc` to use as a reference for finding out whether the element is in the document. + doc = can.$(document.contains ? document : document.body), + children; + // Go through `elems` and trigger the `inserted` event. + // If the first element is not in the document (a Document Fragment) it will exit the function. If it is in the document it sets the `inDocument` flag to true. This means that we only check for the first element and either exit the function or start triggering "inserted" for child elements. + for (var i = 0, elem; + (elem = elems[i]) !== undefined; i++) { + if (!inDocument) { + if (elem.getElementsByTagName) { + if (can.has(doc, elem) + .length) { + inDocument = true; + } else { + return; + } + } else { + continue; + } + } + + // If we've found an element in the document then we can now trigger **"inserted"** for `elem` and all of its children. We are using `getElementsByTagName("*")` so that we grab all of the descendant nodes. + if (inDocument && elem.getElementsByTagName) { + children = can.makeArray(elem.getElementsByTagName("*")); + can.trigger(elem, "inserted", [], false); + for (var j = 0, child; + (child = children[j]) !== undefined; j++) { + can.trigger(child, "inserted", [], false); + } + } + } + }; + + // ## can.appendChild + // Used to append a node to an element and trigger the "inserted" event on all of the newly inserted children. Since `can.inserted` takes an array we convert the child to an array, or in the case of a DocumentFragment we first convert the childNodes to an array and call inserted on those. + can.appendChild = function(el, child) { + var children; + if (child.nodeType === 11) { + children = can.makeArray(child.childNodes); + } else { + children = [child]; + } + el.appendChild(child); + can.inserted(children); + }; + + // ## can.insertBefore + // Like can.appendChild, used to insert a node to an element before a reference node and then trigger the "inserted" event. + can.insertBefore = function(el, child, ref) { + var children; + if (child.nodeType === 11) { + children = can.makeArray(child.childNodes); + } else { + children = [child]; + } + el.insertBefore(child, ref); + can.inserted(children); + }; + })(__m5); + + // ## can/util/jquery/jquery.js + var __m3 = (function($, can, attr, event) { + var isBindableElement = function(node) { + // In IE8 window.window !== window.window, so we allow == here. + + return (node.nodeName && (node.nodeType === 1 || node.nodeType === 9)) || node == window; + }; + // _jQuery node list._ + $.extend(can, $, { + trigger: function(obj, event, args, bubbles) { + if (isBindableElement(obj)) { + $.event.trigger(event, args, obj, !bubbles); + } else if (obj.trigger) { + obj.trigger(event, args); + } else { + if (typeof event === 'string') { + event = { + type: event + }; + } + event.target = event.target || obj; + can.dispatch.call(obj, event, args); + } + }, + event: can.event, + addEvent: can.addEvent, + removeEvent: can.removeEvent, + buildFragment: function(elems, context) { + // Check if this has any html nodes on our own. + var ret; + elems = [elems]; + // Set context per 1.8 logic + context = context || document; + context = !context.nodeType && context[0] || context; + context = context.ownerDocument || context; + ret = $.buildFragment(elems, context); + return ret.cacheable ? $.clone(ret.fragment) : ret.fragment || ret; + }, + $: $, + each: can.each, + bind: function(ev, cb) { + // If we can bind to it... + if (this.bind && this.bind !== can.bind) { + this.bind(ev, cb); + } else if (isBindableElement(this)) { + $.event.add(this, ev, cb); + } else { + // Make it bind-able... + can.addEvent.call(this, ev, cb); + } + return this; + }, + unbind: function(ev, cb) { + // If we can bind to it... + if (this.unbind && this.unbind !== can.unbind) { + this.unbind(ev, cb); + } else if (isBindableElement(this)) { + $.event.remove(this, ev, cb); + } else { + // Make it bind-able... + can.removeEvent.call(this, ev, cb); + } + return this; + }, + delegate: function(selector, ev, cb) { + if (this.delegate) { + this.delegate(selector, ev, cb); + } else if (isBindableElement(this)) { + $(this) + .delegate(selector, ev, cb); + } else { + // make it bind-able ... + can.bind.call(this, ev, cb); + } + return this; + }, + undelegate: function(selector, ev, cb) { + if (this.undelegate) { + this.undelegate(selector, ev, cb); + } else if (isBindableElement(this)) { + $(this) + .undelegate(selector, ev, cb); + } else { + can.unbind.call(this, ev, cb); + } + return this; + }, + proxy: function(fn, context) { + return function() { + return fn.apply(context, arguments); + }; + }, + attr: attr + }); + // Wrap binding functions. + + // Aliases + can.on = can.bind; + can.off = can.unbind; + // Wrap modifier functions. + $.each([ + 'append', + 'filter', + 'addClass', + 'remove', + 'data', + 'get', + 'has' + ], function(i, name) { + can[name] = function(wrapped) { + return wrapped[name].apply(wrapped, can.makeArray(arguments) + .slice(1)); + }; + }); + // Memory safe destruction. + var oldClean = $.cleanData; + $.cleanData = function(elems) { + $.each(elems, function(i, elem) { + if (elem) { + can.trigger(elem, 'removed', [], false); + } + }); + oldClean(elems); + }; + var oldDomManip = $.fn.domManip, + cbIndex; + // feature detect which domManip we are using + $.fn.domManip = function(args, cb1, cb2) { + for (var i = 1; i < arguments.length; i++) { + if (typeof arguments[i] === 'function') { + cbIndex = i; + break; + } + } + return oldDomManip.apply(this, arguments); + }; + $(document.createElement("div")) + .append(document.createElement("div")); + + $.fn.domManip = (cbIndex === 2 ? function(args, table, callback) { + return oldDomManip.call(this, args, table, function(elem) { + var elems; + if (elem.nodeType === 11) { + elems = can.makeArray(elem.childNodes); + } + var ret = callback.apply(this, arguments); + can.inserted(elems ? elems : [elem]); + return ret; + }); + } : function(args, callback) { + return oldDomManip.call(this, args, function(elem) { + var elems; + if (elem.nodeType === 11) { + elems = can.makeArray(elem.childNodes); + } + var ret = callback.apply(this, arguments); + can.inserted(elems ? elems : [elem]); + return ret; + }); + }); + + if (!can.attr.MutationObserver) { + // handle via calls to attr + var oldAttr = $.attr; + $.attr = function(el, attrName) { + var oldValue, newValue; + if (arguments.length >= 3) { + oldValue = oldAttr.call(this, el, attrName); + } + var res = oldAttr.apply(this, arguments); + if (arguments.length >= 3) { + newValue = oldAttr.call(this, el, attrName); + } + if (newValue !== oldValue) { + can.attr.trigger(el, attrName, oldValue); + } + return res; + }; + var oldRemove = $.removeAttr; + $.removeAttr = function(el, attrName) { + var oldValue = oldAttr.call(this, el, attrName), + res = oldRemove.apply(this, arguments); + + if (oldValue != null) { + can.attr.trigger(el, attrName, oldValue); + } + return res; + }; + $.event.special.attributes = { + setup: function() { + can.data(can.$(this), "canHasAttributesBindings", true); + }, + teardown: function() { + $.removeData(this, "canHasAttributesBindings"); + } + }; + } else { + // setup a special events + $.event.special.attributes = { + setup: function() { + var self = this; + var observer = new can.attr.MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + var copy = can.simpleExtend({}, mutation); + can.trigger(self, copy, []); + }); + + }); + observer.observe(this, { + attributes: true, + attributeOldValue: true + }); + can.data(can.$(this), "canAttributesObserver", observer); + }, + teardown: function() { + can.data(can.$(this), "canAttributesObserver") + .disconnect(); + $.removeData(this, "canAttributesObserver"); + + } + }; + } + + // ## Fix build fragment. + // In IE8, we can pass jQuery a fragment and it removes newlines. + // This checks for that and replaces can.buildFragment with something + // that if only a single text node is returned, returns a fragment with + // a text node that is set to the content. + (function() { + + var text = "<-\n>", + frag = can.buildFragment(text, document); + if (text !== frag.childNodes[0].nodeValue) { + + var oldBuildFragment = can.buildFragment; + can.buildFragment = function(content, context) { + var res = oldBuildFragment(content, context); + if (res.childNodes.length === 1 && res.childNodes[0].nodeType === 3) { + res.childNodes[0].nodeValue = content; + } + return res; + }; + + } + + + + })(); + + $.event.special.inserted = {}; + $.event.special.removed = {}; + return can; + })(jQuery, __m5, __m6, __m7, __m8, __m9); + + // ## can/util/string/string.js + var __m2 = (function(can) { + // ##string.js + // _Miscellaneous string utility functions._ + // Several of the methods in this plugin use code adapated from Prototype + // Prototype JavaScript framework, version 1.6.0.1. + // © 2005-2007 Sam Stephenson + var strUndHash = /_|-/, + strColons = /\=\=/, + strWords = /([A-Z]+)([A-Z][a-z])/g, + strLowUp = /([a-z\d])([A-Z])/g, + strDash = /([a-z\d])([A-Z])/g, + strReplacer = /\{([^\}]+)\}/g, + strQuote = /"/g, + strSingleQuote = /'/g, + strHyphenMatch = /-+(.)?/g, + strCamelMatch = /[a-z][A-Z]/g, + // Returns the `prop` property from `obj`. + // If `add` is true and `prop` doesn't exist in `obj`, create it as an + // empty object. + getNext = function(obj, prop, add) { + var result = obj[prop]; + if (result === undefined && add === true) { + result = obj[prop] = {}; + } + return result; + }, + // Returns `true` if the object can have properties (no `null`s). + isContainer = function(current) { + return /^f|^o/.test(typeof current); + }, convertBadValues = function(content) { + // Convert bad values into empty strings + var isInvalid = content === null || content === undefined || isNaN(content) && '' + content === 'NaN'; + return '' + (isInvalid ? '' : content); + }; + can.extend(can, { + esc: function(content) { + return convertBadValues(content) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(strQuote, '"') + .replace(strSingleQuote, '''); + }, + getObject: function(name, roots, add) { + // The parts of the name we are looking up + // `['App','Models','Recipe']` + var parts = name ? name.split('.') : [], + length = parts.length, + current, r = 0, + i, container, rootsLength; + // Make sure roots is an `array`. + roots = can.isArray(roots) ? roots : [roots || window]; + rootsLength = roots.length; + if (!length) { + return roots[0]; + } + // For each root, mark it as current. + for (r; r < rootsLength; r++) { + current = roots[r]; + container = undefined; + // Walk current to the 2nd to last object or until there + // is not a container. + for (i = 0; i < length && isContainer(current); i++) { + container = current; + current = getNext(container, parts[i]); + } + // If we found property break cycle + if (container !== undefined && current !== undefined) { + break; + } + } + // Remove property from found container + if (add === false && current !== undefined) { + delete container[parts[i - 1]]; + } + // When adding property add it to the first root + if (add === true && current === undefined) { + current = roots[0]; + for (i = 0; i < length && isContainer(current); i++) { + current = getNext(current, parts[i], true); + } + } + return current; + }, + capitalize: function(s, cache) { + // Used to make newId. + return s.charAt(0) + .toUpperCase() + s.slice(1); + }, + camelize: function(str) { + return convertBadValues(str) + .replace(strHyphenMatch, function(match, chr) { + return chr ? chr.toUpperCase() : ''; + }); + }, + hyphenate: function(str) { + return convertBadValues(str) + .replace(strCamelMatch, function(str, offset) { + return str.charAt(0) + '-' + str.charAt(1) + .toLowerCase(); + }); + }, + underscore: function(s) { + return s.replace(strColons, '/') + .replace(strWords, '$1_$2') + .replace(strLowUp, '$1_$2') + .replace(strDash, '_') + .toLowerCase(); + }, + sub: function(str, data, remove) { + var obs = []; + str = str || ''; + obs.push(str.replace(strReplacer, function(whole, inside) { + // Convert inside to type. + var ob = can.getObject(inside, data, remove === true ? false : undefined); + if (ob === undefined || ob === null) { + obs = null; + return ''; + } + // If a container, push into objs (which will return objects found). + if (isContainer(ob) && obs) { + obs.push(ob); + return ''; + } + return '' + ob; + })); + return obs === null ? obs : obs.length <= 1 ? obs[0] : obs; + }, + replacer: strReplacer, + undHash: strUndHash + }); + return can; + })(__m3); + + // ## can/construct/construct.js + var __m1 = (function(can) { + // ## construct.js + // `can.Construct` + // _This is a modified version of + // [John Resig's class](http://ejohn.org/blog/simple-javascript-inheritance/). + // It provides class level inheritance and callbacks._ + // A private flag used to initialize a new class instance without + // initializing it's bindings. + var initializing = 0; + + can.Construct = function() { + if (arguments.length) { + return can.Construct.extend.apply(can.Construct, arguments); + } + }; + + can.extend(can.Construct, { + + constructorExtends: true, + + newInstance: function() { + // Get a raw instance object (`init` is not called). + var inst = this.instance(), + args; + // Call `setup` if there is a `setup` + if (inst.setup) { + args = inst.setup.apply(inst, arguments); + } + // Call `init` if there is an `init` + // If `setup` returned `args`, use those as the arguments + if (inst.init) { + inst.init.apply(inst, args || arguments); + } + return inst; + }, + // Overwrites an object with methods. Used in the `super` plugin. + // `newProps` - New properties to add. + // `oldProps` - Where the old properties might be (used with `super`). + // `addTo` - What we are adding to. + _inherit: function(newProps, oldProps, addTo) { + can.extend(addTo || newProps, newProps || {}); + }, + // used for overwriting a single property. + // this should be used for patching other objects + // the super plugin overwrites this + _overwrite: function(what, oldProps, propName, val) { + what[propName] = val; + }, + // Set `defaults` as the merger of the parent `defaults` and this + // object's `defaults`. If you overwrite this method, make sure to + // include option merging logic. + + setup: function(base, fullName) { + this.defaults = can.extend(true, {}, base.defaults, this.defaults); + }, + // Create's a new `class` instance without initializing by setting the + // `initializing` flag. + instance: function() { + // Prevents running `init`. + initializing = 1; + var inst = new this(); + // Allow running `init`. + initializing = 0; + return inst; + }, + // Extends classes. + + extend: function(fullName, klass, proto) { + // Figure out what was passed and normalize it. + if (typeof fullName !== 'string') { + proto = klass; + klass = fullName; + fullName = null; + } + if (!proto) { + proto = klass; + klass = null; + } + proto = proto || {}; + var _super_class = this, + _super = this.prototype, + parts, current, _fullName, _shortName, name, shortName, namespace, prototype; + // Instantiate a base class (but only create the instance, + // don't run the init constructor). + prototype = this.instance(); + // Copy the properties over onto the new prototype. + can.Construct._inherit(proto, _super, prototype); + // The dummy class constructor. + + function Constructor() { + // All construction is actually done in the init method. + if (!initializing) { + + + return this.constructor !== Constructor && + // We are being called without `new` or we are extending. + arguments.length && Constructor.constructorExtends ? Constructor.extend.apply(Constructor, arguments) : + // We are being called with `new`. + Constructor.newInstance.apply(Constructor, arguments); + } + } + // Copy old stuff onto class (can probably be merged w/ inherit) + for (name in _super_class) { + if (_super_class.hasOwnProperty(name)) { + Constructor[name] = _super_class[name]; + } + } + // Copy new static properties on class. + can.Construct._inherit(klass, _super_class, Constructor); + // Setup namespaces. + if (fullName) { + + parts = fullName.split('.'); + shortName = parts.pop(); + current = can.getObject(parts.join('.'), window, true); + namespace = current; + _fullName = can.underscore(fullName.replace(/\./g, "_")); + _shortName = can.underscore(shortName); + + + + current[shortName] = Constructor; + } + // Set things that shouldn't be overwritten. + can.extend(Constructor, { + constructor: Constructor, + prototype: prototype, + + namespace: namespace, + + _shortName: _shortName, + + fullName: fullName, + _fullName: _fullName + }); + // Dojo and YUI extend undefined + if (shortName !== undefined) { + Constructor.shortName = shortName; + } + // Make sure our prototype looks nice. + Constructor.prototype.constructor = Constructor; + // Call the class `setup` and `init` + var t = [_super_class].concat(can.makeArray(arguments)), + args = Constructor.setup.apply(Constructor, t); + if (Constructor.init) { + Constructor.init.apply(Constructor, args || t); + } + + return Constructor; + } + }); + + can.Construct.prototype.setup = function() {}; + + can.Construct.prototype.init = function() {}; + return can.Construct; + })(__m2); + + // ## can/util/bind/bind.js + var __m11 = (function(can) { + + // ## Bind helpers + can.bindAndSetup = function() { + // Add the event to this object + can.addEvent.apply(this, arguments); + // If not initializing, and the first binding + // call bindsetup if the function exists. + if (!this._init) { + if (!this._bindings) { + this._bindings = 1; + // setup live-binding + if (this._bindsetup) { + this._bindsetup(); + } + } else { + this._bindings++; + } + } + return this; + }; + can.unbindAndTeardown = function(ev, handler) { + // Remove the event handler + can.removeEvent.apply(this, arguments); + if (this._bindings === null) { + this._bindings = 0; + } else { + this._bindings--; + } + // If there are no longer any bindings and + // there is a bindteardown method, call it. + if (!this._bindings && this._bindteardown) { + this._bindteardown(); + } + return this; + }; + return can; + })(__m3); + + // ## can/map/bubble.js + var __m12 = (function(can) { + + + + var bubble = can.bubble = { + // Given a binding, returns a string event name used to set up bubbline. + // If no binding should be done, undefined or null should be returned + event: function(map, eventName) { + return map.constructor._bubbleRule(eventName, map); + }, + childrenOf: function(parentMap, eventName) { + + parentMap._each(function(child, prop) { + if (child && child.bind) { + bubble.toParent(child, parentMap, prop, eventName); + } + }); + + }, + teardownChildrenFrom: function(parentMap, eventName) { + parentMap._each(function(child) { + + bubble.teardownFromParent(parentMap, child, eventName); + + }); + }, + toParent: function(child, parent, prop, eventName) { + can.listenTo.call(parent, child, eventName, function() { + // `batchTrigger` the type on this... + var args = can.makeArray(arguments), + ev = args.shift(); + + args[0] = + (can.List && parent instanceof can.List ? + parent.indexOf(child) : + prop) + (args[0] ? "." + args[0] : ""); + + // track objects dispatched on this map + ev.triggeredNS = ev.triggeredNS || {}; + + // if it has already been dispatched exit + if (ev.triggeredNS[parent._cid]) { + return; + } + + ev.triggeredNS[parent._cid] = true; + // send change event with modified attr to parent + can.trigger(parent, ev, args); + }); + }, + teardownFromParent: function(parent, child, eventName) { + if (child && child.unbind) { + can.stopListening.call(parent, child, eventName); + } + }, + bind: function(parent, eventName) { + if (!parent._init) { + var bubbleEvent = bubble.event(parent, eventName); + if (bubbleEvent) { + if (!parent._bubbleBindings) { + parent._bubbleBindings = {}; + } + if (!parent._bubbleBindings[bubbleEvent]) { + parent._bubbleBindings[bubbleEvent] = 1; + // setup live-binding + bubble.childrenOf(parent, bubbleEvent); + } else { + parent._bubbleBindings[bubbleEvent]++; + } + + } + } + }, + unbind: function(parent, eventName) { + var bubbleEvent = bubble.event(parent, eventName); + if (bubbleEvent) { + if (parent._bubbleBindings) { + parent._bubbleBindings[bubbleEvent]--; + } + + if (!parent._bubbleBindings[bubbleEvent]) { + delete parent._bubbleBindings[bubbleEvent]; + bubble.teardownChildrenFrom(parent, bubbleEvent); + if (can.isEmptyObject(parent._bubbleBindings)) { + delete parent._bubbleBindings; + } + } + } + }, + add: function(parent, child, prop) { + if (child instanceof can.Map && parent._bubbleBindings) { + for (var eventName in parent._bubbleBindings) { + if (parent._bubbleBindings[eventName]) { + bubble.teardownFromParent(parent, child, eventName); + bubble.toParent(child, parent, prop, eventName); + } + } + } + }, + removeMany: function(parent, children) { + for (var i = 0, len = children.length; i < len; i++) { + bubble.remove(parent, children[i]); + } + }, + remove: function(parent, child) { + if (child instanceof can.Map && parent._bubbleBindings) { + for (var eventName in parent._bubbleBindings) { + if (parent._bubbleBindings[eventName]) { + bubble.teardownFromParent(parent, child, eventName); + } + } + } + }, + set: function(parent, prop, value, current) { + + //var res = parent.__type(value, prop); + if (can.Map.helpers.isObservable(value)) { + bubble.add(parent, value, prop); + } + // bubble.add will remove, so only remove if we are replacing another object + if (can.Map.helpers.isObservable(current)) { + bubble.remove(parent, current); + } + return value; + } + }; + + return bubble; + + })(__m3); + + // ## can/util/batch/batch.js + var __m13 = (function(can) { + // Which batch of events this is for -- might not want to send multiple + // messages on the same batch. This is mostly for event delegation. + var batchNum = 1, + // how many times has start been called without a stop + transactions = 0, + // an array of events within a transaction + batchEvents = [], + stopCallbacks = []; + can.batch = { + + start: function(batchStopHandler) { + transactions++; + if (batchStopHandler) { + stopCallbacks.push(batchStopHandler); + } + }, + + stop: function(force, callStart) { + if (force) { + transactions = 0; + } else { + transactions--; + } + if (transactions === 0) { + var items = batchEvents.slice(0), + callbacks = stopCallbacks.slice(0), + i, len; + batchEvents = []; + stopCallbacks = []; + batchNum++; + if (callStart) { + can.batch.start(); + } + for (i = 0, len = items.length; i < len; i++) { + can.trigger.apply(can, items[i]); + } + for (i = 0, len = callbacks.length; i < callbacks.length; i++) { + callbacks[i](); + } + } + }, + + trigger: function(item, event, args) { + // Don't send events if initalizing. + if (!item._init) { + if (transactions === 0) { + return can.trigger(item, event, args); + } else { + event = typeof event === 'string' ? { + type: event + } : event; + event.batchNum = batchNum; + batchEvents.push([ + item, + event, + args + ]); + } + } + } + }; + })(__m5); + + // ## can/map/map.js + var __m10 = (function(can, bind, bubble) { + // ## Helpers + + // A temporary map of Maps that have been made from plain JS objects. + var madeMap = null; + // Clears out map of converted objects. + var teardownMap = function() { + for (var cid in madeMap) { + if (madeMap[cid].added) { + delete madeMap[cid].obj._cid; + } + } + madeMap = null; + }; + // Retrieves a Map instance from an Object. + var getMapFromObject = function(obj) { + return madeMap && madeMap[obj._cid] && madeMap[obj._cid].instance; + }; + // A temporary map of Maps + var serializeMap = null; + + + var Map = can.Map = can.Construct.extend({ + + setup: function() { + + can.Construct.setup.apply(this, arguments); + + // Do not run if we are defining can.Map. + if (can.Map) { + if (!this.defaults) { + this.defaults = {}; + } + // Builds a list of compute and non-compute properties in this Object's prototype. + this._computes = []; + + for (var prop in this.prototype) { + // Non-functions are regular defaults. + if (prop !== "define" && typeof this.prototype[prop] !== "function") { + this.defaults[prop] = this.prototype[prop]; + // Functions with an `isComputed` property are computes. + } else if (this.prototype[prop].isComputed) { + this._computes.push(prop); + } + } + this.helpers.define(this); + } + // If we inherit from can.Map, but not can.List, make sure any lists are the correct type. + if (can.List && !(this.prototype instanceof can.List)) { + this.List = Map.List.extend({ + Map: this + }, {}); + } + + }, + // Reference to bubbling helpers. + _bubble: bubble, + // Given an eventName, determine if bubbling should be setup. + _bubbleRule: function(eventName) { + return (eventName === "change" || eventName.indexOf(".") >= 0) && "change"; + }, + // List of computes on the Map's prototype. + _computes: [], + // Adds an event to this Map. + bind: can.bindAndSetup, + on: can.bindAndSetup, + // Removes an event from this Map. + unbind: can.unbindAndTeardown, + off: can.unbindAndTeardown, + // Name of the id field. Used in can.Model. + id: "id", + // ## Internal helpers + helpers: { + // ### can.Map.helpers.define + // Stub function for the define plugin. + define: function() {}, + + // ### can.Map.helpers.attrParts + // Parses attribute name into its parts. + attrParts: function(attr, keepKey) { + //Keep key intact + if (keepKey) { + return [attr]; + } + // Split key on '.' + return can.isArray(attr) ? attr : ("" + attr) + .split("."); + }, + + // ### can.Map.helpers.addToMap + // Tracks Map instances created from JS Objects + addToMap: function(obj, instance) { + var teardown; + // Setup a fresh mapping if `madeMap` is missing. + if (!madeMap) { + teardown = teardownMap; + madeMap = {}; + } + // Record if Object has a `_cid` before adding one. + var hasCid = obj._cid; + var cid = can.cid(obj); + + // Only update if there already isn't one already. + if (!madeMap[cid]) { + + madeMap[cid] = { + obj: obj, + instance: instance, + added: !hasCid + }; + } + return teardown; + }, + + // ### can.Map.helpers.isObservable + // Determines if `obj` is observable. + isObservable: function(obj) { + return obj instanceof can.Map || (obj && obj === can.route); + }, + + // ### can.Map.helpers.canMakeObserve + // Determines if an object can be made into an observable. + canMakeObserve: function(obj) { + return obj && !can.isDeferred(obj) && (can.isArray(obj) || can.isPlainObject(obj)); + }, + + // ### can.Map.helpers.serialize + // Serializes a Map or Map.List + serialize: function(map, how, where) { + var cid = can.cid(map), + firstSerialize = false; + if (!serializeMap) { + firstSerialize = true; + // Serialize might call .attr() so we need to keep different map + serializeMap = { + attr: {}, + serialize: {} + }; + } + serializeMap[how][cid] = where; + // Go through each property. + map.each(function(val, name) { + // If the value is an `object`, and has an `attrs` or `serialize` function. + var result, + isObservable = Map.helpers.isObservable(val), + serialized = isObservable && serializeMap[how][can.cid(val)]; + if (serialized) { + result = serialized; + } else { + if (how === "serialize") { + result = Map.helpers._serialize(map, name, val); + } else { + result = Map.helpers._getValue(map, name, val, how); + } + } + // this is probably removable + if (result !== undefined) { + where[name] = result; + } + }); + + can.__reading(map, '__keys'); + if (firstSerialize) { + serializeMap = null; + } + return where; + }, + _serialize: function(map, name, val) { + return Map.helpers._getValue(map, name, val, "serialize"); + }, + _getValue: function(map, name, val, how) { + if (Map.helpers.isObservable(val)) { + return val[how](); + } else { + return val; + } + } + }, + + keys: function(map) { + var keys = []; + can.__reading(map, '__keys'); + for (var keyName in map._data) { + keys.push(keyName); + } + return keys; + } + }, + + { + setup: function(obj) { + // `_data` is where we keep the properties. + this._data = {}; + + // The namespace this `object` uses to listen to events. + can.cid(this, ".map"); + // Sets all `attrs`. + this._init = 1; + // It's handy if we pass this to comptues, because computes can have a default value. + var defaultValues = this._setupDefaults(); + this._setupComputes(defaultValues); + var teardownMapping = obj && can.Map.helpers.addToMap(obj, this); + + var data = can.extend(can.extend(true, {}, defaultValues), obj); + + this.attr(data); + + if (teardownMapping) { + teardownMapping(); + } + + // `batchTrigger` change events. + this.bind('change', can.proxy(this._changes, this)); + + delete this._init; + }, + // Sets up computed properties on a Map. + _setupComputes: function() { + var computes = this.constructor._computes; + this._computedBindings = {}; + + for (var i = 0, len = computes.length, prop; i < len; i++) { + prop = computes[i]; + // Make the context of the compute the current Map + this[prop] = this[prop].clone(this); + // Keep track of computed properties + this._computedBindings[prop] = { + count: 0 + }; + } + }, + _setupDefaults: function() { + return this.constructor.defaults || {}; + }, + // Setup child bindings. + _bindsetup: function() {}, + // Teardown child bindings. + _bindteardown: function() {}, + // `change`event handler. + _changes: function(ev, attr, how, newVal, oldVal) { + // when a change happens, create the named event. + can.batch.trigger(this, { + type: attr, + batchNum: ev.batchNum + }, [newVal, oldVal]); + + if (how === "remove" || how === "add") { + can.batch.trigger(this, { + type: "__keys", + batchNum: ev.batchNum + }); + } + }, + // Trigger a change event. + _triggerChange: function(attr, how, newVal, oldVal) { + can.batch.trigger(this, "change", can.makeArray(arguments)); + }, + // Iterator that does not trigger live binding. + _each: function(callback) { + var data = this.__get(); + for (var prop in data) { + if (data.hasOwnProperty(prop)) { + callback(data[prop], prop); + } + } + }, + + attr: function(attr, val) { + // This is super obfuscated for space -- basically, we're checking + // if the type of the attribute is not a `number` or a `string`. + var type = typeof attr; + if (type !== "string" && type !== "number") { + return this._attrs(attr, val); + // If we are getting a value. + } else if (arguments.length === 1) { + // Let people know we are reading. + can.__reading(this, attr); + return this._get(attr); + } else { + // Otherwise we are setting. + this._set(attr, val); + return this; + } + }, + + each: function() { + return can.each.apply(undefined, [this].concat(can.makeArray(arguments))); + }, + + removeAttr: function(attr) { + // If this is List. + var isList = can.List && this instanceof can.List, + // Convert the `attr` into parts (if nested). + parts = can.Map.helpers.attrParts(attr), + // The actual property to remove. + prop = parts.shift(), + // The current value. + current = isList ? this[prop] : this._data[prop]; + + // If we have more parts, call `removeAttr` on that part. + if (parts.length && current) { + return current.removeAttr(parts); + } else { + + // If attr does not have a `.` + if (typeof attr === 'string' && !! ~attr.indexOf('.')) { + prop = attr; + } + + this._remove(prop, current); + return current; + } + }, + // Remove a property. + _remove: function(prop, current) { + if (prop in this._data) { + // Delete the property from `_data` and the Map + // as long as it isn't part of the Map's prototype. + delete this._data[prop]; + if (!(prop in this.constructor.prototype)) { + delete this[prop]; + } + // Let others now this property has been removed. + this._triggerChange(prop, "remove", undefined, current); + + } + }, + // Reads a property from the `object`. + _get: function(attr) { + var value; + // Handles the case of a key having a `.` in its name + if (typeof attr === 'string' && !! ~attr.indexOf('.')) { + // Attempt to get the value + value = this.__get(attr); + // For keys with a `.` in them, value will be defined + if (value !== undefined) { + return value; + } + } + + // Otherwise we have to dig deeper into the Map to get the value. + // First, break up the attr (`"foo.bar"`) into parts like `["foo","bar"]`. + var parts = can.Map.helpers.attrParts(attr), + // Then get the value of the first attr name (`"foo"`). + current = this.__get(parts.shift()); + // If there are other attributes to read... + return parts.length ? + // and current has a value... + current ? + // then lookup the remaining attrs on current + current._get(parts) : + // or if there's no current, return undefined. + undefined : + // If there are no more parts, return current. + current; + }, + // Reads a property directly if an `attr` is provided, otherwise + // returns the "real" data object itself. + __get: function(attr) { + if (attr) { + // If property is a compute return the result, otherwise get the value directly + if (this._computedBindings[attr]) { + return this[attr](); + } else { + return this._data[attr]; + } + // If not property is provided, return entire `_data` object + } else { + return this._data; + } + }, + // converts the value into an observable if needed + __type: function(value, prop) { + // If we are getting an object. + if (!(value instanceof can.Map) && can.Map.helpers.canMakeObserve(value)) { + + var cached = getMapFromObject(value); + if (cached) { + return cached; + } + if (can.isArray(value)) { + var List = can.List; + return new List(value); + } else { + var Map = this.constructor.Map || can.Map; + return new Map(value); + } + } + return value; + }, + // Sets `attr` prop as value on this object where. + // `attr` - Is a string of properties or an array of property values. + // `value` - The raw value to set. + _set: function(attr, value, keepKey) { + // Convert `attr` to attr parts (if it isn't already). + var parts = can.Map.helpers.attrParts(attr, keepKey), + // The immediate prop we are setting. + prop = parts.shift(), + // We only need to get the current value if we are not in init. + current = this._init ? undefined : this.__get(prop); + + if (parts.length && Map.helpers.isObservable(current)) { + // If we have an `object` and remaining parts that `object` should set it. + current._set(parts, value); + } else if (!parts.length) { + // We're in "real" set territory. + if (this.__convert) { + //Convert if there is a converter + value = this.__convert(prop, value); + } + this.__set(prop, this.__type(value, prop), current); + } else { + throw "can.Map: Object does not exist"; + } + }, + __set: function(prop, value, current) { + // TODO: Check if value is object and transform. + // Don't do anything if the value isn't changing. + if (value !== current) { + // Check if we are adding this for the first time -- + // if we are, we need to create an `add` event. + var changeType = this.__get() + .hasOwnProperty(prop) ? "set" : "add"; + + // Set the value on `_data` and hook it up to send event. + this.___set(prop, this.constructor._bubble.set(this, prop, value, current)); + + // `batchTrigger` the change event. + this._triggerChange(prop, changeType, value, current); + + // If we can stop listening to our old value, do it. + if (current) { + this.constructor._bubble.teardownFromParent(this, current); + } + } + + }, + // Directly sets a property on this `object`. + ___set: function(prop, val) { + if (this._computedBindings[prop]) { + this[prop](val); + } else { + this._data[prop] = val; + } + // Add property directly for easy writing. + // Check if its on the `prototype` so we don't overwrite methods like `attrs`. + if (!can.isFunction(this.constructor.prototype[prop]) && !this._computedBindings[prop]) { + this[prop] = val; + } + }, + + bind: function(eventName, handler) { + var computedBinding = this._computedBindings && this._computedBindings[eventName]; + if (computedBinding) { + // The first time we bind to this computed property we + // initialize `count` and `batchTrigger` the change event. + if (!computedBinding.count) { + computedBinding.count = 1; + var self = this; + computedBinding.handler = function(ev, newVal, oldVal) { + can.batch.trigger(self, { + type: eventName, + batchNum: ev.batchNum + }, [newVal, oldVal]); + }; + this[eventName].bind("change", computedBinding.handler); + } else { + // Increment number of things listening to this computed property. + computedBinding.count++; + } + + } + // The first time we bind to this Map, `_bindsetup` will + // be called to setup child event bubbling. + this.constructor._bubble.bind(this, eventName); + return can.bindAndSetup.apply(this, arguments); + + }, + + unbind: function(eventName, handler) { + var computedBinding = this._computedBindings && this._computedBindings[eventName]; + if (computedBinding) { + // If there is only one listener, we unbind the change event handler + // and clean it up since no one is listening to this property any more. + if (computedBinding.count === 1) { + computedBinding.count = 0; + this[eventName].unbind("change", computedBinding.handler); + delete computedBinding.handler; + } else { + // Decrement number of things listening to this computed property + computedBinding.count--; + } + + } + this.constructor._bubble.unbind(this, eventName); + return can.unbindAndTeardown.apply(this, arguments); + + }, + + serialize: function() { + return can.Map.helpers.serialize(this, 'serialize', {}); + }, + + _attrs: function(props, remove) { + if (props === undefined) { + return Map.helpers.serialize(this, 'attr', {}); + } + + props = can.simpleExtend({}, props); + var prop, + self = this, + newVal; + + // Batch all of the change events until we are done. + can.batch.start(); + // Merge current properties with the new ones. + this.each(function(curVal, prop) { + // You can not have a _cid property; abort. + if (prop === "_cid") { + return; + } + newVal = props[prop]; + + // If we are merging, remove the property if it has no value. + if (newVal === undefined) { + if (remove) { + self.removeAttr(prop); + } + return; + } + + // Run converter if there is one + if (self.__convert) { + newVal = self.__convert(prop, newVal); + } + + // If we're dealing with models, we want to call _set to let converters run. + if (Map.helpers.isObservable(newVal)) { + + self.__set(prop, self.__type(newVal, prop), curVal); + // If its an object, let attr merge. + } else if (Map.helpers.isObservable(curVal) && Map.helpers.canMakeObserve(newVal)) { + curVal.attr(newVal, remove); + // Otherwise just set. + } else if (curVal !== newVal) { + self.__set(prop, self.__type(newVal, prop), curVal); + } + + delete props[prop]; + }); + // Add remaining props. + for (prop in props) { + // Ignore _cid. + if (prop !== "_cid") { + newVal = props[prop]; + this._set(prop, newVal, true); + } + + } + can.batch.stop(); + return this; + }, + + compute: function(prop) { + // If the property is a function, use it as the getter/setter + // otherwise, create a new compute that returns the value of a property on `this` + if (can.isFunction(this.constructor.prototype[prop])) { + return can.compute(this[prop], this); + } else { + var reads = prop.split("."), + last = reads.length - 1, + options = { + args: [] + }; + return can.compute(function(newVal) { + if (arguments.length) { + can.compute.read(this, reads.slice(0, last)) + .value.attr(reads[last], newVal); + } else { + return can.compute.read(this, reads, options) + .value; + } + }, this); + } + + } + }); + + // Setup on/off aliases + Map.prototype.on = Map.prototype.bind; + Map.prototype.off = Map.prototype.unbind; + + return Map; + })(__m3, __m11, __m12, __m1, __m13); + + // ## can/list/list.js + var __m14 = (function(can, Map, bubble) { + + // Helpers for `observable` lists. + var splice = [].splice, + // test if splice works correctly + spliceRemovesProps = (function() { + // IE's splice doesn't remove properties + var obj = { + 0: "a", + length: 1 + }; + splice.call(obj, 0, 1); + return !obj[0]; + })(); + + + var list = Map.extend( + + { + + Map: Map + + }, + + { + setup: function(instances, options) { + this.length = 0; + can.cid(this, ".map"); + this._init = 1; + this._setupComputes(); + instances = instances || []; + var teardownMapping; + + if (can.isDeferred(instances)) { + this.replace(instances); + } else { + teardownMapping = instances.length && can.Map.helpers.addToMap(instances, this); + this.push.apply(this, can.makeArray(instances || [])); + } + + if (teardownMapping) { + teardownMapping(); + } + + // this change needs to be ignored + this.bind('change', can.proxy(this._changes, this)); + can.simpleExtend(this, options); + delete this._init; + }, + _triggerChange: function(attr, how, newVal, oldVal) { + + Map.prototype._triggerChange.apply(this, arguments); + // `batchTrigger` direct add and remove events... + var index = +attr; + // Make sure this is not nested and not an expando + if (!~attr.indexOf('.') && !isNaN(index)) { + + if (how === 'add') { + can.batch.trigger(this, how, [newVal, index]); + can.batch.trigger(this, 'length', [this.length]); + } else if (how === 'remove') { + can.batch.trigger(this, how, [oldVal, index]); + can.batch.trigger(this, 'length', [this.length]); + } else { + can.batch.trigger(this, how, [newVal, index]); + } + + } + + }, + __get: function(attr) { + if (attr) { + if (this[attr] && this[attr].isComputed && can.isFunction(this.constructor.prototype[attr])) { + return this[attr](); + } else { + return this[attr]; + } + } else { + return this; + } + }, + ___set: function(attr, val) { + this[attr] = val; + if (+attr >= this.length) { + this.length = (+attr + 1); + } + }, + _remove: function(prop, current) { + // if removing an expando property + if (isNaN(+prop)) { + delete this[prop]; + this._triggerChange(prop, "remove", undefined, current); + } else { + this.splice(prop, 1); + } + }, + _each: function(callback) { + var data = this.__get(); + for (var i = 0; i < data.length; i++) { + callback(data[i], i); + } + }, + // Returns the serialized form of this list. + + serialize: function() { + return Map.helpers.serialize(this, 'serialize', []); + }, + + splice: function(index, howMany) { + var args = can.makeArray(arguments), + i; + + for (i = 2; i < args.length; i++) { + args[i] = bubble.set(this, i, this.__type(args[i], i)); + + } + if (howMany === undefined) { + howMany = args[1] = this.length - index; + } + var removed = splice.apply(this, args); + + if (!spliceRemovesProps) { + for (i = this.length; i < removed.length + this.length; i++) { + delete this[i]; + } + } + + can.batch.start(); + if (howMany > 0) { + this._triggerChange("" + index, "remove", undefined, removed); + bubble.removeMany(this, removed); + } + if (args.length > 2) { + this._triggerChange("" + index, "add", args.slice(2), removed); + } + can.batch.stop(); + return removed; + }, + + _attrs: function(items, remove) { + if (items === undefined) { + return Map.helpers.serialize(this, 'attr', []); + } + + // Create a copy. + items = can.makeArray(items); + + can.batch.start(); + this._updateAttrs(items, remove); + can.batch.stop(); + }, + + _updateAttrs: function(items, remove) { + var len = Math.min(items.length, this.length); + + for (var prop = 0; prop < len; prop++) { + var curVal = this[prop], + newVal = items[prop]; + + if (Map.helpers.isObservable(curVal) && Map.helpers.canMakeObserve(newVal)) { + curVal.attr(newVal, remove); + //changed from a coercion to an explicit + } else if (curVal !== newVal) { + this._set(prop, newVal); + } else { + + } + } + if (items.length > this.length) { + // Add in the remaining props. + this.push.apply(this, items.slice(this.length)); + } else if (items.length < this.length && remove) { + this.splice(items.length); + } + } + }), + + // Converts to an `array` of arguments. + getArgs = function(args) { + return args[0] && can.isArray(args[0]) ? + args[0] : + can.makeArray(args); + }; + // Create `push`, `pop`, `shift`, and `unshift` + can.each({ + + push: "length", + + unshift: 0 + }, + // Adds a method + // `name` - The method name. + // `where` - Where items in the `array` should be added. + + function(where, name) { + var orig = [][name]; + list.prototype[name] = function() { + // Get the items being added. + var args = [], + // Where we are going to add items. + len = where ? this.length : 0, + i = arguments.length, + res, val; + + // Go through and convert anything to an `map` that needs to be converted. + while (i--) { + val = arguments[i]; + args[i] = bubble.set(this, i, this.__type(val, i)); + } + + // Call the original method. + res = orig.apply(this, args); + + if (!this.comparator || args.length) { + + this._triggerChange("" + len, "add", args, undefined); + } + + return res; + }; + }); + + can.each({ + + pop: "length", + + shift: 0 + }, + // Creates a `remove` type method + + function(where, name) { + list.prototype[name] = function() { + + var args = getArgs(arguments), + len = where && this.length ? this.length - 1 : 0; + + var res = [][name].apply(this, args); + + // Create a change where the args are + // `len` - Where these items were removed. + // `remove` - Items removed. + // `undefined` - The new values (there are none). + // `res` - The old, removed values (should these be unbound). + this._triggerChange("" + len, "remove", undefined, [res]); + + if (res && res.unbind) { + bubble.remove(this, res); + } + + return res; + }; + }); + + can.extend(list.prototype, { + + indexOf: function(item, fromIndex) { + this.attr('length'); + return can.inArray(item, this, fromIndex); + }, + + + join: function() { + return [].join.apply(this.attr(), arguments); + }, + + + reverse: function() { + var list = can.makeArray([].reverse.call(this)); + this.replace(list); + }, + + + slice: function() { + var temp = Array.prototype.slice.apply(this, arguments); + return new this.constructor(temp); + }, + + + concat: function() { + var args = []; + can.each(can.makeArray(arguments), function(arg, i) { + args[i] = arg instanceof can.List ? arg.serialize() : arg; + }); + return new this.constructor(Array.prototype.concat.apply(this.serialize(), args)); + }, + + + forEach: function(cb, thisarg) { + return can.each(this, cb, thisarg || this); + }, + + + replace: function(newList) { + if (can.isDeferred(newList)) { + newList.then(can.proxy(this.replace, this)); + } else { + this.splice.apply(this, [0, this.length].concat(can.makeArray(newList || []))); + } + + return this; + }, + filter: function(callback, thisArg) { + var filteredList = new can.List(), + self = this, + filtered; + this.each(function(item, index, list) { + filtered = callback.call(thisArg | self, item, index, self); + if (filtered) { + filteredList.push(item); + } + }); + return filteredList; + } + }); + can.List = Map.List = list; + return can.List; + })(__m3, __m10, __m12); + + // ## can/compute/compute.js + var __m15 = (function(can, bind) { + + // ## Reading Helpers + // The following methods are used to call a function that relies on + // observable data and to track the observable events which should + // be listened to when changes occur. + // To do this, [`can.__reading(observable, event)`](#can-__reading) is called to + // "broadcast" the corresponding event on each read. + // ### Observed + // An "Observed" is an object of observable objects and events that + // a function relies on. These objects and events must be listened to + // in order to determine when to check a function for updates. + // This looks like the following: + // { + // "map1|first": {obj: map, event: "first"}, + // "map1|last" : {obj: map, event: "last"} + // } + // Each object-event pair is mapped so no duplicates will be listed. + + // ### State + // `can.__read` may call a function that calls `can.__read` again. For + // example, a compute can read another compute. To track each compute's + // `Observed` object (containing observable objects and events), we maintain + // a stack of Observed values for each call to `__read`. + var stack = []; + + // ### can.__read + // With a given function and context, calls the function + // and returns the resulting value of the function as well + // as the observable properties and events that were read. + can.__read = function(func, self) { + + // Add an object that `can.__read` will write to. + stack.push({}); + + var value = func.call(self); + + // Example return value: + // `{value: 100, observed: Observed}` + return { + value: value, + observed: stack.pop() + }; + }; + + // ### can.__reading + // When an observable value is read, it must call `can.__reading` to + // broadcast which object and event should be listened to. + can.__reading = function(obj, event) { + // Add the observable object and the event + // that was read to the `Observed` object on + // the stack. + if (stack.length) { + stack[stack.length - 1][obj._cid + '|' + event] = { + obj: obj, + event: event + "" + }; + } + + }; + + // ### can.__clearReading + // Clears and returns the current observables. + // This can be used to access a value without + // it being handled as a regular `read`. + can.__clearReading = function() { + if (stack.length) { + var ret = stack[stack.length - 1]; + stack[stack.length - 1] = {}; + return ret; + } + }; + // Specifies current observables. + can.__setReading = function(o) { + if (stack.length) { + stack[stack.length - 1] = o; + } + }; + can.__addReading = function(o) { + if (stack.length) { + can.simpleExtend(stack[stack.length - 1], o); + } + }; + + // ## Section Name + + // ### getValueAndBind + // Calls a function and sets up bindings to call `onchanged` + // when events from its "Observed" object are triggered. + // Removes bindings from `oldObserved` that are no longer needed. + // - func - the function to call. + // - context - the `this` of the function. + // - oldObserved - an object that contains what has already been bound to + // - onchanged - the function to call when any change occurs + var getValueAndBind = function(func, context, oldObserved, onchanged) { + // Call the function, get the value as well as the observed objects and events + var info = can.__read(func, context), + // The objects-event pairs that must be bound to + newObserveSet = info.observed, + // A flag that is used to determine if an event is already being observed. + obEv, + name; + // Go through what needs to be observed. + for (name in newObserveSet) { + + if (oldObserved[name]) { + // After binding is set up, values + // in `oldObserved` will be unbound. So if a name + // has already be observed, remove from `oldObserved` + // to prevent this. + delete oldObserved[name]; + } else { + // If current name has not been observed, listen to it. + obEv = newObserveSet[name]; + obEv.obj.bind(obEv.event, onchanged); + } + } + + // Iterate through oldObserved, looking for observe/attributes + // that are no longer being bound and unbind them. + for (name in oldObserved) { + obEv = oldObserved[name]; + obEv.obj.unbind(obEv.event, onchanged); + } + + return info; + }; + + // ### updateOnChange + // Fires a change event when a compute's value changes + var updateOnChange = function(compute, newValue, oldValue, batchNum) { + // Only trigger event when value has changed + if (newValue !== oldValue) { + can.batch.trigger(compute, batchNum ? { + type: "change", + batchNum: batchNum + } : 'change', [ + newValue, + oldValue + ]); + } + }; + + // ###setupComputeHandlers + // Sets up handlers for a compute. + // - compute - the compute to set up handlers for + // - func - the getter/setter function for the compute + // - context - the `this` for the compute + // - setCachedValue - function for setting cached value + // Returns an object with `on` and `off` functions. + var setupComputeHandlers = function(compute, func, context, setCachedValue) { + var readInfo, + onchanged, + batchNum; + + return { + // Set up handler for when the compute changes + on: function(updater) { + if (!onchanged) { + onchanged = function(ev) { + if (compute.bound && (ev.batchNum === undefined || ev.batchNum !== batchNum)) { + // Keep the old value + var oldValue = readInfo.value; + + // Get the new value + readInfo = getValueAndBind(func, context, readInfo.observed, onchanged); + + // Call the updater with old and new values + updater(readInfo.value, oldValue, ev.batchNum); + + batchNum = batchNum = ev.batchNum; + } + }; + } + + readInfo = getValueAndBind(func, context, {}, onchanged); + + setCachedValue(readInfo.value); + + compute.hasDependencies = !can.isEmptyObject(readInfo.observed); + }, + // Remove handler for the compute + off: function(updater) { + for (var name in readInfo.observed) { + var ob = readInfo.observed[name]; + ob.obj.unbind(ob.event, onchanged); + } + } + }; + }; + + // ###isObserve + // Checks if an object is observable + var isObserve = function(obj) { + return obj instanceof can.Map || obj && obj.__get; + }, + // Instead of calculating whether anything is listening every time, + // use a function to do nothing (which may be overwritten) + k = function() {}; + + // ## Creating a can.compute + // A `can.compute` can be created by + // - [Specifying the getterSeter function](#specifying-gettersetter-function) + // - [Observing a property of an object](#observing-a-property-of-an-object) + // - [Specifying an initial value and a setter function](#specifying-an-initial-value-and-a-setter) + // - [Specifying an initial value and how to read, update, and listen to changes](#specifying-an-initial-value-and-a-settings-object) + // - [Simply specifying an initial value](#specifying-only-a-value) + can.compute = function(getterSetter, context, eventName) { + // ### Setting up + // Do nothing if getterSetter is already a compute + if (getterSetter && getterSetter.isComputed) { + return getterSetter; + } + // The computed object + var computed, + // The following functions are overwritten depending on how compute() is called + // A method to set up listening + on = k, + // A method to teardown listening + off = k, + // Current cached value (valid only when bound is true) + value, + // How the value is read by default + get = function() { + return value; + }, + // How the value is set by default + set = function(newVal) { + value = newVal; + }, + setCached = set, + // Save arguments for cloning + args = can.makeArray(arguments), + // updater for when value is changed + updater = function(newValue, oldValue, batchNum) { + setCached(newValue); + updateOnChange(computed, newValue, oldValue, batchNum); + }, + // the form of the arguments + form; + computed = function(newVal) { + // If the computed function is called with arguments, + // a value should be set + if (arguments.length) { + // Save a reference to the old value + var old = value; + // Setter may return the value if setter + // is for a value maintained exclusively by this compute. + var setVal = set.call(context, newVal, old); + // If the computed function has dependencies, + // return the current value + if (computed.hasDependencies) { + return get.call(context); + } + // Setting may not fire a change event, in which case + // the value must be read + if (setVal === undefined) { + value = get.call(context); + } else { + value = setVal; + } + // Fire the change + updateOnChange(computed, value, old); + return value; + } else { + // Another compute may bind to this `computed` + if (stack.length && computed.canReadForChangeEvent !== false) { + + // Tell the compute to listen to change on this computed + // Use `can.__reading` to allow other compute to listen + // for a change on this `computed` + can.__reading(computed, 'change'); + // We are going to bind on this compute. + // If we are not bound, we should bind so that + // we don't have to re-read to get the value of this compute. + if (!computed.bound) { + can.compute.temporarilyBind(computed); + } + } + // If computed is bound, use the cached value + if (computed.bound) { + return value; + } else { + return get.call(context); + } + } + }; + // ###Specifying getterSetter function + // If `can.compute` is [called with a getterSetter function](http://canjs.com/docs/can.compute.html#sig_can_compute_getterSetter__context__), + // override set and get + if (typeof getterSetter === 'function') { + // `can.compute(getterSetter, [context])` + set = getterSetter; + get = getterSetter; + computed.canReadForChangeEvent = eventName === false ? false : true; + + var handlers = setupComputeHandlers(computed, getterSetter, context || this, setCached); + on = handlers.on; + off = handlers.off; + + // ###Observing a property of an object + // If `can.compute` is called with an + // [object, property name, and optional event name](http://canjs.com/docs/can.compute.html#sig_can_compute_object_propertyName__eventName__), + // create a compute from a property of an object. This allows the + // creation of a compute on objects that can be listened to with [`can.bind`](http://canjs.com/docs/can.bind.html) + } else if (context) { + if (typeof context === 'string') { + // `can.compute(obj, "propertyName", [eventName])` + var propertyName = context, + isObserve = getterSetter instanceof can.Map; + if (isObserve) { + computed.hasDependencies = true; + } + // If object is observable, `attr` will be used + // for getting and setting. + get = function() { + if (isObserve) { + return getterSetter.attr(propertyName); + } else { + return getterSetter[propertyName]; + } + }; + set = function(newValue) { + if (isObserve) { + getterSetter.attr(propertyName, newValue); + } else { + getterSetter[propertyName] = newValue; + } + }; + var handler; + on = function(update) { + handler = function() { + update(get(), value); + }; + can.bind.call(getterSetter, eventName || propertyName, handler); + // use can.__read because + // we should not be indicating that some parent + // reads this property if it happens to be binding on it + value = can.__read(get) + .value; + }; + off = function() { + can.unbind.call(getterSetter, eventName || propertyName, handler); + }; + // ###Specifying an initial value and a setter + // If `can.compute` is called with an [initial value and a setter function](http://canjs.com/docs/can.compute.html#sig_can_compute_initialValue_setter_newVal_oldVal__), + // a compute that can adjust incoming values is set up. + } else { + // `can.compute(initialValue, setter)` + if (typeof context === 'function') { + + value = getterSetter; + set = context; + context = eventName; + form = 'setter'; + // ###Specifying an initial value and a settings object + // If `can.compute` is called with an [initial value and optionally a settings object](http://canjs.com/docs/can.compute.html#sig_can_compute_initialValue__settings__), + // a can.compute is created that can optionally specify how to read, + // update, and listen to changes in dependent values. This form of + // can.compute can be used to derive a compute that derives its + // value from any source + } else { + // `can.compute(initialValue,{get:, set:, on:, off:})` + + + value = getterSetter; + var options = context, + oldUpdater = updater; + + context = options.context || options; + get = options.get || get; + set = options.set || function() { + return value; + }; + // This is a "hack" to allow async computes. + if (options.fn) { + var fn = options.fn, + data; + // make sure get is called with the newVal, but not setter + get = function() { + return fn.call(context, value); + }; + // Check the number of arguments the + // async function takes. + if (fn.length === 0) { + + data = setupComputeHandlers(computed, fn, context, setCached); + + } else if (fn.length === 1) { + data = setupComputeHandlers(computed, function() { + return fn.call(context, value); + }, context, setCached); + } else { + updater = function(newVal) { + if (newVal !== undefined) { + oldUpdater(newVal, value); + } + }; + data = setupComputeHandlers(computed, function() { + var res = fn.call(context, value, function(newVal) { + oldUpdater(newVal, value); + }); + // If undefined is returned, don't update the value. + return res !== undefined ? res : value; + }, context, setCached); + } + + + on = data.on; + off = data.off; + } else { + updater = function() { + var newVal = get.call(context); + oldUpdater(newVal, value); + }; + } + + on = options.on || on; + off = options.off || off; + } + } + // ###Specifying only a value + // If can.compute is called with an initialValue only, + // reads to this value can be observed. + } else { + // `can.compute(initialValue)` + value = getterSetter; + } + can.cid(computed, 'compute'); + return can.simpleExtend(computed, { + + isComputed: true, + _bindsetup: function() { + this.bound = true; + // Set up live-binding + // While binding, this should not count as a read + var oldReading = can.__clearReading(); + on.call(this, updater); + // Restore "Observed" for reading + can.__setReading(oldReading); + }, + _bindteardown: function() { + off.call(this, updater); + this.bound = false; + }, + + bind: can.bindAndSetup, + + unbind: can.unbindAndTeardown, + clone: function(context) { + if (context) { + if (form === 'setter') { + args[2] = context; + } else { + args[1] = context; + } + } + return can.compute.apply(can, args); + } + }); + }; + // A list of temporarily bound computes + var computes, unbindComputes = function() { + for (var i = 0, len = computes.length; i < len; i++) { + computes[i].unbind('change', k); + } + computes = null; + }; + // Binds computes for a moment to retain their value and prevent caching + can.compute.temporarilyBind = function(compute) { + compute.bind('change', k); + if (!computes) { + computes = []; + setTimeout(unbindComputes, 10); + } + computes.push(compute); + }; + + // Whether a compute is truthy + can.compute.truthy = function(compute) { + return can.compute(function() { + var res = compute(); + if (typeof res === 'function') { + res = res(); + } + return !!res; + }); + }; + can.compute.async = function(initialValue, asyncComputer, context) { + return can.compute(initialValue, { + fn: asyncComputer, + context: context + }); + }; + // {map: new can.Map({first: "Justin"})}, ["map","first"] + can.compute.read = function(parent, reads, options) { + options = options || {}; + // `cur` is the current value. + var cur = parent, + type, + // `prev` is the object we are reading from. + prev, + // `foundObs` did we find an observable. + foundObs; + for (var i = 0, readLength = reads.length; i < readLength; i++) { + // Update what we are reading from. + prev = cur; + // Read from the compute. We can't read a property yet. + if (prev && prev.isComputed) { + if (options.foundObservable) { + options.foundObservable(prev, i); + } + prev = prev(); + } + // Look to read a property from something. + if (isObserve(prev)) { + if (!foundObs && options.foundObservable) { + options.foundObservable(prev, i); + } + foundObs = 1; + // is it a method on the prototype? + if (typeof prev[reads[i]] === 'function' && prev.constructor.prototype[reads[i]] === prev[reads[i]]) { + // call that method + if (options.returnObserveMethods) { + cur = cur[reads[i]]; + } else if (reads[i] === 'constructor' && prev instanceof can.Construct) { + cur = prev[reads[i]]; + } else { + cur = prev[reads[i]].apply(prev, options.args || []); + } + } else { + // use attr to get that value + cur = cur.attr(reads[i]); + } + } else { + // just do the dot operator + cur = prev[reads[i]]; + } + type = typeof cur; + // If it's a compute, get the compute's value + // unless we are at the end of the + if (cur && cur.isComputed && (!options.isArgument && i < readLength - 1)) { + if (!foundObs && options.foundObservable) { + options.foundObservable(prev, i + 1); + } + cur = cur(); + } + // If it's an anonymous function, execute as requested + else if (i < reads.length - 1 && type === 'function' && options.executeAnonymousFunctions && !(can.Construct && cur.prototype instanceof can.Construct)) { + cur = cur(); + } + // if there are properties left to read, and we don't have an object, early exit + if (i < reads.length - 1 && (cur === null || type !== 'function' && type !== 'object')) { + if (options.earlyExit) { + options.earlyExit(prev, i, cur); + } + // return undefined so we know this isn't the right value + return { + value: undefined, + parent: prev + }; + } + } + // handle an ending function + // unless it is a can.Construct-derived constructor + if (typeof cur === 'function' && !(can.Construct && cur.prototype instanceof can.Construct)) { + if (options.isArgument) { + if (!cur.isComputed && options.proxyMethods !== false) { + cur = can.proxy(cur, prev); + } + } else { + if (cur.isComputed && !foundObs && options.foundObservable) { + options.foundObservable(cur, i); + } + cur = cur.call(prev); + } + } + // if we don't have a value, exit early. + if (cur === undefined) { + if (options.earlyExit) { + options.earlyExit(prev, i - 1); + } + } + return { + value: cur, + parent: prev + }; + }; + + return can.compute; + })(__m3, __m11, __m13); + + // ## can/model/model.js + var __m16 = (function(can) { + + // ## model.js + // (Don't steal this file directly in your code.) + + // ## pipe + // `pipe` lets you pipe the results of a successful deferred + // through a function before resolving the deferred. + + var pipe = function(def, thisArg, func) { + // The piped result will be available through a new Deferred. + var d = new can.Deferred(); + def.then(function() { + var args = can.makeArray(arguments), + success = true; + + try { + // Pipe the results through the function. + args[0] = func.apply(thisArg, args); + } catch (e) { + success = false; + // The function threw an error, so reject the Deferred. + d.rejectWith(d, [e].concat(args)); + } + if (success) { + // Resolve the new Deferred with the piped value. + d.resolveWith(d, args); + } + }, function() { + // Pass on the rejection if the original Deferred never resolved. + d.rejectWith(this, arguments); + }); + + // `can.ajax` returns a Deferred with an abort method to halt the AJAX call. + if (typeof def.abort === 'function') { + d.abort = function() { + return def.abort(); + }; + } + + // Return the new (piped) Deferred. + return d; + }, + + // ## modelNum + // When new model constructors are set up without a full name, + // `modelNum` lets us name them uniquely (to keep track of them). + modelNum = 0, + + // ## getId + getId = function(inst) { + // `can.__reading` makes a note that `id` was just read. + can.__reading(inst, inst.constructor.id); + // Use `__get` instead of `attr` for performance. (But that means we have to remember to call `can.__reading`.) + return inst.__get(inst.constructor.id); + }, + + // ## ajax + // This helper method makes it easier to make an AJAX call from the configuration of the Model. + ajax = function(ajaxOb, data, type, dataType, success, error) { + + var params = {}; + + // A string here would be something like `"GET /endpoint"`. + if (typeof ajaxOb === 'string') { + // Split on spaces to separate the HTTP method and the URL. + var parts = ajaxOb.split(/\s+/); + params.url = parts.pop(); + if (parts.length) { + params.type = parts.pop(); + } + } else { + // If the first argument is an object, just load it into `params`. + can.extend(params, ajaxOb); + } + + // If the `data` argument is a plain object, copy it into `params`. + params.data = typeof data === "object" && !can.isArray(data) ? + can.extend(params.data || {}, data) : data; + + // Substitute in data for any templated parts of the URL. + params.url = can.sub(params.url, params.data, true); + + return can.ajax(can.extend({ + type: type || 'post', + dataType: dataType || 'json', + success: success, + error: error + }, params)); + }, + + // ## makeRequest + // This function abstracts making the actual AJAX request away from the Model. + makeRequest = function(modelObj, type, success, error, method) { + var args; + + // If `modelObj` is an Array, it it means we are coming from + // the queued request, and we're passing already-serialized data. + if (can.isArray(modelObj)) { + // In that case, modelObj's signature will be `[modelObj, serializedData]`, so we need to unpack it. + args = modelObj[1]; + modelObj = modelObj[0]; + } else { + // If we aren't supplied with serialized data, we'll make our own. + args = modelObj.serialize(); + } + args = [args]; + + var deferred, + model = modelObj.constructor, + jqXHR; + + // When calling `update` and `destroy`, the current ID needs to be the first parameter in the AJAX call. + if (type === 'update' || type === 'destroy') { + args.unshift(getId(modelObj)); + } + jqXHR = model[type].apply(model, args); + + // Make sure that can.Model can react to the request before anything else does. + deferred = pipe(jqXHR, modelObj, function(data) { + // `method` is here because `"destroyed" !== "destroy" + "d"`. + // TODO: Do something smarter/more consistent here? + modelObj[method || type + "d"](data, jqXHR); + return modelObj; + }); + + // Hook up `abort` + if (jqXHR.abort) { + deferred.abort = function() { + jqXHR.abort(); + }; + } + + deferred.then(success, error); + return deferred; + }, + + initializers = { + // ## models + // Returns a function that, when handed a list of objects, makes them into models and returns a model list of them. + // `prop` is the property on `instancesRawData` that has the array of objects in it (if it's not `data`). + models: function(prop) { + return function(instancesRawData, oldList) { + // Increment reqs counter so new instances will be added to the store. + // (This is cleaned up at the end of the method.) + can.Model._reqs++; + + // If there is no data, we can't really do anything with it. + if (!instancesRawData) { + return; + } + + // If the "raw" data is already a List, it's not raw. + if (instancesRawData instanceof this.List) { + return instancesRawData; + } + + var self = this, + // `tmp` will hold the models before we push them onto `modelList`. + tmp = [], + // `ML` (see way below) is just `can.Model.List`. + ListClass = self.List || ML, + modelList = oldList instanceof can.List ? oldList : new ListClass(), + + // Check if we were handed an Array or a model list. + rawDataIsArray = can.isArray(instancesRawData), + rawDataIsList = instancesRawData instanceof ML, + + // Get the "plain" objects from the models from the list/array. + raw = rawDataIsArray ? instancesRawData : ( + rawDataIsList ? instancesRawData.serialize() : can.getObject(prop || "data", instancesRawData)); + + if (typeof raw === 'undefined') { + throw new Error('Could not get any raw data while converting using .models'); + } + + + + // If there was anything left in the list we were given, get rid of it. + if (modelList.length) { + modelList.splice(0); + } + + // If we pushed these directly onto the list, it would cause a change event for each model. + // So, we push them onto `tmp` first and then push everything at once, causing one atomic change event that contains all the models at once. + can.each(raw, function(rawPart) { + tmp.push(self.model(rawPart)); + }); + modelList.push.apply(modelList, tmp); + + // If there was other stuff on `instancesRawData`, let's transfer that onto `modelList` too. + if (!rawDataIsArray) { + can.each(instancesRawData, function(val, prop) { + if (prop !== 'data') { + modelList.attr(prop, val); + } + }); + } + // Clean up the store on the next turn of the event loop. (`this` is a model constructor.) + setTimeout(can.proxy(this._clean, this), 1); + return modelList; + }; + }, + // ## model + // Returns a function that, when handed a plain object, turns it into a model. + // `prop` is the property on `attributes` that has the properties for the model in it. + model: function(prop) { + return function(attributes) { + // If there're no properties, there can be no model. + if (!attributes) { + return; + } + // If this object knows how to serialize, parse, or access itself, we'll use that instead. + if (typeof attributes.serialize === 'function') { + attributes = attributes.serialize(); + } + if (this.parseModel) { + attributes = this.parseModel.apply(this, arguments); + } else if (prop) { + attributes = can.getObject(prop || "data", attributes); + } + + var id = attributes[this.id], + // 0 is a valid ID. + model = (id || id === 0) && this.store[id] ? + // If this model is in the store already, just update it. + this.store[id].attr(attributes, this.removeAttr || false) : + // Otherwise, we need a new model. + new this(attributes); + + return model; + }; + } + }, + + + parserMaker = function(prop) { + return function(attributes) { + return prop ? can.getObject(prop || "data", attributes) : attributes; + }; + }, + + // ## parsers + // This object describes how to take the data from an AJAX request and prepare it for `models` and `model`. + // These functions are meant to be overwritten (if necessary) in an extended model constructor. + parsers = { + + parseModel: parserMaker, + + parseModels: parserMaker + }, + + // ## ajaxMethods + // This object describes how to make an AJAX request for each ajax method (`create`, `update`, etc.) + // Each AJAX method is an object in `ajaxMethods` and can have the following properties: + // - `url`: Which property on the model contains the default URL for this method. + // - `type`: The default HTTP request method. + // - `data`: A method that takes the arguments from `makeRequest` (see above) and returns a data object for use in the AJAX call. + + + ajaxMethods = { + + create: { + url: "_shortName", + type: "post" + }, + + update: { + // ## update.data + data: function(id, attrs) { + attrs = attrs || {}; + + // `this.id` is the property that represents the ID (and is usually `"id"`). + var identity = this.id; + + // If the value of the property being used as the ID changed, + // indicate that in the request and replace the current ID property. + if (attrs[identity] && attrs[identity] !== id) { + attrs["new" + can.capitalize(id)] = attrs[identity]; + delete attrs[identity]; + } + attrs[identity] = id; + + return attrs; + }, + type: "put" + }, + + destroy: { + type: 'delete', + // ## destroy.data + data: function(id, attrs) { + attrs = attrs || {}; + // `this.id` is the property that represents the ID (and is usually `"id"`). + attrs.id = attrs[this.id] = id; + return attrs; + } + }, + + findAll: { + url: "_shortName" + }, + + findOne: {} + }, + // ## ajaxMaker + // Takes a method defined just above and a string that describes how to call that method + // and makes a function that calls that method with the given data. + // - `ajaxMethod`: The object defined above in `ajaxMethods`. + // - `str`: The string the configuration provided (such as `"/recipes.json"` for a `findAll` call). + ajaxMaker = function(ajaxMethod, str) { + return function(data) { + data = ajaxMethod.data ? + // If the AJAX method mentioned above has its own way of getting `data`, use that. + ajaxMethod.data.apply(this, arguments) : + // Otherwise, just use the data passed in. + data; + + // Make the AJAX call with the URL, data, and type indicated by the proper `ajaxMethod` above. + return ajax(str || this[ajaxMethod.url || "_url"], data, ajaxMethod.type || "get"); + }; + }, + // ## createURLFromResource + // For each of the names (create, update, destroy, findOne, and findAll) use the + // URL provided by the `resource` property. For example: + // ToDo = can.Model.extend({ + // resource: "/todos" + // }, {}); + // Will create a can.Model that is identical to: + // ToDo = can.Model.extend({ + // findAll: "GET /todos", + // findOne: "GET /todos/{id}", + // create: "POST /todos", + // update: "PUT /todos/{id}", + // destroy: "DELETE /todos/{id}" + // },{}); + // - `model`: the can.Model that has the resource property + // - `method`: a property from the ajaxMethod object + createURLFromResource = function(model, name) { + if (!model.resource) { + return; + } + + var resource = model.resource.replace(/\/+$/, ""); + if (name === "findAll" || name === "create") { + return resource; + } else { + return resource + "/{" + model.id + "}"; + } + }; + + // # can.Model + // A can.Map that connects to a RESTful interface. + can.Model = can.Map.extend({ + // `fullName` identifies the model type in debugging. + fullName: "can.Model", + _reqs: 0, + // ## can.Model.setup + + setup: function(base, fullName, staticProps, protoProps) { + // Assume `fullName` wasn't passed. (`can.Model.extend({ ... }, { ... })`) + // This is pretty usual. + if (fullName !== "string") { + protoProps = staticProps; + staticProps = fullName; + } + // Assume no static properties were passed. (`can.Model.extend({ ... })`) + // This is really unusual for a model though, since there's so much configuration. + if (!protoProps) { + protoProps = staticProps; + } + + // Create the model store here, in case someone wants to use can.Model without inheriting from it. + this.store = {}; + + can.Map.setup.apply(this, arguments); + if (!can.Model) { + return; + } + + // `List` is just a regular can.Model.List that knows what kind of Model it's hooked up to. + + if (staticProps && staticProps.List) { + this.List = staticProps.List; + this.List.Map = this; + } else { + this.List = base.List.extend({ + Map: this + }, {}); + } + + var self = this, + clean = can.proxy(this._clean, self); + + // Go through `ajaxMethods` and set up static methods according to their configurations. + can.each(ajaxMethods, function(method, name) { + // Check the configuration for this ajaxMethod. + // If the configuration isn't a function, it should be a string (like `"GET /endpoint"`) + // or an object like `{url: "/endpoint", type: 'GET'}`. + if (!can.isFunction(self[name])) { + // Etiher way, `ajaxMaker` will turn it into a function for us. + self[name] = ajaxMaker(method, self[name] ? self[name] : createURLFromResource(self, name)); + } + + // There may also be a "maker" function (like `makeFindAll`) that alters the behavior of acting upon models + // by changing when and how the function we just made with `ajaxMaker` gets called. + // For example, you might cache responses and only make a call when you don't have a cached response. + if (self["make" + can.capitalize(name)]) { + // Use the "maker" function to make the new "ajaxMethod" function. + var newMethod = self["make" + can.capitalize(name)](self[name]); + // Replace the "ajaxMethod" function in the configuration with the new one. + // (`_overwrite` just overwrites a property in a given Construct.) + can.Construct._overwrite(self, base, name, function() { + // Increment the numer of requests... + can.Model._reqs++; + // ...make the AJAX call (and whatever else you're doing)... + var def = newMethod.apply(this, arguments); + // ...and clean up the store. + var then = def.then(clean, clean); + // Pass along `abort` so you can still abort the AJAX call. + then.abort = def.abort; + + return then; + }); + } + }); + + // Set up the methods that will set up `models` and `model`. + can.each(initializers, function(makeInitializer, name) { + var parseName = "parse" + can.capitalize(name), + dataProperty = self[name]; + + // If there was a different property to find the model's data in than `data`, + // make `parseModel` and `parseModels` functions that look that up instead. + if (typeof dataProperty === "string") { + can.Construct._overwrite(self, base, parseName, parsers[parseName](dataProperty)); + can.Construct._overwrite(self, base, name, makeInitializer(dataProperty)); + } + + // If there was no prototype, or no `model` and no `parseModel`, + // we'll have to create a `parseModel`. + else if (!protoProps || (!protoProps[name] && !protoProps[parseName])) { + can.Construct._overwrite(self, base, parseName, parsers[parseName]()); + } + }); + + // With the overridden parse methods, set up `models` and `model`. + can.each(parsers, function(makeParser, name) { + // If there was a different property to find the model's data in than `data`, + // make `model` and `models` functions that look that up instead. + if (typeof self[name] === "string") { + can.Construct._overwrite(self, base, name, makeParser(self[name])); + } + }); + + // Make sure we have a unique name for this Model. + if (self.fullName === "can.Model" || !self.fullName) { + self.fullName = "Model" + (++modelNum); + } + + can.Model._reqs = 0; + this._url = this._shortName + "/{" + this.id + "}"; + }, + _ajax: ajaxMaker, + _makeRequest: makeRequest, + // ## can.Model._clean + // `_clean` cleans up the model store after a request happens. + _clean: function() { + can.Model._reqs--; + // Don't clean up unless we have no pending requests. + if (!can.Model._reqs) { + for (var id in this.store) { + // Delete all items in the store without any event bindings. + if (!this.store[id]._bindings) { + delete this.store[id]; + } + } + } + return arguments[0]; + }, + + models: initializers.models("data"), + + model: initializers.model() + }, + + + { + // ## can.Model#setup + setup: function(attrs) { + // Try to add things as early as possible to the store (#457). + // This is the earliest possible moment, even before any properties are set. + var id = attrs && attrs[this.constructor.id]; + if (can.Model._reqs && id != null) { + this.constructor.store[id] = this; + } + can.Map.prototype.setup.apply(this, arguments); + }, + // ## can.Model#isNew + // Something is new if its ID is `null` or `undefined`. + + isNew: function() { + var id = getId(this); + // 0 is a valid ID. + // TODO: Why not `return id === null || id === undefined;`? + return !(id || id === 0); // If `null` or `undefined` + }, + // ## can.Model#save + // `save` calls `create` or `update` as necessary, based on whether a model is new. + + save: function(success, error) { + return makeRequest(this, this.isNew() ? 'create' : 'update', success, error); + }, + // ## can.Model#destroy + // Acts like can.Map.destroy but it also makes an AJAX call. + + destroy: function(success, error) { + // If this model is new, don't make an AJAX call. + // Instead, we have to construct the Deferred ourselves and return it. + if (this.isNew()) { + var self = this; + var def = can.Deferred(); + def.then(success, error); + + return def.done(function(data) { + self.destroyed(data); + }).resolve(self); + } + + // If it isn't new, though, go ahead and make a request. + return makeRequest(this, 'destroy', success, error, 'destroyed'); + }, + // ## can.Model#bind and can.Model#unbind + // These aren't actually implemented here, but their setup needs to be changed to account for the store. + + _bindsetup: function() { + this.constructor.store[this.__get(this.constructor.id)] = this; + return can.Map.prototype._bindsetup.apply(this, arguments); + }, + + _bindteardown: function() { + delete this.constructor.store[getId(this)]; + return can.Map.prototype._bindteardown.apply(this, arguments); + }, + // Change the behavior of `___set` to account for the store. + ___set: function(prop, val) { + can.Map.prototype.___set.call(this, prop, val); + // If we add or change the ID, update the store accordingly. + // TODO: shouldn't this also delete the record from the old ID in the store? + if (prop === this.constructor.id && this._bindings) { + this.constructor.store[getId(this)] = this; + } + } + }); + + // Returns a function that knows how to prepare data from `findAll` or `findOne` calls. + // `name` should be either `model` or `models`. + var makeGetterHandler = function(name) { + var parseName = "parse" + can.capitalize(name); + return function(data) { + // If there's a `parse...` function, use its output. + if (this[parseName]) { + data = this[parseName].apply(this, arguments); + } + // Run our maybe-parsed data through `model` or `models`. + return this[name](data); + }; + }, + // Handle data returned from `create`, `update`, and `destroy` calls. + createUpdateDestroyHandler = function(data) { + if (this.parseModel) { + return this.parseModel.apply(this, arguments); + } else { + return this.model(data); + } + }; + + var responseHandlers = { + + makeFindAll: makeGetterHandler("models"), + + makeFindOne: makeGetterHandler("model"), + makeCreate: createUpdateDestroyHandler, + makeUpdate: createUpdateDestroyHandler + }; + + // Go through the response handlers and make the actual "make" methods. + can.each(responseHandlers, function(method, name) { + can.Model[name] = function(oldMethod) { + return function() { + var args = can.makeArray(arguments), + // If args[1] is a function, we were only passed one argument before success and failure callbacks. + oldArgs = can.isFunction(args[1]) ? args.splice(0, 1) : args.splice(0, 2), + // Call the AJAX method (`findAll` or `update`, etc.) and pipe it through the response handler from above. + def = pipe(oldMethod.apply(this, oldArgs), this, method); + + def.then(args[0], args[1]); + return def; + }; + }; + }); + + // ## can.Model.created, can.Model.updated, and can.Model.destroyed + // Livecycle methods for models. + can.each([ + + "created", + + "updated", + + "destroyed" + ], function(funcName) { + // Each of these is pretty much the same, except for the events they trigger. + can.Model.prototype[funcName] = function(attrs) { + var stub, + constructor = this.constructor; + + // Update attributes if attributes have been passed + stub = attrs && typeof attrs === 'object' && this.attr(attrs.attr ? attrs.attr() : attrs); + + // triggers change event that bubble's like + // handler( 'change','1.destroyed' ). This is used + // to remove items on destroyed from Model Lists. + // but there should be a better way. + can.trigger(this, "change", funcName); + + + + // Call event on the instance's Class + can.trigger(constructor, funcName, this); + }; + }); + + + // # can.Model.List + // Model Lists are just like `Map.List`s except that when their items are + // destroyed, they automatically get removed from the List. + var ML = can.Model.List = can.List.extend({ + // ## can.Model.List.setup + // On change or a nested named event, setup change bubbling. + // On any other type of event, setup "destroyed" bubbling. + _bubbleRule: function(eventName, list) { + return can.List._bubbleRule(eventName, list) || "destroyed"; + } + }, { + setup: function(params) { + // If there was a plain object passed to the List constructor, + // we use those as parameters for an initial findAll. + if (can.isPlainObject(params) && !can.isArray(params)) { + can.List.prototype.setup.apply(this); + this.replace(this.constructor.Map.findAll(params)); + } else { + // Otherwise, set up the list like normal. + can.List.prototype.setup.apply(this, arguments); + } + this._init = 1; + this.bind('destroyed', can.proxy(this._destroyed, this)); + delete this._init; + }, + _destroyed: function(ev, attr) { + if (/\w+/.test(attr)) { + var index; + while ((index = this.indexOf(ev.target)) > -1) { + this.splice(index, 1); + } + } + } + }); + + return can.Model; + })(__m3, __m10, __m14); + + // ## can/view/view.js + var __m17 = (function(can) { + + var isFunction = can.isFunction, + makeArray = can.makeArray, + // Used for hookup `id`s. + hookupId = 1; + + // internal utility methods + // ------------------------ + + // ##### makeRenderer + + var makeRenderer = function(textRenderer) { + var renderer = function() { + return $view.frag(textRenderer.apply(this, arguments)); + }; + renderer.render = function() { + return textRenderer.apply(textRenderer, arguments); + }; + return renderer; + }; + + // ##### checkText + // Makes sure there's a template, if not, have `steal` provide a warning. + var checkText = function(text, url) { + if (!text.length) { + + // _removed if not used as a steal module_ + + + + throw "can.view: No template or empty template:" + url; + } + }; + + // ##### get + // get a deferred renderer for provided url + + var get = function(obj, async) { + var url = typeof obj === 'string' ? obj : obj.url, + suffix = (obj.engine && '.' + obj.engine) || url.match(/\.[\w\d]+$/), + type, + // If we are reading a script element for the content of the template, + // `el` will be set to that script element. + el, + // A unique identifier for the view (used for caching). + // This is typically derived from the element id or + // the url for the template. + id; + + //If the url has a #, we assume we want to use an inline template + //from a script element and not current page's HTML + if (url.match(/^#/)) { + url = url.substr(1); + } + // If we have an inline template, derive the suffix from the `text/???` part. + // This only supports `