-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
477 lines (477 loc) · 23.8 KB
/
Copy pathindex.html
File metadata and controls
477 lines (477 loc) · 23.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
<!DOCTYPE html>
<html lang="en">
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>pollard</title>
</head>
<body>
<script>
function FunctionalUtilities(){
this.pipe = (...operations)=>{
const _pipe = (a, b) => (arg) => b(a(arg));
return operations.reduce(_pipe)
}
this.Maybe = class Maybe{
constructor(value){
this._value = value
}
static of(value){
return new Maybe(value)
}
static nothing(){
return new Maybe(null)
}
static join(nestedMaybe){
return nestedMaybe.flatMap(x=>x)
}
isNothing(){
return this._value===null||this._value===undefined
}
map(fn){
return this.isNothing()?Maybe.nothing():Maybe.of(fn(this._value))
}
flatMap(fn){
if(this.isNothing()){
return Maybe.nothing()
} else {
let result = fn(this._value)
return result.isNothing()?Maybe.nothing():Maybe.of(result._value)
}
}
apply(maybeValue){
return this.isNothing()?Maybe.nothing():maybeValue.map(this._value)
}
getOrElse(valueIfNothing){
return this.isNothing()?valueIfNothing:this._value
}
toString(){
return `Maybe: ${this._value}`
}
}
}
function TextAnalysisModule(FunctionalUtilities){
this.tokenizeWords = (text)=>
FunctionalUtilities.pipe(
text => text.match(/\S+/g),
words => words?words.map((t)=>t.toLowerCase().replace(/[.,<>?\/#!@$%\^&\*;:{}\[\]=\-\+_`~()"“”]/g,"")):[]
)(text)
this.countTransitions = (tokens) => tokens.reduce((acc,token,index,tokens)=>{
const getPreviousToken = tokens=>tokens[index - 1]
const addToTransitionIfPresent = previousToken =>
acc[previousToken]
? { [previousToken]: acc[previousToken].concat([token]) }
: { [previousToken]: [token] }
const filterOutUndefinedTransitions = transition =>
transition[undefined]
? { [token]: [] }
: transition
const mergeWithPreviousTransitions = transition => { return { ...acc, ...transition } }
return FunctionalUtilities.pipe(
getPreviousToken,
addToTransitionIfPresent,
filterOutUndefinedTransitions,
mergeWithPreviousTransitions
)(tokens)
},{})
this.countSyllablesInWord = (word)=>{
return FunctionalUtilities.pipe(
word=>word.replace(/(?:[^laeiouy]es|e|[^laeiouy]e)$/, ''),
word=>word.replace(/^y/, ''),
word=>word.match(/[aeiouy]{1,2}/g),
syllables=>syllables?syllables.length:word.length
) (word)
}
this.countSyllablesForTokens = (tokens) =>
tokens.reduce((acc,token)=> {
let count = this.countSyllablesInWord(token)
if(acc[count]){
acc[count] = acc[count].concat([token])
} else {
acc[count] = [token]
}
return acc
},{})
}
function TextGenerationModule(TextAnalysis,FunctionalUtilities){
this.getRandomWordFromList = (listOfWords,randomGenerator=Math.random)=>{
const shuffle = ()=> {
for (i=listOfWords.length-1;i>0;i--){
let j = Math.floor(randomGenerator()*i)
let a = listOfWords[i]
let b = listOfWords[j]
listOfWords[i]=b
listOfWords[j]=a
}
}
for(i=0;i<Math.floor(1+randomGenerator()*3);i++){
shuffle()
}
return listOfWords[0]
}
this.generatePoemFromStructure = (structure, transitionTable, wordsBySyllable, wordTokens, randomGenerator=Math.random)=>
FunctionalUtilities.pipe(
structure=>structure.split("\n"),
linesInStructure=>linesInStructure.map((line)=>this.generateLineInStructure(line, transitionTable, wordsBySyllable, wordTokens, randomGenerator)),
linesInPoem=>linesInPoem.join("\n")
)(structure)
this.generateLineInStructure = (structureForLine, transitionTable, wordsBySyllable, wordTokens,randomGenerator=Math.random) => {
let wildcardGroups = structureForLine.match(/[.-]*/g)
let words = structureForLine.match(/[^.-]*/g)
let wordIterator = words[Symbol.iterator]();
let wildcardGroupIterator = wildcardGroups[Symbol.iterator]();
let generatedLine = []
let nextWord = wordIterator.next()
let nextWildcardGroup = wildcardGroupIterator.next()
while(!nextWord.done | !nextWildcardGroup.done) {
if(nextWord.value && nextWord.value.length!==0){
generatedLine.push(nextWord.value)
while(!nextWildcardGroup.done && nextWildcardGroup.value.length===0){
nextWildcardGroup = wildcardGroupIterator.next()
}
nextWord = wordIterator.next()
} else if (nextWildcardGroup.value && nextWildcardGroup.value.length!==0){
while(!nextWord.done && nextWord.value.length===0){
nextWord = wordIterator.next()
}
generatedLine = nextWildcardGroup.value?this.generatePhraseInGroup(nextWildcardGroup.value,transitionTable, wordsBySyllable, wordTokens,randomGenerator, generatedLine):generatedLine
nextWildcardGroup = wildcardGroupIterator.next()
} else {
break;
}
}
return generatedLine.join(" ")
}
this.generatePhraseInGroup = (structure, transitionTable, wordsBySyllable, wordTokens, randomGenerator=Math.random, wordsInGeneratedLine=[]) => {
let syllablesInLine = structure.length
const wordsInTable = Object.keys(transitionTable)
if (syllablesInLine>0) {
let nextWord
let possibleNextWords
if(wordsInGeneratedLine.length==0) {
wordsInGeneratedLine = []
possibleNextWords = filterOutWordsThatAreTooBig(wordsInTable, syllablesInLine, wordsBySyllable)
} else {
let previousWord = wordsInGeneratedLine[wordsInGeneratedLine.length-1]
possibleNextWords = transitionTable[previousWord]
possibleNextWords = possibleNextWords?filterOutWordsThatAreTooBig(possibleNextWords, syllablesInLine, wordsBySyllable):[]
if(possibleNextWords.length<1) {
possibleNextWords = filterOutWordsThatAreTooBig(wordsInTable, syllablesInLine, wordsBySyllable)
}
}
if (possibleNextWords.length===1) {
possibleNextWords.push(this.getRandomWordFromList(wordTokens,randomGenerator))
}
nextWord = this.getRandomWordFromList(filterOutWordsThatAreTooBig(possibleNextWords,syllablesInLine, wordsBySyllable),randomGenerator)
if(nextWord) {
wordsInGeneratedLine.push(nextWord)
let numberOfSyllablesInNextWord = TextAnalysis.countSyllablesInWord(nextWord)
let remainingStructure = structure.slice(numberOfSyllablesInNextWord)
return this.generatePhraseInGroup(remainingStructure, transitionTable, wordsBySyllable, wordTokens, randomGenerator, wordsInGeneratedLine)
} else {
return wordsInGeneratedLine.push(structure)
}
} else {
return wordsInGeneratedLine
}
}
function filterOutWordsThatAreTooBig(listOfWords, maxSyllables, tableOfSyllablesToWord) {
let acceptableWords = []
for (let step=1; step<=maxSyllables; step++) {
acceptableWords.push(tableOfSyllablesToWord[step])
}
acceptableWords = acceptableWords.flat()
return listOfWords.map((word)=>acceptableWords.includes(word)?word:[]).flat()
}
}
'use strict'
function Client() {
this.el = document.createElement('div')
this.el.id = 'pollard'
this.TextAnalysis = new TextAnalysisModule(new FunctionalUtilities)
this.TextGeneration = new TextGenerationModule(this.TextAnalysis,new FunctionalUtilities)
this.structure = new Structure(this)
this.corpus = new Corpus(this)
this.output = new Output(this)
this.menu = new Menu(this)
this.install = function (host = document.body) {
this._wrapper = document.createElement('div')
this._wrapper.id = 'wrapper'
this.structure.install(this._wrapper)
this.corpus.install(this._wrapper)
this.output.install(this._wrapper)
this.menu.install(this._wrapper)
this.el.appendChild(this._wrapper)
host.appendChild(this.el)
}
this.start = function() {
this.structure.start()
this.corpus.start()
this.output.start()
this.menu.start()
}
}
'use strict'
function Corpus (client) {
this.el = document.createElement('div')
this.el.id = 'corpus'
this._input = document.createElement('textarea')
this._input.setAttribute('wrap','hard')
this._input.id = "corpus-input"
this._label = document.createElement('label')
this._label.setAttribute('for','corpus-input')
this._label.innerText = "corpus"
this.wordTokens = []
this.transitionTable = {}
this.wordsBySyllable = {}
this.install = function (host) {
this.el.appendChild(this._input)
this.el.appendChild(this._label)
host.appendChild(this.el)
window.addEventListener('change', (e) => { this.onBlur() }, false)
}
this.start = function(){
this._input.value = this.splash
this.onBlur()
}
this.onBlur = ()=>{
this.wordTokens = client.TextAnalysis.tokenizeWords(this._input.value)
this.transitionTable = client.TextAnalysis.countTransitions(this.wordTokens)
this.wordsBySyllable = client.TextAnalysis.countSyllablesForTokens(this.wordTokens)
}
this.splash = ` You will rejoice to hear that no disaster has accompanied the commencement of an enterprise which you have regarded with such evil forebodings. I arrived here yesterday, and my first task is to assure my dear sister of my welfare and increasing confidence in the success of my undertaking.
I am already far north of London, and as I walk in the streets of Petersburgh, I feel a cold northern breeze play upon my cheeks, which braces my nerves and fills me with delight. Do you understand this feeling? This breeze, which has travelled from the regions towards which I am advancing, gives me a foretaste of those icy climes. Inspirited by this wind of promise, my daydreams become more fervent and vivid. I try in vain to be persuaded that the pole is the seat of frost and desolation; it ever presents itself to my imagination as the region of beauty and delight. There, Margaret, the sun is for ever visible, its broad disk just skirting the horizon and diffusing a perpetual splendour. There—for with your leave, my sister, I will put some trust in preceding navigators—there snow and frost are banished; and, sailing over a calm sea, we may be wafted to a land surpassing in wonders and in beauty every region hitherto discovered on the habitable globe. Its productions and features may be without example, as the phenomena of the heavenly bodies undoubtedly are in those undiscovered solitudes. What may not be expected in a country of eternal light? I may there discover the wondrous power which attracts the needle and may regulate a thousand celestial observations that require only this voyage to render their seeming eccentricities consistent for ever. I shall satiate my ardent curiosity with the sight of a part of the world never before visited, and may tread a land never before imprinted by the foot of man. These are my enticements, and they are sufficient to conquer all fear of danger or death and to induce me to commence this laborious voyage with the joy a child feels when he embarks in a little boat, with his holiday mates, on an expedition of discovery up his native river. But supposing all these conjectures to be false, you cannot contest the inestimable benefit which I shall confer on all mankind, to the last generation, by discovering a passage near the pole to those countries, to reach which at present so many months are requisite; or by ascertaining the secret of the magnet, which, if at all possible, can only be effected by an undertaking such as mine.
These reflections have dispelled the agitation with which I began my letter, and I feel my heart glow with an enthusiasm which elevates me to heaven, for nothing contributes so much to tranquillise the mind as a steady purpose—a point on which the soul may fix its intellectual eye. This expedition has been the favourite dream of my early years. I have read with ardour the accounts of the various voyages which have been made in the prospect of arriving at the North Pacific Ocean through the seas which surround the pole. You may remember that a history of all the voyages made for purposes of discovery composed the whole of our good Uncle Thomas’ library. My education was neglected, yet I was passionately fond of reading. These volumes were my study day and night, and my familiarity with them increased that regret which I had felt, as a child, on learning that my father’s dying injunction had forbidden my uncle to allow me to embark in a seafaring life.
These visions faded when I perused, for the first time, those poets whose effusions entranced my soul and lifted it to heaven. I also became a poet and for one year lived in a paradise of my own creation; I imagined that I also might obtain a niche in the temple where the names of Homer and Shakespeare are consecrated. You are well acquainted with my failure and how heavily I bore the disappointment. But just at that time I inherited the fortune of my cousin, and my thoughts were turned into the channel of their earlier bent.
Six years have passed since I resolved on my present undertaking. I can, even now, remember the hour from which I dedicated myself to this great enterprise. I commenced by inuring my body to hardship. I accompanied the whale-fishers on several expeditions to the North Sea; I voluntarily endured cold, famine, thirst, and want of sleep; I often worked harder than the common sailors during the day and devoted my nights to the study of mathematics, the theory of medicine, and those branches of physical science from which a naval adventurer might derive the greatest practical advantage. Twice I actually hired myself as an under-mate in a Greenland whaler, and acquitted myself to admiration. I must own I felt a little proud when my captain offered me the second dignity in the vessel and entreated me to remain with the greatest earnestness, so valuable did he consider my services.
And now, dear Margaret, do I not deserve to accomplish some great purpose? My life might have been passed in ease and luxury, but I preferred glory to every enticement that wealth placed in my path. Oh, that some encouraging voice would answer in the affirmative! My courage and my resolution is firm; but my hopes fluctuate, and my spirits are often depressed. I am about to proceed on a long and difficult voyage, the emergencies of which will demand all my fortitude: I am required not only to raise the spirits of others, but sometimes to sustain my own, when theirs are failing.
This is the most favourable period for travelling in Russia. They fly quickly over the snow in their sledges; the motion is pleasant, and, in my opinion, far more agreeable than that of an English stagecoach. The cold is not excessive, if you are wrapped in furs—a dress which I have already adopted, for there is a great difference between walking the deck and remaining seated motionless for hours, when no exercise prevents the blood from actually freezing in your veins. I have no ambition to lose my life on the post-road between St. Petersburgh and Archangel.
I shall depart for the latter town in a fortnight or three weeks; and my intention is to hire a ship there, which can easily be done by paying the insurance for the owner, and to engage as many sailors as I think necessary among those who are accustomed to the whale-fishing. I do not intend to sail until the month of June; and when shall I return? Ah, dear sister, how can I answer this question? If I succeed, many, many months, perhaps years, will pass before you and I may meet. If I fail, you will see me again soon, or never.
Farewell, my dear, excellent Margaret. Heaven shower down blessings on you, and save me, that I may again and again testify my gratitude for all your love and kindness.
Your affectionate brother,
R. Walton `
}
'use strict'
function Menu (client) {
const generatePoem = () => client.output.generatePoem(client.structure._input.value)
this.el = document.createElement('ul')
this.el.id = 'menu'
this.pollardItem = document.createElement('li')
this.pollardLink = document.createElement('a')
this.pollardItem.appendChild(this.pollardLink)
this.pollardLink.innerText = "pollard"
this.pollardItemMenu = document.createElement('ul')
this.pollardItem.appendChild(this.pollardItemMenu)
this.generate = document.createElement('li')
this.generate.innerHTML = 'generate <i>control+enter</i>'
this.pollardItemMenu.appendChild(this.generate)
this.el.appendChild(this.pollardItem)
this.install = function (host) {
host.appendChild(this.el)
}
this.start = function() {
this.bindEventListeners()
}
this.onKeyDown = (e) => {
if (event.ctrlKey && event.keyCode === 13) {
client.output.generatePoem(client.structure._input.value)
}
}
this.handleGestureStart = (e)=>{
this.touchStartEvent = e
}
this.handleGestureMove = (e)=>{
if(this.touchStartEvent&&this.touchStartEvent.targetTouches.length>1){
this.touchMoveEvent = e
}
}
this.handleGestureEnd = (e)=>{
if(this.touchStartEvent && this.touchMoveEvent && this.touchStartEvent.targetTouches && this.touchMoveEvent.targetTouches) {
const xi = this.touchStartEvent.targetTouches[0].clientX
const yi = this.touchStartEvent.targetTouches[0].clientY
const xf = this.touchMoveEvent.targetTouches[0].clientX
const yf = this.touchMoveEvent.targetTouches[0].clientY
const run = (xf - xi)
const rise = (yf - yi)
const slope = rise/run
if (run>0 && slope > -1 && slope < 1){
generatePoem()
}
}
this.touchStartEvent = null
this.touchMoveEvent = null
}
this.bindEventListeners = ()=> {
this.generate.addEventListener('click',generatePoem)
window.addEventListener('keydown', this.onKeyDown, false)
window.addEventListener('touchstart', this.handleGestureStart, true)
window.addEventListener('touchmove', this.handleGestureMove, true)
window.addEventListener('touchend', this.handleGestureEnd, true)
}
}
'use strict'
function Output (client) {
this.el = document.createElement('div')
this.el.id = 'output'
this._textarea = document.createElement('textarea')
this._textarea.setAttribute('wrap','hard')
this._textarea.id = "output-area"
this._label = document.createElement('label')
this._label.setAttribute('for',"output-area")
this._label.innerText = "output"
this.install = function (host) {
this.el.appendChild(this._textarea)
this.el.appendChild(this._label)
host.appendChild(this.el)
}
this.start = function(){}
this.generatePoem = (structure)=>{
let transisionTable = client.corpus.transitionTable
let wordsBySyllable = client.corpus.wordsBySyllable
let wordTokens = client.corpus.wordTokens
this._textarea.value = client.TextGeneration.generatePoemFromStructure(structure,transisionTable,wordsBySyllable,wordTokens)
}
}
'use strict'
function Structure (client) {
this.el = document.createElement('div')
this.el.id = 'structure'
this._input = document.createElement('textarea')
this._input.id = 'structure-input'
this._input.setAttribute('wrap','hard')
this._label = document.createElement('label')
this._label.setAttribute('for','structure-input')
this._label.innerText = "structure"
this.install = function (host) {
this.el.appendChild(this._input)
this.el.appendChild(this._label)
host.appendChild(this.el)
}
this.start = function(){
this._input.value = this.splash
setTimeout(() => { this.run() }, 1000)
}
this.run = function (){
client.output.generatePoem(this._input.value)
}
this.splash = '..-.-\n..-...-\n..---'
}
const client = new Client()
client.install(document.body)
window.addEventListener('load', () => {
client.start()
})
</script>
<style>
body {
background:#1F1F1F;
font-family: monospace, monospace;
}
#pollard { height: calc(100vh - 60px); width:calc(100vw - 60px); padding: 30px;}
#pollard #wrapper {
width: 100%;
height: 100%; position: relative;
}
@media all and (min-width: 770px) {
#pollard textarea {
font-size: xx-large;
}
#pollard #wrapper #structure {
position: relative;
overflow: hidden;
height: calc(100vh - 60px);
float: left;
width: 20%;
}
#pollard #wrapper #output {
position: relative;
overflow: hidden;
height: calc(100vh - 60px);
float: none;
width: 60%;
}
#pollard #wrapper #corpus {
position: relative;
overflow: hidden;
height: calc(100vh - 60px);
width: 100%;
float:right;
width: 20%;
}
#pollard #wrapper #output label {
left:4em;
}
#pollard #wrapper #output textarea {
padding-left: 15%;
padding-right: 15%;
}
}
@media all and (max-width: 768px) {
#pollard textarea {
font-size: large;
}
#pollard #wrapper #structure {
position: relative;
overflow: hidden;
height: 30%;
padding-bottom: 1em;
}
#pollard #wrapper #output {
position: relative;
overflow: hidden;
height:50%;
}
#pollard #wrapper #corpus {
position: absolute;
overflow: hidden;
bottom: 0;
height: 15%;
width: 100%;
}
}
/* #pollard label {
width: auto;
} */
#pollard textarea {
background: rgba(220, 220, 220, 0.253);
width:90%;
height: 100%;
padding-left: 2em;
padding-right: 2em;
padding-top: 2em;
box-sizing: border-box;
display: block;
margin-left: auto;
margin-right: auto;
border:none;
resize:none;
}
#pollard #wrapper label {
color: grey;
position: absolute;
top: 0.2em;
bottom: 0;
height: 2em;
left: 2em;
width: 100%;
transition: 0.2s;
}
#pollard #wrapper #output textarea {
width: 90%;
text-align: left;
color: lightpink;
}
#menu { position: fixed;width: 30px;background: red;top: 0;left: 0; width: 100vw; color:black; background:grey; font-size:11px; line-height: 20px; transition: margin-top 0.25s; z-index: 9999; padding-left: 25px; }
#menu.hidden { margin-top:-20px; }
#menu.hidden > li > ul > li { display: none }
#menu > li { float: left; position: relative; cursor: pointer; padding:0px 5px; display: inline-block; }
#menu > li:hover { background: black; color:white; }
#menu > li > ul { display: none; background:white; position: absolute; top:20px; left:0px; color:black; width: 200px; padding:0}
#menu > li:hover > ul { display: block; }
#menu > li > ul > li { padding: 0px 10px; display: block }
#menu > li > ul > li:hover { background: #ccc; }
#menu > li > ul > li > i { display: inline-block; float: right; color: #aaa; }
</style>
</body>
</html>