2011-07-08 19:33:49 -05:00
|
|
|
/**
|
|
|
|
A parallel word-frequency counting program.
|
|
|
|
|
|
|
|
This is meant primarily to demonstrate Rust's MapReduce framework.
|
|
|
|
|
|
|
|
It takes a list of files on the command line and outputs a list of
|
|
|
|
words along with how many times each word is used.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
use std;
|
|
|
|
|
2012-01-31 19:05:20 -06:00
|
|
|
import option = option;
|
2012-01-11 08:15:54 -06:00
|
|
|
import option::{some, none};
|
2012-03-12 22:04:27 -05:00
|
|
|
import std::{map, time};
|
2012-03-07 18:48:57 -06:00
|
|
|
import std::map::hashmap;
|
2012-01-11 08:15:54 -06:00
|
|
|
import io::reader_util;
|
|
|
|
|
2011-12-13 18:25:51 -06:00
|
|
|
import comm::chan;
|
|
|
|
import comm::port;
|
|
|
|
import comm::recv;
|
|
|
|
import comm::send;
|
2011-07-08 19:33:49 -05:00
|
|
|
|
2011-11-11 14:35:43 -06:00
|
|
|
fn map(input: str, emit: map_reduce::putter) {
|
2012-02-29 23:14:04 -06:00
|
|
|
let f = io::str_reader(input);
|
2011-07-12 13:13:15 -05:00
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
|
2012-03-09 18:11:56 -06:00
|
|
|
loop {
|
2012-01-19 00:37:22 -06:00
|
|
|
alt read_word(f) { some(w) { emit(w, 1); } none { break; } }
|
2011-07-12 13:13:15 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-15 02:48:39 -05:00
|
|
|
fn reduce(_word: str, get: map_reduce::getter) {
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut count = 0;
|
2011-07-12 13:13:15 -05:00
|
|
|
|
2012-03-09 18:11:56 -06:00
|
|
|
loop { alt get() { some(_) { count += 1; } none { break; } } }
|
2011-07-12 13:13:15 -05:00
|
|
|
}
|
|
|
|
|
2011-07-08 19:33:49 -05:00
|
|
|
mod map_reduce {
|
|
|
|
export putter;
|
|
|
|
export getter;
|
|
|
|
export mapper;
|
|
|
|
export reducer;
|
|
|
|
export map_reduce;
|
|
|
|
|
2011-10-18 17:07:40 -05:00
|
|
|
type putter = fn@(str, int);
|
2011-07-08 19:33:49 -05:00
|
|
|
|
2012-01-11 14:52:25 -06:00
|
|
|
type mapper = fn@(str, putter);
|
2011-07-08 19:33:49 -05:00
|
|
|
|
2011-10-18 17:07:40 -05:00
|
|
|
type getter = fn@() -> option<int>;
|
2011-07-13 17:44:09 -05:00
|
|
|
|
2012-01-11 14:52:25 -06:00
|
|
|
type reducer = fn@(str, getter);
|
2011-07-08 19:33:49 -05:00
|
|
|
|
2012-01-19 18:05:33 -06:00
|
|
|
enum ctrl_proto {
|
2012-01-19 20:31:08 -06:00
|
|
|
find_reducer(str, chan<chan<reduce_proto>>),
|
|
|
|
mapper_done,
|
2011-07-12 13:13:15 -05:00
|
|
|
}
|
|
|
|
|
2012-01-19 20:31:08 -06:00
|
|
|
enum reduce_proto { emit_val(int), done, ref, release, }
|
2011-07-12 13:13:15 -05:00
|
|
|
|
2011-11-11 14:35:43 -06:00
|
|
|
fn start_mappers(ctrl: chan<ctrl_proto>, -inputs: [str]) ->
|
2012-02-18 18:34:42 -06:00
|
|
|
[future::future<task::task_result>] {
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut results = [];
|
2012-04-06 13:01:43 -05:00
|
|
|
for inputs.each {|i|
|
2012-04-05 16:09:32 -05:00
|
|
|
let builder = task::builder();
|
2012-02-18 18:34:42 -06:00
|
|
|
results += [task::future_result(builder)];
|
|
|
|
task::run(builder) {|| map_task(ctrl, i)}
|
2011-07-12 13:13:15 -05:00
|
|
|
}
|
2012-02-18 18:34:42 -06:00
|
|
|
ret results;
|
2011-07-12 13:13:15 -05:00
|
|
|
}
|
|
|
|
|
2012-01-07 00:02:05 -06:00
|
|
|
fn map_task(ctrl: chan<ctrl_proto>, input: str) {
|
2011-12-22 19:53:53 -06:00
|
|
|
// log(error, "map_task " + input);
|
2012-03-14 14:07:23 -05:00
|
|
|
let intermediates = map::str_hash();
|
2011-07-08 19:33:49 -05:00
|
|
|
|
2011-09-12 04:27:30 -05:00
|
|
|
fn emit(im: map::hashmap<str, chan<reduce_proto>>,
|
|
|
|
ctrl: chan<ctrl_proto>, key: str, val: int) {
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut c;
|
2011-08-31 18:10:22 -05:00
|
|
|
alt im.find(key) {
|
2011-07-27 07:19:39 -05:00
|
|
|
some(_c) {
|
2011-09-15 02:48:39 -05:00
|
|
|
c = _c;
|
2011-07-27 07:19:39 -05:00
|
|
|
}
|
2012-01-19 00:37:22 -06:00
|
|
|
none {
|
2011-08-25 13:20:43 -05:00
|
|
|
let p = port();
|
2011-08-31 18:10:22 -05:00
|
|
|
send(ctrl, find_reducer(key, chan(p)));
|
2011-08-25 13:20:43 -05:00
|
|
|
c = recv(p);
|
2011-08-31 18:10:22 -05:00
|
|
|
im.insert(key, c);
|
2011-08-13 18:03:28 -05:00
|
|
|
send(c, ref);
|
2011-07-27 07:19:39 -05:00
|
|
|
}
|
2011-07-08 19:33:49 -05:00
|
|
|
}
|
2011-08-13 18:03:28 -05:00
|
|
|
send(c, emit_val(val));
|
2011-07-08 19:33:49 -05:00
|
|
|
}
|
|
|
|
|
2011-07-12 13:13:15 -05:00
|
|
|
map(input, bind emit(intermediates, ctrl, _, _));
|
2011-07-21 14:11:05 -05:00
|
|
|
|
2011-10-21 07:12:12 -05:00
|
|
|
intermediates.values {|v| send(v, release); }
|
2011-07-21 14:11:05 -05:00
|
|
|
|
2011-08-13 18:03:28 -05:00
|
|
|
send(ctrl, mapper_done);
|
2011-07-12 13:13:15 -05:00
|
|
|
}
|
2011-07-08 19:33:49 -05:00
|
|
|
|
2012-01-07 00:02:05 -06:00
|
|
|
fn reduce_task(key: str, out: chan<chan<reduce_proto>>) {
|
2011-08-25 13:20:43 -05:00
|
|
|
let p = port();
|
2011-07-12 13:13:15 -05:00
|
|
|
|
2011-08-25 13:20:43 -05:00
|
|
|
send(out, chan(p));
|
2011-07-12 13:13:15 -05:00
|
|
|
|
2012-03-26 20:35:18 -05:00
|
|
|
let state = @{mut ref_count: 0, mut is_done: false};
|
2011-07-12 13:13:15 -05:00
|
|
|
|
2012-03-26 20:35:18 -05:00
|
|
|
fn get(p: port<reduce_proto>, state: @{mut ref_count: int,
|
|
|
|
mut is_done: bool})
|
2011-12-07 08:28:57 -06:00
|
|
|
-> option<int> {
|
|
|
|
while !state.is_done || state.ref_count > 0 {
|
2011-08-25 13:20:43 -05:00
|
|
|
alt recv(p) {
|
2011-07-27 07:19:39 -05:00
|
|
|
emit_val(v) {
|
2011-12-22 16:42:52 -06:00
|
|
|
// #error("received %d", v);
|
2011-07-27 07:19:39 -05:00
|
|
|
ret some(v);
|
|
|
|
}
|
2012-01-19 00:37:22 -06:00
|
|
|
done {
|
2011-12-22 16:42:52 -06:00
|
|
|
// #error("all done");
|
2011-12-07 08:28:57 -06:00
|
|
|
state.is_done = true;
|
2011-07-27 07:19:39 -05:00
|
|
|
}
|
2012-01-19 03:03:57 -06:00
|
|
|
ref { state.ref_count += 1; }
|
|
|
|
release { state.ref_count -= 1; }
|
2011-07-21 14:11:05 -05:00
|
|
|
}
|
2011-07-08 19:33:49 -05:00
|
|
|
}
|
2011-07-21 14:11:05 -05:00
|
|
|
ret none;
|
2011-07-08 19:33:49 -05:00
|
|
|
}
|
|
|
|
|
2011-12-07 08:28:57 -06:00
|
|
|
reduce(key, bind get(p, state));
|
2011-07-08 19:33:49 -05:00
|
|
|
}
|
|
|
|
|
2011-11-11 14:35:43 -06:00
|
|
|
fn map_reduce(-inputs: [str]) {
|
2011-08-25 13:20:43 -05:00
|
|
|
let ctrl = port::<ctrl_proto>();
|
2011-07-08 19:33:49 -05:00
|
|
|
|
2011-08-13 18:03:28 -05:00
|
|
|
// This task becomes the master control task. It task::_spawns
|
2011-07-12 13:13:15 -05:00
|
|
|
// to do the rest.
|
2011-07-08 19:33:49 -05:00
|
|
|
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut reducers: map::hashmap<str, chan<reduce_proto>>;
|
2011-07-08 19:33:49 -05:00
|
|
|
|
2012-03-14 14:07:23 -05:00
|
|
|
reducers = map::str_hash();
|
2011-07-12 13:13:15 -05:00
|
|
|
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut num_mappers = vec::len(inputs) as int;
|
|
|
|
let mut results = start_mappers(chan(ctrl), inputs);
|
2011-07-12 13:13:15 -05:00
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
while num_mappers > 0 {
|
2011-08-25 13:20:43 -05:00
|
|
|
alt recv(ctrl) {
|
2012-01-19 00:37:22 -06:00
|
|
|
mapper_done {
|
2011-12-22 16:42:52 -06:00
|
|
|
// #error("received mapper terminated.");
|
2011-07-27 07:19:39 -05:00
|
|
|
num_mappers -= 1;
|
|
|
|
}
|
2011-08-31 18:10:22 -05:00
|
|
|
find_reducer(k, cc) {
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut c;
|
2011-12-22 19:53:53 -06:00
|
|
|
// log(error, "finding reducer for " + k);
|
2011-07-27 07:19:39 -05:00
|
|
|
alt reducers.find(k) {
|
|
|
|
some(_c) {
|
2011-12-22 19:53:53 -06:00
|
|
|
// log(error,
|
2011-12-22 16:42:52 -06:00
|
|
|
// "reusing existing reducer for " + k);
|
2011-07-27 07:19:39 -05:00
|
|
|
c = _c;
|
|
|
|
}
|
2012-01-19 00:37:22 -06:00
|
|
|
none {
|
2011-12-22 19:53:53 -06:00
|
|
|
// log(error, "creating new reducer for " + k);
|
2011-08-25 13:20:43 -05:00
|
|
|
let p = port();
|
2012-01-07 00:02:05 -06:00
|
|
|
let ch = chan(p);
|
2012-04-05 16:09:32 -05:00
|
|
|
let builder = task::builder();
|
2012-02-18 18:34:42 -06:00
|
|
|
results += [task::future_result(builder)];
|
|
|
|
task::run(builder) {||reduce_task(k, ch)}
|
2011-08-25 13:20:43 -05:00
|
|
|
c = recv(p);
|
2011-07-27 07:19:39 -05:00
|
|
|
reducers.insert(k, c);
|
|
|
|
}
|
2011-07-08 19:33:49 -05:00
|
|
|
}
|
2011-08-13 18:03:28 -05:00
|
|
|
send(cc, c);
|
2011-07-27 07:19:39 -05:00
|
|
|
}
|
2011-07-08 19:33:49 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-21 07:12:12 -05:00
|
|
|
reducers.values {|v| send(v, done); }
|
2011-07-21 14:11:05 -05:00
|
|
|
|
2012-04-06 13:01:43 -05:00
|
|
|
for results.each {|r| future::get(r); }
|
2011-07-12 13:13:15 -05:00
|
|
|
}
|
|
|
|
}
|
2011-07-08 19:33:49 -05:00
|
|
|
|
2011-09-02 17:34:58 -05:00
|
|
|
fn main(argv: [str]) {
|
2011-11-11 14:35:43 -06:00
|
|
|
let inputs = if vec::len(argv) < 2u {
|
|
|
|
[input1(), input2(), input3()]
|
|
|
|
} else {
|
2011-12-16 08:27:50 -06:00
|
|
|
vec::map(vec::slice(argv, 1u, vec::len(argv)),
|
|
|
|
{|f| result::get(io::read_whole_file_str(f)) })
|
2011-11-11 14:35:43 -06:00
|
|
|
};
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
let start = time::precise_time_ns();
|
2011-07-25 17:02:43 -05:00
|
|
|
|
2011-11-11 14:35:43 -06:00
|
|
|
map_reduce::map_reduce(inputs);
|
2011-07-27 07:19:39 -05:00
|
|
|
let stop = time::precise_time_ns();
|
2011-07-21 14:11:05 -05:00
|
|
|
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut elapsed = stop - start;
|
2011-07-21 14:11:05 -05:00
|
|
|
elapsed /= 1000000u64;
|
|
|
|
|
2011-12-22 19:53:53 -06:00
|
|
|
log(error, "MapReduce completed in "
|
2011-12-22 16:42:52 -06:00
|
|
|
+ u64::str(elapsed) + "ms");
|
2011-07-08 19:33:49 -05:00
|
|
|
}
|
|
|
|
|
2011-09-02 17:34:58 -05:00
|
|
|
fn read_word(r: io::reader) -> option<str> {
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut w = "";
|
2011-07-08 19:33:49 -05:00
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
while !r.eof() {
|
|
|
|
let c = r.read_char();
|
2011-07-08 19:33:49 -05:00
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
if is_word_char(c) {
|
2011-09-01 19:27:58 -05:00
|
|
|
w += str::from_char(c);
|
2011-09-02 17:34:58 -05:00
|
|
|
} else { if w != "" { ret some(w); } }
|
2011-07-08 19:33:49 -05:00
|
|
|
}
|
|
|
|
ret none;
|
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn is_digit(c: char) -> bool {
|
|
|
|
alt c {
|
|
|
|
'0' { true }
|
|
|
|
'1' { true }
|
|
|
|
'2' { true }
|
|
|
|
'3' { true }
|
|
|
|
'4' { true }
|
|
|
|
'5' { true }
|
|
|
|
'6' { true }
|
|
|
|
'7' { true }
|
|
|
|
'8' { true }
|
|
|
|
'9' { true }
|
|
|
|
_ { false }
|
2011-07-08 19:33:49 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn is_alpha_lower(c: char) -> bool {
|
|
|
|
alt c {
|
|
|
|
'a' { true }
|
|
|
|
'b' { true }
|
|
|
|
'c' { true }
|
|
|
|
'd' { true }
|
|
|
|
'e' { true }
|
|
|
|
'f' { true }
|
|
|
|
'g' { true }
|
|
|
|
'h' { true }
|
|
|
|
'i' { true }
|
|
|
|
'j' { true }
|
|
|
|
'k' { true }
|
|
|
|
'l' { true }
|
|
|
|
'm' { true }
|
|
|
|
'n' { true }
|
|
|
|
'o' { true }
|
|
|
|
'p' { true }
|
|
|
|
'q' { true }
|
|
|
|
'r' { true }
|
|
|
|
's' { true }
|
|
|
|
't' { true }
|
|
|
|
'u' { true }
|
|
|
|
'v' { true }
|
|
|
|
'w' { true }
|
|
|
|
'x' { true }
|
|
|
|
'y' { true }
|
|
|
|
'z' { true }
|
|
|
|
_ { false }
|
2011-07-08 19:33:49 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn is_alpha_upper(c: char) -> bool {
|
|
|
|
alt c {
|
|
|
|
'A' { true }
|
|
|
|
'B' { true }
|
|
|
|
'C' { true }
|
|
|
|
'D' { true }
|
|
|
|
'E' { true }
|
|
|
|
'F' { true }
|
|
|
|
'G' { true }
|
|
|
|
'H' { true }
|
|
|
|
'I' { true }
|
|
|
|
'J' { true }
|
|
|
|
'K' { true }
|
|
|
|
'L' { true }
|
|
|
|
'M' { true }
|
|
|
|
'N' { true }
|
|
|
|
'O' { true }
|
|
|
|
'P' { true }
|
|
|
|
'Q' { true }
|
|
|
|
'R' { true }
|
|
|
|
'S' { true }
|
|
|
|
'T' { true }
|
|
|
|
'U' { true }
|
|
|
|
'V' { true }
|
|
|
|
'W' { true }
|
|
|
|
'X' { true }
|
|
|
|
'Y' { true }
|
|
|
|
'Z' { true }
|
|
|
|
_ { false }
|
2011-07-08 19:33:49 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn is_alpha(c: char) -> bool { is_alpha_upper(c) || is_alpha_lower(c) }
|
2011-07-08 19:33:49 -05:00
|
|
|
|
2011-07-25 17:02:43 -05:00
|
|
|
fn is_word_char(c: char) -> bool { is_alpha(c) || is_digit(c) || c == '_' }
|
2011-11-11 14:35:43 -06:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn input1() -> str { " Lorem ipsum dolor sit amet, consectetur
|
|
|
|
adipiscing elit. Vestibulum tempor erat a dui commodo congue. Proin ac
|
|
|
|
imperdiet est. Nunc volutpat placerat justo, ac euismod nisl elementum
|
|
|
|
et. Nam a eros eleifend dolor porttitor auctor a a felis. Maecenas dui
|
|
|
|
odio, malesuada eget bibendum at, ultrices suscipit enim. Sed libero
|
|
|
|
dolor, sagittis eget mattis quis, imperdiet quis diam. Praesent eu
|
|
|
|
tristique nunc. Integer blandit commodo elementum. In eros lacus,
|
|
|
|
pretium vel fermentum vitae, euismod ut nulla.
|
|
|
|
|
|
|
|
Cras eget magna tempor mauris gravida laoreet. Suspendisse venenatis
|
|
|
|
volutpat molestie. Pellentesque suscipit nisl feugiat sem blandit
|
|
|
|
venenatis. Mauris id odio nec est elementum congue sed id
|
|
|
|
diam. Maecenas viverra, mi id aliquam commodo, ipsum dolor iaculis
|
|
|
|
odio, sed fringilla neque ipsum quis orci. Pellentesque dui dolor,
|
|
|
|
faucibus a rutrum sed, faucibus a mi. In eget sodales
|
|
|
|
ipsum. Pellentesque sollicitudin dapibus diam, ac interdum tellus
|
|
|
|
porta ac.
|
|
|
|
|
|
|
|
Donec ligula mi, sodales vel cursus a, dapibus ut sapien. In convallis
|
|
|
|
tempor libero, id dapibus mi sodales quis. Suspendisse
|
|
|
|
potenti. Vestibulum feugiat bibendum bibendum. Maecenas metus magna,
|
|
|
|
consequat in mollis at, malesuada id sem. Donec interdum viverra enim
|
|
|
|
nec ornare. Donec pellentesque neque magna.
|
|
|
|
|
|
|
|
Donec euismod, ante quis tempor pretium, leo lectus ornare arcu, sed
|
|
|
|
porttitor nisl ipsum elementum lectus. Nam rhoncus dictum sapien sed
|
|
|
|
tincidunt. Integer sit amet dui orci. Quisque lectus elit, dignissim
|
|
|
|
eget mattis nec, cursus nec erat. Fusce vitae metus nulla, et mattis
|
|
|
|
quam. Nullam sit amet diam augue. Nunc non ante eu enim lacinia
|
|
|
|
condimentum ac eget lectus.
|
|
|
|
|
|
|
|
Aliquam ut pulvinar tellus. Vestibulum ante ipsum primis in faucibus
|
|
|
|
orci luctus et ultrices posuere cubilia Curae; Pellentesque non urna
|
|
|
|
urna. Nulla facilisi. Aenean in felis quis massa aliquam eleifend non
|
|
|
|
sed libero. Proin sit amet iaculis urna. In hac habitasse platea
|
|
|
|
dictumst. Aenean scelerisque aliquet dolor, sit amet viverra est
|
|
|
|
laoreet nec. Curabitur non urna a augue rhoncus pulvinar. Integer
|
|
|
|
placerat vehicula nisl sed egestas. Morbi iaculis diam at erat
|
|
|
|
sollicitudin nec interdum libero tristique. " }
|
|
|
|
|
|
|
|
fn input2() -> str { " Lorem ipsum dolor sit amet, consectetur
|
|
|
|
adipiscing elit. Proin enim nibh, scelerisque faucibus accumsan id,
|
|
|
|
feugiat id ipsum. In luctus mauris a massa consequat dignissim. Donec
|
|
|
|
sit amet sem urna. Nullam pellentesque accumsan mi, at convallis arcu
|
|
|
|
pharetra in. Quisque euismod gravida nibh in rutrum. Phasellus laoreet
|
|
|
|
elit porta augue molestie nec imperdiet quam venenatis. Maecenas et
|
|
|
|
egestas arcu. Donec vulputate mauris enim. Aenean malesuada urna sed
|
|
|
|
dui eleifend quis posuere massa malesuada. Proin varius fringilla
|
|
|
|
feugiat. Donec mollis lorem sit amet ligula blandit quis fermentum dui
|
|
|
|
eleifend. Fusce molestie sodales magna in mattis. Aenean imperdiet,
|
|
|
|
elit sit amet accumsan vehicula, velit massa semper nibh, et varius
|
|
|
|
justo sem ut orci. Sed et magna lectus. Vestibulum vehicula, tellus
|
|
|
|
non dapibus mattis, libero ligula ullamcorper odio, in interdum odio
|
|
|
|
sem at mi.
|
|
|
|
|
|
|
|
Donec ut rhoncus mi. Donec ullamcorper, sem nec laoreet ullamcorper,
|
|
|
|
metus metus accumsan orci, ac luctus est velit a dolor. Donec eros
|
|
|
|
lectus, facilisis ut volutpat sit amet, pellentesque eu
|
|
|
|
velit. Praesent eget nibh et arcu vestibulum consequat. Pellentesque
|
|
|
|
habitant morbi tristique senectus et netus et malesuada fames ac
|
|
|
|
turpis egestas. Pellentesque lectus est, rhoncus ut cursus sit amet,
|
|
|
|
hendrerit quis dui. Maecenas vel purus in tellus luctus semper vel non
|
|
|
|
orci. Proin viverra, erat eget pretium ultrices, quam quam vulputate
|
|
|
|
tortor, eu dapibus risus nunc ac ipsum. Vestibulum ante ipsum primis
|
|
|
|
in faucibus orci luctus et ultrices posuere cubilia Curae; Ut aliquet
|
|
|
|
augue volutpat arcu mattis ullamcorper. Quisque vulputate consectetur
|
|
|
|
massa, quis cursus mauris lacinia vitae. Morbi id mi eu leo accumsan
|
|
|
|
aliquet ac et arcu. Quisque risus nisi, rhoncus vulputate egestas sed,
|
|
|
|
rhoncus quis risus. Sed semper odio sed nulla accumsan vitae auctor
|
|
|
|
tortor mattis.
|
|
|
|
|
|
|
|
Vivamus vitae mauris turpis. Praesent consectetur mi non sem lacinia a
|
|
|
|
cursus sapien gravida. Aenean viverra turpis sit amet ligula
|
|
|
|
vestibulum a ornare nunc feugiat. Mauris et risus arcu. Cras dictum
|
|
|
|
porta cursus. Donec tempus laoreet eros. Nam nec turpis non dui
|
|
|
|
hendrerit laoreet eu ut ipsum. Nam in sem eget turpis lacinia euismod
|
|
|
|
eu eget nulla.
|
|
|
|
|
|
|
|
Suspendisse at varius elit. Donec consectetur pharetra massa nec
|
|
|
|
viverra. Cras vehicula lorem id sapien hendrerit tristique. Mauris
|
|
|
|
vitae mi ipsum. Suspendisse feugiat commodo iaculis. Maecenas vitae
|
|
|
|
dignissim nunc. Sed hendrerit, arcu et aliquet suscipit, urna quam
|
|
|
|
fermentum eros, vel accumsan metus quam quis risus. Praesent id eros
|
|
|
|
pulvinar tellus fringilla cursus. Sed nec vulputate ipsum. Suspendisse
|
|
|
|
sagittis, magna vitae faucibus semper, nibh felis vehicula tortor, et
|
|
|
|
molestie velit lorem ac massa.
|
|
|
|
|
|
|
|
Duis aliquam accumsan lobortis. Morbi interdum cursus risus, vel
|
|
|
|
dapibus nisl fermentum sit amet. Etiam in mauris at lectus lacinia
|
|
|
|
mollis. Proin pretium sem nibh, id scelerisque arcu. Mauris pretium
|
|
|
|
adipiscing metus. Suspendisse quis convallis augue. Aliquam sed dui
|
|
|
|
augue, vel tempor ligula. Suspendisse luctus velit quis urna suscipit
|
|
|
|
sit amet ullamcorper nunc mollis. Praesent vitae velit justo. Donec
|
|
|
|
quis risus felis. Nullam rutrum, odio non varius ornare, tortor odio
|
|
|
|
posuere felis, eget accumsan sem sapien et nunc. Fusce mi neque,
|
|
|
|
elementum non convallis eu, hendrerit id arcu. Morbi tempus tincidunt
|
|
|
|
ullamcorper. Nullam blandit, diam quis sollicitudin tincidunt, elit
|
|
|
|
justo varius lacus, aliquet luctus neque nibh quis turpis. Etiam massa
|
|
|
|
sapien, tristique ut consectetur eu, elementum vel orci. " }
|
|
|
|
|
|
|
|
fn input3() -> str { " Lorem ipsum dolor sit amet, consectetur
|
|
|
|
adipiscing elit. Pellentesque bibendum sapien ut magna fringilla
|
|
|
|
mollis. Vivamus in neque non metus faucibus accumsan eu pretium
|
|
|
|
nunc. Ut erat augue, pulvinar eget blandit nec, cursus quis
|
|
|
|
ipsum. Aliquam eu ornare risus. Mauris ipsum tortor, posuere vel
|
|
|
|
gravida ut, tincidunt eu nunc. Aenean pellentesque, justo eu aliquam
|
|
|
|
condimentum, neque eros feugiat nibh, in dictum nisi augue euismod
|
|
|
|
lectus. Nam fringilla placerat metus aliquam rutrum. Nullam dapibus
|
|
|
|
vehicula ligula ut tempor. Aliquam vehicula, diam vitae fermentum
|
|
|
|
aliquam, justo augue venenatis enim, porta euismod dolor libero in
|
|
|
|
arcu. Sed sollicitudin dictum eros non ornare. Donec nec purus
|
|
|
|
orci. Mauris euismod fringilla consequat. Praesent non erat quis risus
|
|
|
|
dapibus semper ac adipiscing lorem. Aliquam pulvinar dapibus
|
|
|
|
mollis. Donec fermentum sollicitudin metus, sit amet condimentum leo
|
|
|
|
adipiscing a.
|
|
|
|
|
|
|
|
Vestibulum mi felis, commodo placerat rhoncus sed, feugiat tincidunt
|
|
|
|
orci. Integer faucibus ornare placerat. Nam et odio massa. Suspendisse
|
|
|
|
porttitor nunc quis mi mollis imperdiet. Ut ut neque ipsum, sit amet
|
|
|
|
facilisis erat. Nam ac lacinia turpis. Vivamus ullamcorper iaculis
|
|
|
|
odio, et euismod sem imperdiet non. Duis porta felis sit amet nunc
|
|
|
|
venenatis eu vestibulum nisi scelerisque. Nullam luctus mollis nunc
|
|
|
|
vel pulvinar. Nam lorem tellus, imperdiet sed sodales eu, auctor ut
|
|
|
|
nunc.
|
|
|
|
|
|
|
|
Nulla at mauris at leo sagittis varius eu a elit. Etiam consequat,
|
|
|
|
tellus ut sagittis porttitor, est justo convallis eros, quis suscipit
|
|
|
|
justo tortor vitae sem. In in odio augue. Pellentesque habitant morbi
|
|
|
|
tristique senectus et netus et malesuada fames ac turpis
|
|
|
|
egestas. Nulla varius ornare ligula quis euismod. Maecenas lobortis
|
|
|
|
sodales sapien a mattis. Nulla blandit lobortis lacus, ut lobortis
|
|
|
|
neque dictum ut. Praesent semper laoreet nisl. Etiam arcu eros,
|
|
|
|
pretium eget eleifend eu, condimentum quis leo. Donec imperdiet porta
|
|
|
|
erat. Aenean tempor sapien ut arcu porta mollis. Duis ultrices commodo
|
|
|
|
quam venenatis commodo.
|
|
|
|
|
|
|
|
Aliquam odio tellus, tincidunt nec condimentum pellentesque, semper
|
|
|
|
eget magna. Nam et lacus urna. Pellentesque urna nisi, pharetra vitae
|
|
|
|
dignissim non, scelerisque eu massa. Sed sapien neque, cursus a
|
|
|
|
malesuada ut, porta et quam. Donec odio sapien, blandit non aliquam
|
|
|
|
vel, lobortis quis ligula. Nullam fermentum velit nec quam ultrices et
|
|
|
|
venenatis sapien congue. Pellentesque vitae nunc arcu. Nullam eget
|
|
|
|
laoreet nulla. Curabitur dignissim convallis nunc sed blandit. Sed ac
|
|
|
|
ipsum mi. Ut euismod tellus hendrerit arcu egestas sollicitudin. Nam
|
|
|
|
eget laoreet ipsum. Morbi sed nulla odio, at volutpat ante. Vivamus
|
|
|
|
elementum dictum gravida.
|
|
|
|
|
|
|
|
Phasellus diam nisi, ullamcorper et placerat non, ultrices ut
|
|
|
|
lectus. Etiam tincidunt scelerisque imperdiet. Quisque pretium pretium
|
|
|
|
urna quis cursus. Sed sit amet velit sem. Maecenas eu orci et leo
|
|
|
|
ultricies dictum. Mauris pellentesque ante a purus gravida
|
|
|
|
convallis. Integer non tellus ante. Nulla hendrerit lobortis augue sit
|
|
|
|
amet vulputate. Donec cursus hendrerit diam convallis
|
|
|
|
luctus. Curabitur ipsum mauris, fermentum quis tincidunt ac, laoreet
|
|
|
|
sollicitudin sapien. Fusce velit urna, gravida non pulvinar eu, tempor
|
2012-02-29 23:14:04 -06:00
|
|
|
id nunc. " }
|