]> git.r.bdr.sh - rbdr/r.bdr.sh/commitdiff
Merge branch 'master' of bitbucket.org:benbeltran/n-s-o-vocal
authorBen Beltran <redacted>
Thu, 6 Aug 2015 15:20:02 +0000 (10:20 -0500)
committerBen Beltran <redacted>
Thu, 6 Aug 2015 15:20:02 +0000 (10:20 -0500)
Conflicts:
jekyll/about.html
jekyll/projects.html

37 files changed:
.rvmrc [deleted file]
_config.yml
jekyll/_layouts/category_index.html
jekyll/_layouts/default.html
jekyll/_layouts/tag_index.html
jekyll/_plugins/category_generator.rb [moved from _plugins/category_generator.rb with 100% similarity]
jekyll/_plugins/generate_sitemap.rb [moved from _plugins/generate_sitemap.rb with 100% similarity]
jekyll/_plugins/tag_generator.rb [moved from _plugins/tag_generator.rb with 100% similarity]
jekyll/about.html
jekyll/archive.html
jekyll/css/application.css
jekyll/etc.html [deleted file]
jekyll/favicon.ico
jekyll/favicon.png
jekyll/guestbook.html [new file with mode: 0644]
jekyll/img/selfie.gif [new file with mode: 0644]
jekyll/img/unlimited-pizza-animated-logo.gif [new file with mode: 0644]
jekyll/index.html
jekyll/js/unlimited_pizza.js [new file with mode: 0644]
jekyll/js/unlimited_pizza/melty_cheese.js [new file with mode: 0644]
jekyll/js/unlimited_pizza/pepperoni.js [new file with mode: 0644]
jekyll/js/vendor/neon/neon.js [new file with mode: 0644]
jekyll/js/vendor/neon/stdlib/bubbling_support.js [new file with mode: 0644]
jekyll/js/vendor/neon/stdlib/custom_event.js [new file with mode: 0644]
jekyll/js/vendor/neon/stdlib/custom_event_support.js [new file with mode: 0644]
jekyll/js/vendor/neon/stdlib/index.js [new file with mode: 0644]
jekyll/js/vendor/neon/stdlib/node_support.js [new file with mode: 0644]
jekyll/js/vendor/neon/stdlib/widget.js [new file with mode: 0644]
jekyll/js/vendor/recorderjs/.bower.json [new file with mode: 0644]
jekyll/js/vendor/recorderjs/README.md [new file with mode: 0644]
jekyll/js/vendor/recorderjs/bower.json [new file with mode: 0644]
jekyll/js/vendor/recorderjs/example_simple_exportwav.html [new file with mode: 0644]
jekyll/js/vendor/recorderjs/recorder.js [new file with mode: 0644]
jekyll/js/vendor/recorderjs/recorderWorker.js [new file with mode: 0644]
jekyll/projects.html
jekyll/reverb.aiff [new file with mode: 0644]
jekyll/reverb.ogg [new file with mode: 0644]

diff --git a/.rvmrc b/.rvmrc
deleted file mode 100644 (file)
index 6baf41b..0000000
--- a/.rvmrc
+++ /dev/null
@@ -1,8 +0,0 @@
-rvm_gemset_create_on_use_flag=1
-rvm_project_rvmrc_default=1
-
-rvm 1.9.3@nsovocal
-
-if ! command -v bundle ; then
-  gem install bundler
-fi
index 16acbfb723e060b351bd7f1c09f0e30fa798fce2..8b0d96357d56627e61ebe048082c386f77549951 100644 (file)
@@ -1,6 +1,6 @@
 markdown: rdiscount
 permalink: /:year/:month/:day/:title
-exclude: Gemfile, Gemfile.lock
+exclude: ["Gemfile", "Gemfile.lock"]
 source: jekyll
 paginate: 10
 baseurl: "http://nsovocal.com"
index edbe6cafd36765a6e898bc9f80efaf1c273e87e9..48796c908dd8e93448205a83ddec609d16350b5d 100644 (file)
@@ -4,6 +4,7 @@ layout: default
 
 <div class="content">
   <div class="related">
+    <h1>Cat: {{page.category}}</h1>
     <ul>
       {% for post in site.categories[page.category] %}
       <li>
index 4b05c6f10f364637635e7566ea03f7f682f368ed..0e2cec344140912a08a605c386b802f3fb9e7129 100644 (file)
@@ -9,12 +9,40 @@
     <link rel="stylesheet" type="text/css" href="/css/bootstrap-responsive.min.css" />
     <link rel="stylesheet" type="text/css" href="/css/prism.css" />
     <link rel="stylesheet" type="text/css" href="/css/application.css" />
-    <title>N, S o Vocal &bull; {{ page.title }}</title>
+    <title>Unlimited &#127829; {{ page.title }}</title>
     <link href='http://fonts.googleapis.com/css?family=Lato:100,300,700,300italic,700italic|Oswald:400,300' rel='stylesheet' type='text/css'>
     <link href="/atom.xml" type="application/atom+xml" rel="alternate" title="N, S o Vocal — The ATOM!">
     <script src="/js/prism.min.js" type="text/javascript"></script>
+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+    <script src="https://cdn.firebase.com/js/client/1.0.21/firebase.js"></script>
+
+    <script src="/js/vendor/neon/neon.js"></script>
+    <script src="/js/vendor/neon/stdlib/node_support.js"></script>
+    <script src="/js/vendor/neon/stdlib/custom_event.js"></script>
+    <script src="/js/vendor/neon/stdlib/custom_event_support.js"></script>
+    <script src="/js/vendor/neon/stdlib/widget.js"></script>
+
+    <script src="/js/vendor/recorderjs/recorder.js"></script>
+    <script src="/js/vendor/recorderjs/recorderWorker.js"></script>
+
+    <!--
+        /\
+       / O\   The Unlimited Pizza Family's Own Libraries
+      /O o \    * Melty Cheese: Header Expandos Widget
+     |______|   * Pepperoni: Audio Recorder Widget
+                * Tasty Crust: [Coming Soon] Colorful Navigation Widget
+    -->
+    <script src="js/unlimited_pizza.js"></script>
+    <script src="js/unlimited_pizza/melty_cheese.js"></script>
+    <script src="js/unlimited_pizza/pepperoni.js"></script>
     <script type="text/javascript">
 
+      window.addEventListener('load', function () {
+        UnlimitedPizza.instance({
+          element : $('body')
+        }).activate();
+      });
+
       var _gaq = _gaq || [];
       _gaq.push(['_setAccount', 'UA-20018878-4']);
       _gaq.push(['_trackPageview']);
     </header>
     <nav>
       <ul class="mainmenu">
-        <li><a href="/">Blog</a></li>
-        <li><a href="/projects.html">Proyectos</a></li>
-        <li><a href="/about.html">Ben</a></li>
-        <li><a href="/etc.html">Etc</a></li>
+        <li><a href="/">Home</a></li>
+        <li><a href="/archive.html">All</a></li>
+        <li><a href="/projects.html">Proj</a></li>
+        <li><a href="/about.html">????</a></li>
       </ul>
     </nav>
     <div class="main-container">
index 0c872f0e1a72206f9eaa520235afc735871cf3e0..3558e1ed595189cc26e4e1dff6b0f6871b9c8641 100644 (file)
@@ -4,6 +4,7 @@ layout: default
 
 <div class="content">
   <div class="related">
+    <h1>Tag: {{page.tag}}</h1>
     <ul>
       {% for post in site.tags[page.tag] %}
       <li>
index 2229432b77068ab004050e0e793bad64a4a41ac5..8936cf2fdb87e48c136e4a9c71ace0246b143e5f 100644 (file)
@@ -1,43 +1,40 @@
 ---
 layout: default
-title: Acerca de Ben Beltran
-description: "N, S o Vocal es escrito por Ben Beltran cada vez que
-ciertas reglas complicadas de astronomía se cumple. Ben... pues, hace cosas bonitas y así."
+title: ????
+description: "Unlimited Pizza is where Ruben Beltran del Rio puts things, or
+in spanish: Unlimited Pizza es donde pongo cosas... (el nombre viene más atrás)"
 ---
 
 <div class="content">
   <div class="related">
-    <h1>Ben Beltran</h1>
-    <p>N, S o Vocal es escrito por <a href="http://twitter.com/pigeonfolk">Ben Beltrán</a>
-    cuando no está muy ocupado no escribiendo aquí
-    sobre desarrollo web, videojuegos o nerdura general.
-    No es raro ver español e inglés usados libremente en el sitio, lo
-    cual ha causado protestas de muchos grupos que creen que el internet
-    no debería estár en dos lenguajes al mismo tiempo.</p>
-    <p>N, S o Vocal también es parte importante de las reglas de
-    acentuación en español.
-    </p>
-    <p> Para entrar en contacto, por favor diríjase a: </p>
-    <ul>
-      <li><a href="http://twitter.com/pigeonfolk">Twitter</a></li>
-      <li><a href="mailto:ben@nsovocal.com">Email/Jabber</a></li>
-      <li><a href="http://github.com/rbdr">Github</a></li>
-    </ul>
-    <hr/>
-    <p><em>N, S o Vocal is written by <a href="http://twitter.com/pigeonfolk">Ben Beltrán</a>
-      when he's not too busy not writing here
-      about web development, videogames or general
-      nerdstuffs. It is not uncommon to see english and spanish freely
-      mixed in the site, which has caused protests from many groups who
-      believe the internet should not be in two languages at the same
-      time.</em></p>
-    <p><em>N, S o Vocal is also an important part of spanish
-      accentuation rules. </em></p>
-    <p><em>To contact me, please refer to:</em></p>
-    <ul>
-      <li><a href="http://twitter.com/pigeonfolk">Twitter</a></li>
-      <li><a href="mailto:ben@nsovocal.com">Email/Jabber</a></li>
-      <li><a href="http://github.com/rbdr">Github</a></li>
-    </ul>
+    <h1>????</h1>
+
+    <p><img src="/img/selfie.gif" alt="An image of @pigeonfolk."/></p>
+
+    <p>Unlimited Pizza is brought to you by
+    <a href="https://twitter.com/pigeonfolk" class="cyan">@pigeonfolk</a>,
+    usually nerding out elsewhere and not writing here.
+    Still not sure what language to use on the internet,
+    so why not both ¯\_(ツ)_/¯.  Sometimes I like to
+    <a href="https://soundcloud.com/benbeltran" class="orange">make music</a>, sometimes I like to
+    <a href="http://petitcochon.co" class="green">make games</a>, but most of the time
+    I'm <a href="https://github.com/benbeltran" class="red">doing something else</a>.
+    To get in touch you can <a href="mailto:ruben+up@unlimited.pizza">send me
+      an email</a> and I'll probably respond; requests for crude drawings
+    WILL be honored.</p>
+
+    <p><em>Unlimited Pizza es traído a ti por
+    <a href="https://twitter.com/pigeonfolk" class="cyan">@pigeonfolk</a>,
+    usualmente nerdeando en otros lados y no escribiendo aquí.
+    Aún no estoy seguro de que lenguaje usar en el internet,
+    así que por que no los dos ¯\_(ツ)_/¯. A veces me gusta 
+    <a href="https://soundcloud.com/benbeltran" class="orange">hacer música</a>, a veces me gusta
+    <a href="http://petitcochon.co" class="green">hacer juegos</a>, pero la mayoría de las veces
+    estoy <a href="https://github.com/benbeltran" class="red">haciendo algo más</a>.
+    Para entrar en contacto puedes <a href="mailto:ruben+up@unlimited.pizza">mandar
+      un mail</a> y probablemente responderé; solicitudes de dibujos crudos
+    SERÁN atendidas.</em></p>
+
+    <p><a href="/guestbook.html">Audio Guestbook</a></p>
   </div>
 </div>
