annotate src/site.js @ 46:cc20eebaa74a

use openai tts
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 14 Aug 2025 11:27:34 +0900
parents fef7a5c65cfb
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
1 'use strict';
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
2
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
3 function ajax(url,postData) {
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
4 let request = new XMLHttpRequest();
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
5 let method = postData ? "POST" : "GET";
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
6 request.open( method, url );
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
7 if( typeof(postData)==='string' )
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
8 request.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
9 request.onload = function() {
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
10 if( request.status !== 200 ) {
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
11 let err = 'sr_ajax failed: ' + request.status;
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
12 if( request.responseText ) {
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
13 err += '\n' + request.responseText;
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
14 document.write('<pre>'+request.responseText+'</pre>');
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
15 }
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
16 err += '\npage = ' + window.location;
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
17 ajax( '/error_log.js', 'err='+encodeURIComponent(err) );
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
18 return;
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
19 }
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
20 try {
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
21 //console.log(request.responseText);
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
22 eval( request.responseText );
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
23 } catch(e) {
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
24 window.sr_err = '\najax-url = ' + url;
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
25 //window.sr_err += '\n'+('ajax-response =\n' + request.responseText).trim();
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
26 throw e;
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
27 }
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
28 };
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
29 request.send(postData);
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
30 }
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
31
2
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
32 window.onerror = function(msg, url, line, col, error) {
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
33 if( !url )
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
34 return;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
35 let err = msg;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
36 err += '\nurl = ' + url;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
37 if( url != window.location )
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
38 err += '\npage = ' + window.location;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
39 err += '\nline = '+line;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
40 if( col )
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
41 err += '\ncolumn = ' + col;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
42 if( error ) {
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
43 if( error.stack )
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
44 err += '\nstack = ' + error.stack;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
45 if( error.cause )
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
46 err += '\ncause= ' + error.cause;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
47 if( error.fileName )
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
48 err += '\nfileName= ' + error.fileName;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
49 }
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
50 if( window.err ) {
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
51 err += window.err;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
52 window.err = null;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
53 }
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
54 ajax( '/error_log.js', 'err='+encodeURIComponent(err) );
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
55 };
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
56
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
57 function ajaxForm(url,form) {
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
58 let post = '';
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
59 for( let i=0; i<form.length; i++ ) {
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
60 let input = form[i];
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
61 let name = input.name;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
62 if( name === '' )
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
63 continue;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
64 let type = input.type;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
65 if( (type==='radio' || type==='checkbox') && !input.checked )
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
66 continue;
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
67 post += name + '=' + encodeURIComponent(input.value) + '&';
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
68 }
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
69 ajax(url,post,{form:form});
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
70 }
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
71
78708fa556a0 add login
Franklin Schmidt <fschmidt@gmail.com>
parents: 1
diff changeset
72
4
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
73 let currentPulldown = null;
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
74 let newPulldown = null;
1
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
75
4
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
76 function clickMenu(clicked,display) {
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
77 //console.log('clickMenu');
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
78 let pulldown = clicked.parentNode.querySelector('div');
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
79 if( pulldown !== currentPulldown ) {
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
80 pulldown.style.display = display || 'block';
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
81 newPulldown = pulldown;
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
82 window.onclick = function() {
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
83 //console.log('window.onclick');
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
84 if( currentPulldown ) {
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
85 currentPulldown.style.display = 'none';
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
86 if( !newPulldown )
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
87 window.onclick = null;
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
88 }
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
89 currentPulldown = newPulldown;
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
90 newPulldown = null;
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
91 };
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
92 pulldown.scrollIntoViewIfNeeded(false);
1
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
93 }
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
94 }
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
95
4
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
96 function getEnclosingDialog(el) {
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
97 while( el.nodeName !== 'DIALOG' )
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
98 el = el.parentNode;
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
99 return el;
1
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
100 }
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
101
4
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
102 function closeModal(el) {
b1adec083e44 chat work
Franklin Schmidt <fschmidt@gmail.com>
parents: 2
diff changeset
103 getEnclosingDialog(el).close();
1
1c87f785eb42 start chat
Franklin Schmidt <fschmidt@gmail.com>
parents:
diff changeset
104 }
8
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
105
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
106 let lastY = 0;
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
107
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
108 function scrollToTop() {
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
109 lastY = window.scrollY;
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
110 window.scrollTo( 0, 0 );
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
111 }
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
112
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
113 function scrollToBottom() {
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
114 lastY = window.scrollY;
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
115 window.scrollTo( 0, document.body.scrollHeight );
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
116 }
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
117
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
118 function scrollBack() {
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
119 window.scrollTo( 0, lastY );
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
120 }
2b7dcf355a78 better scrolling
Franklin Schmidt <fschmidt@gmail.com>
parents: 4
diff changeset
121
42
1d9d9786d76f textareas
Franklin Schmidt <fschmidt@gmail.com>
parents: 37
diff changeset
122 function fixTextarea(textarea) {
1d9d9786d76f textareas
Franklin Schmidt <fschmidt@gmail.com>
parents: 37
diff changeset
123 textarea.style.height = 'initial';
1d9d9786d76f textareas
Franklin Schmidt <fschmidt@gmail.com>
parents: 37
diff changeset
124 textarea.style.height = (textarea.scrollHeight+2) + 'px';
1d9d9786d76f textareas
Franklin Schmidt <fschmidt@gmail.com>
parents: 37
diff changeset
125 textarea.scrollIntoViewIfNeeded(false);
1d9d9786d76f textareas
Franklin Schmidt <fschmidt@gmail.com>
parents: 37
diff changeset
126 }
1d9d9786d76f textareas
Franklin Schmidt <fschmidt@gmail.com>
parents: 37
diff changeset
127
12
Franklin Schmidt <fschmidt@gmail.com>
parents: 9
diff changeset
128
9
Franklin Schmidt <fschmidt@gmail.com>
parents: 8
diff changeset
129 // requires markdown-it
12
Franklin Schmidt <fschmidt@gmail.com>
parents: 9
diff changeset
130
Franklin Schmidt <fschmidt@gmail.com>
parents: 9
diff changeset
131 let mdDiv = document.createElement('div');
Franklin Schmidt <fschmidt@gmail.com>
parents: 9
diff changeset
132
44
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
133 function toRuby(node) {
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
134 let type = node.nodeType;
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
135 if( type === Node.ELEMENT_NODE ) {
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
136 let name = node.tagName;
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
137 if( name === "PRE" || name === "CODE" )
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
138 return;
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
139 for( let child of node.childNodes ) {
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
140 toRuby(child);
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
141 }
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
142 } else if( type === Node.TEXT_NODE ) {
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
143 let text = node.nodeValue.replace(/\{([^{|}]+)\|([^{|}]+)\}/g, '<ruby>$1<rt>$2</rt></ruby>');
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
144 if( text !== node.nodeValue ) {
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
145 mdDiv.innerHTML = text;
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
146 while(mdDiv.firstChild) {
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
147 node.parentNode.insertBefore(mdDiv.firstChild, node);
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
148 }
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
149 node.remove();
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
150 }
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
151 }
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
152 }
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
153
46
cc20eebaa74a use openai tts
Franklin Schmidt <fschmidt@gmail.com>
parents: 45
diff changeset
154 function handleMarkdown(voice,instructions) {
44
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
155 let converter = window.markdownit();
9
Franklin Schmidt <fschmidt@gmail.com>
parents: 8
diff changeset
156 let divs = document.querySelectorAll('[markdown]');
Franklin Schmidt <fschmidt@gmail.com>
parents: 8
diff changeset
157 for( let div of divs ) {
44
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
158 div.innerHTML = converter.render(div.textContent);
007856fd62c0 ruby fix
Franklin Schmidt <fschmidt@gmail.com>
parents: 42
diff changeset
159 toRuby(div);
34
0fb3488a017d show_text
Franklin Schmidt <fschmidt@gmail.com>
parents: 31
diff changeset
160 div.removeAttribute('markdown');
0fb3488a017d show_text
Franklin Schmidt <fschmidt@gmail.com>
parents: 31
diff changeset
161 let parent = div.parentNode;
0fb3488a017d show_text
Franklin Schmidt <fschmidt@gmail.com>
parents: 31
diff changeset
162 if( parent.getAttribute('role')==='assistant' ) {
45
fef7a5c65cfb j1 work
Franklin Schmidt <fschmidt@gmail.com>
parents: 44
diff changeset
163 mdDiv.innerHTML = div.innerHTML;
12
Franklin Schmidt <fschmidt@gmail.com>
parents: 9
diff changeset
164 let rts = mdDiv.querySelectorAll('rt');
Franklin Schmidt <fschmidt@gmail.com>
parents: 9
diff changeset
165 for( let rt of rts ) {
Franklin Schmidt <fschmidt@gmail.com>
parents: 9
diff changeset
166 rt.remove();
Franklin Schmidt <fschmidt@gmail.com>
parents: 9
diff changeset
167 }
Franklin Schmidt <fschmidt@gmail.com>
parents: 9
diff changeset
168 //console.log(mdDiv.textContent);
46
cc20eebaa74a use openai tts
Franklin Schmidt <fschmidt@gmail.com>
parents: 45
diff changeset
169 parent.querySelector('audio').src = `/tts.mp3?voice=${voice}&instructions=${encodeURIComponent(instructions)}&text=${encodeURIComponent(mdDiv.textContent)}`;
12
Franklin Schmidt <fschmidt@gmail.com>
parents: 9
diff changeset
170 }
9
Franklin Schmidt <fschmidt@gmail.com>
parents: 8
diff changeset
171 }
Franklin Schmidt <fschmidt@gmail.com>
parents: 8
diff changeset
172 }