index dd775181d36624a7bff9191ed0c0f692804698cf..3a4f30ca71e71cbdffcfadd1fbf5c114a7d47c32 100644 (file)
@@ -4,10 +4,12 @@ layout: default
 
 <div class="content">
   <div class="related">
+    <h1>All</h1>
     <ul>
       {% for post in site.posts %}
       <li>
-       <span>{{ post.date | date: "%m/%e/%Y" }}</span> <a href="{{ post.url }}">{{ post.title }}</a>
+      <span>{{ post.date | date: "%m/%e/%Y" }}</span> <a
+        class="{{post.color}}" href="{{ post.url }}">{{ post.title }}</a>
       </li>
       {% endfor %}
     </ul>
index f553df1da6fafc5f552410e48ed53393dc91beaa..24f5ca265bbd8a8f263b24da451333377d94642c 100644 (file)
@@ -1,11 +1,14 @@
 body {background-color: #fff}
-a.logo {display: block; margin: 1.538em 0 0 1.538em; width: 44.615em; height: 7.692em; background-image: url(/img/header.gif)}
+a.logo {display: block; margin: 1.538em auto 0; max-width: 60em; background-size: 100% 100%; height: 6.667em; background-image: url(/img/unlimited-pizza-animated-logo.gif)}
 a.logo span {display:none}
 em {color:#99a3a4}
 
 nav ul{
   list-style: none;
-  margin: 1.536em;
+  margin: 1.536em auto;
+  max-width: 60em;
+  justify-content: space-between;
+  display: flex;
 }
 
 nav ul li{
@@ -14,7 +17,7 @@ nav ul li{
   text-transform: uppercase;
   font-weight: 400;
   font-size: 2.769em;
-  margin: 0.555em;
+  margin: 0.555em 0;
 }
 
 nav ul li a{
@@ -52,6 +55,8 @@ nav ul li a:focus {
 .postcontainer h1{
   color: #d30058;
   margin: 0.666em 1.333em 0;
+  font-size: 3.692em;
+  line-height: 1.0833em;
 }
 
 .postcontainer h2 {
@@ -74,7 +79,8 @@ nav ul li a:focus {
 .postcontainer.purple h1 {color: #400098}
 
 .post-meta {
-  margin-left: 3.077em;
+  margin: 0.714em 4.643em 4.285em;
+  font-size: 1.077em;
 }
 
 .post-meta > div {
@@ -89,13 +95,13 @@ nav ul li a:focus {
 .postcontainer.blue .post-tags a {color: #0081cb}
 .postcontainer.green .post-tags a {color: #43da30}
 .postcontainer.grey .post-tags a {color: #9e978e}
-.postcontainer.yellow .post-tags a {color: #ffda00}
+.postcontainer.yellow .post-tags a {color: #e4c50d}
 .postcontainer.orange .post-tags a {color: #fd3839}
 .postcontainer.red .post-tags a {color: #f32240}
 .postcontainer.cyan .post-tags a {color: #74d0eb}
 .postcontainer.purple .post-tags a {color: #400098}
 
-.post-image {height: 36.923em; background-color: #d30058; margin-top: 3.077em}
+.post-image {max-height: 36.923em; background-color: #d30058; margin-top: 3.077em; background-size: auto 100%; overflow: hidden}
 
 .postcontainer.blue .post-image {background-color: #0081cb}
 .postcontainer.green .post-image {background-color: #43da30}
@@ -106,29 +112,28 @@ nav ul li a:focus {
 .postcontainer.cyan .post-image {background-color: #74d0eb}
 .postcontainer.purple .post-image {background-color: #400098}
 
-.postcontent {margin: 1.538em 3.077em;
-  -webkit-column-width: 36.923em;
-     -moz-column-width: 36.923em;
-          column-width: 36.923em;
-  -webkit-column-gap: 6.154em;
-     -moz-column-gap: 6.154em;
-          column-gap: 6.154em;
+.postcontent {margin: 1.538em 4.923em;
+  max-width: 64.615em;
 }
 
 .related p, .related li,
 .postcontent p, .postcontent li{
-  font-size: 1.077em;
+  font-size: 1.307em;
   line-height: 1.6em;
   padding: 5px 0;
   color: #54575a;
   font-family: "Lato", sans-serif;
 }
 
+.related p, .postcontent p {
+  padding: 10px 0;
+}
+
 .postcontent a {color: #d30058}
 .blue .postcontent a {color: #0081cb}
 .green .postcontent a {color: #43da30}
 .grey .postcontent a {color: #9e978e}
-.yellow .postcontent a {color: #ffda00}
+.yellow .postcontent a {color: #e4c50d}
 .orange .postcontent a {color: #fd3839}
 .red .postcontent a {color: #f32240}
 .cyan .postcontent a {color: #74d0eb}
@@ -151,14 +156,17 @@ nav ul li a:focus {
 
 .related  {margin: 0 3.077em}
 .related ul {margin: 0 1.538em}
-.related li {font-size: 1.077em; font-family: "Lato"}
 .related a {color: #d30058}
 
 .related a.blue {color: #0081cb}
+.related a.python,
 .related a.green {color: #43da30}
+.related a.etc,
 .related a.grey {color: #9e978e}
-.related a.yellow {color: #ffda00}
+.related a.javascript,
+.related a.yellow {color: #e4c50d}
 .related a.orange {color: #fd3839}
+.related a.ruby,
 .related a.red {color: #f32240}
 .related a.cyan {color: #74d0eb}
 .related a.purple {color: #400098}
@@ -176,4 +184,141 @@ nav ul li a:focus {
 .paginator {font-size: 1.077em; margin: 2.857em; font-family: "Lato", sans-serif}
 .paginator a{color:#99a3a4}
 
+.postcontent pre code {font-size: 1.333em; line-height: 1.5em}
 code {overflow-wrap: normal}
+
+/* Guestbook */
+.guestbook-feed, .guestbook-form ul {
+  list-style: none;
+}
+
+.guestbook-form li {
+  display: block;
+}
+
+.guestbook-form .guestbook-label {
+  width: 8.571em;
+  float: left;
+  text-align: right;
+  padding: 0.5em  1.071em;
+  text-transform: uppercase;
+}
+
+.guestbook-form .guestbook-control {
+  float: left;
+}
+
+.guestbook-form .guestbook-control-group {
+  clear: both;
+}
+
+.guestbook-form .comment-control {
+  width: 42.857em;
+  height: 10em;
+}
+
+.guestbook-content, .guestbook-form {
+  clear: both;
+  padding: 2.142em 0;
+}
+
+.guestbook-feed .guestbook-post {
+  display: block;
+  border-bottom: 0.071em solid #99a3a4;
+  padding: 1.071em;
+}
+
+.guestbook-post .author {
+  font-weight: bold;
+}
+
+/*
+ * The Recorder CSS
+ */
+.pepperoni-widget {
+  justify-content: space-between;
+  display: flex;
+}
+
+.pepperoni-widget .record-button {
+  display: flex;
+  font-size: 1.538461em;
+  padding: 1em;
+  margin: 1em;
+  height: 1em;
+  background-color: #f1f1f1;
+  cursor: pointer;
+  transition: background-color 0.2s ease, color 0.2s ease;
+}
+
+.record-info {
+  margin: 1em 0;
+}
+
+.pepperoni-widget .record-button.recording {
+  background-color: #00cc12;
+  color: white;
+  padding: 1em 1.1em 1em 0.68em;
+}
+
+.pepperoni-widget .record-button:hover {
+  text-decoration: none;
+  background-color: #fafafa;
+}
+
+.pepperoni-widget .record-button.recording:hover {
+  background-color: #d30058;
+  color: #f1f1f1;
+}
+
+.pepperoni-widget .record-progress {
+  justify-content: space-between;
+  display: flex;
+  margin: 0.5em 0.76em;
+}
+
+.record-progress-bar-container {
+  background-color: #f1f1f1;
+  height: 2em;
+  width: 15.385em;
+  margin-right: 0.76em;
+}
+
+.record-progress-bar {
+  height: 2em;
+  background-color: #d30058;
+  width: 0;
+}
+
+.record-clear {
+  margin-top: 0.1em;
+  text-transform: uppercase;
+  font-size: 1em;
+  width: 4em;
+  cursor: pointer;
+}
+
+.record-clear:hover {
+  text-decoration: none;
+}
+
+.record-preview {
+  margin: 0.76em;
+  width: 15.385em;
+  height: 2em;
+}
+
+.guestbook-submit {
+  border-radius: 0;
+  border: 0;
+  background-color: #d30058;
+  font-family: 'Oswald', sans-serif;
+  color: #fff;
+  padding: 1em;
+  margin-left: 15em;
+}
+
+.filter-switches label {
+  display: inline;
+  margin-right: 2em;
+}
diff --git a/jekyll/etc.html b/jekyll/etc.html
deleted file mode 100644 (file)
index 52edaa9..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
----
-layout: default
-title: Etc...
-description: "Experimentos raros que he hecho cuando debería estar
-haciendo cosas de verdad"
----
-
-<div class="content">
-  <div class="related">
-    <h1>Etc</h1>
-    <p> Cosas que he hecho de variable utilidad y ridiculés. </p>
-    <p> <em> Things I've built of variable utility and sillyness.</em></p>
-    <hr/>
-    <ul>
-      <li><strong><a href="/wooyay.php">Woo Yay!</a>:
-        </strong> Página para celebrar. • <em> Celebration page </em></li>
-      <li><strong><a href="/clima/">Termometro Fuzzy 1</a>:
-      </strong> Un termometro fuzzy minimalista para Juárez. •
-      <em> A fuzzy and minimalist thermometer for Juarez. </em></li>
-      <li><strong><a href="/clima2/">Termometro Fuzzy 2</a>:
-      </strong> Un termometro fuzzy minimalista para Juárez, ahora con canvas!. •
-      <em> A fuzzy and minimalist thermometer for Juarez, now with canvas!. </em></li>
-      <li><strong><a href="/rosa/">Generador de La Rosa de Guadalupe</a>:
-      </strong> Generador de episodios de la Rosa de Guadalupe. •
-      <em> Episode generator for mexican TV show: La rosa de Guadalupe </em></li>
-      <li><strong><a href="/lolmustache.htm">Mustache</a>:
-      </strong> Una celebración al bigote. •
-      <em> A celebration of mustaches. </em></li>
-      <li><strong><a href="/mesias.htm">Mesias</a>:
-      </strong> Tributo a nuestro salvador gamer. •
-      <em> A tribute to our gamer savior. </em></li>
-    </ul>
-  </div>
-</div>
index 0458e2f4a102bddbaf726fb139f05825b49214fd..81582e2b8b97f043a77294897a26970631370d2e 100644 (file)
Binary files a/jekyll/favicon.ico and b/jekyll/favicon.ico differ
index d9d5c79de1a219a03a9a35c75729716c434590b2..b77a9597fb5fd06a4c04bd3eef84cc340b528e7e 100644 (file)
Binary files a/jekyll/favicon.png and b/jekyll/favicon.png differ
diff --git a/jekyll/guestbook.html b/jekyll/guestbook.html
new file mode 100644 (file)
index 0000000..46ccfda
--- /dev/null
@@ -0,0 +1,36 @@
+---
+layout: default
+title: Guestbook
+description: "Audio Guestbook"
+---
+
+<div class="content">
+  <div class="related">
+    <div class="guestbook-form">
+      <h1>Audio Guestbook</h1>
+      <p>
+      Clips will live for a week before being destroyed.
+      <em>Los clips durarán una semana antes de ser destruídos</em>
+      </p>
+      <form method="post">
+        <ul>
+            <div class="guestbook-control-group">
+              <li class="guestbook-label"><label for="name-control">Nombre / Name</label></li>
+              <li class="guestbook-control"><input name="name" class="name-control" id="name-control" /></li>
+            </div>
+            <div class="guestbook-control-group">
+              <li class="guestbook-control"><div class="pepperoni-widget"></div></li>
+            </div>
+            <div class="guestbook-control-group">
+              <li class="guestbook-control"><input type="submit" value="OK!" class="guestbook-submit" /></li>
+            </div>
+        </ul>
+      </form>
+    </div>
+    <div class="guestbook-content">
+      <h1>CLIPS</h1>
+      <ul class="guestbook-feed">
+      </ul>
+    </div>
+  </div>
+</div>
diff --git a/jekyll/img/selfie.gif b/jekyll/img/selfie.gif
new file mode 100644 (file)
index 0000000..42b0d1f
Binary files /dev/null and b/jekyll/img/selfie.gif differ
diff --git a/jekyll/img/unlimited-pizza-animated-logo.gif b/jekyll/img/unlimited-pizza-animated-logo.gif
new file mode 100644 (file)
index 0000000..ca42ca0
Binary files /dev/null and b/jekyll/img/unlimited-pizza-animated-logo.gif differ
index 891515b6babb2a8e5a0c8d0c594aef8e7d812bfe..4bebacbc33f8512651236beb4133801f0cb6e2ac 100644 (file)
@@ -1,7 +1,7 @@
 ---
 layout: default
-title: Cosas de Ben Beltran
-description: "N, S o Vocal. El lote abandonado de Ben Beltran. Juegos, Web y ñonerías. Siempre."
+title: !!!
+description: "Unlimited Pizza: Juegos, Web, nerdura en general y precios más bajos que en la competencia. Siempre."
 ---
 <div class="content">
       {% for post in paginator.posts %}
diff --git a/jekyll/js/unlimited_pizza.js b/jekyll/js/unlimited_pizza.js
new file mode 100644 (file)
index 0000000..af650ee
--- /dev/null
@@ -0,0 +1,150 @@
+'use strict';
+
+Class("UnlimitedPizza").inherits(Widget)({
+
+  /**
+   * Gets instance, creates it if not available.
+   */
+  instance : function getInstance(config) {
+    if (!this._mainInstance) {
+      this._mainInstance = new this(config);
+    }
+    return this._mainInstance;
+  },
+
+  prototype : {
+    _fb : null,
+    _loaded : false,
+
+    init : function (config) {
+      Widget.prototype.init.call(this, config)
+
+      this._fb = new Firebase("https://guestbook-nsovocal.firebaseio.com");
+
+      this._bindInternalEvents();
+    },
+
+    _bindInternalEvents : function bindInternalEvents() {
+      this.bind('activate', this._onActivate.bind(this));
+    },
+
+    _onActivate : function _activate() {
+      // If this is the first time activating it... then load
+      if (!this._loaded) {
+        this._load();
+      }
+    },
+
+    /*
+     * Loads everything.
+     */
+    _load : function _load() {
+
+      // Melty cheese is our header image widget.
+      this._loadMeltyCheese();
+
+      // Pepperoni is our recording widget.
+      this._loadPepperoni();
+
+      // Simple guestbook functionality
+      this._loadGuestbook();
+      this._loadPosts();
+    },
+
+    _loadMeltyCheese : function () {
+      this.element.find('.post-image').each(function (i, headerElement) {
+
+        // Create and activate
+        this.appendChild(new UnlimitedPizza.MeltyCheese({
+          element : $(headerElement),
+          name : 'header-' + i
+        }));
+        this['header-' + i].activate();
+      }.bind(this));
+    },
+
+    _loadPepperoni : function () {
+      this.element.find('.pepperoni-widget').each(function (i, widgetElement) {
+
+        // Create and activate
+        this.appendChild(new UnlimitedPizza.Pepperoni({
+          element : $(widgetElement),
+          name : 'recorder-' + i
+        }));
+        this['recorder-' + i].activate();
+      }.bind(this));
+    },
+
+    _loadGuestbook : function () {
+      var form = this.element.find('.guestbook-form form');
+      form.on('submit', function submitPost(ev) {
+        ev.preventDefault();
+
+        var formArray = form.serializeArray();
+        var recorder = this['recorder-0'];
+
+        recorder.finalize(function (buffer) {
+          var fb, arrayBuffer, fileReader;
+
+          if (buffer.size <= 44) {
+            alert("You need to record something.");
+            return;
+          }
+          if (formArray[0].value.length === 0) {
+            alert("You need a name.");
+            return;
+          }
+
+          fb = this._fb;
+
+          fileReader = new FileReader();
+          fileReader.onload = function() {
+            var binary, bytes, length, i;
+
+            binary = '';
+            bytes = new Uint8Array( this.result );
+            length = bytes.byteLength;
+            for (i = 0; i < length; i++) {
+              binary += String.fromCharCode( bytes[ i ] );
+            }
+
+            fb.push({
+              buffer: btoa(binary),
+              name: formArray[0].value
+            });
+            recorder.clear();
+          };
+          fileReader.readAsArrayBuffer(buffer);
+        }.bind(this));
+        return false;
+      }.bind(this))
+    },
+
+    _loadPosts : function () {
+      var feed = this.element.find('.guestbook-feed');
+
+      console.log("Loadin", feed.length);
+      if (feed.length > 0) {
+        this._fb.on('value', function (data) {
+          var posts, property, post;
+
+          // Clear feed
+          feed.empty();
+          posts = data.val();
+
+          for (property in posts) {
+            if (posts.hasOwnProperty(property)) {
+              post = posts[property];
+
+              feed.append($('<li>\
+                    <div class="author">FROM: ' + post.name + '</div>\
+                    <div class="content">\
+                    <audio src="data:audio/wav;base64,' + post.buffer + '" controls></audio>\
+                    </div></li>'))
+            }
+          }
+        });
+      }
+    }
+  }
+});
diff --git a/jekyll/js/unlimited_pizza/melty_cheese.js b/jekyll/js/unlimited_pizza/melty_cheese.js
new file mode 100644 (file)
index 0000000..1059a60
--- /dev/null
@@ -0,0 +1,88 @@
+'use strict';
+
+Class(UnlimitedPizza, "MeltyCheese").inherits(Widget)({
+  prototype : {
+    min : 60, // min height of the element
+    max : 480, // max height of the element
+    minThreshold : 200, // distance from bottom before we start
+    maxThreshold : 500, // distance from bottom before we stop
+    _loaded : false,
+
+    init : function (config) {
+      Widget.prototype.init.call(this, config)
+
+      this._bindInternalEvents();
+    },
+
+    _bindInternalEvents : function bindInternalEvents() {
+      this.bind('activate', this._onActivate.bind(this));
+      this.bind('deactivate', this._onDeactivate.bind(this));
+    },
+
+    _onActivate : function _activate() {
+      // If this is the first time activating it... then load
+      if (!this._loaded) {
+        this._load();
+      }
+    },
+
+    _onDeactivate : function _deactivate() {
+      this._unload();
+    },
+
+    /*
+     * Loads everything.
+     */
+    _load : function _load() {
+      this._bindEvents();
+
+      this.image = this.element.find('img')
+      this._onScroll();
+    },
+
+    _unload : function _unload() {
+      this._loaded = false;
+      this._unbindEvents();
+    },
+
+    _bindEvents : function bindEvents() {
+      $(window).on('scroll', this._onScroll.bind(this));
+      $(window).on('resize', this._onScroll.bind(this));
+    },
+
+    _unbindEvents : function unbindEvents() {
+      $(window).off('scroll');
+      $(window).off('resize');
+    },
+
+    /* Listeners beyond */
+
+    _onScroll : function onScroll() {
+      var documentTop, documentBottom, elementTop, diff, height;
+
+
+      documentTop = $(window).scrollTop();
+      documentBottom = documentTop + $(window).height();
+      elementTop = this.element.offset().top;
+      diff = documentBottom - elementTop;
+
+      this.max = this.image.height();
+      this.min = this.max / 10;
+
+      diff -= this.minThreshold;
+
+      height = diff * this.max / this.maxThreshold;
+
+      if (height < this.min) {
+        height = this.min;
+      }
+
+      if (height > this.max) {
+        height = this.max;
+      }
+
+      this.element.height(height);
+    },
+
+  }
+});
diff --git a/jekyll/js/unlimited_pizza/pepperoni.js b/jekyll/js/unlimited_pizza/pepperoni.js
new file mode 100644 (file)
index 0000000..c20f285
--- /dev/null
@@ -0,0 +1,338 @@
+'use strict';
+
+Class(UnlimitedPizza, "Pepperoni").inherits(Widget)({
+  INNER_HTML : ' \
+<a class="record-button">&#11044</a> \
+<div class="record-info"> \
+  <div class="record-progress"> \
+    <div class="record-progress-bar-container"> \
+      <div class="record-progress-bar"></div> \
+    </div> \
+    <a class="record-clear">X</a> \
+  </div> \
+  <audio class="record-preview" controls></audio> \
+  <div class="filter-switches"> \
+    <input class="filter-switch" name="bandpass-filter" type="checkbox" /> <label for="bandpass-filter">Band Pass</label> \
+    <input class="filter-switch" name="hipass-filter" type="checkbox" /> <label for="hipass-filter">Hi Pass</label> \
+    <input class="filter-switch" name="lopass-filter" type="checkbox" /> <label for="lopass-filter">Lo Pass</label> \
+    <input class="filter-switch" name="reverb-filter" type="checkbox" /> <label for="reverb-filter">Reverb</label> \
+    <input class="filter-switch" name="distort-filter" type="checkbox" /> <label for="distort-filter">Distort</label> \
+  </div> \
+</div> \
+  ',
+  PAUSE : '&#9616;&#9616;',
+  RECORD : '&#11044;',
+  prototype : {
+    maxSize : 1048576,
+    recording : false,
+    source : null,
+    recorder : null,
+    context : null,
+    _delayNode : null,
+    _bandPassFilterNode : null,
+    _hiPassFilterNode : null,
+    _loPassFilterNode : null,
+    _convolverNode : null,
+    _distortionNode : null,
+    _activatedNodes : null,
+    workerPath : '/js/vendor/recorderjs/recorderWorker.js',
+    init : function init(config) {
+      var channels, frameCount, reverbBuffer, request, requestHandler;
+
+      Widget.prototype.init.call(this, config);
+
+      if (!this.context) {
+        this.context = new (window.AudioContext || window.webkitAudioContext)();
+      }
+
+      this._delayNode = this.context.createDelay(1.0);
+      this._bandPassFilterNode = this.context.createBiquadFilter();
+      this._hiPassFilterNode = this.context.createBiquadFilter();
+      this._loPassFilterNode = this.context.createBiquadFilter();
+      this._convolverNode = this.context.createConvolver();
+      this._distortionNode = this.context.createWaveShaper();
+
+      this._distortionNode.curve = this._generateDistortion(400);
+      this._distortionNode.oversample = '4x';
+
+      this._activatedNodes = [];
+
+      // config lo pass
+      this._loPassFilterNode.type = "lowpass";
+      this._loPassFilterNode.frequency.value = 1000;
+      this._loPassFilterNode.gain.value = 25;
+
+      // config hi pass
+      this._hiPassFilterNode.type = "highpass";
+      this._hiPassFilterNode.frequency.value = 3000;
+      this._hiPassFilterNode.gain.value = 25;
+
+      // config band pass
+      this._bandPassFilterNode.type = "bandpass";
+      this._bandPassFilterNode.frequency.value = 2000;
+      this._bandPassFilterNode.gain.value = 25;
+
+      requestHandler = function bufferFile(ev) {
+        var request = ev.target;
+        console.log("Reverb loading");
+        this.context.decodeAudioData(request.response, function(buffer){ 
+          console.log("Reverb loaded");
+          this._convolverNode.buffer = buffer;
+        }.bind(this));
+      }.bind(this);
+
+      request = new XMLHttpRequest();
+      request.open('GET', '/reverb.ogg', true);
+      request.responseType = 'arraybuffer';
+      request.addEventListener('load', requestHandler, false);
+      request.send();
+
+      if (!this.source) {
+        this._getUserMedia({
+          audio : true
+        }, this._onUserMedia.bind(this), this._onUserMediaError.bind(this))
+      }
+
+      this.element.html(this.constructor.INNER_HTML);
+
+      this.controlButton = this.element.find('.record-button');
+      this.clearButton = this.element.find('.record-clear');
+      this.audioElement = this.element.find('audio');
+      this.progressBarContainer = this.element.find('.record-progress-bar-container');
+      this.progressBar = this.element.find('.record-progress-bar');
+      this.switches = this.element.find('.filter-switch');
+
+      this._bindEvents();
+    },
+
+    record : function record() {
+      if (this.recorder && !this.recording) {
+        this._canRecord(function handleCanRecord(canRecord) {
+          if (canRecord) {
+            this.recording = true;
+            this.controlButton.addClass('recording')
+            this.controlButton.html(this.constructor.PAUSE);
+            this._interval = setInterval(this._onRecordCheck.bind(this), 100);
+            this.recorder.record();
+          }
+        }.bind(this));
+      }
+    },
+
+    stop : function stop() {
+      if (this.recorder && this.recording) {
+        this.recording = false;
+        this.controlButton.removeClass('recording')
+        this.controlButton.html(this.constructor.RECORD);
+        clearInterval(this._interval);
+        this.recorder.stop();
+        this.recorder.exportWAV();
+      }
+    },
+
+    clear : function clear() {
+      if (this.recorder) {
+        this.progressBar.width(0);
+        this.audioElement.attr('src', '');
+        this.audioElement[0].load();
+        this.recorder.clear()
+      }
+    },
+
+    finalize : function finalize(callback) {
+      if (this.recorder) {
+        this.recorder.exportWAV(callback);
+      }
+    },
+
+    getBuffer : function getBuffer(callback) {
+      if (this.recorder) {
+        this.recorder.getBuffer(callback);
+      }
+    },
+
+    _bindEvents : function bindEvents() {
+      var pepperoni = this;
+
+      this.controlButton.on('click', function () {
+        if (this.recording) {
+          this.stop();
+        } else {
+          this.record();
+        }
+      }.bind(this))
+
+      this.clearButton.on('click', function () {
+        if (!this.recording) {
+          this.clear();
+        }
+      }.bind(this))
+
+      this.switches.on('change', function (ev) {
+        if (!pepperoni.source) {
+          this.checked = false;
+          return false;
+        }
+        switch (this.name) {
+          case 'delay-filter':
+            if (this.checked) {
+              pepperoni._addNode(pepperoni._delayNode);
+            } else {
+              pepperoni._removeNode(pepperoni._delayNode);
+            }
+            break;
+
+          case 'hipass-filter':
+            if (this.checked) {
+              pepperoni._addNode(pepperoni._hiPassFilterNode);
+            } else {
+              pepperoni._removeNode(pepperoni._hiPassFilterNode);
+            }
+            break;
+
+          case 'bandpass-filter':
+            if (this.checked) {
+              pepperoni._addNode(pepperoni._bandPassFilterNode);
+            } else {
+              pepperoni._removeNode(pepperoni._bandPassFilterNode);
+            }
+            break;
+
+          case 'lopass-filter':
+            if (this.checked) {
+              pepperoni._addNode(pepperoni._loPassFilterNode);
+            } else {
+              pepperoni._removeNode(pepperoni._loPassFilterNode);
+            }
+            break;
+
+          case 'reverb-filter':
+            if (this.checked) {
+              pepperoni._addNode(pepperoni._convolverNode);
+            } else {
+              pepperoni._removeNode(pepperoni._convolverNode);
+            }
+            break;
+
+          case 'distort-filter':
+            if (this.checked) {
+              pepperoni._addNode(pepperoni._distortionNode);
+            } else {
+              pepperoni._removeNode(pepperoni._distortionNode);
+            }
+
+            break;
+        }
+      });
+    },
+
+    _onRecording : function _onRecording(buffer) {
+      this._buffer = buffer;
+
+      this.audioElement.attr('src', URL.createObjectURL(buffer));
+      this.audioElement[0].load();
+    },
+
+    _onUserMedia : function _onUserMedia(localMediaStream) {
+      this.source = this.context.createMediaStreamSource(localMediaStream);
+      this.recorder = new Recorder(this.source, {
+        workerPath : this.workerPath,
+        callback : this._onRecording.bind(this)
+      });
+    },
+
+    _onUserMediaError : function _onUserMediaError(error) {
+      console.log("Something went wrong", error);
+      this.disable();
+    },
+
+    _onRecordCheck : function _onRecordCheck() {
+      this._canRecord(function (canRecord, bufferSize) {
+        var width =  bufferSize * this.progressBarContainer.width() / this.maxSize;
+        this.progressBar.width(width);
+        if (!canRecord) {
+          this.stop();
+        }
+      }.bind(this));
+    },
+
+    _canRecord : function _canRecord(callback) {
+      this.recorder.getBuffer(function getBuffer(buffer) {
+        var bufferSize = buffer[0].length + buffer[1].length;
+         callback && callback(bufferSize <= this.maxSize, bufferSize);
+      }.bind(this));
+    },
+
+    _addNode : function _addNode(node) {
+      var i;
+
+      i = this._activatedNodes.length;
+
+      this._activatedNodes.push(node);
+
+      if (i === 0) {
+        this.source.disconnect();
+        this.source.connect(node);
+      } else {
+        this._activatedNodes[i - 1].disconnect();
+        this._activatedNodes[i - 1].connect(node);
+      }
+
+      node.connect(this.recorder.node);
+      this.recorder.context = node.context;
+      this.recorder.node.connect(this.recorder.context.destination)
+
+      console.log("Adding: ", node);
+    },
+
+    _removeNode : function _removeNode(node) {
+      var i;
+
+      i = this._activatedNodes.indexOf(node);
+
+      node.disconnect();
+
+      if (i === 0 && i + 1 === this._activatedNodes.length) {
+        // It was the only one, connect source to recorder.
+        this.source.disconnect();
+        this.source.connect(this.recorder.node);
+      } else if (i === 0) {
+        // Normal 0 case, connect source to node. Recorder stays the same
+        this.source.disconnect();
+        this.source.connect(this._activatedNodes[i+1]);
+      } else if (i + 1 === this._activatedNodes.length) {
+        // It's not the 0 case, but we need to reconnect to recorder.
+        this._activatedNodes[i - 1].disconnect();
+        this._activatedNodes[i - 1].connect(this.recorder.node);
+      } else {
+        // Normal case, connect previous node to node
+        this._activatedNodes[i - 1].disconnect();
+        this._activatedNodes[i - 1].connect(this._activatedNodes[i + 1]);
+      }
+
+      this._activatedNodes.splice(i, 1);
+
+      console.log("Removing: ", node);
+    },
+
+    _generateDistortion : function generateDistortion(amount) {
+      var k = typeof amount === 'number' ? amount : 50,
+        n_samples = 44100,
+        curve = new Float32Array(n_samples),
+        deg = Math.PI / 180,
+        i = 0,
+        x;
+      for ( ; i < n_samples; ++i ) {
+          x = i * 2 / n_samples - 1;
+          curve[i] = ( 3 + k ) * x * 20 * deg / ( Math.PI + k * Math.abs(x) );
+        }
+      return curve;
+    },
+
+    // Normalize get user media
+    _getUserMedia : (navigator.getUserMedia ||
+                     navigator.webkitGetUserMedia ||
+                     navigator.mozGetUserMedia ||
+                     navigator.msGetUserMedia).bind(navigator)
+  }
+});
diff --git a/jekyll/js/vendor/neon/neon.js b/jekyll/js/vendor/neon/neon.js
new file mode 100644 (file)
index 0000000..bf0b94c
--- /dev/null
@@ -0,0 +1,234 @@
+
+if (typeof global === "undefined") {
+  global = window;
+}
+
+global.Interface = function Interface(nameOrNameSpace, name) {
+    var nameSpace, interfaceName, factory;
+    nameSpace = (nameOrNameSpace && name) ? nameOrNameSpace : this;
+    interfaceName = (nameOrNameSpace && name) ? name :
+        (nameOrNameSpace) ? nameOrNameSpace : 'interface' + Math.random().toString();
+    factory = function(definition) {
+        definition.isInterface = true;
+        definition.name = interfaceName;
+        nameSpace[interfaceName] = definition;
+        return nameSpace[interfaceName];
+    };
+    return factory;
+};
+
+global.Module = function Module(nameOrNameSpace, name) {
+    var nameSpace, moduleName, factory, newModule;
+
+    nameSpace = (nameOrNameSpace && name) ? nameOrNameSpace : this;
+    moduleName = (nameOrNameSpace && name) ? name :
+        (nameOrNameSpace) ? nameOrNameSpace : 'module' + Math.random().toString();
+
+    newModule = {
+        moduleName : moduleName,
+         prototype : {},
+         __includedModules : [],
+         include : function(module) {
+             var property;
+             for (property in module) {
+                 if (module.hasOwnProperty(property)
+                         && property !== 'prototype'
+                         && property !== 'isModule'
+                         && property !== '__includedModules'
+                         && property !== 'include'
+                         && property !== 'moduleName') {
+                     newModule[property] = module[property];
+                 }
+             }
+
+             if (module.hasOwnProperty('prototype') && module.prototype) {
+                 for (property in module.prototype) {
+                     if (module.prototype.hasOwnProperty(property)) {
+                         newModule.prototype[property] = module.prototype[property];
+                     }
+                 }
+             }
+             else {
+                module.prototype = {};
+             }
+
+             this.__includedModules.push(module);
+
+             return this;
+         }
+    }
+    
+    factory = function(definition){
+        var property;
+        
+        newModule.isModule = true;
+        
+        for (property in definition) {
+            if (definition.hasOwnProperty(property)
+                && property !== 'prototype'
+                && property !== 'isModule'
+                && property !== '__includedModules'
+                && property !== 'include'
+                && property !== 'moduleName') {
+                newModule[property] = definition[property];
+            }
+        }
+        
+        if (definition.hasOwnProperty('prototype') && definition.prototype) {
+            for (property in definition.prototype) {
+                if (definition.prototype.hasOwnProperty(property)) {
+                    newModule.prototype[property] = definition.prototype[property];
+                }
+            }
+        }
+        
+        nameSpace[moduleName] = newModule;
+        
+        return nameSpace[moduleName];
+    };
+    
+    factory.includes = function () {
+        for(var i = 0; i < arguments.length; i++){
+            newModule.include(arguments[i]);
+        }
+        return factory;
+    };
+    
+    return factory;
+};
+
+global.Class = function Class(classNameOrNameSpace, className) {
+    var nameSpace, newClass, classFactory;
+    nameSpace = (classNameOrNameSpace && className) ? classNameOrNameSpace : global;
+    className = (classNameOrNameSpace && className) ? className :
+        (classNameOrNameSpace) ? classNameOrNameSpace : 'class' + Math.random().toString();
+
+    newClass = function() {
+        if (this.init) {
+            this.init.apply(this, arguments);
+        }
+    };
+
+    newClass.__descendants = [];
+    newClass.__implementedInterfaces = [];
+    newClass.__includedModules = [];
+    newClass.className = className;
+    newClass.include = function(module) {
+        var property;
+        for (property in module) {
+            if (module.hasOwnProperty(property)
+                && property != 'prototype'
+                && property != 'constructor'
+                && property != 'isModule'
+                && property != 'superClass'
+                && property != 'include') {
+                newClass[property] = module[property];
+            }
+        }
+
+        if (module.hasOwnProperty('prototype') && module.prototype) {
+            for (property in module.prototype) {
+                if (module.prototype.hasOwnProperty(property)) {
+                    newClass.prototype[property] = module.prototype[property];
+                }
+            }
+        } else {
+            module.prototype = {};
+        }
+
+        newClass.__includedModules.push(module);
+        return this;
+    };
+
+    classFactory = function(classDefinition) {
+        var i, il, j, jl, property, classPrototype = classDefinition.prototype;
+        if (classPrototype) {
+            for (property in classPrototype) {
+                if (classPrototype.hasOwnProperty(property)) {
+                    newClass.prototype[property] = classPrototype[property];
+                }
+            }
+            delete classDefinition.prototype;
+        }
+        for (property in classDefinition) {
+            if (classDefinition.hasOwnProperty(property)) {
+                newClass[property] = classDefinition[property];
+            }
+        }
+
+        for (i = 0, il = newClass.__implementedInterfaces.length; i < il; i++) {
+            for (j = 0, jl = newClass.__implementedInterfaces[i].constructor.length; j < jl; j++) {
+                if (!newClass[ newClass.__implementedInterfaces[i].constructor[j] ]) {
+                    console.log('must implement static ' + newClass.__implementedInterfaces[i].name);
+                    break;
+                }
+            }
+
+            if (newClass.__implementedInterfaces[i].hasOwnProperty('prototype')
+                && newClass.__implementedInterfaces[i].prototype) {
+                for (j = 0, jl = newClass.__implementedInterfaces[i].prototype.length; j < jl; j++) {
+                    if (!newClass.prototype[newClass.__implementedInterfaces[i].prototype[j]]) {
+                        console.log('must implement prototype ' + newClass.__implementedInterfaces[i].name);
+                        break;
+                    }
+                }
+            }
+        }
+
+        try {
+            if (Li && Li.ObjectSpy && Li.Spy) {
+                newClass.__objectSpy = new Li.ObjectSpy();
+                newClass.__objectSpy.spy(newClass);
+                newClass.__objectSpy.spy(newClass.prototype);
+            }
+        } catch (error) {}
+
+        nameSpace[className] = newClass;
+        return newClass;
+    };
+
+    classFactory.inherits = function(superClass) {
+        var i, inheritedClass;
+        newClass.superClass = superClass;
+        if (superClass.hasOwnProperty('__descendants')) {
+            superClass.__descendants.push(newClass);
+        }
+        inheritedClass = function() {
+        };
+        inheritedClass.prototype = superClass.prototype;
+        newClass.prototype = new inheritedClass();
+        newClass.prototype.constructor = newClass;
+
+        for (i in superClass) {
+            if (superClass.hasOwnProperty(i)
+                && i != 'prototype'
+                && i !== 'className'
+                && i !== 'superClass'
+                && i !== 'include'
+                && i != '__descendants') {
+                newClass[i] = superClass[i];
+            }
+        }
+
+        delete this.inherits;
+        return this;
+    };
+
+    classFactory.ensures = function(interfaces) {
+        for (var i = 0; i < arguments.length; i++) {
+            newClass.__implementedInterfaces.push(arguments[i]);
+        }
+        delete this.ensures;
+        return classFactory;
+    };
+
+    classFactory.includes = function() {
+        for (var i = 0; i < arguments.length; i++) {
+            newClass.include(arguments[i]);
+        }
+        return classFactory;
+    };
+
+    return classFactory;
+
+};
diff --git a/jekyll/js/vendor/neon/stdlib/bubbling_support.js b/jekyll/js/vendor/neon/stdlib/bubbling_support.js
new file mode 100644 (file)
index 0000000..30e0f5d
--- /dev/null
@@ -0,0 +1,32 @@
+Module('BubblingSupport')({
+        dispatch : function (type, data) {
+            data = data || {};
+            var event = CustomEventSupport.prototype.dispatch.call(this, type, data);
+            if (event.isPropagationStopped === false) {
+                if (this.parent && this.parent.dispatch) {
+                    data.target = event.target;
+                    data.currentTarget = this.parent;
+                    this.parent.dispatch(event.type, data);
+                }
+            }
+            return event;
+        },
+
+        prototype : {
+            dispatch : function (type, data) {
+                data = data || {};
+
+                var event = CustomEventSupport.prototype.dispatch.call(this, type, data);
+
+                if (event.isPropagationStopped === false && event.bubbles === true) {
+                    if (this.parent && this.parent.dispatch) {
+                        data.target = event.target;
+                        data.currentTarget = this.parent;
+                        this.parent.dispatch(event.type, data);
+                    }
+                }
+
+                return event;
+            }
+        }
+    });
diff --git a/jekyll/js/vendor/neon/stdlib/custom_event.js b/jekyll/js/vendor/neon/stdlib/custom_event.js
new file mode 100644 (file)
index 0000000..c3c033c
--- /dev/null
@@ -0,0 +1,37 @@
+Class('CustomEvent')({
+    prototype : {
+        bubbles                       : true,
+        cancelable                    : true,
+        currentTarget                 : null,
+        timeStamp                     : 0,
+        target                        : null,
+        type                          : '',
+        isPropagationStopped          : false,
+        isDefaultPrevented            : false,
+        isImmediatePropagationStopped : false,
+        areImmediateHandlersPrevented : false,
+        init : function init(type, data) {
+            this.type = type;
+            if (typeof data !== 'undefined') {
+                for(var property in data) {
+                    if (data.hasOwnProperty(property)) {
+                        this[property] = data[property];
+                    }
+                }
+            }
+        },
+        stopPropagation : function stopPropagation() {
+            this.isPropagationStopped = true;
+        },
+        preventDefault : function preventDefault() {
+            this.isDefaultPrevented = true;
+        },
+        stopImmediatePropagation : function stopImmediatePropagation() {
+            this.preventImmediateHandlers();
+            this.stopPropagation();
+        },
+        preventImmediateHandlers : function preventImmediateHandlers() {
+            this.areImmediateHandlersPrevented = true;
+        }
+    }
+});
diff --git a/jekyll/js/vendor/neon/stdlib/custom_event_support.js b/jekyll/js/vendor/neon/stdlib/custom_event_support.js
new file mode 100644 (file)
index 0000000..fecbd71
--- /dev/null
@@ -0,0 +1,180 @@
+Module('CustomEventSupport')({
+
+    eventListeners : null,
+
+    bind : function(type, eventHandler) {
+        var found, i, listeners;
+
+        if(!this.eventListeners) {
+            this.eventListeners = {};
+        }
+
+        if(!this.eventListeners[type]) {
+            this.eventListeners[type] = [];
+        }
+
+        found  = false;
+
+        listeners = this.eventListeners[type];
+        for (i = 0; i < listeners.length; i++) {
+            if (listeners[i] === eventHandler) {
+                found = true;
+                break;
+            }
+        }
+
+        if(!found) {
+            this.eventListeners[type].push(eventHandler);
+        }
+
+        return this;
+    },
+
+    unbind : function(type, eventHandler) {
+        var i, found, listeners;
+
+        found  = false;
+
+        if(!this.eventListeners) {
+            this.eventListeners = {};
+        }
+
+        if(typeof eventHandler == 'undefined') {
+            this.eventListeners[type] = [];
+        }
+
+        listeners = this.eventListeners[type];
+        for (i = 0; i < listeners.length; i++) {
+            if(listeners[i] === eventHandler) {
+                found = true;
+                break;
+            }
+        }
+
+        if(found) {
+            this.eventListeners[type].splice(i, 1);
+        }
+
+        return this;
+    },
+
+    dispatch : function(type, data) {
+            var event, listeners, instance, i;
+
+            if (this.eventListeners === null) {
+                this.eventListeners = {};
+            }
+
+            if (typeof data === 'undefined') {
+                data = {};
+            }
+
+            if (data.hasOwnProperty('target') === false) {
+                data.target = this;
+            }
+
+            event         = new CustomEvent(type, data);
+            listeners     = this.eventListeners[type] || [];
+            instance      = this;
+
+            for (i = 0; i < listeners.length; i = i + 1) {
+                listeners[i].call(instance, event);
+                if (event.areImmediateHandlersPrevented === true) {
+                    break;
+                }
+            }
+
+            return event;
+    },
+
+    prototype : {
+
+        eventListeners : null,
+
+        bind : function(type, eventHandler) {
+            var found, i, listeners;
+
+            if(!this.eventListeners) {
+                this.eventListeners = {};
+            }
+
+            if(!this.eventListeners[type]) {
+                this.eventListeners[type] = [];
+            }
+
+            found  = false;
+
+            listeners = this.eventListeners[type];
+            for (i = 0; i < listeners.length; i++) {
+                if(listeners[i] === eventHandler) {
+                    found = true;
+                    break;
+                }
+            }
+
+            if(!found) {
+                this.eventListeners[type].push(eventHandler);
+            }
+
+            return this;
+        },
+
+        unbind : function(type, eventHandler) {
+            var i, found, listeners;
+
+            found = false;
+            i     = 0;
+
+            if(!this.eventListeners) {
+                this.eventListeners = {};
+            }
+
+            if(typeof eventHandler == 'undefined') {
+                this.eventListeners[type] = [];
+            }
+
+            listeners = this.eventListeners[type];
+            for (i = 0; i < listeners.length; i++) {
+                if(listeners[i] == eventHandler) {
+                    found = true;
+                    break;
+                }
+            }
+
+            if(found) {
+                this.eventListeners[type].splice(i, 1);
+            }
+
+            return this;
+        },
+
+        dispatch : function(type, data) {
+            var event, listeners, instance, i;
+
+            if (this.eventListeners === null) {
+                this.eventListeners = {};
+            }
+
+            if (typeof data === 'undefined') {
+                data = {};
+            }
+
+            if (data.hasOwnProperty('target') === false) {
+                data.target = this;
+            }
+
+            event         = new CustomEvent(type, data);
+            listeners     = this.eventListeners[type] || [];
+            instance      = this;
+
+            for (i = 0; i < listeners.length; i = i + 1) {
+                listeners[i].call(instance, event);
+                if (event.areImmediateHandlersPrevented === true) {
+                    break;
+                }
+            }
+
+            return event;
+        }
+    }
+});
diff --git a/jekyll/js/vendor/neon/stdlib/index.js b/jekyll/js/vendor/neon/stdlib/index.js
new file mode 100644 (file)
index 0000000..862193b
--- /dev/null
@@ -0,0 +1,7 @@
+// This file is node only
+if(typeof require !== 'undefined'){
+    require('./custom_event');
+    require('./custom_event_support');
+    require('./node_support');
+    require('./bubbling_support');
+}
diff --git a/jekyll/js/vendor/neon/stdlib/node_support.js b/jekyll/js/vendor/neon/stdlib/node_support.js
new file mode 100644 (file)
index 0000000..b1e9473
--- /dev/null
@@ -0,0 +1,123 @@
+Module('NodeSupport')({
+    prototype : {
+        parent      : null,
+
+        children    : [],
+
+        appendChild : function(child) {
+            if(child.parent) {
+                child.parent.removeChild(child);
+            }
+
+            if(!this.hasOwnProperty('children')) {
+                this.children = [];
+            }
+
+            this.children.push(child);
+            this[child.name] = child;
+            child.setParent(this);
+            return child;
+        },
+
+        insertBefore : function (child, beforeChild) {
+            var position;
+
+            if (child.parent) {
+                child.parent.removeChild(child);
+            }
+
+            if (!this.hasOwnProperty('children')) {
+                this.children = [];
+            }
+
+            if (typeof beforeChild === 'undefined') {
+                this.appendChild(child);
+            } else {
+                position = this.children.indexOf(beforeChild);
+                this.children.splice(position, 0, child);
+
+                this[child.name] = child;
+                child.setParent(this);
+            }
+
+            return child;
+
+        },
+
+        insertChild : function(child, position) {
+            console.warn('NodeSupport insertChild method is deprecated, try insertBefore');
+
+            if (child.parent) {
+                child.parent.removeChild(child);
+            }
+
+            if (!this.hasOwnProperty('children')) {
+                this.children = [];
+            }
+
+            if (typeof position == 'undefined') {
+                this.children.push(child);
+                this[child.name] = child;
+                child.setParent(this);
+                return child;
+            }
+
+            this.children.splice(position, 0, child);
+            this[child.name] = child;
+            child.setParent(this);
+            return child;
+        },
+
+        removeChild : function (child) {
+            var position = this.children.indexOf(child);
+
+            if (position !== -1) {
+                this.children.splice(position, 1);
+                delete this[child.name];
+                child.parent = null;
+            }
+
+            return child;
+        },
+
+        setParent   : function (parent) {
+            this.parent = parent;
+            return this;
+        },
+
+        getDescendants : function () {
+            var nodes = [];
+            this.children.forEach(function (node) {
+                nodes.push(node);
+            });
+            this.children.forEach(function (node) {
+                nodes = nodes.concat(node.getDescendants());
+            });
+            return nodes;
+        },
+
+        getPreviousSibling : function () {
+            if (typeof this.parent === 'undefined') {
+                return;
+            }
+
+            if (this.parent.children[0] === this) {
+                return;
+            }
+
+            return this.parent.children[ this.parent.children.indexOf(this) - 1 ];
+        },
+
+        getNextSibling : function () {
+            if (typeof this.parent === 'undefined') {
+                return;
+            }
+
+            if (this.parent.children[ this.parent.children.length - 1 ] === this) {
+                return;
+            }
+
+            return this.parent.children[ this.parent.children.indexOf(this) + 1 ];
+        }
+    }
+});
diff --git a/jekyll/js/vendor/neon/stdlib/widget.js b/jekyll/js/vendor/neon/stdlib/widget.js
new file mode 100644 (file)
index 0000000..2ee6355
--- /dev/null
@@ -0,0 +1,328 @@
+/**
+Base Class from which almost all widgets are based overall the project
+
+The main idea behind constructing a new widget toolkit instead of using one of the many high quality widget
+toolkits avaliable is that we considered that currently, no widget system provides all the features that where
+required for this project.
+
+Features of the widget system
+* A custom and easy to handle event binding, dispatching and manipulation, with some sort of bubbling support
+* A module system which we can use to include specific behaviour to any widget and reuse the code where needed
+* A tree structure support for the widgets that the event system could bubble, and that also serves as
+* A navigation system.
+* The widgets must be able to be grouped to form more complex widgets
+* Remove the complexity of DOM manipulation and handling
+* A way to wrap widgets at our convenience to reuse widgets avaliable and make them comly to our needs
+without the need to hack those widgets, that would force us to maintain the new versions of those widgets
+and that is a very complex task when widgets become so complex.
+* A widget system that would allow us to start wrapping some widgets for a fast start and later code our own widgets
+at will.
+* expose a consistent API that allow us to choose the use of widgets by API calls and user interaction at will and with the same
+clearance and capacity
+* an easy way to allow subclasing widgets
+* an easy way to provide new html, class, and css for a specific instance of a widget that would remove us the need
+to create complex inheritance structures that are hard to maintain.
+
+Usage Example.
+
+The most basic usage of a widget is to simply create an instance and render it at a target element
+in this case body
+var myWidgetInstance = new Breezi.Widget();
+myWidgetInstance.render(document.body);
+
+like this widget does renders does not display anything so lets give it something to display first
+var myWidgetInstance = new Breezi.Widget();
+myWidgetInstance.element.html('Im a simple widget');
+myWidgetInstance.render(document.body);
+
+this reveals that internally every widget has an element property that is initialized by default to a jQuery Instance
+this allow easy DOM manipulation, animation and operations handled by a high quality third party library.
+@class Widget
+@namespace Breezi
+@inlcudes CustomEventSupport
+@includes NodeSupport
+@dependency Neon
+@dependency CustomEventSupport
+@dependency NodeSupport
+**/
+Class('Widget').includes(CustomEventSupport, NodeSupport)({
+
+    /**
+    The default html for the widget, at the most simple case this is just a div.
+    @name HTML
+    @attribute_type CONSTANT
+    @type String
+    */
+    HTML : '<div></div>',
+
+    /**
+    the widget container default class for all widgets is widget
+    @name ELEMENT_CLASS
+    @constant
+    @type String
+    **/
+    ELEMENT_CLASS : 'widget',
+
+    /**
+    @property prototype
+    @type Object
+    **/
+    prototype : {
+        /**
+        Holds the active status of the widget
+        By default all widgets are deactivated waiting
+        for an action to activate it.
+        @property active <public> [Boolean] (false)
+        **/
+        active : false,
+
+        /**
+        Holds the disabled status of the widget
+        By default all widgets are enabled and only by
+        API could be disabled.
+        @property disabled <public> [Boolean] (false)
+        **/
+        disabled : false,
+
+        __destroyed : false,
+
+        init : function init(config) {
+            var property;
+
+            Object.keys(config || {}).forEach(function (propertyName) {
+                this[propertyName] = config[propertyName];
+            }, this);
+
+            if (this.element == null) {
+                this.element = $(this.constructor.HTML.replace(/\s\s+/g, ''));
+                this.element.addClass(this.constructor.ELEMENT_CLASS);
+            }
+
+            if (this.hasOwnProperty('className') === true) {
+                this.element.addClass(this.className);
+            }
+        },
+
+        /**
+        implementation of the activate method, when you need an override, do it
+        over this method instead of doing it on activate
+        @property _activate <private> [Function]
+        @return undefined [undefined]
+        **/
+        _activate : function _activate() {
+            this.active = true;
+            this.element.addClass('active');
+        },
+
+        /**
+        Public activation method for widget, you can listen to this event
+        to take some other actions, but the most important part of this
+        method is that it runs its default action, (its activation)
+        this method uses _activate as its implementation to maintain
+        the events order intact.
+        @property activate <public> [Function]
+        @method
+        @dispatch beforeActivate
+        @dispatch activate
+        @return this [Widget]
+        **/
+        activate : function activate() {
+            if (this.__destroyed === true) {
+                console.warn('calling on destroyed object');
+            }
+            this.dispatch('beforeActivate');
+            this._activate();
+            this.dispatch('activate');
+            return this;
+        },
+
+        /**
+        deactivation implementation
+        this is the oposite of activation method and as such it must be
+        treated as important as that.
+        @property _deactivate <private> [Function]
+        @method
+        @return undefined [undefined]
+        **/
+        _deactivate : function _deactivate() {
+            this.active = false;
+            this.element.removeClass('active');
+        },
+
+        /**
+        Public deactivation method for widget, you can listen to this event
+        to take some other actions, but the most important part of this
+        method is that it runs its default action, (its activation)
+        this method uses _deactivate as its implementation to maintain
+        the events order intact.
+        @property activate <public> [Function]
+        @method
+        @dispatch beforeDeactivatee
+        @dispatch deactivate
+        @return this [Widget]
+        **/
+        deactivate : function deactivate() {
+            if (this.__destroyed === true) {
+                console.warn('calling on destroyed object');
+            }
+            this.dispatch('beforeDeactivate');
+            this._deactivate();
+            this.dispatch('deactivate');
+            return this;
+        },
+
+        /**
+        Enable implementation method
+        if you need to provide a different procedure for enable
+        you must override this method and call "super"
+        @property _enable <private> [Function]
+        @method
+        @return undefined [undefined]
+        **/
+        _enable : function _enable() {
+            this.disabled = false;
+            this.element.removeClass('disable');
+        },
+
+        /**
+        Public enable method, this method should not be
+        overriden.
+        @property enable <public> [Function]
+        @method
+        @return this [Widget]
+        **/
+        enable : function enable() {
+            if (this.__destroyed === true) {
+                console.warn('calling on destroyed object');
+            }
+            this.dispatch('beforeEnable');
+            this._enable();
+            this.dispatch('enable');
+
+            return this;
+        },
+
+        /**
+        Disable implementation
+        @property _disable <private> [Function]
+        @return undefined [undefined]
+        **/
+        _disable : function _disable() {
+            this.disabled = true;
+            this.element.addClass('disable');
+        },
+
+        /**
+        Disables the widget, the idea behind disabling a widget
+        comes from DOM form elements. so following this idea
+        all widgets can be disabled and queried for its disabled
+        state via the disabled property.
+        Same as DOM form elements there is feedback and that is why
+        the default implementation sets the "disable" class
+        on the element so proper visual feedback can be provided
+        to the user.
+        @property disable <public> [Function]
+        @method
+        @return this [Widget]
+        **/
+        disable : function disable() {
+            if (this.__destroyed === true) {
+                console.warn('calling on destroyed object');
+            }
+            this.dispatch('beforeDisable');
+            this._disable();
+            this.dispatch('disable');
+
+            return this;
+        },
+
+        /**
+        Destroy implementation. Its main responsabilities are cleaning
+        all references to other objects so garbage collector can collect
+        the memory used by this and the other objects
+        @property _destroy <private> [Function]
+        @method
+        @return undefined [undefined]
+        **/
+        _destroy : function _destroy() {
+            var childrenLength;
+
+            if (this.element) {
+                this.element.remove();
+            }
+
+            if (this.children !== null){
+                childrenLength = this.children.length;
+                while(childrenLength > 0){
+                    this.children[0].destroy();
+                    if (this.children.length === childrenLength) {
+                        this.children.shift();
+                    }
+                    childrenLength--;
+                }
+            }
+
+            if (this.parent) {
+                this.parent.removeChild(this);
+            }
+
+            this.children       = null;
+            this.element        = null;
+        },
+
+        /**
+        Destroy public method, this one should not be replaced
+        @property destroy <public> [Function]
+        @method
+        @return null [null]
+        **/
+        destroy : function destroy() {
+            if (this.__destroyed === true) {
+                console.warn('calling on destroyed object');
+            }
+
+            this.dispatch('beforeDestroy');
+            this._destroy();
+            this.dispatch('destroy');
+
+            this.eventListeners = null;
+            this.__destroyed    = true;
+
+            return null;
+        },
+
+        /**
+        The render method is the mechanism by which you pass a widget from
+        living only on memory to get into the DOM and with this into the
+        application flow. The recomendation is that render is the last method
+        of the setup of a widget, including appending its children. this is
+        because once a widget gets renderer, further operations cause browser
+        reflows, and DOM operations are slower than memory operations.
+        This method shoudl not be replaced by its children.
+        @property render <public> [Function]
+        @method
+        @argument element <required> [JQuery] (undefined) This is the element
+        into which the widget will be appended.
+        @argument beforeElement <optional> [jQuery] (undefined) this is the element
+        that will be used as a reference to insert the widgets element. this argument
+        must be a child of the "element" argument.
+        @return this [Widget]
+        **/
+        render : function render(element, beforeElement) {
+            if (this.__destroyed === true) {
+                console.warn('calling on destroyed object');
+            }
+            this.dispatch('beforeRender', {
+                element : element,
+                beforeElement : beforeElement
+            });
+            if (beforeElement) {
+                this.element.insertBefore(beforeElement);
+            } else {
+                this.element.appendTo(element);
+            }
+            this.dispatch('render');
+            return this;
+        }
+    }
+});
diff --git a/jekyll/js/vendor/recorderjs/.bower.json b/jekyll/js/vendor/recorderjs/.bower.json
new file mode 100644 (file)
index 0000000..0c6713a
--- /dev/null
@@ -0,0 +1,31 @@
+{
+  "name": "recorderjs",
+  "version": "0.0.0",
+  "homepage": "https://github.com/faradayio/Recorderjs",
+  "authors": [
+    "Tristan Davies <github@tristan.io>"
+  ],
+  "description": "A plugin for recording/exporting the output of Web Audio API nodes",
+  "main": "recorder.js",
+  "moduleType": [
+    "globals"
+  ],
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests"
+  ],
+  "_release": "0.0.0",
+  "_resolution": {
+    "type": "version",
+    "tag": "v0.0.0",
+    "commit": "a60e4a740673ee86d1e1ed67b820511136937058"
+  },
+  "_source": "git://github.com/faradayio/Recorderjs.git",
+  "_target": "~0.0.0",
+  "_originalSource": "recorderjs",
+  "_direct": true
+}
\ No newline at end of file
diff --git a/jekyll/js/vendor/recorderjs/README.md b/jekyll/js/vendor/recorderjs/README.md
new file mode 100644 (file)
index 0000000..3830a91
--- /dev/null
@@ -0,0 +1,76 @@
+# Recorder.js
+
+## A plugin for recording/exporting the output of Web Audio API nodes
+
+### Syntax
+#### Constructor
+    var rec = new Recorder(source [, config])
+
+Creates a recorder instance.
+
+- **source** - The node whose output you wish to capture
+- **config** - (*optional*) A configuration object (see **config** section below)
+
+---------
+#### Config
+
+- **workerPath** - Path to recorder.js worker script. Defaults to 'js/recorderjs/recorderWorker.js'
+- **bufferLen** - The length of the buffer that the internal JavaScriptNode uses to capture the audio. Can be tweaked if experiencing performance issues. Defaults to 4096.
+- **callback** - A default callback to be used with `exportWAV`.
+- **type** - The type of the Blob generated by `exportWAV`. Defaults to 'audio/wav'.
+
+---------
+#### Instance Methods
+
+    rec.record()
+    rec.stop()
+
+Pretty self-explanatory... **record** will begin capturing audio and **stop** will cease capturing audio. Subsequent calls to **record** will add to the current recording.
+
+    rec.clear()
+
+This will clear the recording.
+
+    rec.exportWAV([callback][, type])
+
+This will generate a Blob object containing the recording in WAV format. The callback will be called with the Blob as its sole argument. If a callback is not specified, the default callback (as defined in the config) will be used. If no default has been set, an error will be thrown.
+
+In addition, you may specify the type of Blob to be returned (defaults to 'audio/wav').
+
+    rec.getBuffer([callback])
+
+This will pass the recorded stereo buffer (as an array of two Float32Arrays, for the separate left and right channels) to the callback. It can be played back by creating a new source buffer and setting these buffers as the separate channel data:
+
+       function getBufferCallback( buffers ) {
+               var newSource = audioContext.createBufferSource();
+               var newBuffer = audioContext.createBuffer( 2, buffers[0].length, audioContext.sampleRate );
+               newBuffer.getChannelData(0).set(buffers[0]);
+               newBuffer.getChannelData(1).set(buffers[1]);
+               newSource.buffer = newBuffer;
+
+               newSource.connect( audioContext.destination );
+               newSource.start(0);
+       }
+
+This sample code will play back the stereo buffer.
+
+
+    rec.configure(config)
+
+This will set the configuration for Recorder by passing in a config object.
+
+#### Utility Methods (static)
+
+    Recorder.forceDownload(blob[, filename])
+
+This method will force a download using the new anchor link *download* attribute. Filename defaults to 'output.wav'.
+
+## License (MIT)
+
+Copyright © 2013 Matt Diamond
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/jekyll/js/vendor/recorderjs/bower.json b/jekyll/js/vendor/recorderjs/bower.json
new file mode 100644 (file)
index 0000000..e950b5a
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "name": "recorderjs",
+  "version": "0.0.0",
+  "homepage": "https://github.com/faradayio/Recorderjs",
+  "authors": [
+    "Tristan Davies <github@tristan.io>"
+  ],
+  "description": "A plugin for recording/exporting the output of Web Audio API nodes",
+  "main": "recorder.js",
+  "moduleType": [
+    "globals"
+  ],
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests"
+  ]
+}
diff --git a/jekyll/js/vendor/recorderjs/example_simple_exportwav.html b/jekyll/js/vendor/recorderjs/example_simple_exportwav.html
new file mode 100644 (file)
index 0000000..2388511
--- /dev/null
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+       <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+       <title>Live input record and playback</title>
+  <style type='text/css'>
+    ul { list-style: none; }
+    #recordingslist audio { display: block; margin-bottom: 10px; }
+  </style>
+</head>
+<body>
+
+  <h1>Recorder.js simple WAV export example</h1>
+
+  <p>Make sure you are using a recent version of Google Chrome.</p>
+  <p>Also before you enable microphone input either plug in headphones or turn the volume down if you want to avoid ear splitting feedback!</p>
+
+  <button onclick="startRecording(this);">record</button>
+  <button onclick="stopRecording(this);" disabled>stop</button>
+  
+  <h2>Recordings</h2>
+  <ul id="recordingslist"></ul>
+  
+  <h2>Log</h2>
+  <pre id="log"></pre>
+
+  <script>
+  function __log(e, data) {
+    log.innerHTML += "\n" + e + " " + (data || '');
+  }
+
+  var audio_context;
+  var recorder;
+
+  function startUserMedia(stream) {
+    var input = audio_context.createMediaStreamSource(stream);
+    __log('Media stream created.');
+    
+    input.connect(audio_context.destination);
+    __log('Input connected to audio context destination.');
+    
+    recorder = new Recorder(input);
+    __log('Recorder initialised.');
+  }
+
+  function startRecording(button) {
+    recorder && recorder.record();
+    button.disabled = true;
+    button.nextElementSibling.disabled = false;
+    __log('Recording...');
+  }
+
+  function stopRecording(button) {
+    recorder && recorder.stop();
+    button.disabled = true;
+    button.previousElementSibling.disabled = false;
+    __log('Stopped recording.');
+    
+    // create WAV download link using audio data blob
+    createDownloadLink();
+    
+    recorder.clear();
+  }
+
+  function createDownloadLink() {
+    recorder && recorder.exportWAV(function(blob) {
+      var url = URL.createObjectURL(blob);
+      var li = document.createElement('li');
+      var au = document.createElement('audio');
+      var hf = document.createElement('a');
+      
+      au.controls = true;
+      au.src = url;
+      hf.href = url;
+      hf.download = new Date().toISOString() + '.wav';
+      hf.innerHTML = hf.download;
+      li.appendChild(au);
+      li.appendChild(hf);
+      recordingslist.appendChild(li);
+    });
+  }
+
+  window.onload = function init() {
+    try {
+      // webkit shim
+      window.AudioContext = window.AudioContext || window.webkitAudioContext;
+      navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
+      window.URL = window.URL || window.webkitURL;
+      
+      audio_context = new AudioContext;
+      __log('Audio context set up.');
+      __log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!'));
+    } catch (e) {
+      alert('No web audio support in this browser!');
+    }
+    
+    navigator.getUserMedia({audio: true}, startUserMedia, function(e) {
+      __log('No live audio input: ' + e);
+    });
+  };
+  </script>
+
+  <script src="recorder.js"></script>
+</body>
+</html>
diff --git a/jekyll/js/vendor/recorderjs/recorder.js b/jekyll/js/vendor/recorderjs/recorder.js
new file mode 100644 (file)
index 0000000..84ec0d4
--- /dev/null
@@ -0,0 +1,97 @@
+(function(window){
+
+  var WORKER_PATH = 'recorderWorker.js';
+
+  var Recorder = function(source, cfg){
+    var config = cfg || {};
+    var bufferLen = config.bufferLen || 4096;
+    this.context = source.context;
+    this.node = (this.context.createScriptProcessor ||
+                 this.context.createJavaScriptNode).call(this.context,
+                                                         bufferLen, 2, 2);
+    var worker = new Worker(config.workerPath || WORKER_PATH);
+    worker.postMessage({
+      command: 'init',
+      config: {
+        sampleRate: this.context.sampleRate
+      }
+    });
+    var recording = false,
+      currCallback;
+
+    var self = this;
+    this.node.onaudioprocess = function(e){
+      if (!recording) return;
+      self.ondata && self.ondata(e.inputBuffer.getChannelData(0));
+      worker.postMessage({
+        command: 'record',
+        buffer: [
+          e.inputBuffer.getChannelData(0),
+          e.inputBuffer.getChannelData(1)
+        ]
+      });
+    }
+
+    this.configure = function(cfg){
+      for (var prop in cfg){
+        if (cfg.hasOwnProperty(prop)){
+          config[prop] = cfg[prop];
+        }
+      }
+    }
+
+    this.record = function(){
+      recording = true;
+    }
+
+    this.stop = function(){
+      recording = false;
+    }
+
+    this.clear = function(){
+      worker.postMessage({ command: 'clear' });
+    }
+
+    this.getBuffer = function(cb) {
+      currCallback = cb || config.callback;
+      worker.postMessage({ command: 'getBuffer' })
+    }
+
+    this.exportWAV = function(cb, type){
+      currCallback = cb || config.callback;
+      type = type || config.type || 'audio/wav';
+      if (!currCallback) throw new Error('Callback not set');
+      worker.postMessage({
+        command: 'exportWAV',
+        type: type
+      });
+    }
+
+    this.shutdown = function(){
+      worker.terminate();
+      source.disconnect();
+      this.node.disconnect();
+    };
+
+    worker.onmessage = function(e){
+      var blob = e.data;
+      currCallback(blob);
+    }
+
+    source.connect(this.node);
+    this.node.connect(this.context.destination);    //this should not be necessary
+  };
+
+  Recorder.forceDownload = function(blob, filename){
+    var url = (window.URL || window.webkitURL).createObjectURL(blob);
+    var link = window.document.createElement('a');
+    link.href = url;
+    link.download = filename || 'output.wav';
+    var click = document.createEvent("Event");
+    click.initEvent("click", true, true);
+    link.dispatchEvent(click);
+  }
+
+  window.Recorder = Recorder;
+
+})(window);
diff --git a/jekyll/js/vendor/recorderjs/recorderWorker.js b/jekyll/js/vendor/recorderjs/recorderWorker.js
new file mode 100644 (file)
index 0000000..08ad444
--- /dev/null
@@ -0,0 +1,131 @@
+var recLength = 0,
+  recBuffersL = [],
+  recBuffersR = [],
+  sampleRate;
+
+this.onmessage = function(e){
+  switch(e.data.command){
+    case 'init':
+      init(e.data.config);
+      break;
+    case 'record':
+      record(e.data.buffer);
+      break;
+    case 'exportWAV':
+      exportWAV(e.data.type);
+      break;
+    case 'getBuffer':
+      getBuffer();
+      break;
+    case 'clear':
+      clear();
+      break;
+  }
+};
+
+function init(config){
+  sampleRate = config.sampleRate;
+}
+
+function record(inputBuffer){
+  recBuffersL.push(inputBuffer[0]);
+  recBuffersR.push(inputBuffer[1]);
+  recLength += inputBuffer[0].length;
+}
+
+function exportWAV(type){
+  var bufferL = mergeBuffers(recBuffersL, recLength);
+  var bufferR = mergeBuffers(recBuffersR, recLength);
+  var interleaved = interleave(bufferL, bufferR);
+  var dataview = encodeWAV(interleaved);
+  var audioBlob = new Blob([dataview], { type: type });
+
+  this.postMessage(audioBlob);
+}
+
+function getBuffer() {
+  var buffers = [];
+  buffers.push( mergeBuffers(recBuffersL, recLength) );
+  buffers.push( mergeBuffers(recBuffersR, recLength) );
+  this.postMessage(buffers);
+}
+
+function clear(){
+  recLength = 0;
+  recBuffersL = [];
+  recBuffersR = [];
+}
+
+function mergeBuffers(recBuffers, recLength){
+  var result = new Float32Array(recLength);
+  var offset = 0;
+  for (var i = 0; i < recBuffers.length; i++){
+    result.set(recBuffers[i], offset);
+    offset += recBuffers[i].length;
+  }
+  return result;
+}
+
+function interleave(inputL, inputR){
+  var length = inputL.length + inputR.length;
+  var result = new Float32Array(length);
+
+  var index = 0,
+    inputIndex = 0;
+
+  while (index < length){
+    result[index++] = inputL[inputIndex];
+    result[index++] = inputR[inputIndex];
+    inputIndex++;
+  }
+  return result;
+}
+
+function floatTo16BitPCM(output, offset, input){
+  for (var i = 0; i < input.length; i++, offset+=2){
+    var s = Math.max(-1, Math.min(1, input[i]));
+    output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
+  }
+}
+
+function writeString(view, offset, string){
+  for (var i = 0; i < string.length; i++){
+    view.setUint8(offset + i, string.charCodeAt(i));
+  }
+}
+
+function encodeWAV(samples){
+  var buffer = new ArrayBuffer(44 + samples.length * 2);
+  var view = new DataView(buffer);
+
+  /* RIFF identifier */
+  writeString(view, 0, 'RIFF');
+  /* RIFF chunk length */
+  view.setUint32(4, 36 + samples.length * 2, true);
+  /* RIFF type */
+  writeString(view, 8, 'WAVE');
+  /* format chunk identifier */
+  writeString(view, 12, 'fmt ');
+  /* format chunk length */
+  view.setUint32(16, 16, true);
+  /* sample format (raw) */
+  view.setUint16(20, 1, true);
+  /* channel count */
+  view.setUint16(22, 2, true);
+  /* sample rate */
+  view.setUint32(24, sampleRate, true);
+  /* byte rate (sample rate * block align) */
+  view.setUint32(28, sampleRate * 4, true);
+  /* block align (channel count * bytes per sample) */
+  view.setUint16(32, 4, true);
+  /* bits per sample */
+  view.setUint16(34, 16, true);
+  /* data chunk identifier */
+  writeString(view, 36, 'data');
+  /* data chunk length */
+  view.setUint32(40, samples.length * 2, true);
+
+  floatTo16BitPCM(view, 44, samples);
+
+  return view;
+}
index d6eccc587ae72ae220df20cbd7282694340fd135..97b2ca69dead5a1e966be6130649279d2f5d310e 100644 (file)
@@ -1,53 +1,59 @@
 ---
 layout: default
-title: Proyectos
+title: Proj
 description: "Lista de proyectos de Ben Beltran... cosas en las que estoy o estaba trabajando y he decidido compartir."
 ---
 
 <div class="content">
   <div class="related">
-    <h1>Proyectos / Projects</h1>
+    <h1>Proj</h1>
+    <p>These are some of the things I've done, worked on,
+    am working on, or plan to work on: <br/>
+    <em>Estas son algunas de las cosas que he hecho,
+      en que he trabajado, estoy trabajando, o en que planeo trabajar:</em></p>
+
     <ul>
       <li>
-        <strong><a
-            href="http://github.com/freshout-dev/thulium">Thulium</a>:</strong>
-        Un sistema de templates muy rápido para javascript, con soporte
-        de bloques rompibles imprimibles, una sintaxis sana y spec como
-        se debe.
-        • <em> A really fast templating engine for javascript with breakable
-        printable blocks, a sane syntax and a proper spec.</em>
+        <a href="https://github.com/benbeltran/serpentity" class="javascript">Serpentity</a> &mdash;
+        An entity framework for making games with javascript.
+        <em>Un framework de entidades para hacer juegos con javascript</em>
       </li>
       <li>
-        <strong><a
-            href="http://github.com/rbdr/cobalt">Cobalt</a>:</strong>
-        Un multiplexor sencillo de logs en formato JSON.
-        • <em> A really simple JSON format log multiplexer.</em>
+        <a href="https://github.com/benbeltran/lyricli" class="ruby">Lyricli</a> &mdash;
+        A command line tool to fetch lyrics for your current song or search by title.
+        <em>Herramienta de linea de comandos para ver la letra de la canción
+          que escuchas o buscar por título</em>
       </li>
       <li>
-        <strong><a
-            href="http://github.com/rbdr/lyricli">Lyricli</a>:</strong>
-        Muestra lyrics en tu línea de comando
-      • <em>Get lyrics right in your terminal</em> </li>
-      <li>
-      <strong><a href="/files/polarity.zip">Polarity</a>:</strong> Un juego
-          Arena Shooter con magnetismo! • <em> An Arena Shooter with
-            Magnetism! </em>
+        <a href="https://github.com/benbeltran/cobalt" class="javascript">Cobalt</a> &mdash;
+        A JSON based log multiplexer for javascript: send to a socket or to a
+        file or whatever I'm not your mom.
+        <em>Un multiplexor de logs basado en JSON para javascript: manda por
+          un socket, o un archivo o lo que quieras no soy tu mamá.</em>
       </li>
-      <li><strong>Polarity II (WIP): </strong>
-      Arena Shooter magnetico para Windows, Mac y Linux, hecho con
-      MonoGame•
-      <em> Next version of the magnetic arena shooter polarity, for
-        Windows, Mac and Linux; made with magnetism.</em>
+      <li>
+      <a href="https://github.com/freshout-dev/thulium" class="javascript">Thulium</a> &mdash;
+      A fast and simple EJS-like templating engine with support for printable blocks.
+      <em>Un sistema de templates parecido a EJS rápido y sencillo con soporte
+        de bloques imprimibles</em>
       </li>
       <li>
-        <strong><a
-            href="/cursoc">Curso Express de C</a>:</strong>
-        Curso Express de C basado en K&amp;R que impartí en el Tecnológico de Monterrey
-        Campus Ciudad Juárez. Solo vienen prácticas 01-07 por ahora.
-        Pronto subiré los otros.
-      • <em>Express C course based on K&amp;R that I gave in Monterrey
-        Institute of Technology, Campus Ciudad Juarez. Only Labs 01-07
-        for now, will upload the rest soon.</em> </li>
+        <a href="/files/polarity.zip" class="etc">Polarity</a> &mdash;
+        The first game I made, some years back. An arena shooter with magnnetism!
+        <em>El primer juego que hice, hace unos años. Un arena shooter con magnetismo!</em>
+      </li>
+    </ul>
+
+    <p>I'm also, sometimes (I swear) working on these
+    three game projects, and I sometimes post about them: <br/>
+    <em>También, a veces (lo juro) trabajo en estos tres proyectos,
+      y a veces escribo sobre ellos:</em>
+    </p>
+
+    <ul>
+      <li>Super Polarity (In Development/<em>En desarrollo</em>)</li>
+      <li>Cows (Designing/<em>Diseñando</em>)</li>
+      <li>Bctria (Designing/<em>Diseñando</em>)</li>
     </ul>
   </div>
 </div>
diff --git a/jekyll/reverb.aiff b/jekyll/reverb.aiff
new file mode 100644 (file)
index 0000000..54226d5
Binary files /dev/null and b/jekyll/reverb.aiff differ
diff --git a/jekyll/reverb.ogg b/jekyll/reverb.ogg
new file mode 100644 (file)
index 0000000..cb7db27
Binary files /dev/null and b/jekyll/reverb.ogg differ