diff --git a/.eslintrc b/.eslintrc index 7471ba356..3563e60e0 100644 --- a/.eslintrc +++ b/.eslintrc @@ -202,7 +202,7 @@ "import/no-relative-packages": 2, // Prevent importing packages through relative paths () "import/no-deprecated": 1, // Report imported names marked with @deprecated documentation tag () - "import/no-extraneous-dependencies": 1, // Forbid the use of extraneous packages () + "import/no-extraneous-dependencies": [ "error", { "devDependencies": true } ], // Forbid the use of extraneous packages () "import/no-mutable-exports": 1, // Forbid the use of mutable exports with var or let. () "import/no-unused-modules": 1, // Report modules without exports, or exports without matching import in another module () diff --git a/bdd/data/sequences/data-gen/index.js b/bdd/data/sequences/data-gen/index.js new file mode 100644 index 000000000..9b515c029 --- /dev/null +++ b/bdd/data/sequences/data-gen/index.js @@ -0,0 +1,32 @@ +const { EventEmitter } = require("events"); + +/** + * Simple data generator with rate controls + * + * @param {never} _input input ignored + * @param {number} chunkSize size of a single chunk (3 megs by default) + * @param {number} chunkFrequency rate in Hz (1 Hz) + */ +module.exports = async function* (_input, chunkSize = 3 << 20, chunkFrequency = 1) { + const ee = new EventEmitter(); + let i = 0; + let end = false; + + setInterval(() => ee.emit("tick", i++), 1000 / chunkFrequency); + this.on("stop", () => { end = true; }); + + let n = 0; + + await new Promise(res => this.once("start", res)); + + while (!end) { + const chunkPayload = `${Date.now()}|${n++}`; + const chunk = `${chunkPayload}${" ".repeat(chunkSize - chunkPayload.length)}`; + + yield chunk; + + if (n >= i) { + await new Promise(res => ee.once("tick", res)); + } + } +}; diff --git a/bdd/data/sequences/data-gen/package.json b/bdd/data/sequences/data-gen/package.json new file mode 100644 index 000000000..c28b18da5 --- /dev/null +++ b/bdd/data/sequences/data-gen/package.json @@ -0,0 +1,22 @@ +{ + "name": "@scramjet/data-generator", + "version": "0.33.0", + "description": "", + "main": "index.js", + "scripts": { + "build:refapps": "node ../../../scripts/build-all.js --copy-dist", + "postbuild:refapps": "yarn packseq", + "packseq": "node ../../../scripts/packsequence.js", + "clean": "rm -rf ./dist .bic_cache" + }, + "author": "Scramjet ", + "license": "ISC", + "devDependencies": { + "@scramjet/types": "^0.33.0", + "@types/node": "15.12.5" + }, + "repository": { + "type": "git", + "url": "https://github.com/scramjetorg/transform-hub.git" + } +} diff --git a/bdd/data/sequences/persistentSeq/jest.config.js b/bdd/data/sequences/persistentSeq/jest.config.js new file mode 100644 index 000000000..35e4ea56d --- /dev/null +++ b/bdd/data/sequences/persistentSeq/jest.config.js @@ -0,0 +1,194 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/tmp/jest_rw", + + // Automatically clear mock calls, instances, contexts and results before every test + // clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + // collectCoverage: true, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + coverageDirectory: "coverage", + + // An array of regexp pattern strings used to skip coverage collection + coveragePathIgnorePatterns: [ + "/node_modules/", + "/dist/" + ], + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: "v8", + + // A list of reporter names that Jest uses when writing coverage reports + coverageReporters: [ + // "json", + "text", + // "lcov", + // "clover" + ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + errorOnDeprecated: true, + + // The default configuration for fake timers + // fakeTimers: { + // "enableGlobally": false + // }, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "mjs", + // "cjs", + // "jsx", + // "ts", + // "tsx", + // "json", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + preset: 'ts-jest', + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state before every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state and implementation before every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + testEnvironment: 'node', + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + testMatch: [ + "**/__tests__/**/*.[jt]s?(x)", + "**/test/**/*.[jt]s?(x)", + "**/?(*.)+(spec|test).[tj]s?(x)" + ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + testPathIgnorePatterns: [ + "/node_modules/", + "/dist/", + ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", + + // A map from regular expressions to paths to transformers + // transform: undefined, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\.pnp\\.[^\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; \ No newline at end of file diff --git a/bdd/data/sequences/persistentSeq/package.json b/bdd/data/sequences/persistentSeq/package.json new file mode 100644 index 000000000..e50607a22 --- /dev/null +++ b/bdd/data/sequences/persistentSeq/package.json @@ -0,0 +1,33 @@ +{ + "name": "persistentseq", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "predeploy": "tsc -p tsconfig.json && cp package.json dist/ && (cd dist && npm i --omit=dev)", + "test": "jest --verbose" + }, + "engines": { + "node": ">=16" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/scramjetorg/create-sequence.git" + }, + "bugs": { + "url": "https://github.com/scramjetorg/create-sequence/issues" + }, + "homepage": "https://github.com/scramjetorg/create-sequence#readme", + "devDependencies": { + "@scramjet/types": "^0.31.2", + "@types/jest": "^29.5.1", + "@types/node": "15.12.5", + "jest": "^29.5.0", + "scramjet": "^4.36.9", + "ts-jest": "^29.1.0", + "tsc": "^2.0.4", + "typescript": "^4.9.4" + }, + "author": "", + "license": "ISC" +} diff --git a/bdd/data/sequences/persistentSeq/src/backupingStream.ts b/bdd/data/sequences/persistentSeq/src/backupingStream.ts new file mode 100644 index 000000000..16f01b65b --- /dev/null +++ b/bdd/data/sequences/persistentSeq/src/backupingStream.ts @@ -0,0 +1,74 @@ +import { openSync, readSync, writeSync } from "fs"; +import { Duplex, DuplexOptions } from "stream"; + +type BackupingStreamOptions = Pick + +class BackupingStream extends Duplex { + writeFd: number; + readFd: number; + bytesWritten: number; + bytesRead: number; + readonly backupFile: string; + + constructor(backupFile: string, opts?: BackupingStreamOptions) { + super({ ...opts }); + this.backupFile = backupFile; + this.writeFd = openSync(this.backupFile, "w+"); + this.readFd = openSync(this.backupFile, "r"); + this.bytesWritten = 0; + this.bytesRead = 0; + } + + get bytesInBackup() { return this.bytesWritten - this.bytesRead; } + + _write(chunk: any, encoding: BufferEncoding, + callback: (error?: Error | null | undefined) => void): void { + if (this.bytesInBackup <= 0 && this.readableFlowing === true) { + this.push(chunk, encoding); + callback(); + this.resetBackupFile(); + return; + } + const bytesWritten = this.writeBackup(chunk, encoding); + + this.bytesWritten += bytesWritten; + callback(); + } + + _read(size: number): void { + if (this.bytesInBackup <= 0) return; + + this.pushFromBackupToInternalBuffer(size); + } + + resume(): this { + this.pushFromBackupToInternalBuffer(this.readableHighWaterMark); + return super.resume(); + } + + protected writeBackup(chunk: any, encoding: BufferEncoding) { + if (typeof chunk === "string") { + return writeSync(this.writeFd, chunk, this.bytesWritten, encoding); + } + return writeSync(this.writeFd, chunk, 0, undefined, this.bytesWritten); + } + + protected pushFromBackupToInternalBuffer(size: number) { + const sizeInBuffer = this.readableHighWaterMark - this.readableLength; + const readSize = Math.min(size, sizeInBuffer); + const buffer = Buffer.alloc(readSize); + const bytesRead = readSync(this.readFd, buffer, 0, readSize, this.bytesRead); + + this.bytesRead += bytesRead; + this.push(buffer.subarray(0, bytesRead)); + } + + protected resetBackupFile() { + if (this.bytesWritten <= 0 || this.bytesWritten !== this.bytesRead) return; + this.bytesWritten = 0; + this.bytesRead = 0; + this.writeFd = openSync(this.backupFile, "w+"); + } +} + +export default BackupingStream; diff --git a/bdd/data/sequences/persistentSeq/src/index.ts b/bdd/data/sequences/persistentSeq/src/index.ts new file mode 100644 index 000000000..eb0d2f809 --- /dev/null +++ b/bdd/data/sequences/persistentSeq/src/index.ts @@ -0,0 +1,16 @@ +import { TransformApp } from "@scramjet/types"; +import { PassThrough } from "stream"; +import BackupingStream from "./backupingStream"; +import { resolve } from "path"; + +const mod: TransformApp = async (input) => { + const backupFile = resolve(process.cwd(), "./backupingFile"); + const backupingStream = new BackupingStream(backupFile); + const output = new PassThrough(); + + input.pipe(backupingStream).pipe(output); + + return output; +}; + +export default mod; diff --git a/bdd/data/sequences/persistentSeq/test/backupingStream.spec.ts b/bdd/data/sequences/persistentSeq/test/backupingStream.spec.ts new file mode 100644 index 000000000..a20257f74 --- /dev/null +++ b/bdd/data/sequences/persistentSeq/test/backupingStream.spec.ts @@ -0,0 +1,184 @@ +import BackupingStream from "../src/backupingStream"; +import { createReadStream, createWriteStream } from "fs"; +import { FileHandle, mkdir, open } from "fs/promises"; +import { resolve } from "path"; +import { PassThrough } from "stream"; +import { createInterface } from "readline"; +import { EOL } from "os"; + +const testText = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis eget nisl viverra, efficitur eros quis, sodales eros. Suspendisse feugiat ac ipsum non aliquam. Quisque dapibus nisi libero. Fusce euismod lacus vitae eros suscipit semper in non dui. Sed quis porttitor elit. Nulla a sapien mi. Suspendisse tempus vitae lectus a lobortis. Phasellus et gravida purus, et porta mauris. Integer urna nulla, semper nec leo id, ultrices bibendum odio. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean eu iaculis dui. Ut ac dolor aliquet, placerat sapien vitae, hendrerit purus. + +Proin porta cursus erat, ut dignissim felis. Suspendisse potenti. Duis et aliquet odio. Aliquam congue blandit dolor non dapibus. Vivamus eros dolor, vulputate vitae arcu vel, pretium porttitor lorem. Vivamus eget quam quis arcu lacinia malesuada id a sem. Maecenas in ligula orci. Sed dapibus, urna vel malesuada dictum, lectus ex convallis ante, eget tempor lorem ante ac lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse enim ante, laoreet at urna vel, malesuada vestibulum nulla. Morbi orci metus, imperdiet in mattis a, tincidunt vitae tortor. Vivamus at consectetur mauris. + +In eu nulla luctus, lacinia nulla sit amet, condimentum leo. Vivamus lectus ex, venenatis in nulla eu, congue rutrum sapien. Cras suscipit sed elit non blandit. Nullam volutpat facilisis elit at laoreet. Aliquam mattis quis sem eget rutrum. Duis sapien dui, tincidunt nec ipsum id, rutrum pulvinar purus. Maecenas ut euismod purus, vel porta lacus. Vestibulum sit amet nulla sit amet diam rhoncus pharetra nec at purus. Donec mattis diam sit amet nisi tincidunt accumsan. Donec a nunc sed tortor dictum finibus. In ultricies lectus non urna convallis mollis. Pellentesque aliquam metus ante, laoreet porttitor mauris sodales et. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam quis laoreet nisl. Praesent pulvinar, orci sit amet finibus semper, nibh risus laoreet augue, at blandit tellus nulla ut odio. + +Vestibulum bibendum est a massa porta, vitae tempus enim malesuada. Pellentesque fringilla leo non vehicula pretium. Ut maximus ipsum at diam egestas, sit amet volutpat erat iaculis. Fusce dictum ipsum quam, sit amet hendrerit elit gravida a. Nam efficitur leo in mollis eleifend. Cras quis lorem pretium, condimentum libero sed, lacinia neque. Vestibulum tincidunt quam ut congue consectetur. Nullam congue varius bibendum. Maecenas consequat arcu quis magna rhoncus posuere. Cras vitae lectus ut lectus pharetra pulvinar varius vel justo. + +Ut congue purus ac lorem scelerisque, id congue eros venenatis. Sed rutrum vitae odio vel malesuada. Aliquam vel nibh at ipsum sodales ultricies. Quisque facilisis neque sem, id accumsan leo gravida vel. Vestibulum eros libero, tempus ac arcu vel, tincidunt pulvinar magna. Aliquam dictum ornare magna sed iaculis. Integer vulputate metus at iaculis eleifend. Aenean vestibulum ut sapien id malesuada. Sed eu faucibus lectus, vitae gravida metus. Mauris et iaculis felis, vitae egestas metus. Integer semper, erat in gravida vehicula, justo neque suscipit est, porta dapibus est magna ac metus.`; + +let backupDir: string; +let backupFile: string; +let testFilePath: string; + +beforeAll(async () => { + backupDir = resolve(process.cwd(), "./dist/test/"); + backupFile = resolve(backupDir, "./tmp1"); + await mkdir(backupDir, { recursive: true }); + + testFilePath = resolve(process.cwd(), "./test/testFile.txt"); +}); + +test("Basic read/write", async () => { + const backupingStream = new BackupingStream(backupFile, { encoding: "ascii" }); + + const readingFinished = new Promise(res => { backupingStream.on("readable", () => { res(backupingStream.read()); }); }); + + backupingStream.write(testText); + const result = await readingFinished; + + expect(result).toBe(testText); +}); + +test("Simple piped read/write", async () => { + const provider = new PassThrough({ encoding: "ascii" }); + const consumer = new PassThrough({ encoding: "ascii" }); + const backupingStream = new BackupingStream(backupFile, { encoding: "ascii" }); + + provider.pipe(backupingStream).pipe(consumer); + + const readPromise = new Promise(res => consumer.on("readable", () => { + res(consumer.read()); + })); + + provider.write(testText); + const consumerRead = await readPromise; + + expect(consumerRead).toBe(testText); +}); + +test("Write to backup", async () => { + const backupingStream = new BackupingStream(backupFile, { highWaterMark: 0 }); + + const source = createReadStream(testFilePath); + const readLine = createInterface({ input: source }); + + let lastLineWritten = new Promise(res => { res(); }); + + const inputFinished = new Promise((res) => { + readLine + .on("close", res) + .on("line", (input: string) => { + lastLineWritten = new Promise(wrtieRes => { + backupingStream.write(input); + backupingStream.write(EOL, undefined, () => wrtieRes()); + }); + }); + }); + + await inputFinished; + await lastLineWritten; + + const [inputFile, backupingFile] = await Promise.all([open(testFilePath, "r"), open(backupingStream.backupFile, "r")]); + const [inputBuff, outputBuff] = await Promise.all([inputFile.readFile(), backupingFile.readFile()]); + + const equals = inputBuff.equals(outputBuff); + + await Promise.all([inputFile.close(), backupingFile.close()]); + expect(equals).toBeTruthy(); +}); + +const waitForFileToReachSize = async (file: FileHandle, size: number, timeLimit = 200) => { + + let timeoutOccured = false; + const timeout = setTimeout(() => { timeoutOccured = true; }, timeLimit); + + while (!timeoutOccured) { + const stats = await file.stat(); + + if (stats.size === size) break; + } + clearTimeout(timeout); + return timeoutOccured; +}; + +test("Pipe to consumer from backup", async () => { + const backupingStream = new BackupingStream(backupFile); + + const source = createReadStream(testFilePath); + const readLine = createInterface({ input: source }); + + let lastLineWritten = new Promise(res => { res(); }); + + const inputFinished = new Promise((res) => { + readLine + .on("close", res) + .on("line", (input: string) => { + lastLineWritten = new Promise(wrtieRes => { + backupingStream.write(input); + backupingStream.write(EOL, undefined, () => wrtieRes()); + }); + }); + }); + + await inputFinished; + await lastLineWritten; + + const outputFilePath = resolve(backupDir, "./testBackupingStream_output.txt"); + const outputFile = await open(outputFilePath, "w+"); + const consumer = createWriteStream(outputFilePath, { flags: "w+" }); + + backupingStream.pipe(consumer); + + const [inputFile, resultFile] = await Promise.all([open(testFilePath, "r"), open(outputFilePath, "r")]); + + const inputFileStat = await inputFile.stat(); + + await waitForFileToReachSize(outputFile, inputFileStat.size); + + const [inputBuff, resultBuff] = await Promise.all([inputFile.readFile(), resultFile.readFile()]); + + const equals = inputBuff.equals(resultBuff); + + await Promise.all([inputFile.close(), outputFile.close(), resultFile.close()]); + expect(equals).toBeTruthy(); +}); + +test("Multiple disconnections of consumer", async () => { + const outputPath = resolve(backupDir, "./testBackupingStream_long_output.txt"); + const [source, output] = await Promise.all([open(testFilePath, "r"), open(outputPath, "w+")]); + const sourceSize = (await source.stat()).size; + + const provider = createReadStream(testFilePath, { highWaterMark: 100 }); + const backupingStream = new BackupingStream(backupFile, { writableHighWaterMark: 100, readableHighWaterMark: 200 }); + const consumer = createWriteStream(outputPath, { flags: "w+" }); + + const providerEnd = new Promise(res => { provider.on("end", res); }); + + let readLen = 0; + let piped = true; + let switchLenght = sourceSize / 5; + + provider.on("data", async (chunk) => { + readLen += chunk.length; + if (readLen > switchLenght) { + // eslint-disable-next-line no-unused-expressions + piped ? backupingStream.unpipe() : backupingStream.pipe(consumer); + piped = !piped; + switchLenght += sourceSize / 5; + } + }).pipe(backupingStream).pipe(consumer); + + await providerEnd; + const timeout = await waitForFileToReachSize(output, sourceSize, 200); + + expect(timeout).toBeFalsy(); + + const [sourceBuff, outputBuff] = await Promise.all([source.readFile(), output.readFile()]); + + expect(sourceBuff.length).toEqual(outputBuff.length); + const equals = sourceBuff.equals(outputBuff); + + expect(equals).toBeTruthy(); + + await Promise.all([source.close(), output.close()]); +}); diff --git a/bdd/data/sequences/persistentSeq/test/testFile.txt b/bdd/data/sequences/persistentSeq/test/testFile.txt new file mode 100644 index 000000000..1576c6cdb --- /dev/null +++ b/bdd/data/sequences/persistentSeq/test/testFile.txt @@ -0,0 +1,335 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla quis massa velit. Nam quis luctus purus, in iaculis ligula. In eu iaculis arcu, in commodo urna. Sed ut libero vitae nunc luctus tristique. Cras mollis malesuada ornare. Aliquam a sem ut ex facilisis sollicitudin. Nulla facilisi. Quisque ut varius ligula. Sed porttitor ex a porttitor feugiat. Morbi a tortor tempus diam dignissim blandit. Etiam nec rutrum tortor. Phasellus orci elit, cursus id molestie in, ultrices at ante. + +Nulla malesuada tincidunt elit, a gravida dolor placerat vel. Curabitur molestie sed enim eu egestas. Curabitur maximus malesuada vehicula. Suspendisse vitae gravida est. Sed pharetra fringilla lacus, sit amet convallis turpis tincidunt at. Quisque euismod rhoncus pulvinar. Donec sed ante in felis auctor posuere. + +Quisque nisi velit, ornare eget dictum vel, aliquam in nisl. Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse et nulla ligula. Nam ac ligula vitae tortor consequat fringilla. Donec dignissim gravida magna eu aliquet. Nullam dolor velit, sodales vitae turpis ac, molestie congue dui. Aliquam eros nisl, dignissim non lectus a, volutpat convallis odio. Nunc eu nisl sodales, porttitor turpis sed, euismod justo. + +Etiam sit amet lacus molestie, tristique sem sed, mattis est. Sed rutrum ornare massa, nec auctor metus. Cras at tempor arcu. Nunc velit mauris, pretium ut pellentesque non, fringilla nec elit. Ut tempus laoreet pretium. Phasellus placerat diam tincidunt volutpat cursus. Integer tempor massa purus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; + +Maecenas ac blandit lectus. Praesent ut tincidunt ligula. Sed massa urna, luctus ac auctor eget, scelerisque ut nisi. Nulla ipsum lacus, faucibus non elementum vitae, ornare ac libero. Ut quis semper nunc, non luctus sapien. Suspendisse consectetur pulvinar consequat. Nulla consectetur sagittis nunc at sagittis. Aliquam euismod, velit nec tempus porta, odio tortor iaculis libero, eget vulputate ipsum ante ut sapien. Donec sed velit pharetra, accumsan enim quis, ultricies mauris. Vestibulum aliquet fringilla dictum. Suspendisse sed nibh orci. + +Fusce posuere non dolor mollis laoreet. Maecenas aliquet arcu nec odio interdum, vitae interdum quam malesuada. Maecenas tincidunt finibus nisl, at sagittis est fermentum feugiat. Morbi at varius magna. In pulvinar ut leo id hendrerit. Vivamus et luctus odio. Phasellus ultricies bibendum sapien eget laoreet. Aliquam arcu felis, condimentum et metus a, tincidunt volutpat nulla. + +Fusce non ultrices lectus, vel fermentum ipsum. Curabitur dictum dolor a enim cursus maximus. Maecenas nisl erat, mattis commodo mi et, hendrerit vehicula nibh. In lacinia, tellus in gravida bibendum, risus massa iaculis erat, in venenatis diam justo a libero. Suspendisse est nisi, accumsan a aliquam nec, gravida at velit. Pellentesque viverra posuere justo ac ornare. Nulla turpis tellus, lacinia in felis ac, molestie molestie nisl. Nam felis enim, feugiat in eros et, sollicitudin luctus justo. Nullam lobortis eros ut ultrices facilisis. Cras vitae imperdiet nisl, a ullamcorper elit. Nam non orci vitae orci aliquet faucibus. Donec lobortis iaculis turpis, in semper orci tristique ac. Nulla maximus fringilla lectus, at tristique purus imperdiet nec. Donec viverra risus eu vulputate laoreet. Mauris vel congue odio. + +Aenean libero nisi, facilisis laoreet congue eget, rutrum a quam. Ut id molestie velit, sit amet rhoncus sapien. In sit amet ligula ut purus blandit fringilla eu ut tortor. Donec mattis rutrum metus, sit amet feugiat tortor. Nunc dictum vitae elit vel lobortis. Phasellus vel ante blandit, aliquam neque a, sollicitudin turpis. Phasellus tempor nisi eu eros imperdiet accumsan. Donec scelerisque nibh mauris, vel eleifend justo condimentum et. Pellentesque sit amet faucibus libero. Nulla et libero gravida, vestibulum elit at, vestibulum enim. Sed varius, odio sit amet interdum ultrices, lorem enim laoreet urna, a malesuada magna ex at elit. Fusce a faucibus elit. Etiam sagittis tincidunt diam eu malesuada. In varius diam id nisl auctor condimentum. + +Sed consectetur sagittis odio vel bibendum. Sed blandit tincidunt erat non suscipit. Nullam efficitur tincidunt tellus scelerisque gravida. Donec a dictum magna. Aenean in justo sodales, tempor est at, lacinia nulla. Etiam accumsan nec nunc vel tempus. Nam imperdiet ultrices enim, ac tempus sem. Nulla dapibus semper lobortis. Sed luctus lacinia euismod. Quisque luctus orci risus, quis sollicitudin orci malesuada ac. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In iaculis finibus justo dapibus pharetra. Integer at euismod mi, vitae eleifend urna. + +Nulla facilisis purus nulla, non congue nulla euismod quis. Fusce vitae tellus et sem venenatis iaculis a vitae ex. Aliquam sollicitudin condimentum metus. Aenean consectetur iaculis ligula nec maximus. Mauris ex ipsum, dignissim sed rutrum in, commodo sed libero. Suspendisse fermentum massa sed nunc tempus auctor. Pellentesque imperdiet neque sapien, suscipit luctus enim scelerisque in. Aliquam erat volutpat. Curabitur ac arcu placerat, vehicula neque vel, vestibulum dolor. Vivamus sed vehicula erat. Vivamus pellentesque non tellus in consequat. Etiam commodo, tellus eu vehicula pretium, odio ex ornare leo, et euismod orci velit et augue. Aliquam faucibus risus quis sapien fermentum, eget consectetur lorem lacinia. Nam ac gravida est. In hac habitasse platea dictumst. Mauris varius suscipit turpis ac cursus. + +Morbi et varius metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In congue ipsum neque, ut euismod sapien dignissim a. Maecenas faucibus orci ac viverra vulputate. Ut pellentesque leo at ante gravida, sit amet fermentum ipsum fringilla. Maecenas in interdum risus, non vehicula dolor. Quisque non eros arcu. + +Aliquam ligula tellus, dapibus ac rutrum non, gravida eget arcu. Vestibulum turpis turpis, pellentesque vel sollicitudin sit amet, molestie ac justo. Cras sit amet augue erat. Nullam pellentesque elementum mattis. In hac habitasse platea dictumst. Nulla ac eros ut eros porta sodales. Phasellus tincidunt, felis non mollis suscipit, sem mauris tempus ligula, et posuere mi nulla aliquet eros. Phasellus porttitor pretium tortor et porttitor. Donec vel libero scelerisque urna scelerisque tempus in a purus. Phasellus commodo commodo tristique. Curabitur egestas porttitor odio, et viverra enim. Aliquam semper quis nisl ac tristique. + +Fusce sed tincidunt augue. Etiam fringilla posuere finibus. Aliquam fringilla mollis purus vel hendrerit. In a varius lorem. In aliquet in tortor at convallis. In mattis tempus facilisis. Phasellus pretium nisl vel purus gravida, commodo imperdiet odio pharetra. Duis viverra porta magna nec viverra. Suspendisse at metus metus. + +Mauris congue ullamcorper tortor, id tempus tortor luctus blandit. Sed quis volutpat erat, id elementum lacus. Fusce euismod lacus in euismod egestas. Cras eu diam faucibus, facilisis magna quis, semper magna. Sed fermentum purus eget ex egestas, vel euismod dolor elementum. Nullam faucibus dignissim consectetur. Fusce ut magna risus. Etiam sapien est, elementum quis sapien et, ullamcorper vulputate arcu. Sed in nisl nec leo lacinia feugiat ac in mauris. Morbi dapibus augue metus, id fringilla metus accumsan non. Donec eleifend lacus sit amet venenatis ultricies. Etiam a aliquet tellus. Vivamus nec pellentesque arcu. + +Integer nec nulla sit amet sapien iaculis vestibulum. Aenean a urna aliquam, dignissim dolor eget, vestibulum orci. Nullam tristique leo nulla, et placerat quam gravida semper. Nunc dignissim nisl non augue pellentesque, non interdum sem volutpat. Sed lobortis, sem non pharetra consectetur, ante tortor porta justo, sit amet efficitur tortor ligula id neque. Donec a feugiat quam. Sed vel viverra augue. In interdum mattis tellus, quis sodales ex auctor eget. Curabitur tellus est, mattis eu fermentum sit amet, tincidunt ut nisi. Maecenas auctor lacinia leo at tempor. Integer sed dui et metus ullamcorper pretium. Proin mollis enim ac ex dapibus, vel rhoncus diam euismod. Mauris porttitor lacus ligula, non tristique magna porttitor et. Vestibulum volutpat aliquet enim sit amet mattis. + +In rutrum lobortis efficitur. Sed eget velit augue. Nunc sodales tortor ut sodales finibus. Integer mollis imperdiet lacus at ornare. Donec volutpat et dui mattis vulputate. Aenean sollicitudin turpis viverra pretium dictum. Sed vel gravida nunc. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae faucibus odio. Quisque viverra leo elit, a scelerisque velit efficitur non. Maecenas interdum, justo sed placerat vehicula, justo massa laoreet quam, porttitor vestibulum justo ante vitae est. Sed vitae metus non felis aliquet pharetra. In eleifend est sit amet turpis vehicula sodales. Sed posuere rhoncus sem, pellentesque dignissim eros vehicula id. Quisque vel elit metus. Cras vehicula dictum elit, semper viverra dolor blandit id. + +Phasellus egestas, urna nec congue posuere, purus lacus sagittis ex, eu iaculis sapien quam ut nulla. Nunc bibendum pulvinar nunc vel tempor. Nam varius luctus mollis. Nam lectus nibh, ullamcorper vel orci id, vulputate ornare augue. Aenean gravida nisi vel orci blandit, vitae fringilla sem dapibus. Nullam lobortis odio nec turpis luctus, sed suscipit neque vulputate. Mauris sed mauris dapibus lorem cursus faucibus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas quis ultricies enim. + +Suspendisse eu laoreet mauris. Curabitur sit amet faucibus arcu, ut feugiat justo. Integer in purus ut nulla vehicula mollis et sed tortor. Praesent pulvinar, leo posuere elementum rhoncus, justo ante ultricies ante, eu accumsan lorem elit vitae augue. Etiam vel posuere ipsum, sed auctor risus. Praesent gravida nulla congue, tempor urna sed, interdum velit. Aenean imperdiet, turpis sed venenatis facilisis, nunc ex aliquet dui, at facilisis purus nulla id nunc. + +Fusce non ante sed ipsum lacinia lacinia gravida dignissim augue. In hac habitasse platea dictumst. Nulla fermentum lorem eu sodales feugiat. Etiam aliquet ut nulla nec fermentum. Maecenas et suscipit magna. Vivamus vehicula aliquet nisi quis rhoncus. Integer mattis porttitor enim, ac tincidunt libero malesuada at. + +Nam ac dui et neque ornare euismod. Suspendisse ultricies orci enim. Sed eu euismod leo. Duis condimentum risus risus. Suspendisse id sollicitudin ex. Sed eu massa at magna iaculis mattis vel id est. Donec at bibendum libero. Aliquam congue maximus urna ac pharetra. + +In pretium lectus sit amet maximus varius. Vestibulum id massa pretium, fermentum nulla sed, aliquet turpis. Quisque tincidunt ante vitae massa viverra iaculis. Donec consequat sem sit amet fringilla auctor. Fusce a nunc sollicitudin, tristique erat sed, bibendum sem. Sed eu mollis ex. Pellentesque fermentum nisl tellus, tristique imperdiet odio vehicula eu. + +Cras ullamcorper pulvinar dictum. Aliquam eget accumsan felis. Pellentesque semper, nisl id molestie bibendum, eros tortor feugiat magna, non pretium tortor massa ut quam. Donec blandit pulvinar quam, vitae faucibus ex finibus sit amet. Sed ut libero cursus, viverra dolor eget, pharetra eros. Ut dignissim dui eget risus iaculis mattis. Pellentesque at mi lacus. Curabitur auctor eget nunc id rhoncus. Fusce odio lectus, vestibulum vel ante nec, lacinia iaculis ex. Duis eget orci fringilla, aliquet neque at, gravida leo. Maecenas eget nunc in ligula convallis ultricies fringilla in lorem. + +Curabitur tristique nisl sed turpis luctus, eget ultricies lorem sodales. Praesent viverra, eros tincidunt vehicula venenatis, nisi dui malesuada sapien, et fermentum dui turpis quis purus. Praesent porttitor sed velit quis dapibus. Donec aliquet diam sed gravida efficitur. Suspendisse vel quam congue, mattis ex et, pretium ex. Fusce ex sapien, faucibus et sapien quis, ornare accumsan urna. Phasellus nec nunc et nisi pulvinar consectetur. Suspendisse potenti. Nam a urna et enim iaculis consequat eu sit amet quam. Phasellus suscipit nisl est. Nulla vulputate ipsum orci, sed finibus ipsum sollicitudin et. Curabitur pellentesque pellentesque vehicula. Nullam finibus dui nec velit ornare semper. + +Vestibulum odio mauris, dignissim sed rutrum nec, tristique vel libero. Nam a dictum erat. Ut nec nisi in justo consectetur sollicitudin. Sed pretium est eget ligula maximus sollicitudin at eu nisl. Etiam congue enim a nulla fermentum ullamcorper. Pellentesque aliquet justo vel nunc hendrerit facilisis. Vivamus non leo elit. Nam a euismod felis. Nam dignissim tellus at ligula maximus, a pellentesque nibh euismod. Nam aliquam erat lectus, nec sollicitudin neque ultricies et. In id hendrerit arcu. + +Mauris imperdiet consequat elit vel mollis. Aenean dapibus, orci nec imperdiet porta, enim ligula gravida orci, eu porttitor sem mauris et ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Maecenas luctus augue in dui consectetur tempus. Vivamus sit amet est turpis. Quisque non iaculis erat, ut convallis massa. Vestibulum laoreet arcu eget venenatis tempor. Integer pretium sodales lectus et suscipit. Vivamus auctor ultricies suscipit. Aenean accumsan magna at euismod consectetur. + +Nulla eu risus erat. Cras pellentesque commodo ligula, id tempor neque vulputate nec. Integer lobortis, est id tincidunt gravida, lorem ante lacinia nisi, gravida consectetur massa massa eget metus. Nulla a maximus lacus, et sodales elit. Curabitur et arcu diam. Fusce blandit commodo nunc, ut ornare massa mattis nec. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla facilisi. Ut feugiat ante enim, eu vulputate urna egestas ut. Quisque ante nulla, volutpat vitae mauris ac, euismod auctor metus. Nulla a sodales mi, eu ornare lorem. Quisque fringilla, mi vel pulvinar rhoncus, magna tortor euismod ipsum, sed scelerisque urna velit pretium turpis. Mauris porta augue non imperdiet lobortis. Maecenas faucibus tempor dolor eu interdum. Fusce venenatis laoreet enim, sit amet sagittis leo fringilla a. + +Etiam ac dui at magna vulputate posuere faucibus scelerisque orci. Morbi ut rhoncus arcu, quis pellentesque leo. Nunc sed justo ut quam ultrices lacinia. Donec dictum tristique scelerisque. Mauris vel rhoncus justo. Nunc faucibus molestie dignissim. Vivamus ac auctor nisl. Nunc et nisi id elit gravida suscipit. Nulla auctor, urna nec pretium ultricies, neque neque tincidunt mi, ac venenatis odio felis euismod sapien. + +Nullam aliquam erat quis mi aliquet, ac ultricies enim convallis. Suspendisse interdum maximus ante, vel laoreet urna malesuada ac. Nam iaculis in purus accumsan porttitor. Fusce elit ipsum, ultricies dapibus nisl ac, ullamcorper placerat ligula. Sed in risus urna. Nunc bibendum nisi dignissim libero ultricies mattis. Curabitur tempus mi quis libero pharetra volutpat. Maecenas molestie aliquam velit, eget scelerisque magna ullamcorper ac. Suspendisse quis sagittis leo, quis malesuada quam. Proin nec dolor ac odio consequat euismod nec sed ipsum. Nunc purus diam, sagittis sit amet nibh in, egestas pulvinar quam. Etiam efficitur purus nec mattis molestie. Aenean nec dolor eu neque lobortis pellentesque ut sed leo. + +Cras ornare sodales est, ut fermentum tellus varius sed. Quisque elit enim, egestas quis orci eget, ultricies sagittis turpis. Aliquam erat volutpat. Suspendisse potenti. Etiam sit amet porttitor dolor, vel posuere quam. Aliquam in est lobortis, gravida justo quis, elementum augue. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed at metus risus. Suspendisse tincidunt volutpat felis ac condimentum. Pellentesque ligula sem, pharetra mattis leo nec, euismod dapibus nunc. Vestibulum blandit enim erat, sit amet aliquet velit venenatis rutrum. Donec non mattis odio. Suspendisse massa nisl, auctor sagittis orci a, pulvinar sollicitudin dolor. Donec quis malesuada augue, in imperdiet justo. + +Sed porttitor dignissim ultricies. Nam elementum metus in pulvinar mattis. Cras mauris mauris, tempor in sagittis id, aliquam sed lacus. Duis congue faucibus fermentum. Sed sollicitudin lacus sed orci semper faucibus. Maecenas porttitor fringilla velit, ac vehicula ipsum commodo et. Quisque sapien libero, varius sed neque ac, pretium consectetur tellus. Nulla mi magna, accumsan ac facilisis id, fermentum nec mauris. Vivamus venenatis sem sit amet est imperdiet, efficitur fringilla risus posuere. Cras sagittis congue blandit. + +Ut eget libero tincidunt, malesuada augue quis, malesuada enim. Mauris placerat bibendum lorem, quis ullamcorper diam pulvinar sit amet. Morbi ex augue, tempus sit amet metus vitae, pulvinar egestas tortor. Maecenas pellentesque ultrices venenatis. Sed ornare vitae purus a aliquam. Aenean malesuada consequat tellus, sit amet sodales nisl placerat nec. In hac habitasse platea dictumst. + +In in posuere urna. Sed pharetra dignissim tortor, ac condimentum ante rhoncus ut. Quisque convallis pharetra diam, at accumsan magna eleifend eget. Praesent sollicitudin ligula eu massa vestibulum, eu vestibulum libero tincidunt. Quisque cursus porta lorem a dapibus. Phasellus elit arcu, elementum at ante at, malesuada lacinia massa. Aliquam hendrerit purus vitae mi mollis, at vulputate felis pulvinar. Praesent finibus sit amet lacus at pellentesque. Proin a ultrices nibh. Etiam a pharetra ex. Praesent vitae neque id nisl egestas commodo eget quis nunc. Maecenas porttitor varius tellus, at consectetur est. Aenean maximus lectus at turpis placerat sodales. + +Morbi sapien ipsum, facilisis blandit leo blandit, posuere tincidunt nisi. Sed venenatis lectus quis cursus vulputate. Ut dapibus tincidunt mauris id aliquam. In vulputate eu arcu vitae pretium. Duis malesuada orci orci, et ullamcorper ante mollis eget. Quisque egestas, orci in interdum laoreet, libero neque cursus lacus, nec porta quam magna ac nulla. Nullam mattis porta eros sed aliquam. Donec nisi tellus, luctus at pharetra ac, accumsan at lacus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Praesent fringilla malesuada turpis, sed venenatis elit rutrum sed. Nulla enim lectus, egestas sed tempus sagittis, cursus eu tellus. Nulla facilisis sem eget lobortis lacinia. Vivamus euismod risus at dictum iaculis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Praesent finibus placerat nunc. Proin accumsan iaculis nisi nec malesuada. Vivamus quis dolor id ipsum ultrices lobortis. Duis fringilla ultricies est, non tincidunt turpis porta quis. Proin mollis tellus elit, nec porta neque aliquam eu. Suspendisse feugiat porttitor urna. Praesent lobortis lacinia vulputate. Nulla ex odio, vehicula et fermentum eget, posuere sit amet quam. Proin imperdiet felis vitae ante vehicula cursus. Mauris in sem in urna lobortis tincidunt. Fusce porttitor pharetra posuere. Phasellus nec semper tortor. + +Praesent quis felis odio. Sed et erat ac turpis pellentesque ullamcorper. Nam iaculis massa eget varius vulputate. Etiam varius odio vulputate felis sollicitudin dignissim. Praesent augue turpis, hendrerit a mi vitae, vehicula blandit nulla. Vestibulum vel tristique ligula. Mauris dignissim vitae sem sed suscipit. Fusce sollicitudin lacinia est ac volutpat. Suspendisse rhoncus bibendum lobortis. Nullam laoreet sapien fringilla ante mollis dapibus. Vestibulum eu nisl augue. + +Cras lobortis in massa vitae gravida. Nullam at fermentum massa, eu pellentesque tellus. Suspendisse non porttitor lectus. Cras quis risus purus. In pretium felis at accumsan condimentum. Vivamus facilisis eu eros et condimentum. Proin erat sapien, pulvinar in fermentum eget, dictum euismod neque. Morbi mattis lobortis purus, eget tempor tortor efficitur nec. Proin vitae sapien quam. Nam sed purus vel nibh volutpat aliquam. Proin in leo nisl. Integer finibus nisl vel nibh egestas, ut tempor risus bibendum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque feugiat venenatis quam, sit amet dignissim lorem varius vitae. Duis est orci, interdum non orci at, condimentum tempor nibh. Nullam elementum erat in sapien finibus, vitae placerat nisl accumsan. + +Nulla facilisis diam id turpis vehicula, et fermentum nisl rutrum. Phasellus at suscipit purus. Cras sit amet auctor leo, eu interdum magna. Duis hendrerit mollis tortor at pretium. Aliquam est lectus, tristique vel condimentum sit amet, scelerisque vitae odio. Cras sit amet luctus libero, et accumsan turpis. Ut diam tellus, tempus vitae ullamcorper in, egestas ac nibh. Proin tristique, odio ut tristique sagittis, ex est elementum arcu, ut laoreet est neque et est. Donec vulputate sapien interdum malesuada vestibulum. Aliquam erat volutpat. Nam sit amet lacus a elit egestas tincidunt. Ut quis lorem varius, lobortis metus nec, accumsan est. Phasellus arcu dolor, faucibus eget facilisis et, finibus vel eros. Cras id quam tortor. + +Suspendisse imperdiet interdum vestibulum. Nunc feugiat laoreet nisl, eget dignissim nibh tristique non. Donec malesuada condimentum mauris, et ullamcorper mi tincidunt feugiat. Nulla facilisis venenatis magna, a iaculis orci ultrices tempor. Nam mollis augue non elit mattis tempus quis vitae velit. Praesent dignissim tempus nunc eu rutrum. Sed placerat turpis eget ligula porttitor, eu pellentesque nulla tincidunt. Mauris eu eros elit. Sed sed accumsan leo, non tristique justo. Nam placerat tristique dolor et imperdiet. Maecenas interdum sapien non cursus mollis. Duis sed erat sollicitudin quam facilisis pharetra eu non orci. Phasellus venenatis mi ac fermentum egestas. Sed aliquam neque porttitor, lobortis erat id, volutpat nulla. Fusce sed nibh quis massa euismod consequat ac sed mi. + +Etiam tortor augue, semper ut dictum vitae, pharetra vitae risus. Curabitur vel aliquam sem, a elementum arcu. Sed rutrum, ligula quis tincidunt cursus, augue mi aliquet arcu, sed euismod massa quam sit amet quam. In mattis a erat vel aliquet. Integer sit amet pharetra magna. Donec massa ante, varius ac eros tempus, auctor fermentum lectus. Aliquam consequat rhoncus orci, ut varius nisl fermentum id. + +Ut ac viverra neque. Aenean tincidunt lorem vel ipsum lacinia, vitae elementum sapien pretium. Pellentesque iaculis tristique tristique. In vitae justo leo. Nam sodales rhoncus eros, a viverra lacus lobortis a. Ut sagittis ligula quis orci molestie volutpat. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nunc id urna eros. Duis enim nulla, porta sed leo sed, placerat mollis nisl. Etiam nisi nulla, eleifend vel bibendum in, viverra et lectus. Aenean aliquet justo ultrices lacus accumsan elementum. + +Proin metus neque, consectetur ut consectetur ac, vehicula in dui. Vestibulum volutpat tortor vitae ligula egestas porta. Praesent et enim dolor. Nullam ante ipsum, posuere sed purus a, lacinia aliquet purus. Donec fringilla dolor ac nisl fermentum, sed aliquam odio consequat. Sed bibendum nisl vitae magna mattis volutpat. Quisque semper nulla efficitur, semper libero vitae, molestie ligula. Sed posuere neque eu aliquam hendrerit. + +Nullam accumsan, turpis a maximus ornare, ante lorem pharetra est, sed molestie turpis magna eget diam. Aenean luctus ac purus congue tempus. Curabitur vel leo et nisl lobortis laoreet eu ut nisi. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed leo arcu, vestibulum vitae velit vitae, viverra cursus velit. Ut ut nulla quis nisl varius bibendum. Donec porttitor a lectus sed ultrices. Suspendisse et consectetur nunc. Mauris at accumsan metus, a suscipit nulla. Phasellus sagittis hendrerit augue, quis scelerisque odio pellentesque at. Integer eleifend, nibh vel rutrum mollis, orci ipsum commodo purus, eget viverra lectus sem quis orci. Integer non justo aliquam, tincidunt nulla vel, fermentum libero. Praesent pulvinar, nisl accumsan placerat semper, lorem lectus sagittis justo, iaculis vehicula elit justo nec erat. + +Etiam ante purus, consectetur vitae pharetra posuere, vulputate ac risus. Donec quis libero consectetur, vehicula erat eu, dignissim arcu. Aliquam laoreet elit id orci pulvinar faucibus. Duis in felis blandit, tempus dolor imperdiet, facilisis dolor. Fusce ac fermentum erat. Vivamus vehicula accumsan ex, id eleifend mauris interdum gravida. Curabitur ut consequat est. Nulla eu lorem vel dui pulvinar consectetur et sed justo. Sed ac arcu et enim scelerisque blandit a sit amet dui. Aenean accumsan nulla in libero convallis, non imperdiet est blandit. Vestibulum rutrum quis risus dignissim malesuada. Phasellus pharetra lacus ut ex porttitor, sit amet convallis quam tempus. Sed in leo nulla. Vivamus convallis dapibus enim, nec dignissim turpis sodales ac. + +Nunc nunc dolor, ultricies vitae lacinia sed, condimentum ac nulla. Nulla cursus pellentesque nibh, vel iaculis ex bibendum tristique. Praesent facilisis diam nec laoreet vehicula. Quisque vel dolor ligula. Pellentesque ullamcorper purus nec velit vestibulum condimentum. Donec eget diam mollis, eleifend sem vel, malesuada dui. Cras faucibus porttitor diam id convallis. Ut rhoncus lectus purus, quis accumsan nisl dictum sed. Nam id turpis quis eros auctor consectetur. Ut mauris nisl, ullamcorper sit amet est a, bibendum interdum dolor. Curabitur porta eros vitae felis commodo, ut auctor augue pretium. Suspendisse potenti. Aenean enim felis, sagittis sed pellentesque vitae, tempus vitae ante. + +Integer hendrerit commodo ante a pretium. Aenean lacinia massa sed mi finibus, sit amet molestie nisl euismod. Suspendisse ligula nisi, porta id viverra sit amet, lacinia ut turpis. Proin dignissim sit amet ipsum sed suscipit. Proin nec justo leo. Mauris elementum rutrum fermentum. Pellentesque laoreet erat non quam imperdiet fermentum. Fusce massa lacus, laoreet vel lacus eget, tincidunt fermentum dolor. Nam sed sodales leo. Curabitur mattis nisl vitae enim tempus placerat. Donec et orci aliquam, gravida metus sed, rutrum felis. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed finibus velit ut lacus sollicitudin suscipit. Cras accumsan elit lorem, eget malesuada mauris rhoncus ut. Donec in velit imperdiet, vehicula arcu ut, placerat mi. Mauris rhoncus mi mauris, sed vestibulum magna commodo id. Etiam fermentum lacinia tellus feugiat posuere. Suspendisse sit amet lacinia dolor. + +Nullam cursus sapien cursus nisl fringilla congue. Aenean ac porttitor massa, ut sodales orci. Donec ac est non felis gravida commodo. Integer vel massa orci. Fusce nec magna in nisi viverra facilisis. Nam luctus neque sed neque commodo congue et fermentum velit. Sed a dolor non mauris pharetra bibendum vel at diam. Quisque feugiat magna vitae vulputate congue. + +Cras tempus tempor sem, nec cursus orci auctor vel. In nec augue at eros placerat volutpat id at nibh. Mauris et pulvinar sapien, quis eleifend lacus. Proin ut congue lectus. Curabitur sed dapibus purus, ut facilisis erat. Ut sagittis ex nec augue accumsan fringilla. Nam pulvinar libero ut ipsum convallis interdum. + +Maecenas rhoncus tellus felis, eget blandit diam bibendum non. In maximus eu sapien pharetra posuere. Aenean egestas arcu eu urna pharetra lobortis. Cras viverra dolor felis, id faucibus odio luctus aliquet. Vestibulum vitae convallis augue. Suspendisse accumsan neque eu nisi tincidunt finibus. Aliquam dignissim, nunc ut bibendum fringilla, nulla lectus varius felis, sed hendrerit elit erat eu nisl. Cras orci lectus, varius vel dictum a, eleifend vel lorem. Proin viverra a nibh eget convallis. Duis vel scelerisque est. Cras maximus odio eget odio pretium aliquet. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Quisque at congue enim, in placerat risus. Pellentesque imperdiet eleifend feugiat. Nunc vel mattis justo, in mattis lectus. + +Maecenas lorem eros, condimentum rutrum feugiat ut, laoreet eu lorem. In porttitor turpis sit amet risus viverra pellentesque. Nam rhoncus tristique arcu vel cursus. Sed interdum, metus vel dictum gravida, ante magna efficitur magna, non aliquam dui est nec erat. Quisque fermentum, lacus sit amet maximus aliquet, dolor risus vulputate ex, et convallis orci nisl eu arcu. Sed imperdiet tempus erat, ac aliquam sem feugiat eu. Nullam mattis bibendum lorem vitae ornare. In condimentum vel odio vehicula placerat. Nullam quis magna est. Curabitur luctus eros turpis, sed varius odio convallis sit amet. Duis feugiat est ut tortor vulputate finibus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed ultricies lorem vel mauris lacinia commodo ut eget turpis. + +In in dolor ultricies, mattis urna id, viverra metus. Nunc ut nisi odio. Sed nunc odio, laoreet eu nunc sed, porttitor ultrices enim. Ut iaculis ligula a blandit varius. In eleifend, urna id ultricies convallis, urna odio euismod arcu, id finibus felis felis sit amet felis. Nulla ac consequat libero. Integer quis dolor sapien. Vestibulum in lectus dolor. Nulla nulla nunc, vulputate vitae justo dapibus, consequat varius urna. Cras est felis, sodales eget pulvinar pellentesque, commodo et sapien. + +In dui quam, euismod et mauris a, laoreet porta lacus. Proin nec semper neque. Donec consectetur lacus at nunc gravida, sed tempor dolor vulputate. Nulla facilisi. Curabitur sit amet purus nibh. Aenean dictum sodales mi ac ullamcorper. Vestibulum imperdiet ultrices aliquet. + +Etiam mauris libero, blandit id sem a, elementum tempus magna. Integer bibendum sapien vel est ultricies, a venenatis ante pharetra. Nam ac tempus nisi. Fusce at tortor arcu. Ut mauris lectus, ornare sit amet mollis vitae, iaculis ac felis. In mollis lacus neque, in gravida nisl gravida eget. Nulla facilisi. In neque tortor, faucibus vestibulum nunc a, consectetur commodo est. Praesent tristique lobortis sem posuere efficitur. + +Aliquam non semper ligula. Cras at ultricies mi, non ultrices massa. Nullam ac consectetur sapien. Donec ut urna posuere, mattis justo at, scelerisque neque. Suspendisse potenti. Vivamus aliquam enim sit amet mi feugiat, eget ultrices nunc pulvinar. Pellentesque facilisis, dui at sollicitudin maximus, risus mauris laoreet felis, nec sagittis nulla turpis et elit. Donec elit dui, pharetra facilisis quam sed, mollis ultricies arcu. Ut fermentum ipsum dui, eget maximus dui finibus nec. Mauris et mi arcu. Quisque sagittis pellentesque libero at ultricies. + +Sed ullamcorper vulputate dui, vel tincidunt metus rhoncus ac. Aliquam ut lacus molestie, pulvinar justo accumsan, bibendum neque. In vitae nulla ut metus condimentum rutrum eget nec mauris. Nam sit amet sodales sem. Phasellus sagittis massa quis ipsum gravida tincidunt. Ut ac massa dapibus, vestibulum nibh vitae, scelerisque lorem. Morbi dapibus commodo sodales. Nullam sollicitudin augue quis tristique malesuada. Maecenas convallis egestas ante a luctus. Integer a aliquet turpis. Curabitur augue velit, scelerisque vitae mauris et, tristique placerat ligula. Aliquam ultricies urna nisl, non tincidunt odio faucibus vel. Donec nec magna molestie, pulvinar risus id, bibendum nibh. + +Integer erat purus, sagittis eu ante eget, viverra faucibus erat. Mauris molestie ipsum erat, non imperdiet orci egestas nec. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla nec congue lectus. Fusce facilisis ex eu augue imperdiet pellentesque. Etiam quis mattis erat, in aliquam metus. Mauris fermentum urna ac justo consequat, quis sodales nisl pretium. Morbi venenatis congue quam, nec semper sem placerat vitae. Curabitur scelerisque ipsum vitae est tempus, eu tristique magna euismod. Fusce mattis at nisi eget cursus. Pellentesque ultricies, dui eget mattis mollis, risus turpis molestie leo, auctor placerat sem velit vitae risus. + +Aliquam erat volutpat. Interdum et malesuada fames ac ante ipsum primis in faucibus. Fusce lacinia cursus arcu, quis facilisis nibh elementum et. Donec lacinia eleifend ante eu porta. Curabitur ut accumsan nunc. Quisque viverra, ex quis pretium faucibus, diam justo scelerisque arcu, eget auctor nulla nisi eu magna. Pellentesque arcu nunc, sodales vitae cursus et, molestie eget quam. Integer efficitur eros ullamcorper justo laoreet aliquet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; In sit amet egestas ex, sed molestie purus. Vivamus ac metus et ipsum tristique congue. Ut elementum tellus vitae arcu suscipit, eu semper leo accumsan. Duis at maximus libero. Suspendisse blandit mauris lacus, sit amet aliquet sapien hendrerit sed. Praesent sed neque pulvinar, semper felis nec, eleifend urna. Etiam eget ex nisi. + +Nulla facilisi. Duis condimentum velit id vulputate luctus. Aliquam eu interdum nunc. Morbi eu est mattis, pretium eros ac, accumsan nibh. Quisque sed mauris fringilla augue tincidunt dignissim id vitae tortor. Pellentesque tincidunt magna quis ex facilisis, quis dignissim nunc tincidunt. Nunc semper maximus elit. Donec neque libero, volutpat nec mollis non, scelerisque ac odio. Donec et augue ut elit eleifend pharetra. Donec condimentum tellus turpis. In gravida, tellus hendrerit facilisis aliquet, ligula est auctor tortor, eu interdum turpis sem a ex. + +Sed vestibulum egestas mi sed semper. Cras varius tempus hendrerit. Duis quis ex mauris. Donec tincidunt rutrum tellus ut malesuada. Cras fermentum ut ante in pretium. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut tincidunt aliquam nulla. Duis a justo et diam porttitor hendrerit. Sed dignissim mauris ultricies, volutpat urna ut, sagittis lectus. Morbi facilisis lacus elit, eget varius ligula dignissim vel. Ut ut risus eget tellus viverra consequat non id nisi. + +Ut ut sem sit amet risus maximus accumsan eget id diam. Curabitur consequat arcu in sapien elementum, rhoncus suscipit ipsum ultrices. Duis sed lacinia mi. Maecenas posuere velit vitae eros mollis, accumsan sollicitudin ipsum tempor. Integer tortor leo, vestibulum tempor feugiat non, imperdiet quis nibh. Ut dictum erat vel lacus venenatis pellentesque. Morbi suscipit consectetur elit a pulvinar. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam accumsan ligula vitae dapibus suscipit. Maecenas hendrerit, ante ut euismod lacinia, dolor enim vehicula nunc, at ultrices erat magna et arcu. Etiam lobortis a leo non blandit. + +Morbi vulputate pulvinar odio quis porta. Ut nibh ex, posuere cursus commodo sed, malesuada in tortor. Maecenas sed maximus ligula. Fusce rhoncus nibh id nisl rutrum, eu ultricies erat fringilla. Cras risus nisi, molestie ut cursus vitae, tempor a leo. Quisque euismod neque sit amet est commodo, et consequat risus sollicitudin. Integer interdum odio eu suscipit ultrices. Nunc justo risus, pulvinar at metus ac, rutrum auctor tortor. + +Sed odio leo, posuere id orci sed, congue mattis urna. Nulla vitae ligula purus. Praesent quis fringilla magna, ac pulvinar metus. Donec congue purus ac tortor congue, eu maximus tellus hendrerit. Morbi nec ipsum suscipit, auctor ipsum non, ornare massa. Pellentesque eu lectus vitae ipsum ultricies porttitor nec at massa. Nulla arcu metus, accumsan at ante at, congue interdum quam. + +Vestibulum eleifend erat dignissim mattis scelerisque. Donec a magna vel lorem fermentum molestie. Vestibulum consectetur arcu dui, sed tempor nisl lacinia in. Cras at urna vitae nunc dictum ultricies eget vitae neque. Morbi vel rhoncus ipsum. Pellentesque placerat ultrices venenatis. Donec semper nibh vel imperdiet placerat. Vestibulum eget blandit ipsum, a maximus lacus. Sed sagittis faucibus velit, a mattis sapien. Duis consequat maximus ex, ut dignissim mi volutpat vitae. Vivamus congue diam nec tortor ornare hendrerit. Nam a tortor fermentum ante viverra volutpat ut vitae nisi. Proin consequat dictum velit at varius. + +Aliquam rutrum imperdiet egestas. Pellentesque et condimentum felis. Sed eleifend nunc ligula, at rutrum sapien porttitor ut. Nullam nec felis risus. Vestibulum in rutrum enim, vel luctus odio. Duis nec lacus augue. Suspendisse placerat ex vitae eros varius, at lacinia augue dictum. Sed tincidunt erat non facilisis semper. Duis venenatis tortor quis ligula ullamcorper, sed scelerisque mi sollicitudin. Sed condimentum, mauris ac blandit volutpat, urna ligula tincidunt ex, ut feugiat metus neque eget sapien. Etiam sagittis tincidunt elementum. Nam efficitur, nunc a hendrerit imperdiet, purus orci accumsan libero, quis interdum purus sem eu metus. Ut sem metus, malesuada non sapien at, condimentum dignissim lectus. Nulla vestibulum, mauris pellentesque placerat viverra, eros dui malesuada ligula, id semper magna velit in tellus. Etiam tempor, massa sit amet tempor rutrum, urna sem facilisis enim, at congue libero ex sit amet leo. + +Vivamus scelerisque suscipit eros, id porttitor risus placerat sed. Suspendisse faucibus leo ut dui facilisis iaculis. Aenean sed magna at sem tincidunt sodales. Ut scelerisque lobortis eros. Proin rutrum libero eu aliquam ultrices. Nullam ultrices feugiat diam non facilisis. Nunc et nibh augue. Proin posuere nisl vitae lectus ultricies faucibus. Nam mollis et odio ac tincidunt. Curabitur a ipsum fringilla, placerat eros quis, tempus ligula. Vivamus efficitur aliquam pharetra. Pellentesque maximus ante sapien, placerat condimentum felis bibendum ut. Maecenas massa neque, finibus sit amet augue vitae, scelerisque efficitur erat. Suspendisse id fermentum sapien, in viverra quam. Proin convallis felis ex. Nam mollis dui et tincidunt faucibus. + +Suspendisse potenti. Sed neque augue, fringilla nec leo eget, pharetra luctus nunc. Fusce et malesuada ligula. Nam eget libero interdum, condimentum eros at, aliquet nisi. Etiam aliquet leo quis venenatis auctor. Aenean facilisis, urna eget volutpat maximus, nunc erat faucibus elit, ac euismod nisl ligula faucibus augue. Pellentesque dictum porttitor est vel porta. Fusce scelerisque, odio tristique euismod faucibus, orci leo pretium odio, sit amet aliquet libero magna vel arcu. Integer luctus, felis et mattis sodales, lacus ex laoreet velit, et semper nisl mi eu tellus. Sed a massa et arcu faucibus sodales vitae nec lorem. + +Suspendisse potenti. Duis pulvinar lobortis nisi, at cursus urna dignissim eu. Ut hendrerit lorem sed congue porta. Nullam sollicitudin sem vel risus ultricies rutrum. Donec at lorem a tellus viverra interdum id non felis. Nulla congue tincidunt semper. Etiam finibus magna erat, vitae rutrum orci egestas at. Quisque eget venenatis libero, at malesuada ante. Nulla ut nibh pellentesque, convallis purus id, lacinia lectus. Integer vehicula dui ante, eget cursus ipsum consectetur pulvinar. Cras id molestie massa. Proin mattis semper quam, a convallis enim rhoncus a. Integer dapibus, lacus id sodales sollicitudin, dolor neque accumsan tellus, ac ultricies nunc diam vitae purus. Donec placerat condimentum nibh id porta. Vestibulum in gravida orci. Proin dignissim neque condimentum sagittis tincidunt. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Duis justo mi, faucibus nec facilisis sed, rhoncus ut purus. Duis et sollicitudin arcu. Morbi tempus diam et purus sagittis rutrum. Cras iaculis sem ac magna finibus mattis. Duis maximus tellus arcu, viverra feugiat diam fermentum eget. In hac habitasse platea dictumst. Integer ultrices volutpat purus a viverra. Proin sed euismod nisi. Suspendisse ac facilisis nunc. Vestibulum eleifend nulla sit amet lectus elementum aliquet sit amet vitae lectus. Curabitur consectetur nisi eu mollis venenatis. + +Duis euismod fringilla pharetra. Nunc sodales dolor sed facilisis ultricies. Quisque nec dictum mauris, sed iaculis mauris. Ut euismod feugiat luctus. In hac habitasse platea dictumst. Donec ut molestie massa. Phasellus ac enim nec leo consequat auctor. Cras massa orci, semper in scelerisque in, consectetur eu enim. + +Proin efficitur suscipit purus, nec interdum turpis vestibulum tristique. Nulla pellentesque lectus at neque imperdiet, a fermentum lectus bibendum. Ut vulputate, urna ac pretium porttitor, ligula ex rhoncus magna, vitae faucibus augue metus sed erat. Sed tempor ullamcorper orci ut sodales. Donec in mi bibendum, fermentum mi quis, ullamcorper leo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Phasellus at vulputate massa. Vivamus mattis mauris in orci consequat, at rutrum ante sagittis. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque non fermentum metus. Vestibulum faucibus eros quis dignissim ultrices. Donec id turpis convallis massa finibus blandit tempor id magna. Donec volutpat tellus sit amet mauris faucibus commodo. + +Aliquam eget ex ac magna suscipit lobortis in sit amet dui. Donec non enim placerat, tempor dui tempus, condimentum dui. Cras ultrices, augue et fermentum auctor, justo ante elementum lectus, ac mattis eros augue sed nisl. Nulla facilisi. Nulla porta maximus iaculis. Sed vestibulum odio justo, eget ornare enim ultrices at. Sed vestibulum mauris dolor, quis dictum sem placerat ac. Nullam vel dignissim elit. Mauris at iaculis odio. + +Pellentesque vel odio in libero faucibus ultrices. Aenean ac fringilla nulla. Proin leo tellus, varius sit amet augue ut, facilisis interdum urna. Aliquam molestie, purus vitae dignissim porta, eros sapien tristique nisi, et rhoncus sapien urna at nulla. Vivamus viverra sodales lacus nec aliquam. Etiam convallis rutrum ante, sed ultricies risus mattis vel. Sed blandit nibh quis lectus volutpat convallis. Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque faucibus, est vel lacinia posuere, nunc justo faucibus ligula, nec ornare lorem erat eu ante. Phasellus ligula neque, lobortis quis semper vitae, accumsan et augue. Suspendisse convallis mauris eu tortor vestibulum, volutpat pulvinar lacus venenatis. + +Donec feugiat orci vel magna hendrerit, ut ullamcorper odio consequat. Mauris et tortor sodales, commodo orci in, lacinia sapien. Vivamus posuere, neque sed sollicitudin lacinia, elit metus pellentesque tortor, at congue massa mauris quis turpis. Nulla facilisi. Proin ut maximus ligula, nec varius enim. Mauris ex arcu, tincidunt vel auctor vel, gravida feugiat ligula. Suspendisse odio arcu, euismod eu dignissim vel, rhoncus sed ligula. Donec pharetra bibendum neque, condimentum consectetur sem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Phasellus ornare nisl quis nulla euismod tempor. Maecenas sed enim auctor, venenatis odio non, ornare lacus. Aenean rhoncus efficitur arcu, vitae auctor est luctus at. In eros eros, pretium a laoreet sed, accumsan condimentum odio. Donec maximus congue nisi, non posuere nulla pulvinar et. Integer non erat et orci fringilla euismod. + +Nam efficitur lectus ligula, vitae cursus orci ornare sit amet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; In pharetra, nulla vestibulum suscipit rhoncus, eros quam auctor lorem, vestibulum efficitur eros lectus at ligula. Quisque nec enim a ante ultrices tincidunt eu nec nulla. Praesent ut leo metus. Ut eu tellus enim. Aenean vel consectetur tellus. Aliquam molestie, lectus in pellentesque aliquam, felis lectus ultricies ante, quis mollis ex quam ut orci. Integer volutpat pretium dui, et luctus ante dictum non. Sed porttitor sed lectus ut tristique. Nulla eget ultrices lacus. Integer sit amet magna et turpis consequat scelerisque et sit amet dolor. Ut sollicitudin malesuada libero, non pharetra est vehicula vel. Fusce pellentesque nisl ac metus sagittis dictum. Phasellus id eleifend ante. + +Vestibulum egestas libero in orci porttitor, at eleifend neque condimentum. Donec vitae felis id diam volutpat placerat eget eget felis. Praesent ullamcorper sit amet magna id pellentesque. Nulla est nunc, maximus vel urna sed, consequat dictum lorem. Donec eget ultricies purus, vel congue orci. Aliquam dapibus lobortis blandit. Aliquam sit amet tortor nec dolor varius luctus. Nullam eget felis mauris. Morbi blandit aliquet odio, non euismod felis porttitor vel. + +Curabitur sit amet dolor eu tortor venenatis consequat. Sed efficitur imperdiet quam nec luctus. Morbi vitae est posuere, posuere tortor eu, mollis sapien. Vestibulum eget pretium purus, a eleifend turpis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur massa orci, semper varius sapien sit amet, efficitur tempor nibh. Praesent pulvinar risus neque, vitae tristique lectus aliquet nec. Pellentesque eget orci eu leo maximus maximus sit amet ac eros. Praesent porttitor ligula et ligula vehicula placerat. Ut quis tincidunt orci. Nam ultrices elit ac ornare fermentum. + +In quis auctor purus. Fusce lacinia purus in leo fermentum scelerisque. Vestibulum at cursus odio, vel finibus tortor. Sed quis lectus sit amet velit tincidunt sagittis. Donec id porta enim. Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse eget ultricies augue. Nulla turpis metus, ornare ac tempor eget, dictum eu elit. Phasellus rutrum mauris at mauris accumsan suscipit. Donec eu sapien sollicitudin, viverra nisl et, euismod mauris. Curabitur dictum semper laoreet. Nulla nec malesuada dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Quisque euismod magna vel pharetra ornare. Nam sed finibus urna. Suspendisse augue nulla, luctus a egestas at, tincidunt nec diam. Cras congue justo ac velit euismod, eget volutpat augue porta. Maecenas nec nisl arcu. In at justo in tellus faucibus vehicula et eu ante. Aliquam facilisis mauris turpis, at finibus elit rutrum id. Sed nulla enim, ultricies at nisi et, tristique fringilla libero. Donec mattis volutpat arcu eu lacinia. + +Donec maximus, dui sed bibendum iaculis, lorem odio aliquet metus, in tempor lectus elit vel sapien. Aliquam rhoncus massa sit amet placerat congue. Donec vitae maximus nibh. Sed id fermentum augue. In hac habitasse platea dictumst. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam finibus, orci id tempor ullamcorper, justo purus venenatis augue, vel efficitur elit odio eget nunc. Pellentesque euismod fringilla eleifend. Sed mollis augue urna, eu placerat dolor placerat quis. Mauris id dolor vel velit aliquam dapibus a quis leo. Donec elementum dolor ut auctor accumsan. Cras sed fringilla mauris. + +Vivamus id placerat ligula, a egestas orci. Donec in erat ut tortor gravida pellentesque. Sed felis dolor, dignissim in maximus at, commodo commodo lacus. Cras commodo consectetur nunc, eu tincidunt risus dignissim sit amet. Mauris vel pellentesque urna. Vivamus scelerisque ligula eu velit dapibus rutrum. Nullam eget lobortis lorem. Vestibulum ligula lorem, suscipit convallis lorem at, ultrices mollis metus. + +Morbi varius rhoncus nibh nec varius. Nullam eget porta velit. Nulla lorem elit, ullamcorper non vehicula quis, varius et nisi. Sed molestie auctor nisi, vitae ultricies metus tempor nec. Maecenas imperdiet, nisl vel tincidunt varius, tortor nibh semper felis, at blandit metus tortor eget ipsum. Nullam at risus accumsan nulla bibendum laoreet. Quisque pellentesque ligula vitae lacus pellentesque, euismod convallis justo hendrerit. Sed nisi elit, egestas sit amet velit in, ultricies feugiat nunc. + +Aenean non metus magna. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Sed venenatis magna enim, non feugiat nisi tincidunt quis. Proin sit amet risus quis augue finibus finibus vel euismod enim. Morbi sed vestibulum turpis. Sed facilisis vitae mauris quis ultrices. Quisque a tellus laoreet, laoreet justo sed, cursus nibh. In dolor eros, finibus ut aliquam vitae, facilisis nec velit. Morbi vitae felis sodales, aliquet lorem vitae, ultricies libero. Quisque vehicula lectus non euismod pretium. Vivamus tempus ante justo, ullamcorper porta magna pharetra ac. In eu purus erat. Aliquam tincidunt magna augue, vel maximus dui semper vitae. Maecenas ac tellus ligula. + +Suspendisse lacus ex, hendrerit non diam non, luctus convallis ipsum. Nam lorem eros, facilisis at ultrices sed, porta eu elit. Donec molestie convallis rhoncus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed pretium aliquet pulvinar. Sed euismod nisi id condimentum convallis. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam tristique ipsum at arcu condimentum, sit amet feugiat lectus aliquam. In quis lobortis eros. Vestibulum nunc ex, mattis ut placerat ac, dapibus eu lacus. + +Sed vehicula nec ex ut vulputate. Aenean ornare, lacus nec finibus malesuada, mauris eros consequat ligula, eget blandit ex libero a odio. Praesent et fringilla leo, eget molestie nisl. Ut interdum, sem ut lobortis posuere, ante ligula ultricies nulla, a vulputate tortor est id enim. Fusce vel condimentum dolor, in congue purus. Praesent nec enim dapibus, dictum leo varius, aliquam erat. Duis neque lacus, ullamcorper et eros eget, laoreet venenatis est. Aenean laoreet ex mattis, rhoncus nibh vel, congue massa. Nam viverra ex sit amet erat tempor ullamcorper. Proin condimentum quam felis, in tempus magna ornare vel. + +Quisque faucibus erat sem, vel pharetra odio placerat eget. Suspendisse condimentum bibendum lacus at posuere. Duis eu congue elit. Proin fringilla nibh lorem, ut ornare enim viverra at. Donec a malesuada erat. Cras dolor felis, porttitor in nibh vitae, fermentum venenatis ligula. Vestibulum eget lectus posuere lorem ornare scelerisque. Morbi commodo augue eget tincidunt dignissim. Morbi vitae elit velit. + +Maecenas rhoncus rhoncus eros vitae pharetra. Morbi mi eros, sagittis non libero sed, lobortis venenatis lorem. Vivamus in justo nisl. Nam pulvinar lectus ullamcorper erat finibus imperdiet. Pellentesque malesuada massa ipsum, ac posuere neque iaculis et. Donec convallis tristique nisi non elementum. Duis facilisis lacus leo, sit amet molestie libero dignissim quis. Morbi et justo sit amet est maximus egestas a eget mi. Curabitur condimentum nec enim id tincidunt. Donec ipsum ipsum, pellentesque a efficitur non, mollis id ipsum. Maecenas venenatis sit amet nulla eu blandit. Nunc mollis, odio ut scelerisque aliquet, odio dolor mollis sem, vitae sodales diam nisl at nulla. Mauris vel risus nulla. + +Pellentesque sollicitudin non orci sit amet pellentesque. Morbi id nibh vitae enim dignissim porttitor. Phasellus consequat, diam eget commodo placerat, leo lorem scelerisque tellus, pulvinar lobortis enim risus sed nunc. Aliquam ut tincidunt leo, sed maximus arcu. Vestibulum metus erat, fermentum elementum justo et, iaculis maximus erat. Donec in feugiat erat. Donec dictum sodales venenatis. Morbi neque justo, euismod vitae elementum ut, sollicitudin ac dui. Donec eu lacus in nunc efficitur molestie. Morbi auctor vitae nibh nec aliquam. Morbi volutpat diam in diam tincidunt, id lacinia dolor porttitor. Integer nec urna id lorem placerat fringilla quis non orci. + +Maecenas lacus urna, porta eu dui non, ornare tempor dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam sit amet dignissim orci. Etiam ac mi mollis, posuere elit sit amet, finibus felis. Maecenas aliquet finibus leo vel porttitor. Etiam ipsum leo, convallis ut augue blandit, interdum ultricies risus. Donec vel eros porta, facilisis urna ut, vehicula sapien. Maecenas lacinia pharetra dolor. Vivamus lobortis nec enim ut lacinia. + +Curabitur semper pharetra tristique. Sed sagittis est vitae placerat sodales. Duis ac dolor posuere, fringilla ligula nec, sollicitudin lorem. Curabitur quis dignissim diam, quis varius ipsum. Sed maximus mauris tortor, sit amet imperdiet magna fermentum vitae. Aenean id pulvinar mauris, vel posuere erat. Pellentesque bibendum sodales risus, et maximus sem pretium nec. Sed ultricies rutrum tincidunt. Nullam pulvinar fermentum velit, nec consectetur ante feugiat eu. Maecenas sed enim commodo neque viverra mollis. Fusce imperdiet diam nisl, et pulvinar sapien commodo cursus. Aenean a nulla blandit, pharetra velit a, elementum magna. + +Sed et mi imperdiet, condimentum ipsum sit amet, suscipit felis. Morbi laoreet elit placerat, rhoncus lectus dignissim, finibus velit. Morbi sit amet mollis justo, sed efficitur eros. Suspendisse pharetra commodo nunc vel aliquet. Nam vestibulum ipsum sodales, posuere nunc et, aliquam leo. Nam ut consequat velit. Phasellus sollicitudin quis quam tincidunt pharetra. Proin at pharetra ex, sit amet egestas nunc. Fusce blandit suscipit ipsum vitae pellentesque. Fusce at malesuada lectus. Aliquam erat volutpat. + +In sit amet quam semper, molestie nunc imperdiet, euismod lacus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent eu felis risus. Maecenas venenatis tempus quam in feugiat. Cras auctor vulputate augue a accumsan. Aliquam vitae purus ut mauris volutpat efficitur sit amet id augue. Nunc bibendum magna vitae nisl condimentum maximus. Ut feugiat nisl a mi mattis aliquet. Aliquam euismod leo id massa laoreet sagittis. Phasellus ac posuere elit. Morbi turpis eros, cursus in mollis quis, eleifend vel risus. Phasellus feugiat malesuada congue. Nulla non posuere neque. Donec semper eros risus. + +Integer tristique maximus purus non vulputate. Donec quis semper augue. Nulla volutpat lectus sit amet lacinia malesuada. Fusce sed tellus eget metus egestas convallis at eget turpis. Praesent elementum turpis eget leo pulvinar pretium. Praesent faucibus bibendum magna, sit amet cursus dolor accumsan eget. Proin sagittis ut est non volutpat. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut eget turpis vel enim egestas pharetra. Sed eget vehicula odio. Pellentesque aliquet aliquam ipsum. Sed dapibus nisi urna, porta laoreet massa mattis non. Duis dolor diam, feugiat in eros at, bibendum consectetur lacus. Quisque accumsan nibh est, ac hendrerit arcu sagittis at. Fusce suscipit nunc at elit pulvinar, a fringilla orci posuere. Vestibulum non purus sit amet ligula porta tincidunt. + +Ut ut elementum leo. Donec eu vehicula enim. Nulla ut posuere libero. Suspendisse accumsan sit amet enim non ultrices. Donec a leo eget sapien pulvinar mattis ut eu tortor. Duis nec massa nisi. Morbi elementum felis et dapibus sodales. Suspendisse ut luctus enim. Donec tristique at nisi vel lacinia. In malesuada in tellus nec dapibus. Integer in congue est, sit amet facilisis est. + +Integer suscipit feugiat condimentum. Sed non metus est. Nullam accumsan justo at interdum varius. Curabitur sed risus consectetur, egestas sapien ut, pretium felis. Maecenas eu dolor eget lorem varius pretium. Phasellus consectetur urna a ante sodales dapibus. Donec sollicitudin lorem tempus malesuada tempus. Phasellus luctus condimentum vestibulum. Fusce vel molestie nisl. Nullam imperdiet dolor ut lectus vulputate sollicitudin. Aliquam erat volutpat. Nullam in sollicitudin nulla. Morbi porta felis et lectus auctor porttitor. + +In in ligula et ante posuere luctus. Ut feugiat sit amet quam eu rutrum. Nullam commodo ante nisi, et pellentesque augue pellentesque et. Nulla vulputate, lacus quis efficitur mattis, nisl velit molestie nisl, sit amet rhoncus nisi turpis quis leo. Morbi a magna urna. Donec a iaculis nisl. Nullam eu elit vitae dui interdum bibendum imperdiet quis ante. Curabitur vitae lorem sit amet odio tristique rutrum. + +Sed ut lectus dolor. Suspendisse euismod ut massa id vestibulum. Sed non massa placerat, facilisis dui a, condimentum enim. Fusce vehicula erat eu lacus condimentum euismod. Vivamus ut ultrices ipsum, in ullamcorper velit. Sed enim nulla, tincidunt at purus id, ultrices maximus ipsum. Cras sit amet tortor at enim pellentesque lacinia sed vel sem. + +Integer ac metus nec nulla cursus venenatis. Duis blandit luctus massa a vehicula. Nam vulputate, lectus ut condimentum lacinia, tortor tortor cursus justo, facilisis tempor eros sem vitae nulla. Nullam sed ex massa. Aliquam non arcu et neque scelerisque porttitor. Etiam commodo venenatis maximus. Donec rhoncus erat nec diam efficitur placerat. Mauris pretium mauris libero, sit amet vestibulum ipsum fringilla eu. Cras sed tortor mollis, mollis diam eu, condimentum ex. Etiam gravida nec arcu vel sodales. Pellentesque ut arcu in eros ullamcorper tristique. Praesent luctus in neque eget pharetra. Proin dapibus tellus sed velit commodo interdum. Praesent euismod, massa in semper mollis, tortor ipsum suscipit tortor, sit amet viverra tellus sapien eget orci. Maecenas in molestie justo, eget consequat dolor. + +Praesent vel neque vitae ipsum condimentum pulvinar eu non nisi. Integer mattis quam ut pellentesque auctor. Ut egestas, diam at finibus viverra, felis est tristique nibh, id convallis turpis velit eget ligula. Fusce sed nisl volutpat augue volutpat facilisis. Aliquam erat volutpat. Integer dapibus varius augue, sed fringilla metus varius vitae. Maecenas sed elit a sem dignissim tempus. Maecenas nulla erat, molestie sit amet malesuada eget, blandit at libero. Donec lacinia efficitur nulla a scelerisque. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla hendrerit dui quis orci tristique, id faucibus eros malesuada. Sed ut dolor ex. Sed vel rutrum eros. Nam ac orci sit amet mi consequat aliquet quis quis est. + +Vivamus nec odio vitae orci consectetur suscipit. Donec vehicula eget libero in viverra. Ut laoreet in nulla eget euismod. Phasellus egestas lorem sed dui blandit, rhoncus interdum nulla ultrices. Quisque congue convallis erat ut blandit. Phasellus tempor pulvinar justo, id varius risus tempus eget. Suspendisse tempus, urna et mattis placerat, tellus magna pharetra ipsum, sed porta mi tellus suscipit justo. Vestibulum commodo turpis ut metus lacinia scelerisque. Aliquam fermentum, quam in malesuada ornare, orci mauris molestie mi, vitae tristique nunc quam pharetra enim. Etiam placerat lectus quam, vitae faucibus metus efficitur sit amet. Pellentesque suscipit porttitor ipsum, in fermentum turpis tristique sed. Duis finibus mi nec odio aliquam feugiat. Sed vitae tellus diam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +Sed ac mi libero. Aliquam pulvinar ullamcorper ipsum. In blandit nec arcu ut vehicula. Duis venenatis suscipit laoreet. Cras finibus tincidunt velit in feugiat. Mauris lorem eros, pretium sed ornare et, blandit id quam. Donec cursus, velit quis semper finibus, risus quam gravida sem, quis venenatis est turpis scelerisque lorem. Pellentesque vel accumsan ipsum, in finibus lacus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Morbi ultrices, risus ac euismod tincidunt, felis tortor facilisis eros, et elementum massa velit finibus augue. Sed fermentum faucibus euismod. In nec porta neque, eget mollis leo. Pellentesque dapibus metus vel nunc efficitur, nec suscipit ligula porta. Ut eu justo quis turpis tincidunt dapibus et et lacus. Nunc quis vehicula ligula, ac gravida turpis. Etiam in hendrerit ipsum. + +Nunc scelerisque maximus dui, et porttitor mi hendrerit sit amet. Nam placerat ultricies arcu, ut bibendum arcu fringilla in. Mauris vitae ultrices nisl, ac lobortis leo. Vivamus in nulla elit. Integer a quam eros. Integer volutpat odio ultrices nisi interdum suscipit. Nunc faucibus ultrices scelerisque. Sed hendrerit tortor nec ligula fermentum suscipit. Suspendisse fermentum dignissim hendrerit. Nam posuere sodales nunc ultrices suscipit. Quisque ut ipsum et lorem laoreet mollis. + +Maecenas in interdum orci. Aenean dolor dui, semper quis nisi sed, placerat euismod nisi. Nam at maximus libero. Donec sit amet justo urna. Maecenas sem sapien, viverra ac faucibus vitae, bibendum nec ex. Vivamus commodo dignissim viverra. Morbi semper condimentum augue, nec tempor nisi sodales nec. Suspendisse ut lorem pulvinar, ultricies justo ut, sollicitudin purus. Etiam sed bibendum enim, ac facilisis libero. Nulla rhoncus finibus tempus. Nullam eget imperdiet orci. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec et justo at turpis varius sagittis volutpat vitae elit. Duis posuere nunc nec placerat mollis. Sed pretium purus quis risus commodo, et placerat nibh dapibus. Curabitur neque ex, viverra nec imperdiet fermentum, fermentum in diam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent ultrices metus non nisi aliquet, sed feugiat diam ultrices. Morbi rhoncus risus nec mi bibendum convallis. Nam tellus erat, porttitor vel erat vitae, vehicula pharetra justo. Praesent in nunc eu risus aliquam lobortis id et sem. Aliquam nulla augue, commodo ac ex quis, iaculis imperdiet justo. Fusce rutrum elit at enim ornare pellentesque. + +Morbi lacus nisl, facilisis ut purus a, dapibus ultrices orci. Etiam in pretium ipsum. Nulla ac interdum velit, ut pharetra neque. Maecenas placerat, diam vitae aliquet ultricies, neque ipsum vehicula dui, id blandit est diam non purus. Duis eu mi vitae quam sagittis pulvinar. Donec ligula erat, maximus in cursus eu, elementum eu nulla. Pellentesque ut justo ac orci placerat accumsan vitae in sem. Morbi at consectetur elit, ornare fringilla nibh. Suspendisse sapien lorem, molestie sed tortor vitae, finibus accumsan tortor. Quisque dignissim rhoncus metus, non dapibus dolor auctor sit amet. Aliquam a fermentum tortor. Donec ullamcorper fringilla risus. Ut tellus tellus, tincidunt eu nulla a, rutrum consectetur diam. Nunc arcu mi, tempor eu suscipit eu, vehicula vitae nibh. Aliquam rhoncus ante sit amet nibh volutpat, quis mattis felis imperdiet. Integer tincidunt arcu sed dolor iaculis interdum. + +Donec pharetra consectetur orci quis tempus. Proin laoreet risus eget libero ornare, nec tincidunt massa consequat. Phasellus pharetra felis at velit vulputate suscipit. Proin aliquam elit ut massa malesuada, nec rutrum mi efficitur. Nulla volutpat libero vel quam fringilla posuere. Aliquam sit amet purus arcu. Quisque iaculis sed erat non accumsan. Praesent eu nulla odio. In hac habitasse platea dictumst. Maecenas facilisis, sapien et ornare rutrum, orci est facilisis nisl, id placerat lectus dui eget lacus. Suspendisse potenti. Suspendisse eu tempus nisi. Proin et ipsum ut velit consequat finibus ac non lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; + +Nunc ornare elit non massa semper consequat. Nullam lacinia dignissim mauris nec molestie. Sed id nunc ut ligula ornare finibus in at nibh. Duis turpis nunc, ultrices ultricies fringilla ut, venenatis in justo. Donec volutpat imperdiet interdum. Aenean sollicitudin massa at porta fermentum. Donec et tortor volutpat, hendrerit nulla quis, consequat velit. Nam sed nisl mattis, pharetra ligula id, congue purus. Nulla sed risus non ante sodales mollis nec vehicula justo. Nullam eu ultricies leo. Duis eget consectetur erat, vitae facilisis purus. + +Phasellus ut rutrum eros. Phasellus viverra commodo arcu sagittis porttitor. Etiam suscipit vehicula lacinia. Fusce vel condimentum lorem. Integer rhoncus lorem quis velit hendrerit tempor. Aenean a nisl ante. Phasellus nec ipsum ut quam porta varius et nec sem. + +Pellentesque pellentesque est eu dui placerat, vitae imperdiet erat dictum. Aliquam erat volutpat. Quisque feugiat neque nec faucibus maximus. Mauris eleifend odio at nunc suscipit dapibus. Maecenas mauris mauris, suscipit ac ipsum in, condimentum volutpat risus. Suspendisse gravida risus ex, quis suscipit nisl viverra ut. Phasellus pharetra nisl id odio laoreet bibendum. Morbi semper urna nulla, non ultricies est vehicula vitae. Maecenas non porta ante. Donec nec massa eu purus ultricies euismod. Nam sollicitudin dui metus, vitae ornare libero faucibus sed. Aliquam feugiat tellus nec est dignissim placerat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Quisque dictum placerat leo sed mattis. + +Quisque eu dolor dictum, euismod urna quis, mattis enim. Donec eu magna ultrices lectus fringilla facilisis. Sed finibus gravida purus, posuere interdum magna laoreet quis. Aliquam vehicula volutpat tellus ac tincidunt. Sed volutpat convallis eros, eget ultrices mauris maximus et. Mauris porta leo sit amet urna pretium condimentum. Duis non ex in dui dapibus tristique vel eget velit. Etiam velit quam, dapibus ac scelerisque ac, dignissim non elit. + +In cursus est ut nibh placerat maximus eu blandit tellus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut posuere massa eu odio rhoncus, ut eleifend odio finibus. Maecenas tristique, justo quis auctor laoreet, turpis nibh iaculis nisl, a consequat velit libero id sapien. Curabitur rutrum non justo eget aliquam. Praesent ornare lobortis eros eleifend hendrerit. Integer porta sapien turpis, a imperdiet ante congue et. Nullam ut fringilla enim. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Donec ullamcorper ac tellus a efficitur. Sed lacinia egestas libero, ac luctus turpis imperdiet eu. Morbi et gravida est. Maecenas dapibus erat id ex mollis, eget sollicitudin mi ullamcorper. In sed quam ac lacus dapibus ullamcorper. + +Integer efficitur iaculis porta. Vestibulum nibh augue, aliquam et ultrices at, molestie et neque. Proin ut mauris ac risus sodales congue. Nunc non tristique ligula. Donec orci elit, viverra sit amet iaculis id, maximus eu dui. Morbi condimentum tincidunt nisi, ac ultrices orci auctor id. Nunc congue, sapien vitae interdum euismod, augue massa molestie arcu, ac aliquam risus tellus vitae orci. Nullam sit amet eleifend dui, in pulvinar purus. Nullam vitae sagittis ligula, non iaculis augue. Duis sit amet erat et nibh imperdiet aliquet. Ut vitae laoreet enim. Duis leo mauris, tincidunt non mauris ut, maximus suscipit sem. In in nisi in mi ultricies suscipit. Sed porttitor ante eu dui sodales, in rutrum felis consectetur. Nullam ut enim eget ante dignissim efficitur vitae scelerisque ex. + +Ut aliquet mi id dictum imperdiet. Donec vulputate urna ac quam vehicula, varius viverra ex tempor. Praesent porta, justo id tempor mattis, ligula tellus tincidunt eros, ut varius lacus quam a diam. Fusce eu sagittis dolor. Vivamus vitae velit ut ipsum aliquam posuere at a elit. Aenean imperdiet nec ante euismod tempus. Nam facilisis ut nunc id semper. Phasellus consectetur tincidunt placerat. Suspendisse sed sodales ex, sit amet hendrerit ligula. Nam aliquet urna nec tortor dictum accumsan. Cras ut ex vitae odio tempor consectetur. Suspendisse tincidunt erat ac mauris volutpat viverra. Nullam molestie, enim eget tincidunt hendrerit, nunc metus semper sapien, porttitor rutrum mi velit in quam. + +Vestibulum non interdum turpis. Donec id dolor consequat, condimentum felis a, bibendum nisl. Morbi diam nisi, fermentum nec viverra vel, fermentum elementum tortor. Sed enim massa, aliquet quis mi non, vehicula faucibus justo. Fusce vel risus quis lectus vehicula ullamcorper. Donec mauris velit, lacinia non faucibus vitae, consequat a est. Vivamus tristique eros accumsan, porttitor eros at, interdum mauris. + +Maecenas tempus nulla tristique ex gravida posuere. Aliquam eget eros ac sem rutrum pulvinar sed id magna. Vestibulum suscipit eleifend accumsan. Proin sit amet vestibulum enim. Fusce fringilla pellentesque odio a dapibus. Aenean vel neque vitae augue sagittis luctus nec in orci. Vestibulum blandit felis eu purus condimentum congue. Vestibulum vel tristique risus, dignissim accumsan metus. Duis nisl odio, semper in arcu nec, faucibus lacinia leo. In auctor neque nec augue sagittis volutpat. Aliquam luctus suscipit mauris, ut fringilla tellus laoreet et. Cras pretium est quis ante mattis congue. Nunc dui metus, aliquet egestas neque id, fringilla luctus dolor. + +Donec in dignissim ex. Nullam sed metus sollicitudin nibh aliquet rutrum eget sit amet odio. Vivamus quis fringilla dolor, lobortis suscipit leo. Phasellus non nisi interdum felis cursus gravida ut eget urna. Phasellus bibendum ex id velit imperdiet fringilla. Ut interdum justo at ante porta auctor. Phasellus dictum congue mauris, in hendrerit ante semper ac. Vivamus a mi quis ipsum maximus egestas sed volutpat tortor. Proin interdum dolor in ornare rhoncus. Sed ornare nunc id lacus tincidunt, aliquam faucibus lacus imperdiet. Fusce sed mauris ligula. + +Vestibulum lobortis felis neque, a luctus ligula efficitur vitae. Aenean suscipit molestie velit. Curabitur dapibus dapibus maximus. Nam ultrices, nisi eget semper accumsan, risus massa iaculis diam, ut accumsan libero neque et mi. Etiam rhoncus tellus eros, ac posuere ante bibendum vitae. Curabitur in sollicitudin dolor. Nulla tempus urna vel ligula faucibus finibus. + +Sed sit amet varius magna. Fusce vestibulum interdum magna id vehicula. Nullam quis velit cursus enim egestas semper. Aliquam tristique sapien id neque egestas, eget aliquam nisl pulvinar. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam elementum pellentesque mauris, nec condimentum elit luctus vel. Quisque iaculis, massa quis hendrerit congue, mauris erat euismod sapien, ac dapibus nulla mauris at mauris. + +Nulla bibendum volutpat augue a suscipit. Morbi tortor metus, volutpat ut felis in, malesuada malesuada nunc. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nunc a lobortis nulla, eget elementum sem. Proin eleifend est vitae diam porta gravida. Maecenas a fermentum neque. Sed lorem augue, porttitor eget bibendum ac, pretium et eros. Quisque eu ligula id odio tempor gravida condimentum ac libero. Vivamus nulla purus, cursus quis eleifend ac, ornare at nibh. Nullam a leo tincidunt, viverra odio vel, maximus turpis. Duis consectetur tempus nunc at aliquam. Integer facilisis dolor non sapien lobortis pharetra. Integer ornare metus eu diam lobortis gravida. Donec mauris ipsum, rutrum blandit auctor et, ullamcorper non nisl. Curabitur aliquet, felis in auctor ornare, nunc turpis elementum ipsum, id tempus mauris erat ut justo. Phasellus aliquam, ligula ut pretium mollis, nibh libero dictum mauris, consectetur dapibus ex lectus eu sapien. + +In lobortis in augue quis consequat. Phasellus rhoncus aliquam porta. Suspendisse at ipsum iaculis erat iaculis dapibus. Proin molestie luctus diam a lacinia. Quisque vel augue tristique, ultrices ligula quis, dictum quam. In vehicula ligula at metus tincidunt tristique. Duis pellentesque efficitur lorem, accumsan aliquet eros dignissim sit amet. Praesent volutpat ultricies quam in pharetra. Cras a odio a nisi pellentesque ultricies. Proin maximus tempor quam ut placerat. Quisque nec dolor vitae felis tincidunt molestie eget at nunc. + +Ut ipsum risus, euismod a purus quis, mattis porttitor nisl. Integer feugiat urna vel egestas ultricies. Nulla nulla nisl, fringilla ullamcorper ligula eu, tempor mollis neque. Curabitur semper aliquam dolor eu ullamcorper. Nam tempor ornare mauris sed condimentum. Duis erat velit, bibendum a tristique nec, aliquam eu lacus. Duis ornare sed mauris euismod vulputate. Quisque eros nisi, viverra a lorem at, semper aliquet diam. Sed vitae tortor mauris. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed ante metus, faucibus at nunc sit amet, dignissim sodales felis. Nullam congue maximus ante, placerat facilisis massa ornare vel. Suspendisse nec rhoncus orci. Nam ultricies, lorem vitae viverra pretium, urna libero fringilla sem, nec cursus neque lacus vitae leo. Quisque orci ipsum, elementum vel quam in, aliquam pulvinar nulla. Nunc rutrum leo id orci vehicula maximus eget ac tortor. Donec in enim vel eros egestas tincidunt ac eu sem. Suspendisse in arcu lorem. + +Curabitur venenatis libero at libero eleifend dictum eget in neque. Aliquam ac ligula pharetra, accumsan purus ut, aliquam diam. Nulla sit amet massa elit. Nam non augue lacus. Donec rhoncus arcu non libero ullamcorper, at pulvinar eros vulputate. In placerat, sem quis posuere porttitor, turpis justo blandit justo, ac iaculis quam nunc nec velit. Sed a metus arcu. Fusce mi odio, rhoncus eu dui vel, dapibus aliquam urna. Suspendisse et imperdiet orci, at dictum dui. Ut tempor arcu eu sem efficitur semper. Nunc eu tempus tortor, sed bibendum tortor. Aliquam convallis, mi in scelerisque faucibus, ex arcu laoreet erat, dapibus semper nulla eros vel odio. Vivamus eros erat, viverra sodales euismod ac, vehicula at ligula. Etiam elementum urna metus, vel consequat lectus blandit in. Suspendisse a libero vitae nulla commodo dictum. + +Integer sodales nec lorem ac tristique. Duis faucibus mollis nunc, vitae imperdiet nulla consectetur sit amet. Aenean non semper justo. Quisque eget lectus varius, iaculis ex nec, pulvinar est. Aenean eu eleifend nisl. Vivamus orci nulla, suscipit dignissim dictum eleifend, condimentum eu purus. Mauris at tortor vel dolor ultrices blandit eget quis tortor. Integer ac nisl eu neque luctus condimentum. Etiam nec mi quis magna ullamcorper vehicula. Nam cursus neque vel auctor pharetra. Suspendisse ut augue vel leo porta semper. Proin in fringilla mauris. Vivamus faucibus nulla ligula, ac tincidunt nisi placerat in. Duis congue, libero non finibus finibus, libero enim lacinia eros, nec tincidunt nulla diam pellentesque augue. Aliquam massa neque, vestibulum eu elit vitae, lacinia gravida nulla. + +Vivamus eget turpis sapien. Nam vitae turpis quam. Phasellus ac turpis id mauris fringilla viverra. Donec varius sollicitudin mi, at posuere eros. Fusce varius vitae lectus sed mattis. Pellentesque dapibus porta ex non viverra. Aliquam ut tristique orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam non lorem eu neque aliquet tristique ac non enim. Integer sed lacinia ex, eget congue sem. In hac habitasse platea dictumst. Vivamus posuere neque eget viverra sodales. Morbi in mi ac quam cursus aliquam. + +Duis id nibh vel diam iaculis malesuada elementum ac neque. Donec venenatis lectus vitae tellus consequat gravida. Sed euismod enim eget justo aliquet euismod. In volutpat lacus quam, at molestie erat sodales ac. In id dolor suscipit diam bibendum feugiat ac quis ligula. In molestie massa sed enim rutrum cursus. Praesent porttitor lacus dui, id tincidunt leo volutpat vel. Morbi libero tellus, pharetra id mi sed, dapibus sagittis nisl. Aliquam sed sem interdum, tincidunt purus nec, convallis ante. Praesent commodo laoreet libero, non commodo nisi varius sed. Nam et ante et libero euismod consequat in nec erat. Duis convallis nulla sapien, non commodo libero suscipit vel. + +Aenean facilisis massa ut mi condimentum, non porttitor ex vestibulum. Fusce a tincidunt urna, quis suscipit magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam tristique nisi sit amet metus lacinia aliquet. Nulla rutrum enim vel nisl fringilla vestibulum. Maecenas sapien lectus, auctor eu ex ut, auctor rhoncus neque. Duis lacinia enim at pretium feugiat. + +Nunc ipsum neque, tincidunt ut consequat at, tristique in arcu. Nulla lacinia dictum purus vitae aliquet. Fusce eget dui imperdiet, molestie massa quis, egestas ligula. Maecenas aliquet eu nisl et scelerisque. Fusce mollis quis massa id porttitor. Suspendisse potenti. Sed varius tincidunt tempor. + +Curabitur finibus massa nec aliquam efficitur. Nulla eget nunc velit. Quisque tempor orci non gravida hendrerit. Ut aliquam urna ut urna vehicula, nec facilisis dolor pharetra. Nullam pretium convallis nulla, a sodales lacus egestas id. Duis nec nulla enim. Quisque lorem sapien, laoreet sit amet vulputate aliquam, ullamcorper sit amet nibh. + +Curabitur ut nisl ex. Ut molestie in odio iaculis maximus. Morbi egestas est eu mi pretium feugiat ac sit amet ante. Phasellus eu ex volutpat, ornare ligula eget, maximus eros. Quisque mattis quis massa at elementum. Etiam maximus orci lacus. Duis sagittis, enim eu mattis ornare, urna nunc cursus nibh, in cursus leo turpis egestas sem. Fusce rutrum commodo blandit. Cras elementum augue eu quam lacinia rutrum at vel ante. Nulla sed iaculis felis. Duis in pellentesque nulla. Maecenas neque nisl, condimentum eu ipsum vitae, scelerisque vulputate dui. Aliquam sit amet sem egestas, lacinia velit eu, accumsan nunc. Nam mauris orci, blandit sed nisi at, sodales malesuada mi. + +Suspendisse et laoreet elit, finibus laoreet nunc. Donec ut nibh ullamcorper, accumsan ligula ut, rutrum leo. Etiam hendrerit suscipit condimentum. Maecenas ultrices mattis leo a posuere. Quisque ultricies dolor vitae pretium egestas. Proin auctor ac dui vel tincidunt. Aliquam eleifend ipsum purus, eu maximus elit condimentum eu. Curabitur efficitur pharetra viverra. Ut non nisl iaculis odio tincidunt consectetur ac tempus lorem. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultrices blandit nisi, eget vehicula ligula sagittis vel. Nullam consequat sit amet velit eu pulvinar. Sed nec velit fringilla, pellentesque ante quis, viverra ligula. + +Maecenas et diam eu risus dictum condimentum nec vel arcu. Phasellus in nisi ut erat gravida posuere. Morbi tempor lacus non lacus scelerisque elementum suscipit ac dolor. Vivamus bibendum laoreet commodo. Vivamus rhoncus condimentum ex. Sed cursus ultricies enim, accumsan feugiat neque. Vivamus sapien eros, posuere vel aliquam sed, volutpat ac ex. Duis sagittis nibh sit amet porttitor porta. Fusce arcu sapien, molestie id arcu eget, dapibus ultricies quam. Suspendisse potenti. Sed ut feugiat ipsum. Aliquam tristique viverra turpis et blandit. Ut at quam vitae eros imperdiet rutrum eget ut eros. Proin vel nulla condimentum, bibendum mauris eget, scelerisque ligula. Cras commodo sagittis nisl. + +Integer viverra lorem ac urna scelerisque vulputate. Donec non convallis massa. Fusce commodo libero eu commodo dictum. Duis porttitor justo suscipit leo viverra, et feugiat libero rutrum. Curabitur id odio porttitor, facilisis purus ac, bibendum dolor. Donec vestibulum dui mattis, gravida enim et, finibus massa. In mattis quam eget elit pretium congue. Aenean congue nisi sed purus luctus, eu sodales eros euismod. + +Maecenas hendrerit nisl eu tellus lacinia aliquet. Praesent sit amet ornare lacus. Quisque blandit faucibus consequat. Curabitur dolor ligula, ultricies ut dapibus id, ullamcorper eget quam. Quisque vehicula massa ac magna imperdiet, molestie eleifend metus elementum. Mauris tempor ex orci, ut tempor lorem pellentesque laoreet. Sed aliquet ligula ut risus consectetur, ut venenatis neque dictum. Nulla facilisi. Nullam neque mi, faucibus nec egestas sit amet, luctus a nunc. + +Maecenas sed magna ut nisl sagittis viverra vitae nec orci. Nullam dapibus justo facilisis viverra placerat. Curabitur laoreet erat eu vulputate vestibulum. Nulla consectetur, quam nec ullamcorper lacinia, ipsum libero convallis enim, ac rutrum erat lectus nec massa. Proin placerat posuere tellus. Pellentesque vel metus vestibulum, vestibulum velit vel, mattis mauris. Quisque rhoncus sapien quam, id pellentesque neque interdum sit amet. Praesent aliquam lobortis magna sit amet lobortis. + +Maecenas quis libero erat. Nullam pharetra augue eget lacinia cursus. Donec id tortor pretium, placerat risus in, finibus libero. Mauris ac orci in turpis fermentum volutpat. Cras cursus massa est, quis sodales nulla vulputate quis. Etiam nec diam interdum, semper diam at, blandit nunc. Sed porta dolor at eros eleifend sagittis. Duis maximus eros sed risus viverra pretium. In hac habitasse platea dictumst. + +Vestibulum mollis, metus a sodales porttitor, erat odio volutpat purus, in cursus mauris lorem a velit. Ut non faucibus sapien. Quisque efficitur varius justo non porttitor. Curabitur malesuada non diam quis egestas. Cras mattis rhoncus neque quis viverra. Morbi eu iaculis lacus. Fusce eget diam quis ipsum pharetra sodales. Mauris volutpat lectus non ullamcorper ornare. Integer finibus commodo efficitur. Duis sit amet dui id metus condimentum hendrerit. Suspendisse et elit nulla. Integer lacinia egestas quam, dictum ullamcorper enim laoreet at. Sed lacinia neque et sapien convallis molestie. + +Praesent lectus turpis, imperdiet sit amet euismod sit amet, aliquam vitae libero. Proin imperdiet purus rutrum neque ultricies volutpat. Aenean dignissim at sem et laoreet. Nulla blandit nisl nec condimentum egestas. Vivamus feugiat viverra scelerisque. Maecenas molestie vulputate turpis, eu vestibulum urna malesuada in. Quisque porttitor quam ante. Aenean eu efficitur diam. Aenean purus justo, ultricies luctus orci posuere, dapibus placerat eros. Suspendisse hendrerit molestie libero quis blandit. Nullam dapibus urna vitae aliquet facilisis. Etiam ligula libero, interdum vel lorem non, aliquet auctor tortor. Nullam tincidunt nulla eget nunc pulvinar, non congue sapien gravida. Aliquam finibus quam sit amet scelerisque pharetra. + +Etiam at ornare metus, id sodales lorem. In nec sollicitudin mauris. Donec turpis tellus, sodales nec luctus in, vestibulum vel tortor. Curabitur luctus lorem at tellus eleifend consectetur. Sed facilisis libero in tincidunt consectetur. Vivamus nulla dolor, posuere et turpis at, fringilla blandit mi. Aenean tincidunt lorem vitae tellus semper, ut finibus turpis imperdiet. Aliquam ac diam sapien. Integer ultricies ullamcorper varius. Etiam pellentesque, lacus quis lacinia varius, massa lectus tempor turpis, id imperdiet nunc elit in purus. Sed fringilla ipsum eget velit eleifend imperdiet. Donec et enim erat. Aliquam sed orci tincidunt, porttitor lacus sit amet, fermentum neque. Fusce aliquet eros non faucibus hendrerit. In consectetur neque sem, id viverra nibh ultricies eget. + +Morbi tristique eu arcu ac laoreet. Ut orci tellus, gravida quis neque ac, auctor rutrum neque. Vivamus vitae risus nibh. Sed mollis vel ante et egestas. Aliquam eget bibendum orci. Proin ultricies mauris purus, vel mattis orci eleifend quis. Duis et eros ut tellus vulputate feugiat. Suspendisse potenti. + +Nam in urna quis est ornare semper at nec urna. Morbi ex lorem, hendrerit quis mauris vel, elementum hendrerit lorem. Maecenas ac euismod justo. Sed leo ante, sollicitudin sed leo sed, tristique laoreet lacus. In hac habitasse platea dictumst. Nam rutrum sagittis lectus. Vivamus aliquet maximus nisl, nec mollis sapien pellentesque vitae. Fusce sit amet lectus nisi. Curabitur egestas gravida aliquam. Cras venenatis lobortis faucibus. Curabitur sit amet rhoncus mauris. Maecenas nec ante suscipit erat tempus vehicula. Nunc eleifend nibh imperdiet urna euismod sagittis. Aenean imperdiet id sem vitae semper. + +Curabitur tristique porta ullamcorper. Cras at enim massa. Suspendisse ac rhoncus ante, in lobortis est. Etiam sit amet ullamcorper odio. Praesent volutpat vulputate lectus non faucibus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam congue sed orci vitae laoreet. + +Etiam elit ligula, hendrerit non finibus in, pulvinar eu lectus. Quisque pretium maximus augue sit amet lobortis. Pellentesque condimentum, nulla vitae dignissim pretium, diam neque semper purus, vel tincidunt ante neque a eros. Phasellus ac finibus tellus. In vel aliquet nisl. Nulla a orci a leo ultricies rutrum sit amet vitae dolor. Proin et faucibus tortor, quis hendrerit purus. Quisque maximus eleifend massa, vel facilisis ligula interdum eget. + +Phasellus varius gravida urna, in lacinia nisl posuere in. Aliquam iaculis sapien nisl, eu vehicula nisi hendrerit sit amet. Nam molestie, metus vitae maximus vestibulum, arcu est fermentum nisi, sit amet lobortis ante velit sit amet neque. Nulla vitae ultricies arcu. Pellentesque tincidunt tellus nibh, gravida vulputate justo vulputate quis. Maecenas ornare ante felis, et fermentum elit pretium eu. Quisque tellus sem, dignissim a ex vel, vestibulum porta nibh. Morbi pharetra iaculis dictum. Curabitur pharetra odio sed tincidunt congue. Fusce pellentesque nec felis sodales luctus. Fusce rutrum vitae ligula non sodales. Etiam aliquam suscipit neque, ut eleifend libero. + +Aenean sed euismod lorem. Sed pulvinar ex cursus, hendrerit lectus at, viverra urna. Cras at ligula eu lectus congue viverra. Ut eget pretium risus, non scelerisque enim. Integer eu venenatis risus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus nec pellentesque mauris. Aenean dapibus tempus nisi in pellentesque. Praesent mattis placerat nulla at blandit. Nulla ac consequat eros. Maecenas risus libero, hendrerit vitae dui quis, efficitur pretium nisl. Morbi in quam aliquet, mattis arcu a, rutrum purus. Donec ac sapien bibendum, elementum diam in, ornare felis. Nulla in volutpat felis. + +Nunc tempor ultricies massa, eu fringilla nisl molestie vitae. Vestibulum in pharetra lacus. Aenean nec tortor egestas, elementum risus interdum, suscipit lacus. Nam quis efficitur mauris. Duis egestas nunc semper urna euismod fermentum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque a quam turpis. In varius mauris sed iaculis lacinia. Nam ut nisl vel sem interdum consequat nec id risus. Suspendisse vel varius libero. Praesent vel cursus dolor, sed venenatis nunc. Cras justo tortor, accumsan eget tincidunt sit amet, lacinia vitae elit. Sed suscipit est risus, ornare tincidunt dolor interdum molestie. Etiam sit amet nunc a tortor laoreet laoreet. + +Aliquam sed orci venenatis, efficitur turpis ac, egestas neque. Integer arcu justo, condimentum et fermentum vitae, congue sit amet est. Fusce scelerisque posuere dui sed pharetra. Donec id sem sit amet velit mollis facilisis. Morbi rhoncus libero sed tellus efficitur porttitor. Cras id lobortis dolor, in commodo quam. Pellentesque molestie, lacus sit amet dignissim auctor, dui massa vestibulum dolor, sit amet luctus massa mi eu massa. Nullam fringilla, arcu et placerat rutrum, augue tortor fermentum quam, vitae accumsan est enim nec justo. Quisque lobortis commodo sapien, vel venenatis lorem volutpat vehicula. Fusce porta nisi ac odio commodo, quis commodo mi scelerisque. Nunc a volutpat est. Vestibulum dictum feugiat turpis ut finibus. Sed vitae dictum sem. Praesent sollicitudin nulla ultrices ipsum bibendum vulputate. Maecenas tempor augue bibendum erat maximus porttitor. + +Vestibulum ut ipsum orci. Pellentesque non lacinia nisl. Nam sed velit tempor, malesuada diam id, lacinia lacus. Nam dictum rhoncus lectus ut porta. Pellentesque et turpis ac orci dictum sodales quis ut orci. Suspendisse eget mollis risus. Mauris fermentum tellus at neque luctus, sed tincidunt diam sollicitudin. + +Proin cursus odio et aliquet porta. Vestibulum a odio pulvinar, hendrerit orci condimentum, ornare risus. Quisque pulvinar, sem at placerat porttitor, leo sem malesuada augue, mattis finibus diam velit eget urna. Fusce cursus augue sit amet arcu faucibus scelerisque. Sed nec ullamcorper ipsum, vitae tincidunt dui. Integer eget eros leo. Suspendisse eleifend lorem nec fringilla semper. Etiam elementum ipsum eget nibh vulputate, vitae consequat ligula porta. Nulla pharetra augue sit amet magna tincidunt sodales sit amet vitae eros. Etiam euismod rutrum ligula et sodales. Vestibulum ultrices arcu quis lobortis consequat. Vestibulum fringilla mattis arcu et pharetra. Nunc enim metus, efficitur imperdiet vestibulum sed, pulvinar eget arcu. Ut est odio, condimentum a scelerisque ut, tempor ac erat. + +Aliquam diam nulla, aliquet non mi eget, dignissim eleifend risus. In a gravida turpis. Duis blandit justo vitae tempus lacinia. Cras placerat, ipsum eu rutrum placerat, massa lectus ullamcorper nibh, ut facilisis lacus massa a ligula. Praesent vulputate, massa at consectetur eleifend, ante magna rutrum orci, ac interdum risus lectus ut metus. Donec eu leo nisi. Cras vulputate aliquam lacus vitae tempor. Quisque dolor nibh, tristique et imperdiet vitae, bibendum ut lorem. Nulla vel orci in ante dictum dictum a eget turpis. Vestibulum eget lorem sit amet nunc scelerisque consectetur vitae ut diam. Sed aliquam sagittis ante quis lobortis. Aliquam a elit fringilla, laoreet eros sed, accumsan est. Nullam vitae sollicitudin ex. + +Sed nibh lorem, eleifend quis gravida vel, posuere sed mi. Nullam eget enim lacinia, gravida leo nec, viverra felis. Aenean ac euismod mi. Duis congue, turpis in lacinia dapibus, eros mauris rutrum odio, a congue nunc enim sit amet mauris. Sed in lacus sed velit tempor congue. Suspendisse potenti. Nam et justo lorem. Vivamus dictum sapien eu sapien fermentum, nec finibus augue ultricies. Nunc sodales, urna vitae fringilla scelerisque, quam felis consequat sapien, ut venenatis elit magna vitae lectus. Donec porta condimentum leo eget feugiat. Fusce vulputate mauris tellus, ac vehicula sapien viverra ut. Nullam ac cursus tortor. Maecenas nec facilisis sem. Pellentesque dapibus sed libero vitae cursus. Vestibulum a semper quam, nec finibus tortor. + +Fusce consequat odio eu est aliquam dictum. Aenean ut blandit lacus. Donec pulvinar, mauris et euismod aliquam, metus mauris aliquam ex, a convallis lacus mi a lorem. Aenean eleifend mattis nulla, nec facilisis mi feugiat sed. Maecenas vitae interdum nisl. Vivamus vel mi ac nibh finibus congue. Sed tristique enim ut sollicitudin pulvinar. Maecenas quis accumsan felis. Quisque eget pulvinar quam. Suspendisse pellentesque velit ipsum, in pharetra ligula rutrum ac. Vivamus mattis sollicitudin condimentum. + +Maecenas eu metus vestibulum, sodales tortor vel, aliquet arcu. Integer lorem velit, fringilla facilisis blandit vel, interdum quis massa. Morbi non dui quam. Donec ante diam, tempor nec pharetra nec, ultricies at tortor. Donec ut nibh nibh. Mauris eu orci eget mi convallis porta in sed metus. Suspendisse potenti. Phasellus ullamcorper, purus et rutrum facilisis, quam turpis euismod tellus, nec rhoncus enim risus at ex. Ut tincidunt tempus eros non ornare. Mauris eu vehicula velit, quis posuere urna. Donec lectus est, blandit id rutrum non, accumsan nec justo. Mauris ut mollis tortor, sit amet ornare est. + +Phasellus rhoncus fermentum mauris, in pulvinar arcu rhoncus ut. Curabitur id pharetra orci, sed semper lorem. Cras convallis tempus nibh sit amet sollicitudin. Integer nec sollicitudin dui, non ultrices metus. Ut aliquet ex non arcu dignissim venenatis. Mauris elit massa, pellentesque ac tristique nec, porttitor eget nisi. Nunc at libero nisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; + +Sed pharetra sagittis interdum. Vestibulum sit amet mauris nec nunc mollis malesuada quis vitae nulla. Vestibulum consequat felis ac lorem tincidunt, ut ullamcorper leo posuere. Etiam commodo augue sit amet lacus congue mattis. Aenean nibh nunc, dignissim pulvinar arcu quis, venenatis placerat est. Proin tellus nibh, vestibulum id facilisis iaculis, facilisis in justo. Mauris libero erat, consequat eget finibus ut, tristique nec magna. Etiam quis mi non tellus feugiat fringilla. Ut pulvinar nibh nulla, ac viverra massa dictum semper. Ut non sollicitudin dui. + +Mauris convallis sem a eros suscipit, ut mattis quam pretium. Vestibulum sed elit dapibus, ullamcorper risus faucibus, pharetra felis. Proin libero massa, fermentum a imperdiet scelerisque, dapibus ut sem. Fusce id arcu nec leo bibendum laoreet eget sed sem. Nunc ac elementum ipsum. Nullam felis magna, sollicitudin quis justo vel, bibendum eleifend neque. Phasellus vestibulum nulla ac suscipit pharetra. Praesent rutrum odio id leo malesuada aliquet. Aliquam lorem lacus, feugiat non ultrices nec, venenatis varius ipsum. Proin a metus vitae felis ullamcorper auctor. Proin vitae blandit massa. Ut at tellus interdum, pretium mi id, ultrices augue. Nam rutrum risus tristique dui eleifend, non venenatis turpis dictum. Suspendisse nec mattis nulla. Nunc id enim orci. + +Nullam et sollicitudin ex. Ut iaculis consectetur lacus, eu luctus libero fringilla vel. Praesent aliquet libero at erat mollis facilisis. Vivamus tristique posuere diam, vitae interdum tortor accumsan a. Donec arcu est, bibendum eu dictum et, fringilla ac dui. Duis vel erat elit. Fusce fermentum vitae lacus ac auctor. Suspendisse potenti. Donec viverra tortor orci. Sed tempor ultricies sapien, at sollicitudin nunc aliquam eu. + +Nullam eleifend semper justo, at feugiat ex hendrerit sit amet. In vitae ipsum odio. Quisque pellentesque molestie quam, non feugiat quam mollis sed. Etiam accumsan, neque id placerat aliquet, risus tellus tincidunt orci, ut consequat tortor massa vel arcu. Phasellus sed erat et elit iaculis imperdiet. Mauris felis ante, venenatis quis lobortis eget, mollis non ipsum. Donec semper sodales ex vel sollicitudin. Nam ipsum lorem, hendrerit ac euismod non, cursus a tellus. + +Etiam auctor turpis eget lorem malesuada imperdiet et interdum ligula. Nunc dapibus finibus ante, in aliquet nulla. Proin quis ante odio. Mauris eu laoreet neque. Proin varius est sed lacus mollis tempus. In maximus sed nisl at posuere. Vestibulum accumsan urna quis faucibus blandit. Curabitur ornare egestas ipsum ac elementum. Nulla ac justo non enim posuere ornare. Fusce a hendrerit nisl. Fusce laoreet, felis eu mollis blandit, urna elit bibendum felis, ut imperdiet mauris leo ac massa. Fusce fringilla, quam et dictum commodo, dui tellus blandit mauris, sed eleifend dui est ut mauris. Pellentesque ut elit sollicitudin, placerat quam a, pharetra diam. Ut egestas velit ac lacinia sodales. Ut ullamcorper velit non erat suscipit, vel lobortis est ultrices. + +Fusce tristique eros eu mi tincidunt, at vulputate neque tempor. Aenean sit amet arcu a arcu porttitor semper id sit amet nulla. Pellentesque posuere lobortis lorem sed porta. Nullam nibh justo, finibus vitae varius sed, fermentum ut mauris. Nam sed vulputate ante. Suspendisse tristique libero in diam egestas, at varius sapien pulvinar. Vestibulum eu elit nec magna convallis lobortis. Duis a nisi odio. Quisque erat felis, molestie ut hendrerit pretium, consectetur ut risus. Phasellus malesuada maximus lacus vitae scelerisque. Nulla facilisis urna non ipsum mattis fermentum. Etiam semper quam ut ipsum euismod luctus. + +Ut sed feugiat ipsum. Nam quis bibendum enim, quis sollicitudin urna. Ut pharetra, leo ac feugiat pellentesque, libero diam tempus sapien, et pretium ex lacus a eros. Vestibulum sed augue nisl. Nunc id malesuada neque, quis rhoncus purus. Suspendisse nulla dui, sagittis luctus sapien quis, iaculis feugiat odio. Sed venenatis accumsan neque, sit amet tempus leo sodales id. Etiam eleifend, magna vel rutrum porta, sem quam ornare eros, vel tincidunt arcu ex a ligula. Ut a consequat dui. Aliquam vestibulum id felis a aliquet. Nullam sit amet arcu a orci lobortis tincidunt sed eget ante. In interdum, metus aliquet posuere lobortis, lectus tellus tristique elit, ultricies dictum erat ex a leo. Nulla lacinia, neque id volutpat pharetra, ex neque luctus tellus, eu blandit turpis magna mollis ipsum. + +Suspendisse nec maximus dui. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas felis justo, hendrerit eget turpis sit amet, dignissim hendrerit libero. Maecenas a leo nunc. Donec sit amet sem pellentesque, eleifend risus a, rutrum dui. Praesent diam libero, egestas a eros non, posuere varius augue. Integer ipsum eros, dictum viverra lectus a, condimentum aliquam orci. Ut tristique quam non mollis mollis. Vivamus a placerat tellus, vel vehicula orci. Praesent ac tempus felis, laoreet venenatis eros. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam turpis nunc, posuere et arcu ut, lacinia pellentesque sapien. Quisque sagittis sit amet erat sed tincidunt. Curabitur id tempus eros. Sed suscipit a nibh vitae interdum. Mauris sapien velit, cursus in justo eu, sollicitudin dapibus tellus. Vivamus et feugiat massa. Phasellus mattis vulputate imperdiet. In ut gravida massa. In eu elit diam. Cras nec urna tincidunt, ornare lorem at, aliquet magna. Sed maximus tortor ipsum, quis maximus nunc sagittis eu. Cras pellentesque eu nulla nec mattis. Morbi suscipit sed neque sed auctor. Pellentesque dignissim tellus vel neque gravida, nec vestibulum nulla eleifend. + +Fusce tristique gravida purus. Curabitur laoreet augue nec metus auctor, ut mollis nisl suscipit. Nullam eget commodo erat. Quisque vitae lobortis lorem. In hac habitasse platea dictumst. Etiam eu orci facilisis, efficitur eros eget, posuere ante. Quisque in risus in orci convallis porttitor. Cras eleifend fringilla dictum. Pellentesque ut orci leo. Aliquam tincidunt condimentum dapibus. Donec vitae leo sed dolor tempor sagittis id ut odio. Aenean mollis tristique commodo. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque pretium viverra magna, eu feugiat tellus porttitor in. Nulla erat felis, sagittis quis dolor ac, aliquet pharetra metus. + +Etiam nec viverra lacus, nec gravida metus. Phasellus ipsum ex, malesuada sed pretium eu, ornare nec tortor. Ut eu leo sit amet elit euismod placerat. In porta ante et accumsan porta. Donec hendrerit ac libero sed facilisis. Proin bibendum justo vel vulputate tincidunt. Vestibulum molestie neque tortor, at elementum leo pulvinar in. Sed rhoncus malesuada risus, ut sagittis odio posuere vel. Vestibulum faucibus rhoncus nibh ut porta. Donec elementum urna consequat, scelerisque tortor in, bibendum lacus. Nulla erat nunc, lacinia at lobortis a, maximus eu dolor. Fusce viverra, erat semper placerat egestas, sapien diam lobortis urna, sit amet semper mauris est in risus. Cras eget porttitor massa. + +Fusce eget cursus neque. Donec erat elit, mattis sit amet faucibus in, dignissim eget arcu. Praesent sem erat, porttitor ut hendrerit sed, fermentum sed nisl. Suspendisse efficitur facilisis condimentum. In efficitur purus tortor, a pulvinar dolor venenatis quis. Proin consequat, risus nec condimentum placerat, quam massa dignissim mauris, at semper purus lorem et nunc. Phasellus luctus dictum ante, quis vestibulum eros auctor eu. Proin quis nisi quis ligula convallis rhoncus. Suspendisse id eros vitae neque efficitur malesuada. Praesent sit amet tincidunt lectus. In ante elit, blandit vel faucibus quis, aliquet euismod purus. Duis eu purus volutpat, porta ante sit amet, efficitur augue. Donec congue a risus quis malesuada. Aenean sed est sollicitudin, efficitur enim nec, viverra quam. + +Sed vel iaculis leo. In lobortis accumsan lacus sit amet sollicitudin. Donec vel porta purus, vel vulputate est. Maecenas volutpat nisl id accumsan pellentesque. Vestibulum posuere id lorem sit amet faucibus. Aenean dictum lectus lacus, varius semper dolor cursus nec. Aliquam a tortor nisl. Maecenas sit amet diam fringilla, sodales nulla vel, iaculis lectus. + +Cras pulvinar mattis faucibus. Pellentesque semper, felis vel elementum porttitor, mi ex vestibulum libero, a rhoncus ante libero at dolor. Pellentesque maximus lorem vel massa venenatis cursus. Maecenas sed facilisis orci, vel consectetur ligula. Sed porttitor tellus magna, in placerat enim tristique sit amet. Curabitur leo lectus, fringilla dignissim augue quis, scelerisque posuere nunc. Ut sollicitudin massa ac facilisis dictum. Proin et nulla gravida, auctor ante ut, accumsan massa. + +Vestibulum faucibus lectus eget eleifend tristique. Aliquam tristique felis quis metus pretium, sed egestas sem mattis. Pellentesque ac enim at mi fermentum lacinia non eget tellus. Proin lacus enim, imperdiet et turpis sed, viverra auctor leo. Nam augue ante, tristique a neque ut, ullamcorper tempor tellus. Curabitur porttitor ornare lectus vel commodo. Nunc luctus, purus et cursus viverra, dolor magna condimentum libero, maximus tristique lacus felis vel ligula. Phasellus lacinia faucibus leo, id pretium ipsum suscipit quis. Fusce mollis enim sed augue bibendum vehicula. Nunc mollis lorem vel erat molestie, non hendrerit id. diff --git a/bdd/data/sequences/persistentSeq/tsconfig.json b/bdd/data/sequences/persistentSeq/tsconfig.json new file mode 100644 index 000000000..55d97646a --- /dev/null +++ b/bdd/data/sequences/persistentSeq/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "lib": [ + "ESNext" + ], + "target": "ESNext", + "module": "CommonJS", + "outDir": "./dist", + "esModuleInterop": true, + "resolveJsonModule": true + }, + "include": [ + "./src", + "./test" + ], + "exclude": [ + "**/node_modules", + "**/*.spec.ts", + "dist" + ] +} \ No newline at end of file diff --git a/bdd/data/test-data/loremIpsum.txt b/bdd/data/test-data/loremIpsum.txt new file mode 100644 index 000000000..1576c6cdb --- /dev/null +++ b/bdd/data/test-data/loremIpsum.txt @@ -0,0 +1,335 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla quis massa velit. Nam quis luctus purus, in iaculis ligula. In eu iaculis arcu, in commodo urna. Sed ut libero vitae nunc luctus tristique. Cras mollis malesuada ornare. Aliquam a sem ut ex facilisis sollicitudin. Nulla facilisi. Quisque ut varius ligula. Sed porttitor ex a porttitor feugiat. Morbi a tortor tempus diam dignissim blandit. Etiam nec rutrum tortor. Phasellus orci elit, cursus id molestie in, ultrices at ante. + +Nulla malesuada tincidunt elit, a gravida dolor placerat vel. Curabitur molestie sed enim eu egestas. Curabitur maximus malesuada vehicula. Suspendisse vitae gravida est. Sed pharetra fringilla lacus, sit amet convallis turpis tincidunt at. Quisque euismod rhoncus pulvinar. Donec sed ante in felis auctor posuere. + +Quisque nisi velit, ornare eget dictum vel, aliquam in nisl. Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse et nulla ligula. Nam ac ligula vitae tortor consequat fringilla. Donec dignissim gravida magna eu aliquet. Nullam dolor velit, sodales vitae turpis ac, molestie congue dui. Aliquam eros nisl, dignissim non lectus a, volutpat convallis odio. Nunc eu nisl sodales, porttitor turpis sed, euismod justo. + +Etiam sit amet lacus molestie, tristique sem sed, mattis est. Sed rutrum ornare massa, nec auctor metus. Cras at tempor arcu. Nunc velit mauris, pretium ut pellentesque non, fringilla nec elit. Ut tempus laoreet pretium. Phasellus placerat diam tincidunt volutpat cursus. Integer tempor massa purus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; + +Maecenas ac blandit lectus. Praesent ut tincidunt ligula. Sed massa urna, luctus ac auctor eget, scelerisque ut nisi. Nulla ipsum lacus, faucibus non elementum vitae, ornare ac libero. Ut quis semper nunc, non luctus sapien. Suspendisse consectetur pulvinar consequat. Nulla consectetur sagittis nunc at sagittis. Aliquam euismod, velit nec tempus porta, odio tortor iaculis libero, eget vulputate ipsum ante ut sapien. Donec sed velit pharetra, accumsan enim quis, ultricies mauris. Vestibulum aliquet fringilla dictum. Suspendisse sed nibh orci. + +Fusce posuere non dolor mollis laoreet. Maecenas aliquet arcu nec odio interdum, vitae interdum quam malesuada. Maecenas tincidunt finibus nisl, at sagittis est fermentum feugiat. Morbi at varius magna. In pulvinar ut leo id hendrerit. Vivamus et luctus odio. Phasellus ultricies bibendum sapien eget laoreet. Aliquam arcu felis, condimentum et metus a, tincidunt volutpat nulla. + +Fusce non ultrices lectus, vel fermentum ipsum. Curabitur dictum dolor a enim cursus maximus. Maecenas nisl erat, mattis commodo mi et, hendrerit vehicula nibh. In lacinia, tellus in gravida bibendum, risus massa iaculis erat, in venenatis diam justo a libero. Suspendisse est nisi, accumsan a aliquam nec, gravida at velit. Pellentesque viverra posuere justo ac ornare. Nulla turpis tellus, lacinia in felis ac, molestie molestie nisl. Nam felis enim, feugiat in eros et, sollicitudin luctus justo. Nullam lobortis eros ut ultrices facilisis. Cras vitae imperdiet nisl, a ullamcorper elit. Nam non orci vitae orci aliquet faucibus. Donec lobortis iaculis turpis, in semper orci tristique ac. Nulla maximus fringilla lectus, at tristique purus imperdiet nec. Donec viverra risus eu vulputate laoreet. Mauris vel congue odio. + +Aenean libero nisi, facilisis laoreet congue eget, rutrum a quam. Ut id molestie velit, sit amet rhoncus sapien. In sit amet ligula ut purus blandit fringilla eu ut tortor. Donec mattis rutrum metus, sit amet feugiat tortor. Nunc dictum vitae elit vel lobortis. Phasellus vel ante blandit, aliquam neque a, sollicitudin turpis. Phasellus tempor nisi eu eros imperdiet accumsan. Donec scelerisque nibh mauris, vel eleifend justo condimentum et. Pellentesque sit amet faucibus libero. Nulla et libero gravida, vestibulum elit at, vestibulum enim. Sed varius, odio sit amet interdum ultrices, lorem enim laoreet urna, a malesuada magna ex at elit. Fusce a faucibus elit. Etiam sagittis tincidunt diam eu malesuada. In varius diam id nisl auctor condimentum. + +Sed consectetur sagittis odio vel bibendum. Sed blandit tincidunt erat non suscipit. Nullam efficitur tincidunt tellus scelerisque gravida. Donec a dictum magna. Aenean in justo sodales, tempor est at, lacinia nulla. Etiam accumsan nec nunc vel tempus. Nam imperdiet ultrices enim, ac tempus sem. Nulla dapibus semper lobortis. Sed luctus lacinia euismod. Quisque luctus orci risus, quis sollicitudin orci malesuada ac. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In iaculis finibus justo dapibus pharetra. Integer at euismod mi, vitae eleifend urna. + +Nulla facilisis purus nulla, non congue nulla euismod quis. Fusce vitae tellus et sem venenatis iaculis a vitae ex. Aliquam sollicitudin condimentum metus. Aenean consectetur iaculis ligula nec maximus. Mauris ex ipsum, dignissim sed rutrum in, commodo sed libero. Suspendisse fermentum massa sed nunc tempus auctor. Pellentesque imperdiet neque sapien, suscipit luctus enim scelerisque in. Aliquam erat volutpat. Curabitur ac arcu placerat, vehicula neque vel, vestibulum dolor. Vivamus sed vehicula erat. Vivamus pellentesque non tellus in consequat. Etiam commodo, tellus eu vehicula pretium, odio ex ornare leo, et euismod orci velit et augue. Aliquam faucibus risus quis sapien fermentum, eget consectetur lorem lacinia. Nam ac gravida est. In hac habitasse platea dictumst. Mauris varius suscipit turpis ac cursus. + +Morbi et varius metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In congue ipsum neque, ut euismod sapien dignissim a. Maecenas faucibus orci ac viverra vulputate. Ut pellentesque leo at ante gravida, sit amet fermentum ipsum fringilla. Maecenas in interdum risus, non vehicula dolor. Quisque non eros arcu. + +Aliquam ligula tellus, dapibus ac rutrum non, gravida eget arcu. Vestibulum turpis turpis, pellentesque vel sollicitudin sit amet, molestie ac justo. Cras sit amet augue erat. Nullam pellentesque elementum mattis. In hac habitasse platea dictumst. Nulla ac eros ut eros porta sodales. Phasellus tincidunt, felis non mollis suscipit, sem mauris tempus ligula, et posuere mi nulla aliquet eros. Phasellus porttitor pretium tortor et porttitor. Donec vel libero scelerisque urna scelerisque tempus in a purus. Phasellus commodo commodo tristique. Curabitur egestas porttitor odio, et viverra enim. Aliquam semper quis nisl ac tristique. + +Fusce sed tincidunt augue. Etiam fringilla posuere finibus. Aliquam fringilla mollis purus vel hendrerit. In a varius lorem. In aliquet in tortor at convallis. In mattis tempus facilisis. Phasellus pretium nisl vel purus gravida, commodo imperdiet odio pharetra. Duis viverra porta magna nec viverra. Suspendisse at metus metus. + +Mauris congue ullamcorper tortor, id tempus tortor luctus blandit. Sed quis volutpat erat, id elementum lacus. Fusce euismod lacus in euismod egestas. Cras eu diam faucibus, facilisis magna quis, semper magna. Sed fermentum purus eget ex egestas, vel euismod dolor elementum. Nullam faucibus dignissim consectetur. Fusce ut magna risus. Etiam sapien est, elementum quis sapien et, ullamcorper vulputate arcu. Sed in nisl nec leo lacinia feugiat ac in mauris. Morbi dapibus augue metus, id fringilla metus accumsan non. Donec eleifend lacus sit amet venenatis ultricies. Etiam a aliquet tellus. Vivamus nec pellentesque arcu. + +Integer nec nulla sit amet sapien iaculis vestibulum. Aenean a urna aliquam, dignissim dolor eget, vestibulum orci. Nullam tristique leo nulla, et placerat quam gravida semper. Nunc dignissim nisl non augue pellentesque, non interdum sem volutpat. Sed lobortis, sem non pharetra consectetur, ante tortor porta justo, sit amet efficitur tortor ligula id neque. Donec a feugiat quam. Sed vel viverra augue. In interdum mattis tellus, quis sodales ex auctor eget. Curabitur tellus est, mattis eu fermentum sit amet, tincidunt ut nisi. Maecenas auctor lacinia leo at tempor. Integer sed dui et metus ullamcorper pretium. Proin mollis enim ac ex dapibus, vel rhoncus diam euismod. Mauris porttitor lacus ligula, non tristique magna porttitor et. Vestibulum volutpat aliquet enim sit amet mattis. + +In rutrum lobortis efficitur. Sed eget velit augue. Nunc sodales tortor ut sodales finibus. Integer mollis imperdiet lacus at ornare. Donec volutpat et dui mattis vulputate. Aenean sollicitudin turpis viverra pretium dictum. Sed vel gravida nunc. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae faucibus odio. Quisque viverra leo elit, a scelerisque velit efficitur non. Maecenas interdum, justo sed placerat vehicula, justo massa laoreet quam, porttitor vestibulum justo ante vitae est. Sed vitae metus non felis aliquet pharetra. In eleifend est sit amet turpis vehicula sodales. Sed posuere rhoncus sem, pellentesque dignissim eros vehicula id. Quisque vel elit metus. Cras vehicula dictum elit, semper viverra dolor blandit id. + +Phasellus egestas, urna nec congue posuere, purus lacus sagittis ex, eu iaculis sapien quam ut nulla. Nunc bibendum pulvinar nunc vel tempor. Nam varius luctus mollis. Nam lectus nibh, ullamcorper vel orci id, vulputate ornare augue. Aenean gravida nisi vel orci blandit, vitae fringilla sem dapibus. Nullam lobortis odio nec turpis luctus, sed suscipit neque vulputate. Mauris sed mauris dapibus lorem cursus faucibus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas quis ultricies enim. + +Suspendisse eu laoreet mauris. Curabitur sit amet faucibus arcu, ut feugiat justo. Integer in purus ut nulla vehicula mollis et sed tortor. Praesent pulvinar, leo posuere elementum rhoncus, justo ante ultricies ante, eu accumsan lorem elit vitae augue. Etiam vel posuere ipsum, sed auctor risus. Praesent gravida nulla congue, tempor urna sed, interdum velit. Aenean imperdiet, turpis sed venenatis facilisis, nunc ex aliquet dui, at facilisis purus nulla id nunc. + +Fusce non ante sed ipsum lacinia lacinia gravida dignissim augue. In hac habitasse platea dictumst. Nulla fermentum lorem eu sodales feugiat. Etiam aliquet ut nulla nec fermentum. Maecenas et suscipit magna. Vivamus vehicula aliquet nisi quis rhoncus. Integer mattis porttitor enim, ac tincidunt libero malesuada at. + +Nam ac dui et neque ornare euismod. Suspendisse ultricies orci enim. Sed eu euismod leo. Duis condimentum risus risus. Suspendisse id sollicitudin ex. Sed eu massa at magna iaculis mattis vel id est. Donec at bibendum libero. Aliquam congue maximus urna ac pharetra. + +In pretium lectus sit amet maximus varius. Vestibulum id massa pretium, fermentum nulla sed, aliquet turpis. Quisque tincidunt ante vitae massa viverra iaculis. Donec consequat sem sit amet fringilla auctor. Fusce a nunc sollicitudin, tristique erat sed, bibendum sem. Sed eu mollis ex. Pellentesque fermentum nisl tellus, tristique imperdiet odio vehicula eu. + +Cras ullamcorper pulvinar dictum. Aliquam eget accumsan felis. Pellentesque semper, nisl id molestie bibendum, eros tortor feugiat magna, non pretium tortor massa ut quam. Donec blandit pulvinar quam, vitae faucibus ex finibus sit amet. Sed ut libero cursus, viverra dolor eget, pharetra eros. Ut dignissim dui eget risus iaculis mattis. Pellentesque at mi lacus. Curabitur auctor eget nunc id rhoncus. Fusce odio lectus, vestibulum vel ante nec, lacinia iaculis ex. Duis eget orci fringilla, aliquet neque at, gravida leo. Maecenas eget nunc in ligula convallis ultricies fringilla in lorem. + +Curabitur tristique nisl sed turpis luctus, eget ultricies lorem sodales. Praesent viverra, eros tincidunt vehicula venenatis, nisi dui malesuada sapien, et fermentum dui turpis quis purus. Praesent porttitor sed velit quis dapibus. Donec aliquet diam sed gravida efficitur. Suspendisse vel quam congue, mattis ex et, pretium ex. Fusce ex sapien, faucibus et sapien quis, ornare accumsan urna. Phasellus nec nunc et nisi pulvinar consectetur. Suspendisse potenti. Nam a urna et enim iaculis consequat eu sit amet quam. Phasellus suscipit nisl est. Nulla vulputate ipsum orci, sed finibus ipsum sollicitudin et. Curabitur pellentesque pellentesque vehicula. Nullam finibus dui nec velit ornare semper. + +Vestibulum odio mauris, dignissim sed rutrum nec, tristique vel libero. Nam a dictum erat. Ut nec nisi in justo consectetur sollicitudin. Sed pretium est eget ligula maximus sollicitudin at eu nisl. Etiam congue enim a nulla fermentum ullamcorper. Pellentesque aliquet justo vel nunc hendrerit facilisis. Vivamus non leo elit. Nam a euismod felis. Nam dignissim tellus at ligula maximus, a pellentesque nibh euismod. Nam aliquam erat lectus, nec sollicitudin neque ultricies et. In id hendrerit arcu. + +Mauris imperdiet consequat elit vel mollis. Aenean dapibus, orci nec imperdiet porta, enim ligula gravida orci, eu porttitor sem mauris et ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Maecenas luctus augue in dui consectetur tempus. Vivamus sit amet est turpis. Quisque non iaculis erat, ut convallis massa. Vestibulum laoreet arcu eget venenatis tempor. Integer pretium sodales lectus et suscipit. Vivamus auctor ultricies suscipit. Aenean accumsan magna at euismod consectetur. + +Nulla eu risus erat. Cras pellentesque commodo ligula, id tempor neque vulputate nec. Integer lobortis, est id tincidunt gravida, lorem ante lacinia nisi, gravida consectetur massa massa eget metus. Nulla a maximus lacus, et sodales elit. Curabitur et arcu diam. Fusce blandit commodo nunc, ut ornare massa mattis nec. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla facilisi. Ut feugiat ante enim, eu vulputate urna egestas ut. Quisque ante nulla, volutpat vitae mauris ac, euismod auctor metus. Nulla a sodales mi, eu ornare lorem. Quisque fringilla, mi vel pulvinar rhoncus, magna tortor euismod ipsum, sed scelerisque urna velit pretium turpis. Mauris porta augue non imperdiet lobortis. Maecenas faucibus tempor dolor eu interdum. Fusce venenatis laoreet enim, sit amet sagittis leo fringilla a. + +Etiam ac dui at magna vulputate posuere faucibus scelerisque orci. Morbi ut rhoncus arcu, quis pellentesque leo. Nunc sed justo ut quam ultrices lacinia. Donec dictum tristique scelerisque. Mauris vel rhoncus justo. Nunc faucibus molestie dignissim. Vivamus ac auctor nisl. Nunc et nisi id elit gravida suscipit. Nulla auctor, urna nec pretium ultricies, neque neque tincidunt mi, ac venenatis odio felis euismod sapien. + +Nullam aliquam erat quis mi aliquet, ac ultricies enim convallis. Suspendisse interdum maximus ante, vel laoreet urna malesuada ac. Nam iaculis in purus accumsan porttitor. Fusce elit ipsum, ultricies dapibus nisl ac, ullamcorper placerat ligula. Sed in risus urna. Nunc bibendum nisi dignissim libero ultricies mattis. Curabitur tempus mi quis libero pharetra volutpat. Maecenas molestie aliquam velit, eget scelerisque magna ullamcorper ac. Suspendisse quis sagittis leo, quis malesuada quam. Proin nec dolor ac odio consequat euismod nec sed ipsum. Nunc purus diam, sagittis sit amet nibh in, egestas pulvinar quam. Etiam efficitur purus nec mattis molestie. Aenean nec dolor eu neque lobortis pellentesque ut sed leo. + +Cras ornare sodales est, ut fermentum tellus varius sed. Quisque elit enim, egestas quis orci eget, ultricies sagittis turpis. Aliquam erat volutpat. Suspendisse potenti. Etiam sit amet porttitor dolor, vel posuere quam. Aliquam in est lobortis, gravida justo quis, elementum augue. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed at metus risus. Suspendisse tincidunt volutpat felis ac condimentum. Pellentesque ligula sem, pharetra mattis leo nec, euismod dapibus nunc. Vestibulum blandit enim erat, sit amet aliquet velit venenatis rutrum. Donec non mattis odio. Suspendisse massa nisl, auctor sagittis orci a, pulvinar sollicitudin dolor. Donec quis malesuada augue, in imperdiet justo. + +Sed porttitor dignissim ultricies. Nam elementum metus in pulvinar mattis. Cras mauris mauris, tempor in sagittis id, aliquam sed lacus. Duis congue faucibus fermentum. Sed sollicitudin lacus sed orci semper faucibus. Maecenas porttitor fringilla velit, ac vehicula ipsum commodo et. Quisque sapien libero, varius sed neque ac, pretium consectetur tellus. Nulla mi magna, accumsan ac facilisis id, fermentum nec mauris. Vivamus venenatis sem sit amet est imperdiet, efficitur fringilla risus posuere. Cras sagittis congue blandit. + +Ut eget libero tincidunt, malesuada augue quis, malesuada enim. Mauris placerat bibendum lorem, quis ullamcorper diam pulvinar sit amet. Morbi ex augue, tempus sit amet metus vitae, pulvinar egestas tortor. Maecenas pellentesque ultrices venenatis. Sed ornare vitae purus a aliquam. Aenean malesuada consequat tellus, sit amet sodales nisl placerat nec. In hac habitasse platea dictumst. + +In in posuere urna. Sed pharetra dignissim tortor, ac condimentum ante rhoncus ut. Quisque convallis pharetra diam, at accumsan magna eleifend eget. Praesent sollicitudin ligula eu massa vestibulum, eu vestibulum libero tincidunt. Quisque cursus porta lorem a dapibus. Phasellus elit arcu, elementum at ante at, malesuada lacinia massa. Aliquam hendrerit purus vitae mi mollis, at vulputate felis pulvinar. Praesent finibus sit amet lacus at pellentesque. Proin a ultrices nibh. Etiam a pharetra ex. Praesent vitae neque id nisl egestas commodo eget quis nunc. Maecenas porttitor varius tellus, at consectetur est. Aenean maximus lectus at turpis placerat sodales. + +Morbi sapien ipsum, facilisis blandit leo blandit, posuere tincidunt nisi. Sed venenatis lectus quis cursus vulputate. Ut dapibus tincidunt mauris id aliquam. In vulputate eu arcu vitae pretium. Duis malesuada orci orci, et ullamcorper ante mollis eget. Quisque egestas, orci in interdum laoreet, libero neque cursus lacus, nec porta quam magna ac nulla. Nullam mattis porta eros sed aliquam. Donec nisi tellus, luctus at pharetra ac, accumsan at lacus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Praesent fringilla malesuada turpis, sed venenatis elit rutrum sed. Nulla enim lectus, egestas sed tempus sagittis, cursus eu tellus. Nulla facilisis sem eget lobortis lacinia. Vivamus euismod risus at dictum iaculis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Praesent finibus placerat nunc. Proin accumsan iaculis nisi nec malesuada. Vivamus quis dolor id ipsum ultrices lobortis. Duis fringilla ultricies est, non tincidunt turpis porta quis. Proin mollis tellus elit, nec porta neque aliquam eu. Suspendisse feugiat porttitor urna. Praesent lobortis lacinia vulputate. Nulla ex odio, vehicula et fermentum eget, posuere sit amet quam. Proin imperdiet felis vitae ante vehicula cursus. Mauris in sem in urna lobortis tincidunt. Fusce porttitor pharetra posuere. Phasellus nec semper tortor. + +Praesent quis felis odio. Sed et erat ac turpis pellentesque ullamcorper. Nam iaculis massa eget varius vulputate. Etiam varius odio vulputate felis sollicitudin dignissim. Praesent augue turpis, hendrerit a mi vitae, vehicula blandit nulla. Vestibulum vel tristique ligula. Mauris dignissim vitae sem sed suscipit. Fusce sollicitudin lacinia est ac volutpat. Suspendisse rhoncus bibendum lobortis. Nullam laoreet sapien fringilla ante mollis dapibus. Vestibulum eu nisl augue. + +Cras lobortis in massa vitae gravida. Nullam at fermentum massa, eu pellentesque tellus. Suspendisse non porttitor lectus. Cras quis risus purus. In pretium felis at accumsan condimentum. Vivamus facilisis eu eros et condimentum. Proin erat sapien, pulvinar in fermentum eget, dictum euismod neque. Morbi mattis lobortis purus, eget tempor tortor efficitur nec. Proin vitae sapien quam. Nam sed purus vel nibh volutpat aliquam. Proin in leo nisl. Integer finibus nisl vel nibh egestas, ut tempor risus bibendum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque feugiat venenatis quam, sit amet dignissim lorem varius vitae. Duis est orci, interdum non orci at, condimentum tempor nibh. Nullam elementum erat in sapien finibus, vitae placerat nisl accumsan. + +Nulla facilisis diam id turpis vehicula, et fermentum nisl rutrum. Phasellus at suscipit purus. Cras sit amet auctor leo, eu interdum magna. Duis hendrerit mollis tortor at pretium. Aliquam est lectus, tristique vel condimentum sit amet, scelerisque vitae odio. Cras sit amet luctus libero, et accumsan turpis. Ut diam tellus, tempus vitae ullamcorper in, egestas ac nibh. Proin tristique, odio ut tristique sagittis, ex est elementum arcu, ut laoreet est neque et est. Donec vulputate sapien interdum malesuada vestibulum. Aliquam erat volutpat. Nam sit amet lacus a elit egestas tincidunt. Ut quis lorem varius, lobortis metus nec, accumsan est. Phasellus arcu dolor, faucibus eget facilisis et, finibus vel eros. Cras id quam tortor. + +Suspendisse imperdiet interdum vestibulum. Nunc feugiat laoreet nisl, eget dignissim nibh tristique non. Donec malesuada condimentum mauris, et ullamcorper mi tincidunt feugiat. Nulla facilisis venenatis magna, a iaculis orci ultrices tempor. Nam mollis augue non elit mattis tempus quis vitae velit. Praesent dignissim tempus nunc eu rutrum. Sed placerat turpis eget ligula porttitor, eu pellentesque nulla tincidunt. Mauris eu eros elit. Sed sed accumsan leo, non tristique justo. Nam placerat tristique dolor et imperdiet. Maecenas interdum sapien non cursus mollis. Duis sed erat sollicitudin quam facilisis pharetra eu non orci. Phasellus venenatis mi ac fermentum egestas. Sed aliquam neque porttitor, lobortis erat id, volutpat nulla. Fusce sed nibh quis massa euismod consequat ac sed mi. + +Etiam tortor augue, semper ut dictum vitae, pharetra vitae risus. Curabitur vel aliquam sem, a elementum arcu. Sed rutrum, ligula quis tincidunt cursus, augue mi aliquet arcu, sed euismod massa quam sit amet quam. In mattis a erat vel aliquet. Integer sit amet pharetra magna. Donec massa ante, varius ac eros tempus, auctor fermentum lectus. Aliquam consequat rhoncus orci, ut varius nisl fermentum id. + +Ut ac viverra neque. Aenean tincidunt lorem vel ipsum lacinia, vitae elementum sapien pretium. Pellentesque iaculis tristique tristique. In vitae justo leo. Nam sodales rhoncus eros, a viverra lacus lobortis a. Ut sagittis ligula quis orci molestie volutpat. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nunc id urna eros. Duis enim nulla, porta sed leo sed, placerat mollis nisl. Etiam nisi nulla, eleifend vel bibendum in, viverra et lectus. Aenean aliquet justo ultrices lacus accumsan elementum. + +Proin metus neque, consectetur ut consectetur ac, vehicula in dui. Vestibulum volutpat tortor vitae ligula egestas porta. Praesent et enim dolor. Nullam ante ipsum, posuere sed purus a, lacinia aliquet purus. Donec fringilla dolor ac nisl fermentum, sed aliquam odio consequat. Sed bibendum nisl vitae magna mattis volutpat. Quisque semper nulla efficitur, semper libero vitae, molestie ligula. Sed posuere neque eu aliquam hendrerit. + +Nullam accumsan, turpis a maximus ornare, ante lorem pharetra est, sed molestie turpis magna eget diam. Aenean luctus ac purus congue tempus. Curabitur vel leo et nisl lobortis laoreet eu ut nisi. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed leo arcu, vestibulum vitae velit vitae, viverra cursus velit. Ut ut nulla quis nisl varius bibendum. Donec porttitor a lectus sed ultrices. Suspendisse et consectetur nunc. Mauris at accumsan metus, a suscipit nulla. Phasellus sagittis hendrerit augue, quis scelerisque odio pellentesque at. Integer eleifend, nibh vel rutrum mollis, orci ipsum commodo purus, eget viverra lectus sem quis orci. Integer non justo aliquam, tincidunt nulla vel, fermentum libero. Praesent pulvinar, nisl accumsan placerat semper, lorem lectus sagittis justo, iaculis vehicula elit justo nec erat. + +Etiam ante purus, consectetur vitae pharetra posuere, vulputate ac risus. Donec quis libero consectetur, vehicula erat eu, dignissim arcu. Aliquam laoreet elit id orci pulvinar faucibus. Duis in felis blandit, tempus dolor imperdiet, facilisis dolor. Fusce ac fermentum erat. Vivamus vehicula accumsan ex, id eleifend mauris interdum gravida. Curabitur ut consequat est. Nulla eu lorem vel dui pulvinar consectetur et sed justo. Sed ac arcu et enim scelerisque blandit a sit amet dui. Aenean accumsan nulla in libero convallis, non imperdiet est blandit. Vestibulum rutrum quis risus dignissim malesuada. Phasellus pharetra lacus ut ex porttitor, sit amet convallis quam tempus. Sed in leo nulla. Vivamus convallis dapibus enim, nec dignissim turpis sodales ac. + +Nunc nunc dolor, ultricies vitae lacinia sed, condimentum ac nulla. Nulla cursus pellentesque nibh, vel iaculis ex bibendum tristique. Praesent facilisis diam nec laoreet vehicula. Quisque vel dolor ligula. Pellentesque ullamcorper purus nec velit vestibulum condimentum. Donec eget diam mollis, eleifend sem vel, malesuada dui. Cras faucibus porttitor diam id convallis. Ut rhoncus lectus purus, quis accumsan nisl dictum sed. Nam id turpis quis eros auctor consectetur. Ut mauris nisl, ullamcorper sit amet est a, bibendum interdum dolor. Curabitur porta eros vitae felis commodo, ut auctor augue pretium. Suspendisse potenti. Aenean enim felis, sagittis sed pellentesque vitae, tempus vitae ante. + +Integer hendrerit commodo ante a pretium. Aenean lacinia massa sed mi finibus, sit amet molestie nisl euismod. Suspendisse ligula nisi, porta id viverra sit amet, lacinia ut turpis. Proin dignissim sit amet ipsum sed suscipit. Proin nec justo leo. Mauris elementum rutrum fermentum. Pellentesque laoreet erat non quam imperdiet fermentum. Fusce massa lacus, laoreet vel lacus eget, tincidunt fermentum dolor. Nam sed sodales leo. Curabitur mattis nisl vitae enim tempus placerat. Donec et orci aliquam, gravida metus sed, rutrum felis. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed finibus velit ut lacus sollicitudin suscipit. Cras accumsan elit lorem, eget malesuada mauris rhoncus ut. Donec in velit imperdiet, vehicula arcu ut, placerat mi. Mauris rhoncus mi mauris, sed vestibulum magna commodo id. Etiam fermentum lacinia tellus feugiat posuere. Suspendisse sit amet lacinia dolor. + +Nullam cursus sapien cursus nisl fringilla congue. Aenean ac porttitor massa, ut sodales orci. Donec ac est non felis gravida commodo. Integer vel massa orci. Fusce nec magna in nisi viverra facilisis. Nam luctus neque sed neque commodo congue et fermentum velit. Sed a dolor non mauris pharetra bibendum vel at diam. Quisque feugiat magna vitae vulputate congue. + +Cras tempus tempor sem, nec cursus orci auctor vel. In nec augue at eros placerat volutpat id at nibh. Mauris et pulvinar sapien, quis eleifend lacus. Proin ut congue lectus. Curabitur sed dapibus purus, ut facilisis erat. Ut sagittis ex nec augue accumsan fringilla. Nam pulvinar libero ut ipsum convallis interdum. + +Maecenas rhoncus tellus felis, eget blandit diam bibendum non. In maximus eu sapien pharetra posuere. Aenean egestas arcu eu urna pharetra lobortis. Cras viverra dolor felis, id faucibus odio luctus aliquet. Vestibulum vitae convallis augue. Suspendisse accumsan neque eu nisi tincidunt finibus. Aliquam dignissim, nunc ut bibendum fringilla, nulla lectus varius felis, sed hendrerit elit erat eu nisl. Cras orci lectus, varius vel dictum a, eleifend vel lorem. Proin viverra a nibh eget convallis. Duis vel scelerisque est. Cras maximus odio eget odio pretium aliquet. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Quisque at congue enim, in placerat risus. Pellentesque imperdiet eleifend feugiat. Nunc vel mattis justo, in mattis lectus. + +Maecenas lorem eros, condimentum rutrum feugiat ut, laoreet eu lorem. In porttitor turpis sit amet risus viverra pellentesque. Nam rhoncus tristique arcu vel cursus. Sed interdum, metus vel dictum gravida, ante magna efficitur magna, non aliquam dui est nec erat. Quisque fermentum, lacus sit amet maximus aliquet, dolor risus vulputate ex, et convallis orci nisl eu arcu. Sed imperdiet tempus erat, ac aliquam sem feugiat eu. Nullam mattis bibendum lorem vitae ornare. In condimentum vel odio vehicula placerat. Nullam quis magna est. Curabitur luctus eros turpis, sed varius odio convallis sit amet. Duis feugiat est ut tortor vulputate finibus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed ultricies lorem vel mauris lacinia commodo ut eget turpis. + +In in dolor ultricies, mattis urna id, viverra metus. Nunc ut nisi odio. Sed nunc odio, laoreet eu nunc sed, porttitor ultrices enim. Ut iaculis ligula a blandit varius. In eleifend, urna id ultricies convallis, urna odio euismod arcu, id finibus felis felis sit amet felis. Nulla ac consequat libero. Integer quis dolor sapien. Vestibulum in lectus dolor. Nulla nulla nunc, vulputate vitae justo dapibus, consequat varius urna. Cras est felis, sodales eget pulvinar pellentesque, commodo et sapien. + +In dui quam, euismod et mauris a, laoreet porta lacus. Proin nec semper neque. Donec consectetur lacus at nunc gravida, sed tempor dolor vulputate. Nulla facilisi. Curabitur sit amet purus nibh. Aenean dictum sodales mi ac ullamcorper. Vestibulum imperdiet ultrices aliquet. + +Etiam mauris libero, blandit id sem a, elementum tempus magna. Integer bibendum sapien vel est ultricies, a venenatis ante pharetra. Nam ac tempus nisi. Fusce at tortor arcu. Ut mauris lectus, ornare sit amet mollis vitae, iaculis ac felis. In mollis lacus neque, in gravida nisl gravida eget. Nulla facilisi. In neque tortor, faucibus vestibulum nunc a, consectetur commodo est. Praesent tristique lobortis sem posuere efficitur. + +Aliquam non semper ligula. Cras at ultricies mi, non ultrices massa. Nullam ac consectetur sapien. Donec ut urna posuere, mattis justo at, scelerisque neque. Suspendisse potenti. Vivamus aliquam enim sit amet mi feugiat, eget ultrices nunc pulvinar. Pellentesque facilisis, dui at sollicitudin maximus, risus mauris laoreet felis, nec sagittis nulla turpis et elit. Donec elit dui, pharetra facilisis quam sed, mollis ultricies arcu. Ut fermentum ipsum dui, eget maximus dui finibus nec. Mauris et mi arcu. Quisque sagittis pellentesque libero at ultricies. + +Sed ullamcorper vulputate dui, vel tincidunt metus rhoncus ac. Aliquam ut lacus molestie, pulvinar justo accumsan, bibendum neque. In vitae nulla ut metus condimentum rutrum eget nec mauris. Nam sit amet sodales sem. Phasellus sagittis massa quis ipsum gravida tincidunt. Ut ac massa dapibus, vestibulum nibh vitae, scelerisque lorem. Morbi dapibus commodo sodales. Nullam sollicitudin augue quis tristique malesuada. Maecenas convallis egestas ante a luctus. Integer a aliquet turpis. Curabitur augue velit, scelerisque vitae mauris et, tristique placerat ligula. Aliquam ultricies urna nisl, non tincidunt odio faucibus vel. Donec nec magna molestie, pulvinar risus id, bibendum nibh. + +Integer erat purus, sagittis eu ante eget, viverra faucibus erat. Mauris molestie ipsum erat, non imperdiet orci egestas nec. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla nec congue lectus. Fusce facilisis ex eu augue imperdiet pellentesque. Etiam quis mattis erat, in aliquam metus. Mauris fermentum urna ac justo consequat, quis sodales nisl pretium. Morbi venenatis congue quam, nec semper sem placerat vitae. Curabitur scelerisque ipsum vitae est tempus, eu tristique magna euismod. Fusce mattis at nisi eget cursus. Pellentesque ultricies, dui eget mattis mollis, risus turpis molestie leo, auctor placerat sem velit vitae risus. + +Aliquam erat volutpat. Interdum et malesuada fames ac ante ipsum primis in faucibus. Fusce lacinia cursus arcu, quis facilisis nibh elementum et. Donec lacinia eleifend ante eu porta. Curabitur ut accumsan nunc. Quisque viverra, ex quis pretium faucibus, diam justo scelerisque arcu, eget auctor nulla nisi eu magna. Pellentesque arcu nunc, sodales vitae cursus et, molestie eget quam. Integer efficitur eros ullamcorper justo laoreet aliquet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; In sit amet egestas ex, sed molestie purus. Vivamus ac metus et ipsum tristique congue. Ut elementum tellus vitae arcu suscipit, eu semper leo accumsan. Duis at maximus libero. Suspendisse blandit mauris lacus, sit amet aliquet sapien hendrerit sed. Praesent sed neque pulvinar, semper felis nec, eleifend urna. Etiam eget ex nisi. + +Nulla facilisi. Duis condimentum velit id vulputate luctus. Aliquam eu interdum nunc. Morbi eu est mattis, pretium eros ac, accumsan nibh. Quisque sed mauris fringilla augue tincidunt dignissim id vitae tortor. Pellentesque tincidunt magna quis ex facilisis, quis dignissim nunc tincidunt. Nunc semper maximus elit. Donec neque libero, volutpat nec mollis non, scelerisque ac odio. Donec et augue ut elit eleifend pharetra. Donec condimentum tellus turpis. In gravida, tellus hendrerit facilisis aliquet, ligula est auctor tortor, eu interdum turpis sem a ex. + +Sed vestibulum egestas mi sed semper. Cras varius tempus hendrerit. Duis quis ex mauris. Donec tincidunt rutrum tellus ut malesuada. Cras fermentum ut ante in pretium. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut tincidunt aliquam nulla. Duis a justo et diam porttitor hendrerit. Sed dignissim mauris ultricies, volutpat urna ut, sagittis lectus. Morbi facilisis lacus elit, eget varius ligula dignissim vel. Ut ut risus eget tellus viverra consequat non id nisi. + +Ut ut sem sit amet risus maximus accumsan eget id diam. Curabitur consequat arcu in sapien elementum, rhoncus suscipit ipsum ultrices. Duis sed lacinia mi. Maecenas posuere velit vitae eros mollis, accumsan sollicitudin ipsum tempor. Integer tortor leo, vestibulum tempor feugiat non, imperdiet quis nibh. Ut dictum erat vel lacus venenatis pellentesque. Morbi suscipit consectetur elit a pulvinar. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam accumsan ligula vitae dapibus suscipit. Maecenas hendrerit, ante ut euismod lacinia, dolor enim vehicula nunc, at ultrices erat magna et arcu. Etiam lobortis a leo non blandit. + +Morbi vulputate pulvinar odio quis porta. Ut nibh ex, posuere cursus commodo sed, malesuada in tortor. Maecenas sed maximus ligula. Fusce rhoncus nibh id nisl rutrum, eu ultricies erat fringilla. Cras risus nisi, molestie ut cursus vitae, tempor a leo. Quisque euismod neque sit amet est commodo, et consequat risus sollicitudin. Integer interdum odio eu suscipit ultrices. Nunc justo risus, pulvinar at metus ac, rutrum auctor tortor. + +Sed odio leo, posuere id orci sed, congue mattis urna. Nulla vitae ligula purus. Praesent quis fringilla magna, ac pulvinar metus. Donec congue purus ac tortor congue, eu maximus tellus hendrerit. Morbi nec ipsum suscipit, auctor ipsum non, ornare massa. Pellentesque eu lectus vitae ipsum ultricies porttitor nec at massa. Nulla arcu metus, accumsan at ante at, congue interdum quam. + +Vestibulum eleifend erat dignissim mattis scelerisque. Donec a magna vel lorem fermentum molestie. Vestibulum consectetur arcu dui, sed tempor nisl lacinia in. Cras at urna vitae nunc dictum ultricies eget vitae neque. Morbi vel rhoncus ipsum. Pellentesque placerat ultrices venenatis. Donec semper nibh vel imperdiet placerat. Vestibulum eget blandit ipsum, a maximus lacus. Sed sagittis faucibus velit, a mattis sapien. Duis consequat maximus ex, ut dignissim mi volutpat vitae. Vivamus congue diam nec tortor ornare hendrerit. Nam a tortor fermentum ante viverra volutpat ut vitae nisi. Proin consequat dictum velit at varius. + +Aliquam rutrum imperdiet egestas. Pellentesque et condimentum felis. Sed eleifend nunc ligula, at rutrum sapien porttitor ut. Nullam nec felis risus. Vestibulum in rutrum enim, vel luctus odio. Duis nec lacus augue. Suspendisse placerat ex vitae eros varius, at lacinia augue dictum. Sed tincidunt erat non facilisis semper. Duis venenatis tortor quis ligula ullamcorper, sed scelerisque mi sollicitudin. Sed condimentum, mauris ac blandit volutpat, urna ligula tincidunt ex, ut feugiat metus neque eget sapien. Etiam sagittis tincidunt elementum. Nam efficitur, nunc a hendrerit imperdiet, purus orci accumsan libero, quis interdum purus sem eu metus. Ut sem metus, malesuada non sapien at, condimentum dignissim lectus. Nulla vestibulum, mauris pellentesque placerat viverra, eros dui malesuada ligula, id semper magna velit in tellus. Etiam tempor, massa sit amet tempor rutrum, urna sem facilisis enim, at congue libero ex sit amet leo. + +Vivamus scelerisque suscipit eros, id porttitor risus placerat sed. Suspendisse faucibus leo ut dui facilisis iaculis. Aenean sed magna at sem tincidunt sodales. Ut scelerisque lobortis eros. Proin rutrum libero eu aliquam ultrices. Nullam ultrices feugiat diam non facilisis. Nunc et nibh augue. Proin posuere nisl vitae lectus ultricies faucibus. Nam mollis et odio ac tincidunt. Curabitur a ipsum fringilla, placerat eros quis, tempus ligula. Vivamus efficitur aliquam pharetra. Pellentesque maximus ante sapien, placerat condimentum felis bibendum ut. Maecenas massa neque, finibus sit amet augue vitae, scelerisque efficitur erat. Suspendisse id fermentum sapien, in viverra quam. Proin convallis felis ex. Nam mollis dui et tincidunt faucibus. + +Suspendisse potenti. Sed neque augue, fringilla nec leo eget, pharetra luctus nunc. Fusce et malesuada ligula. Nam eget libero interdum, condimentum eros at, aliquet nisi. Etiam aliquet leo quis venenatis auctor. Aenean facilisis, urna eget volutpat maximus, nunc erat faucibus elit, ac euismod nisl ligula faucibus augue. Pellentesque dictum porttitor est vel porta. Fusce scelerisque, odio tristique euismod faucibus, orci leo pretium odio, sit amet aliquet libero magna vel arcu. Integer luctus, felis et mattis sodales, lacus ex laoreet velit, et semper nisl mi eu tellus. Sed a massa et arcu faucibus sodales vitae nec lorem. + +Suspendisse potenti. Duis pulvinar lobortis nisi, at cursus urna dignissim eu. Ut hendrerit lorem sed congue porta. Nullam sollicitudin sem vel risus ultricies rutrum. Donec at lorem a tellus viverra interdum id non felis. Nulla congue tincidunt semper. Etiam finibus magna erat, vitae rutrum orci egestas at. Quisque eget venenatis libero, at malesuada ante. Nulla ut nibh pellentesque, convallis purus id, lacinia lectus. Integer vehicula dui ante, eget cursus ipsum consectetur pulvinar. Cras id molestie massa. Proin mattis semper quam, a convallis enim rhoncus a. Integer dapibus, lacus id sodales sollicitudin, dolor neque accumsan tellus, ac ultricies nunc diam vitae purus. Donec placerat condimentum nibh id porta. Vestibulum in gravida orci. Proin dignissim neque condimentum sagittis tincidunt. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Duis justo mi, faucibus nec facilisis sed, rhoncus ut purus. Duis et sollicitudin arcu. Morbi tempus diam et purus sagittis rutrum. Cras iaculis sem ac magna finibus mattis. Duis maximus tellus arcu, viverra feugiat diam fermentum eget. In hac habitasse platea dictumst. Integer ultrices volutpat purus a viverra. Proin sed euismod nisi. Suspendisse ac facilisis nunc. Vestibulum eleifend nulla sit amet lectus elementum aliquet sit amet vitae lectus. Curabitur consectetur nisi eu mollis venenatis. + +Duis euismod fringilla pharetra. Nunc sodales dolor sed facilisis ultricies. Quisque nec dictum mauris, sed iaculis mauris. Ut euismod feugiat luctus. In hac habitasse platea dictumst. Donec ut molestie massa. Phasellus ac enim nec leo consequat auctor. Cras massa orci, semper in scelerisque in, consectetur eu enim. + +Proin efficitur suscipit purus, nec interdum turpis vestibulum tristique. Nulla pellentesque lectus at neque imperdiet, a fermentum lectus bibendum. Ut vulputate, urna ac pretium porttitor, ligula ex rhoncus magna, vitae faucibus augue metus sed erat. Sed tempor ullamcorper orci ut sodales. Donec in mi bibendum, fermentum mi quis, ullamcorper leo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Phasellus at vulputate massa. Vivamus mattis mauris in orci consequat, at rutrum ante sagittis. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque non fermentum metus. Vestibulum faucibus eros quis dignissim ultrices. Donec id turpis convallis massa finibus blandit tempor id magna. Donec volutpat tellus sit amet mauris faucibus commodo. + +Aliquam eget ex ac magna suscipit lobortis in sit amet dui. Donec non enim placerat, tempor dui tempus, condimentum dui. Cras ultrices, augue et fermentum auctor, justo ante elementum lectus, ac mattis eros augue sed nisl. Nulla facilisi. Nulla porta maximus iaculis. Sed vestibulum odio justo, eget ornare enim ultrices at. Sed vestibulum mauris dolor, quis dictum sem placerat ac. Nullam vel dignissim elit. Mauris at iaculis odio. + +Pellentesque vel odio in libero faucibus ultrices. Aenean ac fringilla nulla. Proin leo tellus, varius sit amet augue ut, facilisis interdum urna. Aliquam molestie, purus vitae dignissim porta, eros sapien tristique nisi, et rhoncus sapien urna at nulla. Vivamus viverra sodales lacus nec aliquam. Etiam convallis rutrum ante, sed ultricies risus mattis vel. Sed blandit nibh quis lectus volutpat convallis. Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque faucibus, est vel lacinia posuere, nunc justo faucibus ligula, nec ornare lorem erat eu ante. Phasellus ligula neque, lobortis quis semper vitae, accumsan et augue. Suspendisse convallis mauris eu tortor vestibulum, volutpat pulvinar lacus venenatis. + +Donec feugiat orci vel magna hendrerit, ut ullamcorper odio consequat. Mauris et tortor sodales, commodo orci in, lacinia sapien. Vivamus posuere, neque sed sollicitudin lacinia, elit metus pellentesque tortor, at congue massa mauris quis turpis. Nulla facilisi. Proin ut maximus ligula, nec varius enim. Mauris ex arcu, tincidunt vel auctor vel, gravida feugiat ligula. Suspendisse odio arcu, euismod eu dignissim vel, rhoncus sed ligula. Donec pharetra bibendum neque, condimentum consectetur sem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Phasellus ornare nisl quis nulla euismod tempor. Maecenas sed enim auctor, venenatis odio non, ornare lacus. Aenean rhoncus efficitur arcu, vitae auctor est luctus at. In eros eros, pretium a laoreet sed, accumsan condimentum odio. Donec maximus congue nisi, non posuere nulla pulvinar et. Integer non erat et orci fringilla euismod. + +Nam efficitur lectus ligula, vitae cursus orci ornare sit amet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; In pharetra, nulla vestibulum suscipit rhoncus, eros quam auctor lorem, vestibulum efficitur eros lectus at ligula. Quisque nec enim a ante ultrices tincidunt eu nec nulla. Praesent ut leo metus. Ut eu tellus enim. Aenean vel consectetur tellus. Aliquam molestie, lectus in pellentesque aliquam, felis lectus ultricies ante, quis mollis ex quam ut orci. Integer volutpat pretium dui, et luctus ante dictum non. Sed porttitor sed lectus ut tristique. Nulla eget ultrices lacus. Integer sit amet magna et turpis consequat scelerisque et sit amet dolor. Ut sollicitudin malesuada libero, non pharetra est vehicula vel. Fusce pellentesque nisl ac metus sagittis dictum. Phasellus id eleifend ante. + +Vestibulum egestas libero in orci porttitor, at eleifend neque condimentum. Donec vitae felis id diam volutpat placerat eget eget felis. Praesent ullamcorper sit amet magna id pellentesque. Nulla est nunc, maximus vel urna sed, consequat dictum lorem. Donec eget ultricies purus, vel congue orci. Aliquam dapibus lobortis blandit. Aliquam sit amet tortor nec dolor varius luctus. Nullam eget felis mauris. Morbi blandit aliquet odio, non euismod felis porttitor vel. + +Curabitur sit amet dolor eu tortor venenatis consequat. Sed efficitur imperdiet quam nec luctus. Morbi vitae est posuere, posuere tortor eu, mollis sapien. Vestibulum eget pretium purus, a eleifend turpis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur massa orci, semper varius sapien sit amet, efficitur tempor nibh. Praesent pulvinar risus neque, vitae tristique lectus aliquet nec. Pellentesque eget orci eu leo maximus maximus sit amet ac eros. Praesent porttitor ligula et ligula vehicula placerat. Ut quis tincidunt orci. Nam ultrices elit ac ornare fermentum. + +In quis auctor purus. Fusce lacinia purus in leo fermentum scelerisque. Vestibulum at cursus odio, vel finibus tortor. Sed quis lectus sit amet velit tincidunt sagittis. Donec id porta enim. Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse eget ultricies augue. Nulla turpis metus, ornare ac tempor eget, dictum eu elit. Phasellus rutrum mauris at mauris accumsan suscipit. Donec eu sapien sollicitudin, viverra nisl et, euismod mauris. Curabitur dictum semper laoreet. Nulla nec malesuada dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Quisque euismod magna vel pharetra ornare. Nam sed finibus urna. Suspendisse augue nulla, luctus a egestas at, tincidunt nec diam. Cras congue justo ac velit euismod, eget volutpat augue porta. Maecenas nec nisl arcu. In at justo in tellus faucibus vehicula et eu ante. Aliquam facilisis mauris turpis, at finibus elit rutrum id. Sed nulla enim, ultricies at nisi et, tristique fringilla libero. Donec mattis volutpat arcu eu lacinia. + +Donec maximus, dui sed bibendum iaculis, lorem odio aliquet metus, in tempor lectus elit vel sapien. Aliquam rhoncus massa sit amet placerat congue. Donec vitae maximus nibh. Sed id fermentum augue. In hac habitasse platea dictumst. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam finibus, orci id tempor ullamcorper, justo purus venenatis augue, vel efficitur elit odio eget nunc. Pellentesque euismod fringilla eleifend. Sed mollis augue urna, eu placerat dolor placerat quis. Mauris id dolor vel velit aliquam dapibus a quis leo. Donec elementum dolor ut auctor accumsan. Cras sed fringilla mauris. + +Vivamus id placerat ligula, a egestas orci. Donec in erat ut tortor gravida pellentesque. Sed felis dolor, dignissim in maximus at, commodo commodo lacus. Cras commodo consectetur nunc, eu tincidunt risus dignissim sit amet. Mauris vel pellentesque urna. Vivamus scelerisque ligula eu velit dapibus rutrum. Nullam eget lobortis lorem. Vestibulum ligula lorem, suscipit convallis lorem at, ultrices mollis metus. + +Morbi varius rhoncus nibh nec varius. Nullam eget porta velit. Nulla lorem elit, ullamcorper non vehicula quis, varius et nisi. Sed molestie auctor nisi, vitae ultricies metus tempor nec. Maecenas imperdiet, nisl vel tincidunt varius, tortor nibh semper felis, at blandit metus tortor eget ipsum. Nullam at risus accumsan nulla bibendum laoreet. Quisque pellentesque ligula vitae lacus pellentesque, euismod convallis justo hendrerit. Sed nisi elit, egestas sit amet velit in, ultricies feugiat nunc. + +Aenean non metus magna. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Sed venenatis magna enim, non feugiat nisi tincidunt quis. Proin sit amet risus quis augue finibus finibus vel euismod enim. Morbi sed vestibulum turpis. Sed facilisis vitae mauris quis ultrices. Quisque a tellus laoreet, laoreet justo sed, cursus nibh. In dolor eros, finibus ut aliquam vitae, facilisis nec velit. Morbi vitae felis sodales, aliquet lorem vitae, ultricies libero. Quisque vehicula lectus non euismod pretium. Vivamus tempus ante justo, ullamcorper porta magna pharetra ac. In eu purus erat. Aliquam tincidunt magna augue, vel maximus dui semper vitae. Maecenas ac tellus ligula. + +Suspendisse lacus ex, hendrerit non diam non, luctus convallis ipsum. Nam lorem eros, facilisis at ultrices sed, porta eu elit. Donec molestie convallis rhoncus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed pretium aliquet pulvinar. Sed euismod nisi id condimentum convallis. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam tristique ipsum at arcu condimentum, sit amet feugiat lectus aliquam. In quis lobortis eros. Vestibulum nunc ex, mattis ut placerat ac, dapibus eu lacus. + +Sed vehicula nec ex ut vulputate. Aenean ornare, lacus nec finibus malesuada, mauris eros consequat ligula, eget blandit ex libero a odio. Praesent et fringilla leo, eget molestie nisl. Ut interdum, sem ut lobortis posuere, ante ligula ultricies nulla, a vulputate tortor est id enim. Fusce vel condimentum dolor, in congue purus. Praesent nec enim dapibus, dictum leo varius, aliquam erat. Duis neque lacus, ullamcorper et eros eget, laoreet venenatis est. Aenean laoreet ex mattis, rhoncus nibh vel, congue massa. Nam viverra ex sit amet erat tempor ullamcorper. Proin condimentum quam felis, in tempus magna ornare vel. + +Quisque faucibus erat sem, vel pharetra odio placerat eget. Suspendisse condimentum bibendum lacus at posuere. Duis eu congue elit. Proin fringilla nibh lorem, ut ornare enim viverra at. Donec a malesuada erat. Cras dolor felis, porttitor in nibh vitae, fermentum venenatis ligula. Vestibulum eget lectus posuere lorem ornare scelerisque. Morbi commodo augue eget tincidunt dignissim. Morbi vitae elit velit. + +Maecenas rhoncus rhoncus eros vitae pharetra. Morbi mi eros, sagittis non libero sed, lobortis venenatis lorem. Vivamus in justo nisl. Nam pulvinar lectus ullamcorper erat finibus imperdiet. Pellentesque malesuada massa ipsum, ac posuere neque iaculis et. Donec convallis tristique nisi non elementum. Duis facilisis lacus leo, sit amet molestie libero dignissim quis. Morbi et justo sit amet est maximus egestas a eget mi. Curabitur condimentum nec enim id tincidunt. Donec ipsum ipsum, pellentesque a efficitur non, mollis id ipsum. Maecenas venenatis sit amet nulla eu blandit. Nunc mollis, odio ut scelerisque aliquet, odio dolor mollis sem, vitae sodales diam nisl at nulla. Mauris vel risus nulla. + +Pellentesque sollicitudin non orci sit amet pellentesque. Morbi id nibh vitae enim dignissim porttitor. Phasellus consequat, diam eget commodo placerat, leo lorem scelerisque tellus, pulvinar lobortis enim risus sed nunc. Aliquam ut tincidunt leo, sed maximus arcu. Vestibulum metus erat, fermentum elementum justo et, iaculis maximus erat. Donec in feugiat erat. Donec dictum sodales venenatis. Morbi neque justo, euismod vitae elementum ut, sollicitudin ac dui. Donec eu lacus in nunc efficitur molestie. Morbi auctor vitae nibh nec aliquam. Morbi volutpat diam in diam tincidunt, id lacinia dolor porttitor. Integer nec urna id lorem placerat fringilla quis non orci. + +Maecenas lacus urna, porta eu dui non, ornare tempor dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam sit amet dignissim orci. Etiam ac mi mollis, posuere elit sit amet, finibus felis. Maecenas aliquet finibus leo vel porttitor. Etiam ipsum leo, convallis ut augue blandit, interdum ultricies risus. Donec vel eros porta, facilisis urna ut, vehicula sapien. Maecenas lacinia pharetra dolor. Vivamus lobortis nec enim ut lacinia. + +Curabitur semper pharetra tristique. Sed sagittis est vitae placerat sodales. Duis ac dolor posuere, fringilla ligula nec, sollicitudin lorem. Curabitur quis dignissim diam, quis varius ipsum. Sed maximus mauris tortor, sit amet imperdiet magna fermentum vitae. Aenean id pulvinar mauris, vel posuere erat. Pellentesque bibendum sodales risus, et maximus sem pretium nec. Sed ultricies rutrum tincidunt. Nullam pulvinar fermentum velit, nec consectetur ante feugiat eu. Maecenas sed enim commodo neque viverra mollis. Fusce imperdiet diam nisl, et pulvinar sapien commodo cursus. Aenean a nulla blandit, pharetra velit a, elementum magna. + +Sed et mi imperdiet, condimentum ipsum sit amet, suscipit felis. Morbi laoreet elit placerat, rhoncus lectus dignissim, finibus velit. Morbi sit amet mollis justo, sed efficitur eros. Suspendisse pharetra commodo nunc vel aliquet. Nam vestibulum ipsum sodales, posuere nunc et, aliquam leo. Nam ut consequat velit. Phasellus sollicitudin quis quam tincidunt pharetra. Proin at pharetra ex, sit amet egestas nunc. Fusce blandit suscipit ipsum vitae pellentesque. Fusce at malesuada lectus. Aliquam erat volutpat. + +In sit amet quam semper, molestie nunc imperdiet, euismod lacus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent eu felis risus. Maecenas venenatis tempus quam in feugiat. Cras auctor vulputate augue a accumsan. Aliquam vitae purus ut mauris volutpat efficitur sit amet id augue. Nunc bibendum magna vitae nisl condimentum maximus. Ut feugiat nisl a mi mattis aliquet. Aliquam euismod leo id massa laoreet sagittis. Phasellus ac posuere elit. Morbi turpis eros, cursus in mollis quis, eleifend vel risus. Phasellus feugiat malesuada congue. Nulla non posuere neque. Donec semper eros risus. + +Integer tristique maximus purus non vulputate. Donec quis semper augue. Nulla volutpat lectus sit amet lacinia malesuada. Fusce sed tellus eget metus egestas convallis at eget turpis. Praesent elementum turpis eget leo pulvinar pretium. Praesent faucibus bibendum magna, sit amet cursus dolor accumsan eget. Proin sagittis ut est non volutpat. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut eget turpis vel enim egestas pharetra. Sed eget vehicula odio. Pellentesque aliquet aliquam ipsum. Sed dapibus nisi urna, porta laoreet massa mattis non. Duis dolor diam, feugiat in eros at, bibendum consectetur lacus. Quisque accumsan nibh est, ac hendrerit arcu sagittis at. Fusce suscipit nunc at elit pulvinar, a fringilla orci posuere. Vestibulum non purus sit amet ligula porta tincidunt. + +Ut ut elementum leo. Donec eu vehicula enim. Nulla ut posuere libero. Suspendisse accumsan sit amet enim non ultrices. Donec a leo eget sapien pulvinar mattis ut eu tortor. Duis nec massa nisi. Morbi elementum felis et dapibus sodales. Suspendisse ut luctus enim. Donec tristique at nisi vel lacinia. In malesuada in tellus nec dapibus. Integer in congue est, sit amet facilisis est. + +Integer suscipit feugiat condimentum. Sed non metus est. Nullam accumsan justo at interdum varius. Curabitur sed risus consectetur, egestas sapien ut, pretium felis. Maecenas eu dolor eget lorem varius pretium. Phasellus consectetur urna a ante sodales dapibus. Donec sollicitudin lorem tempus malesuada tempus. Phasellus luctus condimentum vestibulum. Fusce vel molestie nisl. Nullam imperdiet dolor ut lectus vulputate sollicitudin. Aliquam erat volutpat. Nullam in sollicitudin nulla. Morbi porta felis et lectus auctor porttitor. + +In in ligula et ante posuere luctus. Ut feugiat sit amet quam eu rutrum. Nullam commodo ante nisi, et pellentesque augue pellentesque et. Nulla vulputate, lacus quis efficitur mattis, nisl velit molestie nisl, sit amet rhoncus nisi turpis quis leo. Morbi a magna urna. Donec a iaculis nisl. Nullam eu elit vitae dui interdum bibendum imperdiet quis ante. Curabitur vitae lorem sit amet odio tristique rutrum. + +Sed ut lectus dolor. Suspendisse euismod ut massa id vestibulum. Sed non massa placerat, facilisis dui a, condimentum enim. Fusce vehicula erat eu lacus condimentum euismod. Vivamus ut ultrices ipsum, in ullamcorper velit. Sed enim nulla, tincidunt at purus id, ultrices maximus ipsum. Cras sit amet tortor at enim pellentesque lacinia sed vel sem. + +Integer ac metus nec nulla cursus venenatis. Duis blandit luctus massa a vehicula. Nam vulputate, lectus ut condimentum lacinia, tortor tortor cursus justo, facilisis tempor eros sem vitae nulla. Nullam sed ex massa. Aliquam non arcu et neque scelerisque porttitor. Etiam commodo venenatis maximus. Donec rhoncus erat nec diam efficitur placerat. Mauris pretium mauris libero, sit amet vestibulum ipsum fringilla eu. Cras sed tortor mollis, mollis diam eu, condimentum ex. Etiam gravida nec arcu vel sodales. Pellentesque ut arcu in eros ullamcorper tristique. Praesent luctus in neque eget pharetra. Proin dapibus tellus sed velit commodo interdum. Praesent euismod, massa in semper mollis, tortor ipsum suscipit tortor, sit amet viverra tellus sapien eget orci. Maecenas in molestie justo, eget consequat dolor. + +Praesent vel neque vitae ipsum condimentum pulvinar eu non nisi. Integer mattis quam ut pellentesque auctor. Ut egestas, diam at finibus viverra, felis est tristique nibh, id convallis turpis velit eget ligula. Fusce sed nisl volutpat augue volutpat facilisis. Aliquam erat volutpat. Integer dapibus varius augue, sed fringilla metus varius vitae. Maecenas sed elit a sem dignissim tempus. Maecenas nulla erat, molestie sit amet malesuada eget, blandit at libero. Donec lacinia efficitur nulla a scelerisque. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla hendrerit dui quis orci tristique, id faucibus eros malesuada. Sed ut dolor ex. Sed vel rutrum eros. Nam ac orci sit amet mi consequat aliquet quis quis est. + +Vivamus nec odio vitae orci consectetur suscipit. Donec vehicula eget libero in viverra. Ut laoreet in nulla eget euismod. Phasellus egestas lorem sed dui blandit, rhoncus interdum nulla ultrices. Quisque congue convallis erat ut blandit. Phasellus tempor pulvinar justo, id varius risus tempus eget. Suspendisse tempus, urna et mattis placerat, tellus magna pharetra ipsum, sed porta mi tellus suscipit justo. Vestibulum commodo turpis ut metus lacinia scelerisque. Aliquam fermentum, quam in malesuada ornare, orci mauris molestie mi, vitae tristique nunc quam pharetra enim. Etiam placerat lectus quam, vitae faucibus metus efficitur sit amet. Pellentesque suscipit porttitor ipsum, in fermentum turpis tristique sed. Duis finibus mi nec odio aliquam feugiat. Sed vitae tellus diam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +Sed ac mi libero. Aliquam pulvinar ullamcorper ipsum. In blandit nec arcu ut vehicula. Duis venenatis suscipit laoreet. Cras finibus tincidunt velit in feugiat. Mauris lorem eros, pretium sed ornare et, blandit id quam. Donec cursus, velit quis semper finibus, risus quam gravida sem, quis venenatis est turpis scelerisque lorem. Pellentesque vel accumsan ipsum, in finibus lacus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Morbi ultrices, risus ac euismod tincidunt, felis tortor facilisis eros, et elementum massa velit finibus augue. Sed fermentum faucibus euismod. In nec porta neque, eget mollis leo. Pellentesque dapibus metus vel nunc efficitur, nec suscipit ligula porta. Ut eu justo quis turpis tincidunt dapibus et et lacus. Nunc quis vehicula ligula, ac gravida turpis. Etiam in hendrerit ipsum. + +Nunc scelerisque maximus dui, et porttitor mi hendrerit sit amet. Nam placerat ultricies arcu, ut bibendum arcu fringilla in. Mauris vitae ultrices nisl, ac lobortis leo. Vivamus in nulla elit. Integer a quam eros. Integer volutpat odio ultrices nisi interdum suscipit. Nunc faucibus ultrices scelerisque. Sed hendrerit tortor nec ligula fermentum suscipit. Suspendisse fermentum dignissim hendrerit. Nam posuere sodales nunc ultrices suscipit. Quisque ut ipsum et lorem laoreet mollis. + +Maecenas in interdum orci. Aenean dolor dui, semper quis nisi sed, placerat euismod nisi. Nam at maximus libero. Donec sit amet justo urna. Maecenas sem sapien, viverra ac faucibus vitae, bibendum nec ex. Vivamus commodo dignissim viverra. Morbi semper condimentum augue, nec tempor nisi sodales nec. Suspendisse ut lorem pulvinar, ultricies justo ut, sollicitudin purus. Etiam sed bibendum enim, ac facilisis libero. Nulla rhoncus finibus tempus. Nullam eget imperdiet orci. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec et justo at turpis varius sagittis volutpat vitae elit. Duis posuere nunc nec placerat mollis. Sed pretium purus quis risus commodo, et placerat nibh dapibus. Curabitur neque ex, viverra nec imperdiet fermentum, fermentum in diam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent ultrices metus non nisi aliquet, sed feugiat diam ultrices. Morbi rhoncus risus nec mi bibendum convallis. Nam tellus erat, porttitor vel erat vitae, vehicula pharetra justo. Praesent in nunc eu risus aliquam lobortis id et sem. Aliquam nulla augue, commodo ac ex quis, iaculis imperdiet justo. Fusce rutrum elit at enim ornare pellentesque. + +Morbi lacus nisl, facilisis ut purus a, dapibus ultrices orci. Etiam in pretium ipsum. Nulla ac interdum velit, ut pharetra neque. Maecenas placerat, diam vitae aliquet ultricies, neque ipsum vehicula dui, id blandit est diam non purus. Duis eu mi vitae quam sagittis pulvinar. Donec ligula erat, maximus in cursus eu, elementum eu nulla. Pellentesque ut justo ac orci placerat accumsan vitae in sem. Morbi at consectetur elit, ornare fringilla nibh. Suspendisse sapien lorem, molestie sed tortor vitae, finibus accumsan tortor. Quisque dignissim rhoncus metus, non dapibus dolor auctor sit amet. Aliquam a fermentum tortor. Donec ullamcorper fringilla risus. Ut tellus tellus, tincidunt eu nulla a, rutrum consectetur diam. Nunc arcu mi, tempor eu suscipit eu, vehicula vitae nibh. Aliquam rhoncus ante sit amet nibh volutpat, quis mattis felis imperdiet. Integer tincidunt arcu sed dolor iaculis interdum. + +Donec pharetra consectetur orci quis tempus. Proin laoreet risus eget libero ornare, nec tincidunt massa consequat. Phasellus pharetra felis at velit vulputate suscipit. Proin aliquam elit ut massa malesuada, nec rutrum mi efficitur. Nulla volutpat libero vel quam fringilla posuere. Aliquam sit amet purus arcu. Quisque iaculis sed erat non accumsan. Praesent eu nulla odio. In hac habitasse platea dictumst. Maecenas facilisis, sapien et ornare rutrum, orci est facilisis nisl, id placerat lectus dui eget lacus. Suspendisse potenti. Suspendisse eu tempus nisi. Proin et ipsum ut velit consequat finibus ac non lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; + +Nunc ornare elit non massa semper consequat. Nullam lacinia dignissim mauris nec molestie. Sed id nunc ut ligula ornare finibus in at nibh. Duis turpis nunc, ultrices ultricies fringilla ut, venenatis in justo. Donec volutpat imperdiet interdum. Aenean sollicitudin massa at porta fermentum. Donec et tortor volutpat, hendrerit nulla quis, consequat velit. Nam sed nisl mattis, pharetra ligula id, congue purus. Nulla sed risus non ante sodales mollis nec vehicula justo. Nullam eu ultricies leo. Duis eget consectetur erat, vitae facilisis purus. + +Phasellus ut rutrum eros. Phasellus viverra commodo arcu sagittis porttitor. Etiam suscipit vehicula lacinia. Fusce vel condimentum lorem. Integer rhoncus lorem quis velit hendrerit tempor. Aenean a nisl ante. Phasellus nec ipsum ut quam porta varius et nec sem. + +Pellentesque pellentesque est eu dui placerat, vitae imperdiet erat dictum. Aliquam erat volutpat. Quisque feugiat neque nec faucibus maximus. Mauris eleifend odio at nunc suscipit dapibus. Maecenas mauris mauris, suscipit ac ipsum in, condimentum volutpat risus. Suspendisse gravida risus ex, quis suscipit nisl viverra ut. Phasellus pharetra nisl id odio laoreet bibendum. Morbi semper urna nulla, non ultricies est vehicula vitae. Maecenas non porta ante. Donec nec massa eu purus ultricies euismod. Nam sollicitudin dui metus, vitae ornare libero faucibus sed. Aliquam feugiat tellus nec est dignissim placerat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Quisque dictum placerat leo sed mattis. + +Quisque eu dolor dictum, euismod urna quis, mattis enim. Donec eu magna ultrices lectus fringilla facilisis. Sed finibus gravida purus, posuere interdum magna laoreet quis. Aliquam vehicula volutpat tellus ac tincidunt. Sed volutpat convallis eros, eget ultrices mauris maximus et. Mauris porta leo sit amet urna pretium condimentum. Duis non ex in dui dapibus tristique vel eget velit. Etiam velit quam, dapibus ac scelerisque ac, dignissim non elit. + +In cursus est ut nibh placerat maximus eu blandit tellus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut posuere massa eu odio rhoncus, ut eleifend odio finibus. Maecenas tristique, justo quis auctor laoreet, turpis nibh iaculis nisl, a consequat velit libero id sapien. Curabitur rutrum non justo eget aliquam. Praesent ornare lobortis eros eleifend hendrerit. Integer porta sapien turpis, a imperdiet ante congue et. Nullam ut fringilla enim. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Donec ullamcorper ac tellus a efficitur. Sed lacinia egestas libero, ac luctus turpis imperdiet eu. Morbi et gravida est. Maecenas dapibus erat id ex mollis, eget sollicitudin mi ullamcorper. In sed quam ac lacus dapibus ullamcorper. + +Integer efficitur iaculis porta. Vestibulum nibh augue, aliquam et ultrices at, molestie et neque. Proin ut mauris ac risus sodales congue. Nunc non tristique ligula. Donec orci elit, viverra sit amet iaculis id, maximus eu dui. Morbi condimentum tincidunt nisi, ac ultrices orci auctor id. Nunc congue, sapien vitae interdum euismod, augue massa molestie arcu, ac aliquam risus tellus vitae orci. Nullam sit amet eleifend dui, in pulvinar purus. Nullam vitae sagittis ligula, non iaculis augue. Duis sit amet erat et nibh imperdiet aliquet. Ut vitae laoreet enim. Duis leo mauris, tincidunt non mauris ut, maximus suscipit sem. In in nisi in mi ultricies suscipit. Sed porttitor ante eu dui sodales, in rutrum felis consectetur. Nullam ut enim eget ante dignissim efficitur vitae scelerisque ex. + +Ut aliquet mi id dictum imperdiet. Donec vulputate urna ac quam vehicula, varius viverra ex tempor. Praesent porta, justo id tempor mattis, ligula tellus tincidunt eros, ut varius lacus quam a diam. Fusce eu sagittis dolor. Vivamus vitae velit ut ipsum aliquam posuere at a elit. Aenean imperdiet nec ante euismod tempus. Nam facilisis ut nunc id semper. Phasellus consectetur tincidunt placerat. Suspendisse sed sodales ex, sit amet hendrerit ligula. Nam aliquet urna nec tortor dictum accumsan. Cras ut ex vitae odio tempor consectetur. Suspendisse tincidunt erat ac mauris volutpat viverra. Nullam molestie, enim eget tincidunt hendrerit, nunc metus semper sapien, porttitor rutrum mi velit in quam. + +Vestibulum non interdum turpis. Donec id dolor consequat, condimentum felis a, bibendum nisl. Morbi diam nisi, fermentum nec viverra vel, fermentum elementum tortor. Sed enim massa, aliquet quis mi non, vehicula faucibus justo. Fusce vel risus quis lectus vehicula ullamcorper. Donec mauris velit, lacinia non faucibus vitae, consequat a est. Vivamus tristique eros accumsan, porttitor eros at, interdum mauris. + +Maecenas tempus nulla tristique ex gravida posuere. Aliquam eget eros ac sem rutrum pulvinar sed id magna. Vestibulum suscipit eleifend accumsan. Proin sit amet vestibulum enim. Fusce fringilla pellentesque odio a dapibus. Aenean vel neque vitae augue sagittis luctus nec in orci. Vestibulum blandit felis eu purus condimentum congue. Vestibulum vel tristique risus, dignissim accumsan metus. Duis nisl odio, semper in arcu nec, faucibus lacinia leo. In auctor neque nec augue sagittis volutpat. Aliquam luctus suscipit mauris, ut fringilla tellus laoreet et. Cras pretium est quis ante mattis congue. Nunc dui metus, aliquet egestas neque id, fringilla luctus dolor. + +Donec in dignissim ex. Nullam sed metus sollicitudin nibh aliquet rutrum eget sit amet odio. Vivamus quis fringilla dolor, lobortis suscipit leo. Phasellus non nisi interdum felis cursus gravida ut eget urna. Phasellus bibendum ex id velit imperdiet fringilla. Ut interdum justo at ante porta auctor. Phasellus dictum congue mauris, in hendrerit ante semper ac. Vivamus a mi quis ipsum maximus egestas sed volutpat tortor. Proin interdum dolor in ornare rhoncus. Sed ornare nunc id lacus tincidunt, aliquam faucibus lacus imperdiet. Fusce sed mauris ligula. + +Vestibulum lobortis felis neque, a luctus ligula efficitur vitae. Aenean suscipit molestie velit. Curabitur dapibus dapibus maximus. Nam ultrices, nisi eget semper accumsan, risus massa iaculis diam, ut accumsan libero neque et mi. Etiam rhoncus tellus eros, ac posuere ante bibendum vitae. Curabitur in sollicitudin dolor. Nulla tempus urna vel ligula faucibus finibus. + +Sed sit amet varius magna. Fusce vestibulum interdum magna id vehicula. Nullam quis velit cursus enim egestas semper. Aliquam tristique sapien id neque egestas, eget aliquam nisl pulvinar. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam elementum pellentesque mauris, nec condimentum elit luctus vel. Quisque iaculis, massa quis hendrerit congue, mauris erat euismod sapien, ac dapibus nulla mauris at mauris. + +Nulla bibendum volutpat augue a suscipit. Morbi tortor metus, volutpat ut felis in, malesuada malesuada nunc. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nunc a lobortis nulla, eget elementum sem. Proin eleifend est vitae diam porta gravida. Maecenas a fermentum neque. Sed lorem augue, porttitor eget bibendum ac, pretium et eros. Quisque eu ligula id odio tempor gravida condimentum ac libero. Vivamus nulla purus, cursus quis eleifend ac, ornare at nibh. Nullam a leo tincidunt, viverra odio vel, maximus turpis. Duis consectetur tempus nunc at aliquam. Integer facilisis dolor non sapien lobortis pharetra. Integer ornare metus eu diam lobortis gravida. Donec mauris ipsum, rutrum blandit auctor et, ullamcorper non nisl. Curabitur aliquet, felis in auctor ornare, nunc turpis elementum ipsum, id tempus mauris erat ut justo. Phasellus aliquam, ligula ut pretium mollis, nibh libero dictum mauris, consectetur dapibus ex lectus eu sapien. + +In lobortis in augue quis consequat. Phasellus rhoncus aliquam porta. Suspendisse at ipsum iaculis erat iaculis dapibus. Proin molestie luctus diam a lacinia. Quisque vel augue tristique, ultrices ligula quis, dictum quam. In vehicula ligula at metus tincidunt tristique. Duis pellentesque efficitur lorem, accumsan aliquet eros dignissim sit amet. Praesent volutpat ultricies quam in pharetra. Cras a odio a nisi pellentesque ultricies. Proin maximus tempor quam ut placerat. Quisque nec dolor vitae felis tincidunt molestie eget at nunc. + +Ut ipsum risus, euismod a purus quis, mattis porttitor nisl. Integer feugiat urna vel egestas ultricies. Nulla nulla nisl, fringilla ullamcorper ligula eu, tempor mollis neque. Curabitur semper aliquam dolor eu ullamcorper. Nam tempor ornare mauris sed condimentum. Duis erat velit, bibendum a tristique nec, aliquam eu lacus. Duis ornare sed mauris euismod vulputate. Quisque eros nisi, viverra a lorem at, semper aliquet diam. Sed vitae tortor mauris. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed ante metus, faucibus at nunc sit amet, dignissim sodales felis. Nullam congue maximus ante, placerat facilisis massa ornare vel. Suspendisse nec rhoncus orci. Nam ultricies, lorem vitae viverra pretium, urna libero fringilla sem, nec cursus neque lacus vitae leo. Quisque orci ipsum, elementum vel quam in, aliquam pulvinar nulla. Nunc rutrum leo id orci vehicula maximus eget ac tortor. Donec in enim vel eros egestas tincidunt ac eu sem. Suspendisse in arcu lorem. + +Curabitur venenatis libero at libero eleifend dictum eget in neque. Aliquam ac ligula pharetra, accumsan purus ut, aliquam diam. Nulla sit amet massa elit. Nam non augue lacus. Donec rhoncus arcu non libero ullamcorper, at pulvinar eros vulputate. In placerat, sem quis posuere porttitor, turpis justo blandit justo, ac iaculis quam nunc nec velit. Sed a metus arcu. Fusce mi odio, rhoncus eu dui vel, dapibus aliquam urna. Suspendisse et imperdiet orci, at dictum dui. Ut tempor arcu eu sem efficitur semper. Nunc eu tempus tortor, sed bibendum tortor. Aliquam convallis, mi in scelerisque faucibus, ex arcu laoreet erat, dapibus semper nulla eros vel odio. Vivamus eros erat, viverra sodales euismod ac, vehicula at ligula. Etiam elementum urna metus, vel consequat lectus blandit in. Suspendisse a libero vitae nulla commodo dictum. + +Integer sodales nec lorem ac tristique. Duis faucibus mollis nunc, vitae imperdiet nulla consectetur sit amet. Aenean non semper justo. Quisque eget lectus varius, iaculis ex nec, pulvinar est. Aenean eu eleifend nisl. Vivamus orci nulla, suscipit dignissim dictum eleifend, condimentum eu purus. Mauris at tortor vel dolor ultrices blandit eget quis tortor. Integer ac nisl eu neque luctus condimentum. Etiam nec mi quis magna ullamcorper vehicula. Nam cursus neque vel auctor pharetra. Suspendisse ut augue vel leo porta semper. Proin in fringilla mauris. Vivamus faucibus nulla ligula, ac tincidunt nisi placerat in. Duis congue, libero non finibus finibus, libero enim lacinia eros, nec tincidunt nulla diam pellentesque augue. Aliquam massa neque, vestibulum eu elit vitae, lacinia gravida nulla. + +Vivamus eget turpis sapien. Nam vitae turpis quam. Phasellus ac turpis id mauris fringilla viverra. Donec varius sollicitudin mi, at posuere eros. Fusce varius vitae lectus sed mattis. Pellentesque dapibus porta ex non viverra. Aliquam ut tristique orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam non lorem eu neque aliquet tristique ac non enim. Integer sed lacinia ex, eget congue sem. In hac habitasse platea dictumst. Vivamus posuere neque eget viverra sodales. Morbi in mi ac quam cursus aliquam. + +Duis id nibh vel diam iaculis malesuada elementum ac neque. Donec venenatis lectus vitae tellus consequat gravida. Sed euismod enim eget justo aliquet euismod. In volutpat lacus quam, at molestie erat sodales ac. In id dolor suscipit diam bibendum feugiat ac quis ligula. In molestie massa sed enim rutrum cursus. Praesent porttitor lacus dui, id tincidunt leo volutpat vel. Morbi libero tellus, pharetra id mi sed, dapibus sagittis nisl. Aliquam sed sem interdum, tincidunt purus nec, convallis ante. Praesent commodo laoreet libero, non commodo nisi varius sed. Nam et ante et libero euismod consequat in nec erat. Duis convallis nulla sapien, non commodo libero suscipit vel. + +Aenean facilisis massa ut mi condimentum, non porttitor ex vestibulum. Fusce a tincidunt urna, quis suscipit magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam tristique nisi sit amet metus lacinia aliquet. Nulla rutrum enim vel nisl fringilla vestibulum. Maecenas sapien lectus, auctor eu ex ut, auctor rhoncus neque. Duis lacinia enim at pretium feugiat. + +Nunc ipsum neque, tincidunt ut consequat at, tristique in arcu. Nulla lacinia dictum purus vitae aliquet. Fusce eget dui imperdiet, molestie massa quis, egestas ligula. Maecenas aliquet eu nisl et scelerisque. Fusce mollis quis massa id porttitor. Suspendisse potenti. Sed varius tincidunt tempor. + +Curabitur finibus massa nec aliquam efficitur. Nulla eget nunc velit. Quisque tempor orci non gravida hendrerit. Ut aliquam urna ut urna vehicula, nec facilisis dolor pharetra. Nullam pretium convallis nulla, a sodales lacus egestas id. Duis nec nulla enim. Quisque lorem sapien, laoreet sit amet vulputate aliquam, ullamcorper sit amet nibh. + +Curabitur ut nisl ex. Ut molestie in odio iaculis maximus. Morbi egestas est eu mi pretium feugiat ac sit amet ante. Phasellus eu ex volutpat, ornare ligula eget, maximus eros. Quisque mattis quis massa at elementum. Etiam maximus orci lacus. Duis sagittis, enim eu mattis ornare, urna nunc cursus nibh, in cursus leo turpis egestas sem. Fusce rutrum commodo blandit. Cras elementum augue eu quam lacinia rutrum at vel ante. Nulla sed iaculis felis. Duis in pellentesque nulla. Maecenas neque nisl, condimentum eu ipsum vitae, scelerisque vulputate dui. Aliquam sit amet sem egestas, lacinia velit eu, accumsan nunc. Nam mauris orci, blandit sed nisi at, sodales malesuada mi. + +Suspendisse et laoreet elit, finibus laoreet nunc. Donec ut nibh ullamcorper, accumsan ligula ut, rutrum leo. Etiam hendrerit suscipit condimentum. Maecenas ultrices mattis leo a posuere. Quisque ultricies dolor vitae pretium egestas. Proin auctor ac dui vel tincidunt. Aliquam eleifend ipsum purus, eu maximus elit condimentum eu. Curabitur efficitur pharetra viverra. Ut non nisl iaculis odio tincidunt consectetur ac tempus lorem. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultrices blandit nisi, eget vehicula ligula sagittis vel. Nullam consequat sit amet velit eu pulvinar. Sed nec velit fringilla, pellentesque ante quis, viverra ligula. + +Maecenas et diam eu risus dictum condimentum nec vel arcu. Phasellus in nisi ut erat gravida posuere. Morbi tempor lacus non lacus scelerisque elementum suscipit ac dolor. Vivamus bibendum laoreet commodo. Vivamus rhoncus condimentum ex. Sed cursus ultricies enim, accumsan feugiat neque. Vivamus sapien eros, posuere vel aliquam sed, volutpat ac ex. Duis sagittis nibh sit amet porttitor porta. Fusce arcu sapien, molestie id arcu eget, dapibus ultricies quam. Suspendisse potenti. Sed ut feugiat ipsum. Aliquam tristique viverra turpis et blandit. Ut at quam vitae eros imperdiet rutrum eget ut eros. Proin vel nulla condimentum, bibendum mauris eget, scelerisque ligula. Cras commodo sagittis nisl. + +Integer viverra lorem ac urna scelerisque vulputate. Donec non convallis massa. Fusce commodo libero eu commodo dictum. Duis porttitor justo suscipit leo viverra, et feugiat libero rutrum. Curabitur id odio porttitor, facilisis purus ac, bibendum dolor. Donec vestibulum dui mattis, gravida enim et, finibus massa. In mattis quam eget elit pretium congue. Aenean congue nisi sed purus luctus, eu sodales eros euismod. + +Maecenas hendrerit nisl eu tellus lacinia aliquet. Praesent sit amet ornare lacus. Quisque blandit faucibus consequat. Curabitur dolor ligula, ultricies ut dapibus id, ullamcorper eget quam. Quisque vehicula massa ac magna imperdiet, molestie eleifend metus elementum. Mauris tempor ex orci, ut tempor lorem pellentesque laoreet. Sed aliquet ligula ut risus consectetur, ut venenatis neque dictum. Nulla facilisi. Nullam neque mi, faucibus nec egestas sit amet, luctus a nunc. + +Maecenas sed magna ut nisl sagittis viverra vitae nec orci. Nullam dapibus justo facilisis viverra placerat. Curabitur laoreet erat eu vulputate vestibulum. Nulla consectetur, quam nec ullamcorper lacinia, ipsum libero convallis enim, ac rutrum erat lectus nec massa. Proin placerat posuere tellus. Pellentesque vel metus vestibulum, vestibulum velit vel, mattis mauris. Quisque rhoncus sapien quam, id pellentesque neque interdum sit amet. Praesent aliquam lobortis magna sit amet lobortis. + +Maecenas quis libero erat. Nullam pharetra augue eget lacinia cursus. Donec id tortor pretium, placerat risus in, finibus libero. Mauris ac orci in turpis fermentum volutpat. Cras cursus massa est, quis sodales nulla vulputate quis. Etiam nec diam interdum, semper diam at, blandit nunc. Sed porta dolor at eros eleifend sagittis. Duis maximus eros sed risus viverra pretium. In hac habitasse platea dictumst. + +Vestibulum mollis, metus a sodales porttitor, erat odio volutpat purus, in cursus mauris lorem a velit. Ut non faucibus sapien. Quisque efficitur varius justo non porttitor. Curabitur malesuada non diam quis egestas. Cras mattis rhoncus neque quis viverra. Morbi eu iaculis lacus. Fusce eget diam quis ipsum pharetra sodales. Mauris volutpat lectus non ullamcorper ornare. Integer finibus commodo efficitur. Duis sit amet dui id metus condimentum hendrerit. Suspendisse et elit nulla. Integer lacinia egestas quam, dictum ullamcorper enim laoreet at. Sed lacinia neque et sapien convallis molestie. + +Praesent lectus turpis, imperdiet sit amet euismod sit amet, aliquam vitae libero. Proin imperdiet purus rutrum neque ultricies volutpat. Aenean dignissim at sem et laoreet. Nulla blandit nisl nec condimentum egestas. Vivamus feugiat viverra scelerisque. Maecenas molestie vulputate turpis, eu vestibulum urna malesuada in. Quisque porttitor quam ante. Aenean eu efficitur diam. Aenean purus justo, ultricies luctus orci posuere, dapibus placerat eros. Suspendisse hendrerit molestie libero quis blandit. Nullam dapibus urna vitae aliquet facilisis. Etiam ligula libero, interdum vel lorem non, aliquet auctor tortor. Nullam tincidunt nulla eget nunc pulvinar, non congue sapien gravida. Aliquam finibus quam sit amet scelerisque pharetra. + +Etiam at ornare metus, id sodales lorem. In nec sollicitudin mauris. Donec turpis tellus, sodales nec luctus in, vestibulum vel tortor. Curabitur luctus lorem at tellus eleifend consectetur. Sed facilisis libero in tincidunt consectetur. Vivamus nulla dolor, posuere et turpis at, fringilla blandit mi. Aenean tincidunt lorem vitae tellus semper, ut finibus turpis imperdiet. Aliquam ac diam sapien. Integer ultricies ullamcorper varius. Etiam pellentesque, lacus quis lacinia varius, massa lectus tempor turpis, id imperdiet nunc elit in purus. Sed fringilla ipsum eget velit eleifend imperdiet. Donec et enim erat. Aliquam sed orci tincidunt, porttitor lacus sit amet, fermentum neque. Fusce aliquet eros non faucibus hendrerit. In consectetur neque sem, id viverra nibh ultricies eget. + +Morbi tristique eu arcu ac laoreet. Ut orci tellus, gravida quis neque ac, auctor rutrum neque. Vivamus vitae risus nibh. Sed mollis vel ante et egestas. Aliquam eget bibendum orci. Proin ultricies mauris purus, vel mattis orci eleifend quis. Duis et eros ut tellus vulputate feugiat. Suspendisse potenti. + +Nam in urna quis est ornare semper at nec urna. Morbi ex lorem, hendrerit quis mauris vel, elementum hendrerit lorem. Maecenas ac euismod justo. Sed leo ante, sollicitudin sed leo sed, tristique laoreet lacus. In hac habitasse platea dictumst. Nam rutrum sagittis lectus. Vivamus aliquet maximus nisl, nec mollis sapien pellentesque vitae. Fusce sit amet lectus nisi. Curabitur egestas gravida aliquam. Cras venenatis lobortis faucibus. Curabitur sit amet rhoncus mauris. Maecenas nec ante suscipit erat tempus vehicula. Nunc eleifend nibh imperdiet urna euismod sagittis. Aenean imperdiet id sem vitae semper. + +Curabitur tristique porta ullamcorper. Cras at enim massa. Suspendisse ac rhoncus ante, in lobortis est. Etiam sit amet ullamcorper odio. Praesent volutpat vulputate lectus non faucibus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam congue sed orci vitae laoreet. + +Etiam elit ligula, hendrerit non finibus in, pulvinar eu lectus. Quisque pretium maximus augue sit amet lobortis. Pellentesque condimentum, nulla vitae dignissim pretium, diam neque semper purus, vel tincidunt ante neque a eros. Phasellus ac finibus tellus. In vel aliquet nisl. Nulla a orci a leo ultricies rutrum sit amet vitae dolor. Proin et faucibus tortor, quis hendrerit purus. Quisque maximus eleifend massa, vel facilisis ligula interdum eget. + +Phasellus varius gravida urna, in lacinia nisl posuere in. Aliquam iaculis sapien nisl, eu vehicula nisi hendrerit sit amet. Nam molestie, metus vitae maximus vestibulum, arcu est fermentum nisi, sit amet lobortis ante velit sit amet neque. Nulla vitae ultricies arcu. Pellentesque tincidunt tellus nibh, gravida vulputate justo vulputate quis. Maecenas ornare ante felis, et fermentum elit pretium eu. Quisque tellus sem, dignissim a ex vel, vestibulum porta nibh. Morbi pharetra iaculis dictum. Curabitur pharetra odio sed tincidunt congue. Fusce pellentesque nec felis sodales luctus. Fusce rutrum vitae ligula non sodales. Etiam aliquam suscipit neque, ut eleifend libero. + +Aenean sed euismod lorem. Sed pulvinar ex cursus, hendrerit lectus at, viverra urna. Cras at ligula eu lectus congue viverra. Ut eget pretium risus, non scelerisque enim. Integer eu venenatis risus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus nec pellentesque mauris. Aenean dapibus tempus nisi in pellentesque. Praesent mattis placerat nulla at blandit. Nulla ac consequat eros. Maecenas risus libero, hendrerit vitae dui quis, efficitur pretium nisl. Morbi in quam aliquet, mattis arcu a, rutrum purus. Donec ac sapien bibendum, elementum diam in, ornare felis. Nulla in volutpat felis. + +Nunc tempor ultricies massa, eu fringilla nisl molestie vitae. Vestibulum in pharetra lacus. Aenean nec tortor egestas, elementum risus interdum, suscipit lacus. Nam quis efficitur mauris. Duis egestas nunc semper urna euismod fermentum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque a quam turpis. In varius mauris sed iaculis lacinia. Nam ut nisl vel sem interdum consequat nec id risus. Suspendisse vel varius libero. Praesent vel cursus dolor, sed venenatis nunc. Cras justo tortor, accumsan eget tincidunt sit amet, lacinia vitae elit. Sed suscipit est risus, ornare tincidunt dolor interdum molestie. Etiam sit amet nunc a tortor laoreet laoreet. + +Aliquam sed orci venenatis, efficitur turpis ac, egestas neque. Integer arcu justo, condimentum et fermentum vitae, congue sit amet est. Fusce scelerisque posuere dui sed pharetra. Donec id sem sit amet velit mollis facilisis. Morbi rhoncus libero sed tellus efficitur porttitor. Cras id lobortis dolor, in commodo quam. Pellentesque molestie, lacus sit amet dignissim auctor, dui massa vestibulum dolor, sit amet luctus massa mi eu massa. Nullam fringilla, arcu et placerat rutrum, augue tortor fermentum quam, vitae accumsan est enim nec justo. Quisque lobortis commodo sapien, vel venenatis lorem volutpat vehicula. Fusce porta nisi ac odio commodo, quis commodo mi scelerisque. Nunc a volutpat est. Vestibulum dictum feugiat turpis ut finibus. Sed vitae dictum sem. Praesent sollicitudin nulla ultrices ipsum bibendum vulputate. Maecenas tempor augue bibendum erat maximus porttitor. + +Vestibulum ut ipsum orci. Pellentesque non lacinia nisl. Nam sed velit tempor, malesuada diam id, lacinia lacus. Nam dictum rhoncus lectus ut porta. Pellentesque et turpis ac orci dictum sodales quis ut orci. Suspendisse eget mollis risus. Mauris fermentum tellus at neque luctus, sed tincidunt diam sollicitudin. + +Proin cursus odio et aliquet porta. Vestibulum a odio pulvinar, hendrerit orci condimentum, ornare risus. Quisque pulvinar, sem at placerat porttitor, leo sem malesuada augue, mattis finibus diam velit eget urna. Fusce cursus augue sit amet arcu faucibus scelerisque. Sed nec ullamcorper ipsum, vitae tincidunt dui. Integer eget eros leo. Suspendisse eleifend lorem nec fringilla semper. Etiam elementum ipsum eget nibh vulputate, vitae consequat ligula porta. Nulla pharetra augue sit amet magna tincidunt sodales sit amet vitae eros. Etiam euismod rutrum ligula et sodales. Vestibulum ultrices arcu quis lobortis consequat. Vestibulum fringilla mattis arcu et pharetra. Nunc enim metus, efficitur imperdiet vestibulum sed, pulvinar eget arcu. Ut est odio, condimentum a scelerisque ut, tempor ac erat. + +Aliquam diam nulla, aliquet non mi eget, dignissim eleifend risus. In a gravida turpis. Duis blandit justo vitae tempus lacinia. Cras placerat, ipsum eu rutrum placerat, massa lectus ullamcorper nibh, ut facilisis lacus massa a ligula. Praesent vulputate, massa at consectetur eleifend, ante magna rutrum orci, ac interdum risus lectus ut metus. Donec eu leo nisi. Cras vulputate aliquam lacus vitae tempor. Quisque dolor nibh, tristique et imperdiet vitae, bibendum ut lorem. Nulla vel orci in ante dictum dictum a eget turpis. Vestibulum eget lorem sit amet nunc scelerisque consectetur vitae ut diam. Sed aliquam sagittis ante quis lobortis. Aliquam a elit fringilla, laoreet eros sed, accumsan est. Nullam vitae sollicitudin ex. + +Sed nibh lorem, eleifend quis gravida vel, posuere sed mi. Nullam eget enim lacinia, gravida leo nec, viverra felis. Aenean ac euismod mi. Duis congue, turpis in lacinia dapibus, eros mauris rutrum odio, a congue nunc enim sit amet mauris. Sed in lacus sed velit tempor congue. Suspendisse potenti. Nam et justo lorem. Vivamus dictum sapien eu sapien fermentum, nec finibus augue ultricies. Nunc sodales, urna vitae fringilla scelerisque, quam felis consequat sapien, ut venenatis elit magna vitae lectus. Donec porta condimentum leo eget feugiat. Fusce vulputate mauris tellus, ac vehicula sapien viverra ut. Nullam ac cursus tortor. Maecenas nec facilisis sem. Pellentesque dapibus sed libero vitae cursus. Vestibulum a semper quam, nec finibus tortor. + +Fusce consequat odio eu est aliquam dictum. Aenean ut blandit lacus. Donec pulvinar, mauris et euismod aliquam, metus mauris aliquam ex, a convallis lacus mi a lorem. Aenean eleifend mattis nulla, nec facilisis mi feugiat sed. Maecenas vitae interdum nisl. Vivamus vel mi ac nibh finibus congue. Sed tristique enim ut sollicitudin pulvinar. Maecenas quis accumsan felis. Quisque eget pulvinar quam. Suspendisse pellentesque velit ipsum, in pharetra ligula rutrum ac. Vivamus mattis sollicitudin condimentum. + +Maecenas eu metus vestibulum, sodales tortor vel, aliquet arcu. Integer lorem velit, fringilla facilisis blandit vel, interdum quis massa. Morbi non dui quam. Donec ante diam, tempor nec pharetra nec, ultricies at tortor. Donec ut nibh nibh. Mauris eu orci eget mi convallis porta in sed metus. Suspendisse potenti. Phasellus ullamcorper, purus et rutrum facilisis, quam turpis euismod tellus, nec rhoncus enim risus at ex. Ut tincidunt tempus eros non ornare. Mauris eu vehicula velit, quis posuere urna. Donec lectus est, blandit id rutrum non, accumsan nec justo. Mauris ut mollis tortor, sit amet ornare est. + +Phasellus rhoncus fermentum mauris, in pulvinar arcu rhoncus ut. Curabitur id pharetra orci, sed semper lorem. Cras convallis tempus nibh sit amet sollicitudin. Integer nec sollicitudin dui, non ultrices metus. Ut aliquet ex non arcu dignissim venenatis. Mauris elit massa, pellentesque ac tristique nec, porttitor eget nisi. Nunc at libero nisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; + +Sed pharetra sagittis interdum. Vestibulum sit amet mauris nec nunc mollis malesuada quis vitae nulla. Vestibulum consequat felis ac lorem tincidunt, ut ullamcorper leo posuere. Etiam commodo augue sit amet lacus congue mattis. Aenean nibh nunc, dignissim pulvinar arcu quis, venenatis placerat est. Proin tellus nibh, vestibulum id facilisis iaculis, facilisis in justo. Mauris libero erat, consequat eget finibus ut, tristique nec magna. Etiam quis mi non tellus feugiat fringilla. Ut pulvinar nibh nulla, ac viverra massa dictum semper. Ut non sollicitudin dui. + +Mauris convallis sem a eros suscipit, ut mattis quam pretium. Vestibulum sed elit dapibus, ullamcorper risus faucibus, pharetra felis. Proin libero massa, fermentum a imperdiet scelerisque, dapibus ut sem. Fusce id arcu nec leo bibendum laoreet eget sed sem. Nunc ac elementum ipsum. Nullam felis magna, sollicitudin quis justo vel, bibendum eleifend neque. Phasellus vestibulum nulla ac suscipit pharetra. Praesent rutrum odio id leo malesuada aliquet. Aliquam lorem lacus, feugiat non ultrices nec, venenatis varius ipsum. Proin a metus vitae felis ullamcorper auctor. Proin vitae blandit massa. Ut at tellus interdum, pretium mi id, ultrices augue. Nam rutrum risus tristique dui eleifend, non venenatis turpis dictum. Suspendisse nec mattis nulla. Nunc id enim orci. + +Nullam et sollicitudin ex. Ut iaculis consectetur lacus, eu luctus libero fringilla vel. Praesent aliquet libero at erat mollis facilisis. Vivamus tristique posuere diam, vitae interdum tortor accumsan a. Donec arcu est, bibendum eu dictum et, fringilla ac dui. Duis vel erat elit. Fusce fermentum vitae lacus ac auctor. Suspendisse potenti. Donec viverra tortor orci. Sed tempor ultricies sapien, at sollicitudin nunc aliquam eu. + +Nullam eleifend semper justo, at feugiat ex hendrerit sit amet. In vitae ipsum odio. Quisque pellentesque molestie quam, non feugiat quam mollis sed. Etiam accumsan, neque id placerat aliquet, risus tellus tincidunt orci, ut consequat tortor massa vel arcu. Phasellus sed erat et elit iaculis imperdiet. Mauris felis ante, venenatis quis lobortis eget, mollis non ipsum. Donec semper sodales ex vel sollicitudin. Nam ipsum lorem, hendrerit ac euismod non, cursus a tellus. + +Etiam auctor turpis eget lorem malesuada imperdiet et interdum ligula. Nunc dapibus finibus ante, in aliquet nulla. Proin quis ante odio. Mauris eu laoreet neque. Proin varius est sed lacus mollis tempus. In maximus sed nisl at posuere. Vestibulum accumsan urna quis faucibus blandit. Curabitur ornare egestas ipsum ac elementum. Nulla ac justo non enim posuere ornare. Fusce a hendrerit nisl. Fusce laoreet, felis eu mollis blandit, urna elit bibendum felis, ut imperdiet mauris leo ac massa. Fusce fringilla, quam et dictum commodo, dui tellus blandit mauris, sed eleifend dui est ut mauris. Pellentesque ut elit sollicitudin, placerat quam a, pharetra diam. Ut egestas velit ac lacinia sodales. Ut ullamcorper velit non erat suscipit, vel lobortis est ultrices. + +Fusce tristique eros eu mi tincidunt, at vulputate neque tempor. Aenean sit amet arcu a arcu porttitor semper id sit amet nulla. Pellentesque posuere lobortis lorem sed porta. Nullam nibh justo, finibus vitae varius sed, fermentum ut mauris. Nam sed vulputate ante. Suspendisse tristique libero in diam egestas, at varius sapien pulvinar. Vestibulum eu elit nec magna convallis lobortis. Duis a nisi odio. Quisque erat felis, molestie ut hendrerit pretium, consectetur ut risus. Phasellus malesuada maximus lacus vitae scelerisque. Nulla facilisis urna non ipsum mattis fermentum. Etiam semper quam ut ipsum euismod luctus. + +Ut sed feugiat ipsum. Nam quis bibendum enim, quis sollicitudin urna. Ut pharetra, leo ac feugiat pellentesque, libero diam tempus sapien, et pretium ex lacus a eros. Vestibulum sed augue nisl. Nunc id malesuada neque, quis rhoncus purus. Suspendisse nulla dui, sagittis luctus sapien quis, iaculis feugiat odio. Sed venenatis accumsan neque, sit amet tempus leo sodales id. Etiam eleifend, magna vel rutrum porta, sem quam ornare eros, vel tincidunt arcu ex a ligula. Ut a consequat dui. Aliquam vestibulum id felis a aliquet. Nullam sit amet arcu a orci lobortis tincidunt sed eget ante. In interdum, metus aliquet posuere lobortis, lectus tellus tristique elit, ultricies dictum erat ex a leo. Nulla lacinia, neque id volutpat pharetra, ex neque luctus tellus, eu blandit turpis magna mollis ipsum. + +Suspendisse nec maximus dui. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas felis justo, hendrerit eget turpis sit amet, dignissim hendrerit libero. Maecenas a leo nunc. Donec sit amet sem pellentesque, eleifend risus a, rutrum dui. Praesent diam libero, egestas a eros non, posuere varius augue. Integer ipsum eros, dictum viverra lectus a, condimentum aliquam orci. Ut tristique quam non mollis mollis. Vivamus a placerat tellus, vel vehicula orci. Praesent ac tempus felis, laoreet venenatis eros. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam turpis nunc, posuere et arcu ut, lacinia pellentesque sapien. Quisque sagittis sit amet erat sed tincidunt. Curabitur id tempus eros. Sed suscipit a nibh vitae interdum. Mauris sapien velit, cursus in justo eu, sollicitudin dapibus tellus. Vivamus et feugiat massa. Phasellus mattis vulputate imperdiet. In ut gravida massa. In eu elit diam. Cras nec urna tincidunt, ornare lorem at, aliquet magna. Sed maximus tortor ipsum, quis maximus nunc sagittis eu. Cras pellentesque eu nulla nec mattis. Morbi suscipit sed neque sed auctor. Pellentesque dignissim tellus vel neque gravida, nec vestibulum nulla eleifend. + +Fusce tristique gravida purus. Curabitur laoreet augue nec metus auctor, ut mollis nisl suscipit. Nullam eget commodo erat. Quisque vitae lobortis lorem. In hac habitasse platea dictumst. Etiam eu orci facilisis, efficitur eros eget, posuere ante. Quisque in risus in orci convallis porttitor. Cras eleifend fringilla dictum. Pellentesque ut orci leo. Aliquam tincidunt condimentum dapibus. Donec vitae leo sed dolor tempor sagittis id ut odio. Aenean mollis tristique commodo. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque pretium viverra magna, eu feugiat tellus porttitor in. Nulla erat felis, sagittis quis dolor ac, aliquet pharetra metus. + +Etiam nec viverra lacus, nec gravida metus. Phasellus ipsum ex, malesuada sed pretium eu, ornare nec tortor. Ut eu leo sit amet elit euismod placerat. In porta ante et accumsan porta. Donec hendrerit ac libero sed facilisis. Proin bibendum justo vel vulputate tincidunt. Vestibulum molestie neque tortor, at elementum leo pulvinar in. Sed rhoncus malesuada risus, ut sagittis odio posuere vel. Vestibulum faucibus rhoncus nibh ut porta. Donec elementum urna consequat, scelerisque tortor in, bibendum lacus. Nulla erat nunc, lacinia at lobortis a, maximus eu dolor. Fusce viverra, erat semper placerat egestas, sapien diam lobortis urna, sit amet semper mauris est in risus. Cras eget porttitor massa. + +Fusce eget cursus neque. Donec erat elit, mattis sit amet faucibus in, dignissim eget arcu. Praesent sem erat, porttitor ut hendrerit sed, fermentum sed nisl. Suspendisse efficitur facilisis condimentum. In efficitur purus tortor, a pulvinar dolor venenatis quis. Proin consequat, risus nec condimentum placerat, quam massa dignissim mauris, at semper purus lorem et nunc. Phasellus luctus dictum ante, quis vestibulum eros auctor eu. Proin quis nisi quis ligula convallis rhoncus. Suspendisse id eros vitae neque efficitur malesuada. Praesent sit amet tincidunt lectus. In ante elit, blandit vel faucibus quis, aliquet euismod purus. Duis eu purus volutpat, porta ante sit amet, efficitur augue. Donec congue a risus quis malesuada. Aenean sed est sollicitudin, efficitur enim nec, viverra quam. + +Sed vel iaculis leo. In lobortis accumsan lacus sit amet sollicitudin. Donec vel porta purus, vel vulputate est. Maecenas volutpat nisl id accumsan pellentesque. Vestibulum posuere id lorem sit amet faucibus. Aenean dictum lectus lacus, varius semper dolor cursus nec. Aliquam a tortor nisl. Maecenas sit amet diam fringilla, sodales nulla vel, iaculis lectus. + +Cras pulvinar mattis faucibus. Pellentesque semper, felis vel elementum porttitor, mi ex vestibulum libero, a rhoncus ante libero at dolor. Pellentesque maximus lorem vel massa venenatis cursus. Maecenas sed facilisis orci, vel consectetur ligula. Sed porttitor tellus magna, in placerat enim tristique sit amet. Curabitur leo lectus, fringilla dignissim augue quis, scelerisque posuere nunc. Ut sollicitudin massa ac facilisis dictum. Proin et nulla gravida, auctor ante ut, accumsan massa. + +Vestibulum faucibus lectus eget eleifend tristique. Aliquam tristique felis quis metus pretium, sed egestas sem mattis. Pellentesque ac enim at mi fermentum lacinia non eget tellus. Proin lacus enim, imperdiet et turpis sed, viverra auctor leo. Nam augue ante, tristique a neque ut, ullamcorper tempor tellus. Curabitur porttitor ornare lectus vel commodo. Nunc luctus, purus et cursus viverra, dolor magna condimentum libero, maximus tristique lacus felis vel ligula. Phasellus lacinia faucibus leo, id pretium ipsum suscipit quis. Fusce mollis enim sed augue bibendum vehicula. Nunc mollis lorem vel erat molestie, non hendrerit id. diff --git a/bdd/data/test-data/topicOutput.txt b/bdd/data/test-data/topicOutput.txt new file mode 100644 index 000000000..1576c6cdb --- /dev/null +++ b/bdd/data/test-data/topicOutput.txt @@ -0,0 +1,335 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla quis massa velit. Nam quis luctus purus, in iaculis ligula. In eu iaculis arcu, in commodo urna. Sed ut libero vitae nunc luctus tristique. Cras mollis malesuada ornare. Aliquam a sem ut ex facilisis sollicitudin. Nulla facilisi. Quisque ut varius ligula. Sed porttitor ex a porttitor feugiat. Morbi a tortor tempus diam dignissim blandit. Etiam nec rutrum tortor. Phasellus orci elit, cursus id molestie in, ultrices at ante. + +Nulla malesuada tincidunt elit, a gravida dolor placerat vel. Curabitur molestie sed enim eu egestas. Curabitur maximus malesuada vehicula. Suspendisse vitae gravida est. Sed pharetra fringilla lacus, sit amet convallis turpis tincidunt at. Quisque euismod rhoncus pulvinar. Donec sed ante in felis auctor posuere. + +Quisque nisi velit, ornare eget dictum vel, aliquam in nisl. Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse et nulla ligula. Nam ac ligula vitae tortor consequat fringilla. Donec dignissim gravida magna eu aliquet. Nullam dolor velit, sodales vitae turpis ac, molestie congue dui. Aliquam eros nisl, dignissim non lectus a, volutpat convallis odio. Nunc eu nisl sodales, porttitor turpis sed, euismod justo. + +Etiam sit amet lacus molestie, tristique sem sed, mattis est. Sed rutrum ornare massa, nec auctor metus. Cras at tempor arcu. Nunc velit mauris, pretium ut pellentesque non, fringilla nec elit. Ut tempus laoreet pretium. Phasellus placerat diam tincidunt volutpat cursus. Integer tempor massa purus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; + +Maecenas ac blandit lectus. Praesent ut tincidunt ligula. Sed massa urna, luctus ac auctor eget, scelerisque ut nisi. Nulla ipsum lacus, faucibus non elementum vitae, ornare ac libero. Ut quis semper nunc, non luctus sapien. Suspendisse consectetur pulvinar consequat. Nulla consectetur sagittis nunc at sagittis. Aliquam euismod, velit nec tempus porta, odio tortor iaculis libero, eget vulputate ipsum ante ut sapien. Donec sed velit pharetra, accumsan enim quis, ultricies mauris. Vestibulum aliquet fringilla dictum. Suspendisse sed nibh orci. + +Fusce posuere non dolor mollis laoreet. Maecenas aliquet arcu nec odio interdum, vitae interdum quam malesuada. Maecenas tincidunt finibus nisl, at sagittis est fermentum feugiat. Morbi at varius magna. In pulvinar ut leo id hendrerit. Vivamus et luctus odio. Phasellus ultricies bibendum sapien eget laoreet. Aliquam arcu felis, condimentum et metus a, tincidunt volutpat nulla. + +Fusce non ultrices lectus, vel fermentum ipsum. Curabitur dictum dolor a enim cursus maximus. Maecenas nisl erat, mattis commodo mi et, hendrerit vehicula nibh. In lacinia, tellus in gravida bibendum, risus massa iaculis erat, in venenatis diam justo a libero. Suspendisse est nisi, accumsan a aliquam nec, gravida at velit. Pellentesque viverra posuere justo ac ornare. Nulla turpis tellus, lacinia in felis ac, molestie molestie nisl. Nam felis enim, feugiat in eros et, sollicitudin luctus justo. Nullam lobortis eros ut ultrices facilisis. Cras vitae imperdiet nisl, a ullamcorper elit. Nam non orci vitae orci aliquet faucibus. Donec lobortis iaculis turpis, in semper orci tristique ac. Nulla maximus fringilla lectus, at tristique purus imperdiet nec. Donec viverra risus eu vulputate laoreet. Mauris vel congue odio. + +Aenean libero nisi, facilisis laoreet congue eget, rutrum a quam. Ut id molestie velit, sit amet rhoncus sapien. In sit amet ligula ut purus blandit fringilla eu ut tortor. Donec mattis rutrum metus, sit amet feugiat tortor. Nunc dictum vitae elit vel lobortis. Phasellus vel ante blandit, aliquam neque a, sollicitudin turpis. Phasellus tempor nisi eu eros imperdiet accumsan. Donec scelerisque nibh mauris, vel eleifend justo condimentum et. Pellentesque sit amet faucibus libero. Nulla et libero gravida, vestibulum elit at, vestibulum enim. Sed varius, odio sit amet interdum ultrices, lorem enim laoreet urna, a malesuada magna ex at elit. Fusce a faucibus elit. Etiam sagittis tincidunt diam eu malesuada. In varius diam id nisl auctor condimentum. + +Sed consectetur sagittis odio vel bibendum. Sed blandit tincidunt erat non suscipit. Nullam efficitur tincidunt tellus scelerisque gravida. Donec a dictum magna. Aenean in justo sodales, tempor est at, lacinia nulla. Etiam accumsan nec nunc vel tempus. Nam imperdiet ultrices enim, ac tempus sem. Nulla dapibus semper lobortis. Sed luctus lacinia euismod. Quisque luctus orci risus, quis sollicitudin orci malesuada ac. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In iaculis finibus justo dapibus pharetra. Integer at euismod mi, vitae eleifend urna. + +Nulla facilisis purus nulla, non congue nulla euismod quis. Fusce vitae tellus et sem venenatis iaculis a vitae ex. Aliquam sollicitudin condimentum metus. Aenean consectetur iaculis ligula nec maximus. Mauris ex ipsum, dignissim sed rutrum in, commodo sed libero. Suspendisse fermentum massa sed nunc tempus auctor. Pellentesque imperdiet neque sapien, suscipit luctus enim scelerisque in. Aliquam erat volutpat. Curabitur ac arcu placerat, vehicula neque vel, vestibulum dolor. Vivamus sed vehicula erat. Vivamus pellentesque non tellus in consequat. Etiam commodo, tellus eu vehicula pretium, odio ex ornare leo, et euismod orci velit et augue. Aliquam faucibus risus quis sapien fermentum, eget consectetur lorem lacinia. Nam ac gravida est. In hac habitasse platea dictumst. Mauris varius suscipit turpis ac cursus. + +Morbi et varius metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In congue ipsum neque, ut euismod sapien dignissim a. Maecenas faucibus orci ac viverra vulputate. Ut pellentesque leo at ante gravida, sit amet fermentum ipsum fringilla. Maecenas in interdum risus, non vehicula dolor. Quisque non eros arcu. + +Aliquam ligula tellus, dapibus ac rutrum non, gravida eget arcu. Vestibulum turpis turpis, pellentesque vel sollicitudin sit amet, molestie ac justo. Cras sit amet augue erat. Nullam pellentesque elementum mattis. In hac habitasse platea dictumst. Nulla ac eros ut eros porta sodales. Phasellus tincidunt, felis non mollis suscipit, sem mauris tempus ligula, et posuere mi nulla aliquet eros. Phasellus porttitor pretium tortor et porttitor. Donec vel libero scelerisque urna scelerisque tempus in a purus. Phasellus commodo commodo tristique. Curabitur egestas porttitor odio, et viverra enim. Aliquam semper quis nisl ac tristique. + +Fusce sed tincidunt augue. Etiam fringilla posuere finibus. Aliquam fringilla mollis purus vel hendrerit. In a varius lorem. In aliquet in tortor at convallis. In mattis tempus facilisis. Phasellus pretium nisl vel purus gravida, commodo imperdiet odio pharetra. Duis viverra porta magna nec viverra. Suspendisse at metus metus. + +Mauris congue ullamcorper tortor, id tempus tortor luctus blandit. Sed quis volutpat erat, id elementum lacus. Fusce euismod lacus in euismod egestas. Cras eu diam faucibus, facilisis magna quis, semper magna. Sed fermentum purus eget ex egestas, vel euismod dolor elementum. Nullam faucibus dignissim consectetur. Fusce ut magna risus. Etiam sapien est, elementum quis sapien et, ullamcorper vulputate arcu. Sed in nisl nec leo lacinia feugiat ac in mauris. Morbi dapibus augue metus, id fringilla metus accumsan non. Donec eleifend lacus sit amet venenatis ultricies. Etiam a aliquet tellus. Vivamus nec pellentesque arcu. + +Integer nec nulla sit amet sapien iaculis vestibulum. Aenean a urna aliquam, dignissim dolor eget, vestibulum orci. Nullam tristique leo nulla, et placerat quam gravida semper. Nunc dignissim nisl non augue pellentesque, non interdum sem volutpat. Sed lobortis, sem non pharetra consectetur, ante tortor porta justo, sit amet efficitur tortor ligula id neque. Donec a feugiat quam. Sed vel viverra augue. In interdum mattis tellus, quis sodales ex auctor eget. Curabitur tellus est, mattis eu fermentum sit amet, tincidunt ut nisi. Maecenas auctor lacinia leo at tempor. Integer sed dui et metus ullamcorper pretium. Proin mollis enim ac ex dapibus, vel rhoncus diam euismod. Mauris porttitor lacus ligula, non tristique magna porttitor et. Vestibulum volutpat aliquet enim sit amet mattis. + +In rutrum lobortis efficitur. Sed eget velit augue. Nunc sodales tortor ut sodales finibus. Integer mollis imperdiet lacus at ornare. Donec volutpat et dui mattis vulputate. Aenean sollicitudin turpis viverra pretium dictum. Sed vel gravida nunc. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae faucibus odio. Quisque viverra leo elit, a scelerisque velit efficitur non. Maecenas interdum, justo sed placerat vehicula, justo massa laoreet quam, porttitor vestibulum justo ante vitae est. Sed vitae metus non felis aliquet pharetra. In eleifend est sit amet turpis vehicula sodales. Sed posuere rhoncus sem, pellentesque dignissim eros vehicula id. Quisque vel elit metus. Cras vehicula dictum elit, semper viverra dolor blandit id. + +Phasellus egestas, urna nec congue posuere, purus lacus sagittis ex, eu iaculis sapien quam ut nulla. Nunc bibendum pulvinar nunc vel tempor. Nam varius luctus mollis. Nam lectus nibh, ullamcorper vel orci id, vulputate ornare augue. Aenean gravida nisi vel orci blandit, vitae fringilla sem dapibus. Nullam lobortis odio nec turpis luctus, sed suscipit neque vulputate. Mauris sed mauris dapibus lorem cursus faucibus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas quis ultricies enim. + +Suspendisse eu laoreet mauris. Curabitur sit amet faucibus arcu, ut feugiat justo. Integer in purus ut nulla vehicula mollis et sed tortor. Praesent pulvinar, leo posuere elementum rhoncus, justo ante ultricies ante, eu accumsan lorem elit vitae augue. Etiam vel posuere ipsum, sed auctor risus. Praesent gravida nulla congue, tempor urna sed, interdum velit. Aenean imperdiet, turpis sed venenatis facilisis, nunc ex aliquet dui, at facilisis purus nulla id nunc. + +Fusce non ante sed ipsum lacinia lacinia gravida dignissim augue. In hac habitasse platea dictumst. Nulla fermentum lorem eu sodales feugiat. Etiam aliquet ut nulla nec fermentum. Maecenas et suscipit magna. Vivamus vehicula aliquet nisi quis rhoncus. Integer mattis porttitor enim, ac tincidunt libero malesuada at. + +Nam ac dui et neque ornare euismod. Suspendisse ultricies orci enim. Sed eu euismod leo. Duis condimentum risus risus. Suspendisse id sollicitudin ex. Sed eu massa at magna iaculis mattis vel id est. Donec at bibendum libero. Aliquam congue maximus urna ac pharetra. + +In pretium lectus sit amet maximus varius. Vestibulum id massa pretium, fermentum nulla sed, aliquet turpis. Quisque tincidunt ante vitae massa viverra iaculis. Donec consequat sem sit amet fringilla auctor. Fusce a nunc sollicitudin, tristique erat sed, bibendum sem. Sed eu mollis ex. Pellentesque fermentum nisl tellus, tristique imperdiet odio vehicula eu. + +Cras ullamcorper pulvinar dictum. Aliquam eget accumsan felis. Pellentesque semper, nisl id molestie bibendum, eros tortor feugiat magna, non pretium tortor massa ut quam. Donec blandit pulvinar quam, vitae faucibus ex finibus sit amet. Sed ut libero cursus, viverra dolor eget, pharetra eros. Ut dignissim dui eget risus iaculis mattis. Pellentesque at mi lacus. Curabitur auctor eget nunc id rhoncus. Fusce odio lectus, vestibulum vel ante nec, lacinia iaculis ex. Duis eget orci fringilla, aliquet neque at, gravida leo. Maecenas eget nunc in ligula convallis ultricies fringilla in lorem. + +Curabitur tristique nisl sed turpis luctus, eget ultricies lorem sodales. Praesent viverra, eros tincidunt vehicula venenatis, nisi dui malesuada sapien, et fermentum dui turpis quis purus. Praesent porttitor sed velit quis dapibus. Donec aliquet diam sed gravida efficitur. Suspendisse vel quam congue, mattis ex et, pretium ex. Fusce ex sapien, faucibus et sapien quis, ornare accumsan urna. Phasellus nec nunc et nisi pulvinar consectetur. Suspendisse potenti. Nam a urna et enim iaculis consequat eu sit amet quam. Phasellus suscipit nisl est. Nulla vulputate ipsum orci, sed finibus ipsum sollicitudin et. Curabitur pellentesque pellentesque vehicula. Nullam finibus dui nec velit ornare semper. + +Vestibulum odio mauris, dignissim sed rutrum nec, tristique vel libero. Nam a dictum erat. Ut nec nisi in justo consectetur sollicitudin. Sed pretium est eget ligula maximus sollicitudin at eu nisl. Etiam congue enim a nulla fermentum ullamcorper. Pellentesque aliquet justo vel nunc hendrerit facilisis. Vivamus non leo elit. Nam a euismod felis. Nam dignissim tellus at ligula maximus, a pellentesque nibh euismod. Nam aliquam erat lectus, nec sollicitudin neque ultricies et. In id hendrerit arcu. + +Mauris imperdiet consequat elit vel mollis. Aenean dapibus, orci nec imperdiet porta, enim ligula gravida orci, eu porttitor sem mauris et ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Maecenas luctus augue in dui consectetur tempus. Vivamus sit amet est turpis. Quisque non iaculis erat, ut convallis massa. Vestibulum laoreet arcu eget venenatis tempor. Integer pretium sodales lectus et suscipit. Vivamus auctor ultricies suscipit. Aenean accumsan magna at euismod consectetur. + +Nulla eu risus erat. Cras pellentesque commodo ligula, id tempor neque vulputate nec. Integer lobortis, est id tincidunt gravida, lorem ante lacinia nisi, gravida consectetur massa massa eget metus. Nulla a maximus lacus, et sodales elit. Curabitur et arcu diam. Fusce blandit commodo nunc, ut ornare massa mattis nec. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla facilisi. Ut feugiat ante enim, eu vulputate urna egestas ut. Quisque ante nulla, volutpat vitae mauris ac, euismod auctor metus. Nulla a sodales mi, eu ornare lorem. Quisque fringilla, mi vel pulvinar rhoncus, magna tortor euismod ipsum, sed scelerisque urna velit pretium turpis. Mauris porta augue non imperdiet lobortis. Maecenas faucibus tempor dolor eu interdum. Fusce venenatis laoreet enim, sit amet sagittis leo fringilla a. + +Etiam ac dui at magna vulputate posuere faucibus scelerisque orci. Morbi ut rhoncus arcu, quis pellentesque leo. Nunc sed justo ut quam ultrices lacinia. Donec dictum tristique scelerisque. Mauris vel rhoncus justo. Nunc faucibus molestie dignissim. Vivamus ac auctor nisl. Nunc et nisi id elit gravida suscipit. Nulla auctor, urna nec pretium ultricies, neque neque tincidunt mi, ac venenatis odio felis euismod sapien. + +Nullam aliquam erat quis mi aliquet, ac ultricies enim convallis. Suspendisse interdum maximus ante, vel laoreet urna malesuada ac. Nam iaculis in purus accumsan porttitor. Fusce elit ipsum, ultricies dapibus nisl ac, ullamcorper placerat ligula. Sed in risus urna. Nunc bibendum nisi dignissim libero ultricies mattis. Curabitur tempus mi quis libero pharetra volutpat. Maecenas molestie aliquam velit, eget scelerisque magna ullamcorper ac. Suspendisse quis sagittis leo, quis malesuada quam. Proin nec dolor ac odio consequat euismod nec sed ipsum. Nunc purus diam, sagittis sit amet nibh in, egestas pulvinar quam. Etiam efficitur purus nec mattis molestie. Aenean nec dolor eu neque lobortis pellentesque ut sed leo. + +Cras ornare sodales est, ut fermentum tellus varius sed. Quisque elit enim, egestas quis orci eget, ultricies sagittis turpis. Aliquam erat volutpat. Suspendisse potenti. Etiam sit amet porttitor dolor, vel posuere quam. Aliquam in est lobortis, gravida justo quis, elementum augue. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed at metus risus. Suspendisse tincidunt volutpat felis ac condimentum. Pellentesque ligula sem, pharetra mattis leo nec, euismod dapibus nunc. Vestibulum blandit enim erat, sit amet aliquet velit venenatis rutrum. Donec non mattis odio. Suspendisse massa nisl, auctor sagittis orci a, pulvinar sollicitudin dolor. Donec quis malesuada augue, in imperdiet justo. + +Sed porttitor dignissim ultricies. Nam elementum metus in pulvinar mattis. Cras mauris mauris, tempor in sagittis id, aliquam sed lacus. Duis congue faucibus fermentum. Sed sollicitudin lacus sed orci semper faucibus. Maecenas porttitor fringilla velit, ac vehicula ipsum commodo et. Quisque sapien libero, varius sed neque ac, pretium consectetur tellus. Nulla mi magna, accumsan ac facilisis id, fermentum nec mauris. Vivamus venenatis sem sit amet est imperdiet, efficitur fringilla risus posuere. Cras sagittis congue blandit. + +Ut eget libero tincidunt, malesuada augue quis, malesuada enim. Mauris placerat bibendum lorem, quis ullamcorper diam pulvinar sit amet. Morbi ex augue, tempus sit amet metus vitae, pulvinar egestas tortor. Maecenas pellentesque ultrices venenatis. Sed ornare vitae purus a aliquam. Aenean malesuada consequat tellus, sit amet sodales nisl placerat nec. In hac habitasse platea dictumst. + +In in posuere urna. Sed pharetra dignissim tortor, ac condimentum ante rhoncus ut. Quisque convallis pharetra diam, at accumsan magna eleifend eget. Praesent sollicitudin ligula eu massa vestibulum, eu vestibulum libero tincidunt. Quisque cursus porta lorem a dapibus. Phasellus elit arcu, elementum at ante at, malesuada lacinia massa. Aliquam hendrerit purus vitae mi mollis, at vulputate felis pulvinar. Praesent finibus sit amet lacus at pellentesque. Proin a ultrices nibh. Etiam a pharetra ex. Praesent vitae neque id nisl egestas commodo eget quis nunc. Maecenas porttitor varius tellus, at consectetur est. Aenean maximus lectus at turpis placerat sodales. + +Morbi sapien ipsum, facilisis blandit leo blandit, posuere tincidunt nisi. Sed venenatis lectus quis cursus vulputate. Ut dapibus tincidunt mauris id aliquam. In vulputate eu arcu vitae pretium. Duis malesuada orci orci, et ullamcorper ante mollis eget. Quisque egestas, orci in interdum laoreet, libero neque cursus lacus, nec porta quam magna ac nulla. Nullam mattis porta eros sed aliquam. Donec nisi tellus, luctus at pharetra ac, accumsan at lacus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Praesent fringilla malesuada turpis, sed venenatis elit rutrum sed. Nulla enim lectus, egestas sed tempus sagittis, cursus eu tellus. Nulla facilisis sem eget lobortis lacinia. Vivamus euismod risus at dictum iaculis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Praesent finibus placerat nunc. Proin accumsan iaculis nisi nec malesuada. Vivamus quis dolor id ipsum ultrices lobortis. Duis fringilla ultricies est, non tincidunt turpis porta quis. Proin mollis tellus elit, nec porta neque aliquam eu. Suspendisse feugiat porttitor urna. Praesent lobortis lacinia vulputate. Nulla ex odio, vehicula et fermentum eget, posuere sit amet quam. Proin imperdiet felis vitae ante vehicula cursus. Mauris in sem in urna lobortis tincidunt. Fusce porttitor pharetra posuere. Phasellus nec semper tortor. + +Praesent quis felis odio. Sed et erat ac turpis pellentesque ullamcorper. Nam iaculis massa eget varius vulputate. Etiam varius odio vulputate felis sollicitudin dignissim. Praesent augue turpis, hendrerit a mi vitae, vehicula blandit nulla. Vestibulum vel tristique ligula. Mauris dignissim vitae sem sed suscipit. Fusce sollicitudin lacinia est ac volutpat. Suspendisse rhoncus bibendum lobortis. Nullam laoreet sapien fringilla ante mollis dapibus. Vestibulum eu nisl augue. + +Cras lobortis in massa vitae gravida. Nullam at fermentum massa, eu pellentesque tellus. Suspendisse non porttitor lectus. Cras quis risus purus. In pretium felis at accumsan condimentum. Vivamus facilisis eu eros et condimentum. Proin erat sapien, pulvinar in fermentum eget, dictum euismod neque. Morbi mattis lobortis purus, eget tempor tortor efficitur nec. Proin vitae sapien quam. Nam sed purus vel nibh volutpat aliquam. Proin in leo nisl. Integer finibus nisl vel nibh egestas, ut tempor risus bibendum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque feugiat venenatis quam, sit amet dignissim lorem varius vitae. Duis est orci, interdum non orci at, condimentum tempor nibh. Nullam elementum erat in sapien finibus, vitae placerat nisl accumsan. + +Nulla facilisis diam id turpis vehicula, et fermentum nisl rutrum. Phasellus at suscipit purus. Cras sit amet auctor leo, eu interdum magna. Duis hendrerit mollis tortor at pretium. Aliquam est lectus, tristique vel condimentum sit amet, scelerisque vitae odio. Cras sit amet luctus libero, et accumsan turpis. Ut diam tellus, tempus vitae ullamcorper in, egestas ac nibh. Proin tristique, odio ut tristique sagittis, ex est elementum arcu, ut laoreet est neque et est. Donec vulputate sapien interdum malesuada vestibulum. Aliquam erat volutpat. Nam sit amet lacus a elit egestas tincidunt. Ut quis lorem varius, lobortis metus nec, accumsan est. Phasellus arcu dolor, faucibus eget facilisis et, finibus vel eros. Cras id quam tortor. + +Suspendisse imperdiet interdum vestibulum. Nunc feugiat laoreet nisl, eget dignissim nibh tristique non. Donec malesuada condimentum mauris, et ullamcorper mi tincidunt feugiat. Nulla facilisis venenatis magna, a iaculis orci ultrices tempor. Nam mollis augue non elit mattis tempus quis vitae velit. Praesent dignissim tempus nunc eu rutrum. Sed placerat turpis eget ligula porttitor, eu pellentesque nulla tincidunt. Mauris eu eros elit. Sed sed accumsan leo, non tristique justo. Nam placerat tristique dolor et imperdiet. Maecenas interdum sapien non cursus mollis. Duis sed erat sollicitudin quam facilisis pharetra eu non orci. Phasellus venenatis mi ac fermentum egestas. Sed aliquam neque porttitor, lobortis erat id, volutpat nulla. Fusce sed nibh quis massa euismod consequat ac sed mi. + +Etiam tortor augue, semper ut dictum vitae, pharetra vitae risus. Curabitur vel aliquam sem, a elementum arcu. Sed rutrum, ligula quis tincidunt cursus, augue mi aliquet arcu, sed euismod massa quam sit amet quam. In mattis a erat vel aliquet. Integer sit amet pharetra magna. Donec massa ante, varius ac eros tempus, auctor fermentum lectus. Aliquam consequat rhoncus orci, ut varius nisl fermentum id. + +Ut ac viverra neque. Aenean tincidunt lorem vel ipsum lacinia, vitae elementum sapien pretium. Pellentesque iaculis tristique tristique. In vitae justo leo. Nam sodales rhoncus eros, a viverra lacus lobortis a. Ut sagittis ligula quis orci molestie volutpat. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nunc id urna eros. Duis enim nulla, porta sed leo sed, placerat mollis nisl. Etiam nisi nulla, eleifend vel bibendum in, viverra et lectus. Aenean aliquet justo ultrices lacus accumsan elementum. + +Proin metus neque, consectetur ut consectetur ac, vehicula in dui. Vestibulum volutpat tortor vitae ligula egestas porta. Praesent et enim dolor. Nullam ante ipsum, posuere sed purus a, lacinia aliquet purus. Donec fringilla dolor ac nisl fermentum, sed aliquam odio consequat. Sed bibendum nisl vitae magna mattis volutpat. Quisque semper nulla efficitur, semper libero vitae, molestie ligula. Sed posuere neque eu aliquam hendrerit. + +Nullam accumsan, turpis a maximus ornare, ante lorem pharetra est, sed molestie turpis magna eget diam. Aenean luctus ac purus congue tempus. Curabitur vel leo et nisl lobortis laoreet eu ut nisi. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed leo arcu, vestibulum vitae velit vitae, viverra cursus velit. Ut ut nulla quis nisl varius bibendum. Donec porttitor a lectus sed ultrices. Suspendisse et consectetur nunc. Mauris at accumsan metus, a suscipit nulla. Phasellus sagittis hendrerit augue, quis scelerisque odio pellentesque at. Integer eleifend, nibh vel rutrum mollis, orci ipsum commodo purus, eget viverra lectus sem quis orci. Integer non justo aliquam, tincidunt nulla vel, fermentum libero. Praesent pulvinar, nisl accumsan placerat semper, lorem lectus sagittis justo, iaculis vehicula elit justo nec erat. + +Etiam ante purus, consectetur vitae pharetra posuere, vulputate ac risus. Donec quis libero consectetur, vehicula erat eu, dignissim arcu. Aliquam laoreet elit id orci pulvinar faucibus. Duis in felis blandit, tempus dolor imperdiet, facilisis dolor. Fusce ac fermentum erat. Vivamus vehicula accumsan ex, id eleifend mauris interdum gravida. Curabitur ut consequat est. Nulla eu lorem vel dui pulvinar consectetur et sed justo. Sed ac arcu et enim scelerisque blandit a sit amet dui. Aenean accumsan nulla in libero convallis, non imperdiet est blandit. Vestibulum rutrum quis risus dignissim malesuada. Phasellus pharetra lacus ut ex porttitor, sit amet convallis quam tempus. Sed in leo nulla. Vivamus convallis dapibus enim, nec dignissim turpis sodales ac. + +Nunc nunc dolor, ultricies vitae lacinia sed, condimentum ac nulla. Nulla cursus pellentesque nibh, vel iaculis ex bibendum tristique. Praesent facilisis diam nec laoreet vehicula. Quisque vel dolor ligula. Pellentesque ullamcorper purus nec velit vestibulum condimentum. Donec eget diam mollis, eleifend sem vel, malesuada dui. Cras faucibus porttitor diam id convallis. Ut rhoncus lectus purus, quis accumsan nisl dictum sed. Nam id turpis quis eros auctor consectetur. Ut mauris nisl, ullamcorper sit amet est a, bibendum interdum dolor. Curabitur porta eros vitae felis commodo, ut auctor augue pretium. Suspendisse potenti. Aenean enim felis, sagittis sed pellentesque vitae, tempus vitae ante. + +Integer hendrerit commodo ante a pretium. Aenean lacinia massa sed mi finibus, sit amet molestie nisl euismod. Suspendisse ligula nisi, porta id viverra sit amet, lacinia ut turpis. Proin dignissim sit amet ipsum sed suscipit. Proin nec justo leo. Mauris elementum rutrum fermentum. Pellentesque laoreet erat non quam imperdiet fermentum. Fusce massa lacus, laoreet vel lacus eget, tincidunt fermentum dolor. Nam sed sodales leo. Curabitur mattis nisl vitae enim tempus placerat. Donec et orci aliquam, gravida metus sed, rutrum felis. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed finibus velit ut lacus sollicitudin suscipit. Cras accumsan elit lorem, eget malesuada mauris rhoncus ut. Donec in velit imperdiet, vehicula arcu ut, placerat mi. Mauris rhoncus mi mauris, sed vestibulum magna commodo id. Etiam fermentum lacinia tellus feugiat posuere. Suspendisse sit amet lacinia dolor. + +Nullam cursus sapien cursus nisl fringilla congue. Aenean ac porttitor massa, ut sodales orci. Donec ac est non felis gravida commodo. Integer vel massa orci. Fusce nec magna in nisi viverra facilisis. Nam luctus neque sed neque commodo congue et fermentum velit. Sed a dolor non mauris pharetra bibendum vel at diam. Quisque feugiat magna vitae vulputate congue. + +Cras tempus tempor sem, nec cursus orci auctor vel. In nec augue at eros placerat volutpat id at nibh. Mauris et pulvinar sapien, quis eleifend lacus. Proin ut congue lectus. Curabitur sed dapibus purus, ut facilisis erat. Ut sagittis ex nec augue accumsan fringilla. Nam pulvinar libero ut ipsum convallis interdum. + +Maecenas rhoncus tellus felis, eget blandit diam bibendum non. In maximus eu sapien pharetra posuere. Aenean egestas arcu eu urna pharetra lobortis. Cras viverra dolor felis, id faucibus odio luctus aliquet. Vestibulum vitae convallis augue. Suspendisse accumsan neque eu nisi tincidunt finibus. Aliquam dignissim, nunc ut bibendum fringilla, nulla lectus varius felis, sed hendrerit elit erat eu nisl. Cras orci lectus, varius vel dictum a, eleifend vel lorem. Proin viverra a nibh eget convallis. Duis vel scelerisque est. Cras maximus odio eget odio pretium aliquet. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Quisque at congue enim, in placerat risus. Pellentesque imperdiet eleifend feugiat. Nunc vel mattis justo, in mattis lectus. + +Maecenas lorem eros, condimentum rutrum feugiat ut, laoreet eu lorem. In porttitor turpis sit amet risus viverra pellentesque. Nam rhoncus tristique arcu vel cursus. Sed interdum, metus vel dictum gravida, ante magna efficitur magna, non aliquam dui est nec erat. Quisque fermentum, lacus sit amet maximus aliquet, dolor risus vulputate ex, et convallis orci nisl eu arcu. Sed imperdiet tempus erat, ac aliquam sem feugiat eu. Nullam mattis bibendum lorem vitae ornare. In condimentum vel odio vehicula placerat. Nullam quis magna est. Curabitur luctus eros turpis, sed varius odio convallis sit amet. Duis feugiat est ut tortor vulputate finibus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed ultricies lorem vel mauris lacinia commodo ut eget turpis. + +In in dolor ultricies, mattis urna id, viverra metus. Nunc ut nisi odio. Sed nunc odio, laoreet eu nunc sed, porttitor ultrices enim. Ut iaculis ligula a blandit varius. In eleifend, urna id ultricies convallis, urna odio euismod arcu, id finibus felis felis sit amet felis. Nulla ac consequat libero. Integer quis dolor sapien. Vestibulum in lectus dolor. Nulla nulla nunc, vulputate vitae justo dapibus, consequat varius urna. Cras est felis, sodales eget pulvinar pellentesque, commodo et sapien. + +In dui quam, euismod et mauris a, laoreet porta lacus. Proin nec semper neque. Donec consectetur lacus at nunc gravida, sed tempor dolor vulputate. Nulla facilisi. Curabitur sit amet purus nibh. Aenean dictum sodales mi ac ullamcorper. Vestibulum imperdiet ultrices aliquet. + +Etiam mauris libero, blandit id sem a, elementum tempus magna. Integer bibendum sapien vel est ultricies, a venenatis ante pharetra. Nam ac tempus nisi. Fusce at tortor arcu. Ut mauris lectus, ornare sit amet mollis vitae, iaculis ac felis. In mollis lacus neque, in gravida nisl gravida eget. Nulla facilisi. In neque tortor, faucibus vestibulum nunc a, consectetur commodo est. Praesent tristique lobortis sem posuere efficitur. + +Aliquam non semper ligula. Cras at ultricies mi, non ultrices massa. Nullam ac consectetur sapien. Donec ut urna posuere, mattis justo at, scelerisque neque. Suspendisse potenti. Vivamus aliquam enim sit amet mi feugiat, eget ultrices nunc pulvinar. Pellentesque facilisis, dui at sollicitudin maximus, risus mauris laoreet felis, nec sagittis nulla turpis et elit. Donec elit dui, pharetra facilisis quam sed, mollis ultricies arcu. Ut fermentum ipsum dui, eget maximus dui finibus nec. Mauris et mi arcu. Quisque sagittis pellentesque libero at ultricies. + +Sed ullamcorper vulputate dui, vel tincidunt metus rhoncus ac. Aliquam ut lacus molestie, pulvinar justo accumsan, bibendum neque. In vitae nulla ut metus condimentum rutrum eget nec mauris. Nam sit amet sodales sem. Phasellus sagittis massa quis ipsum gravida tincidunt. Ut ac massa dapibus, vestibulum nibh vitae, scelerisque lorem. Morbi dapibus commodo sodales. Nullam sollicitudin augue quis tristique malesuada. Maecenas convallis egestas ante a luctus. Integer a aliquet turpis. Curabitur augue velit, scelerisque vitae mauris et, tristique placerat ligula. Aliquam ultricies urna nisl, non tincidunt odio faucibus vel. Donec nec magna molestie, pulvinar risus id, bibendum nibh. + +Integer erat purus, sagittis eu ante eget, viverra faucibus erat. Mauris molestie ipsum erat, non imperdiet orci egestas nec. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla nec congue lectus. Fusce facilisis ex eu augue imperdiet pellentesque. Etiam quis mattis erat, in aliquam metus. Mauris fermentum urna ac justo consequat, quis sodales nisl pretium. Morbi venenatis congue quam, nec semper sem placerat vitae. Curabitur scelerisque ipsum vitae est tempus, eu tristique magna euismod. Fusce mattis at nisi eget cursus. Pellentesque ultricies, dui eget mattis mollis, risus turpis molestie leo, auctor placerat sem velit vitae risus. + +Aliquam erat volutpat. Interdum et malesuada fames ac ante ipsum primis in faucibus. Fusce lacinia cursus arcu, quis facilisis nibh elementum et. Donec lacinia eleifend ante eu porta. Curabitur ut accumsan nunc. Quisque viverra, ex quis pretium faucibus, diam justo scelerisque arcu, eget auctor nulla nisi eu magna. Pellentesque arcu nunc, sodales vitae cursus et, molestie eget quam. Integer efficitur eros ullamcorper justo laoreet aliquet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; In sit amet egestas ex, sed molestie purus. Vivamus ac metus et ipsum tristique congue. Ut elementum tellus vitae arcu suscipit, eu semper leo accumsan. Duis at maximus libero. Suspendisse blandit mauris lacus, sit amet aliquet sapien hendrerit sed. Praesent sed neque pulvinar, semper felis nec, eleifend urna. Etiam eget ex nisi. + +Nulla facilisi. Duis condimentum velit id vulputate luctus. Aliquam eu interdum nunc. Morbi eu est mattis, pretium eros ac, accumsan nibh. Quisque sed mauris fringilla augue tincidunt dignissim id vitae tortor. Pellentesque tincidunt magna quis ex facilisis, quis dignissim nunc tincidunt. Nunc semper maximus elit. Donec neque libero, volutpat nec mollis non, scelerisque ac odio. Donec et augue ut elit eleifend pharetra. Donec condimentum tellus turpis. In gravida, tellus hendrerit facilisis aliquet, ligula est auctor tortor, eu interdum turpis sem a ex. + +Sed vestibulum egestas mi sed semper. Cras varius tempus hendrerit. Duis quis ex mauris. Donec tincidunt rutrum tellus ut malesuada. Cras fermentum ut ante in pretium. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut tincidunt aliquam nulla. Duis a justo et diam porttitor hendrerit. Sed dignissim mauris ultricies, volutpat urna ut, sagittis lectus. Morbi facilisis lacus elit, eget varius ligula dignissim vel. Ut ut risus eget tellus viverra consequat non id nisi. + +Ut ut sem sit amet risus maximus accumsan eget id diam. Curabitur consequat arcu in sapien elementum, rhoncus suscipit ipsum ultrices. Duis sed lacinia mi. Maecenas posuere velit vitae eros mollis, accumsan sollicitudin ipsum tempor. Integer tortor leo, vestibulum tempor feugiat non, imperdiet quis nibh. Ut dictum erat vel lacus venenatis pellentesque. Morbi suscipit consectetur elit a pulvinar. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam accumsan ligula vitae dapibus suscipit. Maecenas hendrerit, ante ut euismod lacinia, dolor enim vehicula nunc, at ultrices erat magna et arcu. Etiam lobortis a leo non blandit. + +Morbi vulputate pulvinar odio quis porta. Ut nibh ex, posuere cursus commodo sed, malesuada in tortor. Maecenas sed maximus ligula. Fusce rhoncus nibh id nisl rutrum, eu ultricies erat fringilla. Cras risus nisi, molestie ut cursus vitae, tempor a leo. Quisque euismod neque sit amet est commodo, et consequat risus sollicitudin. Integer interdum odio eu suscipit ultrices. Nunc justo risus, pulvinar at metus ac, rutrum auctor tortor. + +Sed odio leo, posuere id orci sed, congue mattis urna. Nulla vitae ligula purus. Praesent quis fringilla magna, ac pulvinar metus. Donec congue purus ac tortor congue, eu maximus tellus hendrerit. Morbi nec ipsum suscipit, auctor ipsum non, ornare massa. Pellentesque eu lectus vitae ipsum ultricies porttitor nec at massa. Nulla arcu metus, accumsan at ante at, congue interdum quam. + +Vestibulum eleifend erat dignissim mattis scelerisque. Donec a magna vel lorem fermentum molestie. Vestibulum consectetur arcu dui, sed tempor nisl lacinia in. Cras at urna vitae nunc dictum ultricies eget vitae neque. Morbi vel rhoncus ipsum. Pellentesque placerat ultrices venenatis. Donec semper nibh vel imperdiet placerat. Vestibulum eget blandit ipsum, a maximus lacus. Sed sagittis faucibus velit, a mattis sapien. Duis consequat maximus ex, ut dignissim mi volutpat vitae. Vivamus congue diam nec tortor ornare hendrerit. Nam a tortor fermentum ante viverra volutpat ut vitae nisi. Proin consequat dictum velit at varius. + +Aliquam rutrum imperdiet egestas. Pellentesque et condimentum felis. Sed eleifend nunc ligula, at rutrum sapien porttitor ut. Nullam nec felis risus. Vestibulum in rutrum enim, vel luctus odio. Duis nec lacus augue. Suspendisse placerat ex vitae eros varius, at lacinia augue dictum. Sed tincidunt erat non facilisis semper. Duis venenatis tortor quis ligula ullamcorper, sed scelerisque mi sollicitudin. Sed condimentum, mauris ac blandit volutpat, urna ligula tincidunt ex, ut feugiat metus neque eget sapien. Etiam sagittis tincidunt elementum. Nam efficitur, nunc a hendrerit imperdiet, purus orci accumsan libero, quis interdum purus sem eu metus. Ut sem metus, malesuada non sapien at, condimentum dignissim lectus. Nulla vestibulum, mauris pellentesque placerat viverra, eros dui malesuada ligula, id semper magna velit in tellus. Etiam tempor, massa sit amet tempor rutrum, urna sem facilisis enim, at congue libero ex sit amet leo. + +Vivamus scelerisque suscipit eros, id porttitor risus placerat sed. Suspendisse faucibus leo ut dui facilisis iaculis. Aenean sed magna at sem tincidunt sodales. Ut scelerisque lobortis eros. Proin rutrum libero eu aliquam ultrices. Nullam ultrices feugiat diam non facilisis. Nunc et nibh augue. Proin posuere nisl vitae lectus ultricies faucibus. Nam mollis et odio ac tincidunt. Curabitur a ipsum fringilla, placerat eros quis, tempus ligula. Vivamus efficitur aliquam pharetra. Pellentesque maximus ante sapien, placerat condimentum felis bibendum ut. Maecenas massa neque, finibus sit amet augue vitae, scelerisque efficitur erat. Suspendisse id fermentum sapien, in viverra quam. Proin convallis felis ex. Nam mollis dui et tincidunt faucibus. + +Suspendisse potenti. Sed neque augue, fringilla nec leo eget, pharetra luctus nunc. Fusce et malesuada ligula. Nam eget libero interdum, condimentum eros at, aliquet nisi. Etiam aliquet leo quis venenatis auctor. Aenean facilisis, urna eget volutpat maximus, nunc erat faucibus elit, ac euismod nisl ligula faucibus augue. Pellentesque dictum porttitor est vel porta. Fusce scelerisque, odio tristique euismod faucibus, orci leo pretium odio, sit amet aliquet libero magna vel arcu. Integer luctus, felis et mattis sodales, lacus ex laoreet velit, et semper nisl mi eu tellus. Sed a massa et arcu faucibus sodales vitae nec lorem. + +Suspendisse potenti. Duis pulvinar lobortis nisi, at cursus urna dignissim eu. Ut hendrerit lorem sed congue porta. Nullam sollicitudin sem vel risus ultricies rutrum. Donec at lorem a tellus viverra interdum id non felis. Nulla congue tincidunt semper. Etiam finibus magna erat, vitae rutrum orci egestas at. Quisque eget venenatis libero, at malesuada ante. Nulla ut nibh pellentesque, convallis purus id, lacinia lectus. Integer vehicula dui ante, eget cursus ipsum consectetur pulvinar. Cras id molestie massa. Proin mattis semper quam, a convallis enim rhoncus a. Integer dapibus, lacus id sodales sollicitudin, dolor neque accumsan tellus, ac ultricies nunc diam vitae purus. Donec placerat condimentum nibh id porta. Vestibulum in gravida orci. Proin dignissim neque condimentum sagittis tincidunt. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Duis justo mi, faucibus nec facilisis sed, rhoncus ut purus. Duis et sollicitudin arcu. Morbi tempus diam et purus sagittis rutrum. Cras iaculis sem ac magna finibus mattis. Duis maximus tellus arcu, viverra feugiat diam fermentum eget. In hac habitasse platea dictumst. Integer ultrices volutpat purus a viverra. Proin sed euismod nisi. Suspendisse ac facilisis nunc. Vestibulum eleifend nulla sit amet lectus elementum aliquet sit amet vitae lectus. Curabitur consectetur nisi eu mollis venenatis. + +Duis euismod fringilla pharetra. Nunc sodales dolor sed facilisis ultricies. Quisque nec dictum mauris, sed iaculis mauris. Ut euismod feugiat luctus. In hac habitasse platea dictumst. Donec ut molestie massa. Phasellus ac enim nec leo consequat auctor. Cras massa orci, semper in scelerisque in, consectetur eu enim. + +Proin efficitur suscipit purus, nec interdum turpis vestibulum tristique. Nulla pellentesque lectus at neque imperdiet, a fermentum lectus bibendum. Ut vulputate, urna ac pretium porttitor, ligula ex rhoncus magna, vitae faucibus augue metus sed erat. Sed tempor ullamcorper orci ut sodales. Donec in mi bibendum, fermentum mi quis, ullamcorper leo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Phasellus at vulputate massa. Vivamus mattis mauris in orci consequat, at rutrum ante sagittis. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque non fermentum metus. Vestibulum faucibus eros quis dignissim ultrices. Donec id turpis convallis massa finibus blandit tempor id magna. Donec volutpat tellus sit amet mauris faucibus commodo. + +Aliquam eget ex ac magna suscipit lobortis in sit amet dui. Donec non enim placerat, tempor dui tempus, condimentum dui. Cras ultrices, augue et fermentum auctor, justo ante elementum lectus, ac mattis eros augue sed nisl. Nulla facilisi. Nulla porta maximus iaculis. Sed vestibulum odio justo, eget ornare enim ultrices at. Sed vestibulum mauris dolor, quis dictum sem placerat ac. Nullam vel dignissim elit. Mauris at iaculis odio. + +Pellentesque vel odio in libero faucibus ultrices. Aenean ac fringilla nulla. Proin leo tellus, varius sit amet augue ut, facilisis interdum urna. Aliquam molestie, purus vitae dignissim porta, eros sapien tristique nisi, et rhoncus sapien urna at nulla. Vivamus viverra sodales lacus nec aliquam. Etiam convallis rutrum ante, sed ultricies risus mattis vel. Sed blandit nibh quis lectus volutpat convallis. Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque faucibus, est vel lacinia posuere, nunc justo faucibus ligula, nec ornare lorem erat eu ante. Phasellus ligula neque, lobortis quis semper vitae, accumsan et augue. Suspendisse convallis mauris eu tortor vestibulum, volutpat pulvinar lacus venenatis. + +Donec feugiat orci vel magna hendrerit, ut ullamcorper odio consequat. Mauris et tortor sodales, commodo orci in, lacinia sapien. Vivamus posuere, neque sed sollicitudin lacinia, elit metus pellentesque tortor, at congue massa mauris quis turpis. Nulla facilisi. Proin ut maximus ligula, nec varius enim. Mauris ex arcu, tincidunt vel auctor vel, gravida feugiat ligula. Suspendisse odio arcu, euismod eu dignissim vel, rhoncus sed ligula. Donec pharetra bibendum neque, condimentum consectetur sem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Phasellus ornare nisl quis nulla euismod tempor. Maecenas sed enim auctor, venenatis odio non, ornare lacus. Aenean rhoncus efficitur arcu, vitae auctor est luctus at. In eros eros, pretium a laoreet sed, accumsan condimentum odio. Donec maximus congue nisi, non posuere nulla pulvinar et. Integer non erat et orci fringilla euismod. + +Nam efficitur lectus ligula, vitae cursus orci ornare sit amet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; In pharetra, nulla vestibulum suscipit rhoncus, eros quam auctor lorem, vestibulum efficitur eros lectus at ligula. Quisque nec enim a ante ultrices tincidunt eu nec nulla. Praesent ut leo metus. Ut eu tellus enim. Aenean vel consectetur tellus. Aliquam molestie, lectus in pellentesque aliquam, felis lectus ultricies ante, quis mollis ex quam ut orci. Integer volutpat pretium dui, et luctus ante dictum non. Sed porttitor sed lectus ut tristique. Nulla eget ultrices lacus. Integer sit amet magna et turpis consequat scelerisque et sit amet dolor. Ut sollicitudin malesuada libero, non pharetra est vehicula vel. Fusce pellentesque nisl ac metus sagittis dictum. Phasellus id eleifend ante. + +Vestibulum egestas libero in orci porttitor, at eleifend neque condimentum. Donec vitae felis id diam volutpat placerat eget eget felis. Praesent ullamcorper sit amet magna id pellentesque. Nulla est nunc, maximus vel urna sed, consequat dictum lorem. Donec eget ultricies purus, vel congue orci. Aliquam dapibus lobortis blandit. Aliquam sit amet tortor nec dolor varius luctus. Nullam eget felis mauris. Morbi blandit aliquet odio, non euismod felis porttitor vel. + +Curabitur sit amet dolor eu tortor venenatis consequat. Sed efficitur imperdiet quam nec luctus. Morbi vitae est posuere, posuere tortor eu, mollis sapien. Vestibulum eget pretium purus, a eleifend turpis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur massa orci, semper varius sapien sit amet, efficitur tempor nibh. Praesent pulvinar risus neque, vitae tristique lectus aliquet nec. Pellentesque eget orci eu leo maximus maximus sit amet ac eros. Praesent porttitor ligula et ligula vehicula placerat. Ut quis tincidunt orci. Nam ultrices elit ac ornare fermentum. + +In quis auctor purus. Fusce lacinia purus in leo fermentum scelerisque. Vestibulum at cursus odio, vel finibus tortor. Sed quis lectus sit amet velit tincidunt sagittis. Donec id porta enim. Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse eget ultricies augue. Nulla turpis metus, ornare ac tempor eget, dictum eu elit. Phasellus rutrum mauris at mauris accumsan suscipit. Donec eu sapien sollicitudin, viverra nisl et, euismod mauris. Curabitur dictum semper laoreet. Nulla nec malesuada dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. + +Quisque euismod magna vel pharetra ornare. Nam sed finibus urna. Suspendisse augue nulla, luctus a egestas at, tincidunt nec diam. Cras congue justo ac velit euismod, eget volutpat augue porta. Maecenas nec nisl arcu. In at justo in tellus faucibus vehicula et eu ante. Aliquam facilisis mauris turpis, at finibus elit rutrum id. Sed nulla enim, ultricies at nisi et, tristique fringilla libero. Donec mattis volutpat arcu eu lacinia. + +Donec maximus, dui sed bibendum iaculis, lorem odio aliquet metus, in tempor lectus elit vel sapien. Aliquam rhoncus massa sit amet placerat congue. Donec vitae maximus nibh. Sed id fermentum augue. In hac habitasse platea dictumst. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam finibus, orci id tempor ullamcorper, justo purus venenatis augue, vel efficitur elit odio eget nunc. Pellentesque euismod fringilla eleifend. Sed mollis augue urna, eu placerat dolor placerat quis. Mauris id dolor vel velit aliquam dapibus a quis leo. Donec elementum dolor ut auctor accumsan. Cras sed fringilla mauris. + +Vivamus id placerat ligula, a egestas orci. Donec in erat ut tortor gravida pellentesque. Sed felis dolor, dignissim in maximus at, commodo commodo lacus. Cras commodo consectetur nunc, eu tincidunt risus dignissim sit amet. Mauris vel pellentesque urna. Vivamus scelerisque ligula eu velit dapibus rutrum. Nullam eget lobortis lorem. Vestibulum ligula lorem, suscipit convallis lorem at, ultrices mollis metus. + +Morbi varius rhoncus nibh nec varius. Nullam eget porta velit. Nulla lorem elit, ullamcorper non vehicula quis, varius et nisi. Sed molestie auctor nisi, vitae ultricies metus tempor nec. Maecenas imperdiet, nisl vel tincidunt varius, tortor nibh semper felis, at blandit metus tortor eget ipsum. Nullam at risus accumsan nulla bibendum laoreet. Quisque pellentesque ligula vitae lacus pellentesque, euismod convallis justo hendrerit. Sed nisi elit, egestas sit amet velit in, ultricies feugiat nunc. + +Aenean non metus magna. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Sed venenatis magna enim, non feugiat nisi tincidunt quis. Proin sit amet risus quis augue finibus finibus vel euismod enim. Morbi sed vestibulum turpis. Sed facilisis vitae mauris quis ultrices. Quisque a tellus laoreet, laoreet justo sed, cursus nibh. In dolor eros, finibus ut aliquam vitae, facilisis nec velit. Morbi vitae felis sodales, aliquet lorem vitae, ultricies libero. Quisque vehicula lectus non euismod pretium. Vivamus tempus ante justo, ullamcorper porta magna pharetra ac. In eu purus erat. Aliquam tincidunt magna augue, vel maximus dui semper vitae. Maecenas ac tellus ligula. + +Suspendisse lacus ex, hendrerit non diam non, luctus convallis ipsum. Nam lorem eros, facilisis at ultrices sed, porta eu elit. Donec molestie convallis rhoncus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed pretium aliquet pulvinar. Sed euismod nisi id condimentum convallis. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam tristique ipsum at arcu condimentum, sit amet feugiat lectus aliquam. In quis lobortis eros. Vestibulum nunc ex, mattis ut placerat ac, dapibus eu lacus. + +Sed vehicula nec ex ut vulputate. Aenean ornare, lacus nec finibus malesuada, mauris eros consequat ligula, eget blandit ex libero a odio. Praesent et fringilla leo, eget molestie nisl. Ut interdum, sem ut lobortis posuere, ante ligula ultricies nulla, a vulputate tortor est id enim. Fusce vel condimentum dolor, in congue purus. Praesent nec enim dapibus, dictum leo varius, aliquam erat. Duis neque lacus, ullamcorper et eros eget, laoreet venenatis est. Aenean laoreet ex mattis, rhoncus nibh vel, congue massa. Nam viverra ex sit amet erat tempor ullamcorper. Proin condimentum quam felis, in tempus magna ornare vel. + +Quisque faucibus erat sem, vel pharetra odio placerat eget. Suspendisse condimentum bibendum lacus at posuere. Duis eu congue elit. Proin fringilla nibh lorem, ut ornare enim viverra at. Donec a malesuada erat. Cras dolor felis, porttitor in nibh vitae, fermentum venenatis ligula. Vestibulum eget lectus posuere lorem ornare scelerisque. Morbi commodo augue eget tincidunt dignissim. Morbi vitae elit velit. + +Maecenas rhoncus rhoncus eros vitae pharetra. Morbi mi eros, sagittis non libero sed, lobortis venenatis lorem. Vivamus in justo nisl. Nam pulvinar lectus ullamcorper erat finibus imperdiet. Pellentesque malesuada massa ipsum, ac posuere neque iaculis et. Donec convallis tristique nisi non elementum. Duis facilisis lacus leo, sit amet molestie libero dignissim quis. Morbi et justo sit amet est maximus egestas a eget mi. Curabitur condimentum nec enim id tincidunt. Donec ipsum ipsum, pellentesque a efficitur non, mollis id ipsum. Maecenas venenatis sit amet nulla eu blandit. Nunc mollis, odio ut scelerisque aliquet, odio dolor mollis sem, vitae sodales diam nisl at nulla. Mauris vel risus nulla. + +Pellentesque sollicitudin non orci sit amet pellentesque. Morbi id nibh vitae enim dignissim porttitor. Phasellus consequat, diam eget commodo placerat, leo lorem scelerisque tellus, pulvinar lobortis enim risus sed nunc. Aliquam ut tincidunt leo, sed maximus arcu. Vestibulum metus erat, fermentum elementum justo et, iaculis maximus erat. Donec in feugiat erat. Donec dictum sodales venenatis. Morbi neque justo, euismod vitae elementum ut, sollicitudin ac dui. Donec eu lacus in nunc efficitur molestie. Morbi auctor vitae nibh nec aliquam. Morbi volutpat diam in diam tincidunt, id lacinia dolor porttitor. Integer nec urna id lorem placerat fringilla quis non orci. + +Maecenas lacus urna, porta eu dui non, ornare tempor dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam sit amet dignissim orci. Etiam ac mi mollis, posuere elit sit amet, finibus felis. Maecenas aliquet finibus leo vel porttitor. Etiam ipsum leo, convallis ut augue blandit, interdum ultricies risus. Donec vel eros porta, facilisis urna ut, vehicula sapien. Maecenas lacinia pharetra dolor. Vivamus lobortis nec enim ut lacinia. + +Curabitur semper pharetra tristique. Sed sagittis est vitae placerat sodales. Duis ac dolor posuere, fringilla ligula nec, sollicitudin lorem. Curabitur quis dignissim diam, quis varius ipsum. Sed maximus mauris tortor, sit amet imperdiet magna fermentum vitae. Aenean id pulvinar mauris, vel posuere erat. Pellentesque bibendum sodales risus, et maximus sem pretium nec. Sed ultricies rutrum tincidunt. Nullam pulvinar fermentum velit, nec consectetur ante feugiat eu. Maecenas sed enim commodo neque viverra mollis. Fusce imperdiet diam nisl, et pulvinar sapien commodo cursus. Aenean a nulla blandit, pharetra velit a, elementum magna. + +Sed et mi imperdiet, condimentum ipsum sit amet, suscipit felis. Morbi laoreet elit placerat, rhoncus lectus dignissim, finibus velit. Morbi sit amet mollis justo, sed efficitur eros. Suspendisse pharetra commodo nunc vel aliquet. Nam vestibulum ipsum sodales, posuere nunc et, aliquam leo. Nam ut consequat velit. Phasellus sollicitudin quis quam tincidunt pharetra. Proin at pharetra ex, sit amet egestas nunc. Fusce blandit suscipit ipsum vitae pellentesque. Fusce at malesuada lectus. Aliquam erat volutpat. + +In sit amet quam semper, molestie nunc imperdiet, euismod lacus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent eu felis risus. Maecenas venenatis tempus quam in feugiat. Cras auctor vulputate augue a accumsan. Aliquam vitae purus ut mauris volutpat efficitur sit amet id augue. Nunc bibendum magna vitae nisl condimentum maximus. Ut feugiat nisl a mi mattis aliquet. Aliquam euismod leo id massa laoreet sagittis. Phasellus ac posuere elit. Morbi turpis eros, cursus in mollis quis, eleifend vel risus. Phasellus feugiat malesuada congue. Nulla non posuere neque. Donec semper eros risus. + +Integer tristique maximus purus non vulputate. Donec quis semper augue. Nulla volutpat lectus sit amet lacinia malesuada. Fusce sed tellus eget metus egestas convallis at eget turpis. Praesent elementum turpis eget leo pulvinar pretium. Praesent faucibus bibendum magna, sit amet cursus dolor accumsan eget. Proin sagittis ut est non volutpat. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut eget turpis vel enim egestas pharetra. Sed eget vehicula odio. Pellentesque aliquet aliquam ipsum. Sed dapibus nisi urna, porta laoreet massa mattis non. Duis dolor diam, feugiat in eros at, bibendum consectetur lacus. Quisque accumsan nibh est, ac hendrerit arcu sagittis at. Fusce suscipit nunc at elit pulvinar, a fringilla orci posuere. Vestibulum non purus sit amet ligula porta tincidunt. + +Ut ut elementum leo. Donec eu vehicula enim. Nulla ut posuere libero. Suspendisse accumsan sit amet enim non ultrices. Donec a leo eget sapien pulvinar mattis ut eu tortor. Duis nec massa nisi. Morbi elementum felis et dapibus sodales. Suspendisse ut luctus enim. Donec tristique at nisi vel lacinia. In malesuada in tellus nec dapibus. Integer in congue est, sit amet facilisis est. + +Integer suscipit feugiat condimentum. Sed non metus est. Nullam accumsan justo at interdum varius. Curabitur sed risus consectetur, egestas sapien ut, pretium felis. Maecenas eu dolor eget lorem varius pretium. Phasellus consectetur urna a ante sodales dapibus. Donec sollicitudin lorem tempus malesuada tempus. Phasellus luctus condimentum vestibulum. Fusce vel molestie nisl. Nullam imperdiet dolor ut lectus vulputate sollicitudin. Aliquam erat volutpat. Nullam in sollicitudin nulla. Morbi porta felis et lectus auctor porttitor. + +In in ligula et ante posuere luctus. Ut feugiat sit amet quam eu rutrum. Nullam commodo ante nisi, et pellentesque augue pellentesque et. Nulla vulputate, lacus quis efficitur mattis, nisl velit molestie nisl, sit amet rhoncus nisi turpis quis leo. Morbi a magna urna. Donec a iaculis nisl. Nullam eu elit vitae dui interdum bibendum imperdiet quis ante. Curabitur vitae lorem sit amet odio tristique rutrum. + +Sed ut lectus dolor. Suspendisse euismod ut massa id vestibulum. Sed non massa placerat, facilisis dui a, condimentum enim. Fusce vehicula erat eu lacus condimentum euismod. Vivamus ut ultrices ipsum, in ullamcorper velit. Sed enim nulla, tincidunt at purus id, ultrices maximus ipsum. Cras sit amet tortor at enim pellentesque lacinia sed vel sem. + +Integer ac metus nec nulla cursus venenatis. Duis blandit luctus massa a vehicula. Nam vulputate, lectus ut condimentum lacinia, tortor tortor cursus justo, facilisis tempor eros sem vitae nulla. Nullam sed ex massa. Aliquam non arcu et neque scelerisque porttitor. Etiam commodo venenatis maximus. Donec rhoncus erat nec diam efficitur placerat. Mauris pretium mauris libero, sit amet vestibulum ipsum fringilla eu. Cras sed tortor mollis, mollis diam eu, condimentum ex. Etiam gravida nec arcu vel sodales. Pellentesque ut arcu in eros ullamcorper tristique. Praesent luctus in neque eget pharetra. Proin dapibus tellus sed velit commodo interdum. Praesent euismod, massa in semper mollis, tortor ipsum suscipit tortor, sit amet viverra tellus sapien eget orci. Maecenas in molestie justo, eget consequat dolor. + +Praesent vel neque vitae ipsum condimentum pulvinar eu non nisi. Integer mattis quam ut pellentesque auctor. Ut egestas, diam at finibus viverra, felis est tristique nibh, id convallis turpis velit eget ligula. Fusce sed nisl volutpat augue volutpat facilisis. Aliquam erat volutpat. Integer dapibus varius augue, sed fringilla metus varius vitae. Maecenas sed elit a sem dignissim tempus. Maecenas nulla erat, molestie sit amet malesuada eget, blandit at libero. Donec lacinia efficitur nulla a scelerisque. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla hendrerit dui quis orci tristique, id faucibus eros malesuada. Sed ut dolor ex. Sed vel rutrum eros. Nam ac orci sit amet mi consequat aliquet quis quis est. + +Vivamus nec odio vitae orci consectetur suscipit. Donec vehicula eget libero in viverra. Ut laoreet in nulla eget euismod. Phasellus egestas lorem sed dui blandit, rhoncus interdum nulla ultrices. Quisque congue convallis erat ut blandit. Phasellus tempor pulvinar justo, id varius risus tempus eget. Suspendisse tempus, urna et mattis placerat, tellus magna pharetra ipsum, sed porta mi tellus suscipit justo. Vestibulum commodo turpis ut metus lacinia scelerisque. Aliquam fermentum, quam in malesuada ornare, orci mauris molestie mi, vitae tristique nunc quam pharetra enim. Etiam placerat lectus quam, vitae faucibus metus efficitur sit amet. Pellentesque suscipit porttitor ipsum, in fermentum turpis tristique sed. Duis finibus mi nec odio aliquam feugiat. Sed vitae tellus diam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +Sed ac mi libero. Aliquam pulvinar ullamcorper ipsum. In blandit nec arcu ut vehicula. Duis venenatis suscipit laoreet. Cras finibus tincidunt velit in feugiat. Mauris lorem eros, pretium sed ornare et, blandit id quam. Donec cursus, velit quis semper finibus, risus quam gravida sem, quis venenatis est turpis scelerisque lorem. Pellentesque vel accumsan ipsum, in finibus lacus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Morbi ultrices, risus ac euismod tincidunt, felis tortor facilisis eros, et elementum massa velit finibus augue. Sed fermentum faucibus euismod. In nec porta neque, eget mollis leo. Pellentesque dapibus metus vel nunc efficitur, nec suscipit ligula porta. Ut eu justo quis turpis tincidunt dapibus et et lacus. Nunc quis vehicula ligula, ac gravida turpis. Etiam in hendrerit ipsum. + +Nunc scelerisque maximus dui, et porttitor mi hendrerit sit amet. Nam placerat ultricies arcu, ut bibendum arcu fringilla in. Mauris vitae ultrices nisl, ac lobortis leo. Vivamus in nulla elit. Integer a quam eros. Integer volutpat odio ultrices nisi interdum suscipit. Nunc faucibus ultrices scelerisque. Sed hendrerit tortor nec ligula fermentum suscipit. Suspendisse fermentum dignissim hendrerit. Nam posuere sodales nunc ultrices suscipit. Quisque ut ipsum et lorem laoreet mollis. + +Maecenas in interdum orci. Aenean dolor dui, semper quis nisi sed, placerat euismod nisi. Nam at maximus libero. Donec sit amet justo urna. Maecenas sem sapien, viverra ac faucibus vitae, bibendum nec ex. Vivamus commodo dignissim viverra. Morbi semper condimentum augue, nec tempor nisi sodales nec. Suspendisse ut lorem pulvinar, ultricies justo ut, sollicitudin purus. Etiam sed bibendum enim, ac facilisis libero. Nulla rhoncus finibus tempus. Nullam eget imperdiet orci. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec et justo at turpis varius sagittis volutpat vitae elit. Duis posuere nunc nec placerat mollis. Sed pretium purus quis risus commodo, et placerat nibh dapibus. Curabitur neque ex, viverra nec imperdiet fermentum, fermentum in diam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent ultrices metus non nisi aliquet, sed feugiat diam ultrices. Morbi rhoncus risus nec mi bibendum convallis. Nam tellus erat, porttitor vel erat vitae, vehicula pharetra justo. Praesent in nunc eu risus aliquam lobortis id et sem. Aliquam nulla augue, commodo ac ex quis, iaculis imperdiet justo. Fusce rutrum elit at enim ornare pellentesque. + +Morbi lacus nisl, facilisis ut purus a, dapibus ultrices orci. Etiam in pretium ipsum. Nulla ac interdum velit, ut pharetra neque. Maecenas placerat, diam vitae aliquet ultricies, neque ipsum vehicula dui, id blandit est diam non purus. Duis eu mi vitae quam sagittis pulvinar. Donec ligula erat, maximus in cursus eu, elementum eu nulla. Pellentesque ut justo ac orci placerat accumsan vitae in sem. Morbi at consectetur elit, ornare fringilla nibh. Suspendisse sapien lorem, molestie sed tortor vitae, finibus accumsan tortor. Quisque dignissim rhoncus metus, non dapibus dolor auctor sit amet. Aliquam a fermentum tortor. Donec ullamcorper fringilla risus. Ut tellus tellus, tincidunt eu nulla a, rutrum consectetur diam. Nunc arcu mi, tempor eu suscipit eu, vehicula vitae nibh. Aliquam rhoncus ante sit amet nibh volutpat, quis mattis felis imperdiet. Integer tincidunt arcu sed dolor iaculis interdum. + +Donec pharetra consectetur orci quis tempus. Proin laoreet risus eget libero ornare, nec tincidunt massa consequat. Phasellus pharetra felis at velit vulputate suscipit. Proin aliquam elit ut massa malesuada, nec rutrum mi efficitur. Nulla volutpat libero vel quam fringilla posuere. Aliquam sit amet purus arcu. Quisque iaculis sed erat non accumsan. Praesent eu nulla odio. In hac habitasse platea dictumst. Maecenas facilisis, sapien et ornare rutrum, orci est facilisis nisl, id placerat lectus dui eget lacus. Suspendisse potenti. Suspendisse eu tempus nisi. Proin et ipsum ut velit consequat finibus ac non lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; + +Nunc ornare elit non massa semper consequat. Nullam lacinia dignissim mauris nec molestie. Sed id nunc ut ligula ornare finibus in at nibh. Duis turpis nunc, ultrices ultricies fringilla ut, venenatis in justo. Donec volutpat imperdiet interdum. Aenean sollicitudin massa at porta fermentum. Donec et tortor volutpat, hendrerit nulla quis, consequat velit. Nam sed nisl mattis, pharetra ligula id, congue purus. Nulla sed risus non ante sodales mollis nec vehicula justo. Nullam eu ultricies leo. Duis eget consectetur erat, vitae facilisis purus. + +Phasellus ut rutrum eros. Phasellus viverra commodo arcu sagittis porttitor. Etiam suscipit vehicula lacinia. Fusce vel condimentum lorem. Integer rhoncus lorem quis velit hendrerit tempor. Aenean a nisl ante. Phasellus nec ipsum ut quam porta varius et nec sem. + +Pellentesque pellentesque est eu dui placerat, vitae imperdiet erat dictum. Aliquam erat volutpat. Quisque feugiat neque nec faucibus maximus. Mauris eleifend odio at nunc suscipit dapibus. Maecenas mauris mauris, suscipit ac ipsum in, condimentum volutpat risus. Suspendisse gravida risus ex, quis suscipit nisl viverra ut. Phasellus pharetra nisl id odio laoreet bibendum. Morbi semper urna nulla, non ultricies est vehicula vitae. Maecenas non porta ante. Donec nec massa eu purus ultricies euismod. Nam sollicitudin dui metus, vitae ornare libero faucibus sed. Aliquam feugiat tellus nec est dignissim placerat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Quisque dictum placerat leo sed mattis. + +Quisque eu dolor dictum, euismod urna quis, mattis enim. Donec eu magna ultrices lectus fringilla facilisis. Sed finibus gravida purus, posuere interdum magna laoreet quis. Aliquam vehicula volutpat tellus ac tincidunt. Sed volutpat convallis eros, eget ultrices mauris maximus et. Mauris porta leo sit amet urna pretium condimentum. Duis non ex in dui dapibus tristique vel eget velit. Etiam velit quam, dapibus ac scelerisque ac, dignissim non elit. + +In cursus est ut nibh placerat maximus eu blandit tellus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut posuere massa eu odio rhoncus, ut eleifend odio finibus. Maecenas tristique, justo quis auctor laoreet, turpis nibh iaculis nisl, a consequat velit libero id sapien. Curabitur rutrum non justo eget aliquam. Praesent ornare lobortis eros eleifend hendrerit. Integer porta sapien turpis, a imperdiet ante congue et. Nullam ut fringilla enim. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Donec ullamcorper ac tellus a efficitur. Sed lacinia egestas libero, ac luctus turpis imperdiet eu. Morbi et gravida est. Maecenas dapibus erat id ex mollis, eget sollicitudin mi ullamcorper. In sed quam ac lacus dapibus ullamcorper. + +Integer efficitur iaculis porta. Vestibulum nibh augue, aliquam et ultrices at, molestie et neque. Proin ut mauris ac risus sodales congue. Nunc non tristique ligula. Donec orci elit, viverra sit amet iaculis id, maximus eu dui. Morbi condimentum tincidunt nisi, ac ultrices orci auctor id. Nunc congue, sapien vitae interdum euismod, augue massa molestie arcu, ac aliquam risus tellus vitae orci. Nullam sit amet eleifend dui, in pulvinar purus. Nullam vitae sagittis ligula, non iaculis augue. Duis sit amet erat et nibh imperdiet aliquet. Ut vitae laoreet enim. Duis leo mauris, tincidunt non mauris ut, maximus suscipit sem. In in nisi in mi ultricies suscipit. Sed porttitor ante eu dui sodales, in rutrum felis consectetur. Nullam ut enim eget ante dignissim efficitur vitae scelerisque ex. + +Ut aliquet mi id dictum imperdiet. Donec vulputate urna ac quam vehicula, varius viverra ex tempor. Praesent porta, justo id tempor mattis, ligula tellus tincidunt eros, ut varius lacus quam a diam. Fusce eu sagittis dolor. Vivamus vitae velit ut ipsum aliquam posuere at a elit. Aenean imperdiet nec ante euismod tempus. Nam facilisis ut nunc id semper. Phasellus consectetur tincidunt placerat. Suspendisse sed sodales ex, sit amet hendrerit ligula. Nam aliquet urna nec tortor dictum accumsan. Cras ut ex vitae odio tempor consectetur. Suspendisse tincidunt erat ac mauris volutpat viverra. Nullam molestie, enim eget tincidunt hendrerit, nunc metus semper sapien, porttitor rutrum mi velit in quam. + +Vestibulum non interdum turpis. Donec id dolor consequat, condimentum felis a, bibendum nisl. Morbi diam nisi, fermentum nec viverra vel, fermentum elementum tortor. Sed enim massa, aliquet quis mi non, vehicula faucibus justo. Fusce vel risus quis lectus vehicula ullamcorper. Donec mauris velit, lacinia non faucibus vitae, consequat a est. Vivamus tristique eros accumsan, porttitor eros at, interdum mauris. + +Maecenas tempus nulla tristique ex gravida posuere. Aliquam eget eros ac sem rutrum pulvinar sed id magna. Vestibulum suscipit eleifend accumsan. Proin sit amet vestibulum enim. Fusce fringilla pellentesque odio a dapibus. Aenean vel neque vitae augue sagittis luctus nec in orci. Vestibulum blandit felis eu purus condimentum congue. Vestibulum vel tristique risus, dignissim accumsan metus. Duis nisl odio, semper in arcu nec, faucibus lacinia leo. In auctor neque nec augue sagittis volutpat. Aliquam luctus suscipit mauris, ut fringilla tellus laoreet et. Cras pretium est quis ante mattis congue. Nunc dui metus, aliquet egestas neque id, fringilla luctus dolor. + +Donec in dignissim ex. Nullam sed metus sollicitudin nibh aliquet rutrum eget sit amet odio. Vivamus quis fringilla dolor, lobortis suscipit leo. Phasellus non nisi interdum felis cursus gravida ut eget urna. Phasellus bibendum ex id velit imperdiet fringilla. Ut interdum justo at ante porta auctor. Phasellus dictum congue mauris, in hendrerit ante semper ac. Vivamus a mi quis ipsum maximus egestas sed volutpat tortor. Proin interdum dolor in ornare rhoncus. Sed ornare nunc id lacus tincidunt, aliquam faucibus lacus imperdiet. Fusce sed mauris ligula. + +Vestibulum lobortis felis neque, a luctus ligula efficitur vitae. Aenean suscipit molestie velit. Curabitur dapibus dapibus maximus. Nam ultrices, nisi eget semper accumsan, risus massa iaculis diam, ut accumsan libero neque et mi. Etiam rhoncus tellus eros, ac posuere ante bibendum vitae. Curabitur in sollicitudin dolor. Nulla tempus urna vel ligula faucibus finibus. + +Sed sit amet varius magna. Fusce vestibulum interdum magna id vehicula. Nullam quis velit cursus enim egestas semper. Aliquam tristique sapien id neque egestas, eget aliquam nisl pulvinar. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam elementum pellentesque mauris, nec condimentum elit luctus vel. Quisque iaculis, massa quis hendrerit congue, mauris erat euismod sapien, ac dapibus nulla mauris at mauris. + +Nulla bibendum volutpat augue a suscipit. Morbi tortor metus, volutpat ut felis in, malesuada malesuada nunc. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nunc a lobortis nulla, eget elementum sem. Proin eleifend est vitae diam porta gravida. Maecenas a fermentum neque. Sed lorem augue, porttitor eget bibendum ac, pretium et eros. Quisque eu ligula id odio tempor gravida condimentum ac libero. Vivamus nulla purus, cursus quis eleifend ac, ornare at nibh. Nullam a leo tincidunt, viverra odio vel, maximus turpis. Duis consectetur tempus nunc at aliquam. Integer facilisis dolor non sapien lobortis pharetra. Integer ornare metus eu diam lobortis gravida. Donec mauris ipsum, rutrum blandit auctor et, ullamcorper non nisl. Curabitur aliquet, felis in auctor ornare, nunc turpis elementum ipsum, id tempus mauris erat ut justo. Phasellus aliquam, ligula ut pretium mollis, nibh libero dictum mauris, consectetur dapibus ex lectus eu sapien. + +In lobortis in augue quis consequat. Phasellus rhoncus aliquam porta. Suspendisse at ipsum iaculis erat iaculis dapibus. Proin molestie luctus diam a lacinia. Quisque vel augue tristique, ultrices ligula quis, dictum quam. In vehicula ligula at metus tincidunt tristique. Duis pellentesque efficitur lorem, accumsan aliquet eros dignissim sit amet. Praesent volutpat ultricies quam in pharetra. Cras a odio a nisi pellentesque ultricies. Proin maximus tempor quam ut placerat. Quisque nec dolor vitae felis tincidunt molestie eget at nunc. + +Ut ipsum risus, euismod a purus quis, mattis porttitor nisl. Integer feugiat urna vel egestas ultricies. Nulla nulla nisl, fringilla ullamcorper ligula eu, tempor mollis neque. Curabitur semper aliquam dolor eu ullamcorper. Nam tempor ornare mauris sed condimentum. Duis erat velit, bibendum a tristique nec, aliquam eu lacus. Duis ornare sed mauris euismod vulputate. Quisque eros nisi, viverra a lorem at, semper aliquet diam. Sed vitae tortor mauris. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed ante metus, faucibus at nunc sit amet, dignissim sodales felis. Nullam congue maximus ante, placerat facilisis massa ornare vel. Suspendisse nec rhoncus orci. Nam ultricies, lorem vitae viverra pretium, urna libero fringilla sem, nec cursus neque lacus vitae leo. Quisque orci ipsum, elementum vel quam in, aliquam pulvinar nulla. Nunc rutrum leo id orci vehicula maximus eget ac tortor. Donec in enim vel eros egestas tincidunt ac eu sem. Suspendisse in arcu lorem. + +Curabitur venenatis libero at libero eleifend dictum eget in neque. Aliquam ac ligula pharetra, accumsan purus ut, aliquam diam. Nulla sit amet massa elit. Nam non augue lacus. Donec rhoncus arcu non libero ullamcorper, at pulvinar eros vulputate. In placerat, sem quis posuere porttitor, turpis justo blandit justo, ac iaculis quam nunc nec velit. Sed a metus arcu. Fusce mi odio, rhoncus eu dui vel, dapibus aliquam urna. Suspendisse et imperdiet orci, at dictum dui. Ut tempor arcu eu sem efficitur semper. Nunc eu tempus tortor, sed bibendum tortor. Aliquam convallis, mi in scelerisque faucibus, ex arcu laoreet erat, dapibus semper nulla eros vel odio. Vivamus eros erat, viverra sodales euismod ac, vehicula at ligula. Etiam elementum urna metus, vel consequat lectus blandit in. Suspendisse a libero vitae nulla commodo dictum. + +Integer sodales nec lorem ac tristique. Duis faucibus mollis nunc, vitae imperdiet nulla consectetur sit amet. Aenean non semper justo. Quisque eget lectus varius, iaculis ex nec, pulvinar est. Aenean eu eleifend nisl. Vivamus orci nulla, suscipit dignissim dictum eleifend, condimentum eu purus. Mauris at tortor vel dolor ultrices blandit eget quis tortor. Integer ac nisl eu neque luctus condimentum. Etiam nec mi quis magna ullamcorper vehicula. Nam cursus neque vel auctor pharetra. Suspendisse ut augue vel leo porta semper. Proin in fringilla mauris. Vivamus faucibus nulla ligula, ac tincidunt nisi placerat in. Duis congue, libero non finibus finibus, libero enim lacinia eros, nec tincidunt nulla diam pellentesque augue. Aliquam massa neque, vestibulum eu elit vitae, lacinia gravida nulla. + +Vivamus eget turpis sapien. Nam vitae turpis quam. Phasellus ac turpis id mauris fringilla viverra. Donec varius sollicitudin mi, at posuere eros. Fusce varius vitae lectus sed mattis. Pellentesque dapibus porta ex non viverra. Aliquam ut tristique orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam non lorem eu neque aliquet tristique ac non enim. Integer sed lacinia ex, eget congue sem. In hac habitasse platea dictumst. Vivamus posuere neque eget viverra sodales. Morbi in mi ac quam cursus aliquam. + +Duis id nibh vel diam iaculis malesuada elementum ac neque. Donec venenatis lectus vitae tellus consequat gravida. Sed euismod enim eget justo aliquet euismod. In volutpat lacus quam, at molestie erat sodales ac. In id dolor suscipit diam bibendum feugiat ac quis ligula. In molestie massa sed enim rutrum cursus. Praesent porttitor lacus dui, id tincidunt leo volutpat vel. Morbi libero tellus, pharetra id mi sed, dapibus sagittis nisl. Aliquam sed sem interdum, tincidunt purus nec, convallis ante. Praesent commodo laoreet libero, non commodo nisi varius sed. Nam et ante et libero euismod consequat in nec erat. Duis convallis nulla sapien, non commodo libero suscipit vel. + +Aenean facilisis massa ut mi condimentum, non porttitor ex vestibulum. Fusce a tincidunt urna, quis suscipit magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam tristique nisi sit amet metus lacinia aliquet. Nulla rutrum enim vel nisl fringilla vestibulum. Maecenas sapien lectus, auctor eu ex ut, auctor rhoncus neque. Duis lacinia enim at pretium feugiat. + +Nunc ipsum neque, tincidunt ut consequat at, tristique in arcu. Nulla lacinia dictum purus vitae aliquet. Fusce eget dui imperdiet, molestie massa quis, egestas ligula. Maecenas aliquet eu nisl et scelerisque. Fusce mollis quis massa id porttitor. Suspendisse potenti. Sed varius tincidunt tempor. + +Curabitur finibus massa nec aliquam efficitur. Nulla eget nunc velit. Quisque tempor orci non gravida hendrerit. Ut aliquam urna ut urna vehicula, nec facilisis dolor pharetra. Nullam pretium convallis nulla, a sodales lacus egestas id. Duis nec nulla enim. Quisque lorem sapien, laoreet sit amet vulputate aliquam, ullamcorper sit amet nibh. + +Curabitur ut nisl ex. Ut molestie in odio iaculis maximus. Morbi egestas est eu mi pretium feugiat ac sit amet ante. Phasellus eu ex volutpat, ornare ligula eget, maximus eros. Quisque mattis quis massa at elementum. Etiam maximus orci lacus. Duis sagittis, enim eu mattis ornare, urna nunc cursus nibh, in cursus leo turpis egestas sem. Fusce rutrum commodo blandit. Cras elementum augue eu quam lacinia rutrum at vel ante. Nulla sed iaculis felis. Duis in pellentesque nulla. Maecenas neque nisl, condimentum eu ipsum vitae, scelerisque vulputate dui. Aliquam sit amet sem egestas, lacinia velit eu, accumsan nunc. Nam mauris orci, blandit sed nisi at, sodales malesuada mi. + +Suspendisse et laoreet elit, finibus laoreet nunc. Donec ut nibh ullamcorper, accumsan ligula ut, rutrum leo. Etiam hendrerit suscipit condimentum. Maecenas ultrices mattis leo a posuere. Quisque ultricies dolor vitae pretium egestas. Proin auctor ac dui vel tincidunt. Aliquam eleifend ipsum purus, eu maximus elit condimentum eu. Curabitur efficitur pharetra viverra. Ut non nisl iaculis odio tincidunt consectetur ac tempus lorem. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultrices blandit nisi, eget vehicula ligula sagittis vel. Nullam consequat sit amet velit eu pulvinar. Sed nec velit fringilla, pellentesque ante quis, viverra ligula. + +Maecenas et diam eu risus dictum condimentum nec vel arcu. Phasellus in nisi ut erat gravida posuere. Morbi tempor lacus non lacus scelerisque elementum suscipit ac dolor. Vivamus bibendum laoreet commodo. Vivamus rhoncus condimentum ex. Sed cursus ultricies enim, accumsan feugiat neque. Vivamus sapien eros, posuere vel aliquam sed, volutpat ac ex. Duis sagittis nibh sit amet porttitor porta. Fusce arcu sapien, molestie id arcu eget, dapibus ultricies quam. Suspendisse potenti. Sed ut feugiat ipsum. Aliquam tristique viverra turpis et blandit. Ut at quam vitae eros imperdiet rutrum eget ut eros. Proin vel nulla condimentum, bibendum mauris eget, scelerisque ligula. Cras commodo sagittis nisl. + +Integer viverra lorem ac urna scelerisque vulputate. Donec non convallis massa. Fusce commodo libero eu commodo dictum. Duis porttitor justo suscipit leo viverra, et feugiat libero rutrum. Curabitur id odio porttitor, facilisis purus ac, bibendum dolor. Donec vestibulum dui mattis, gravida enim et, finibus massa. In mattis quam eget elit pretium congue. Aenean congue nisi sed purus luctus, eu sodales eros euismod. + +Maecenas hendrerit nisl eu tellus lacinia aliquet. Praesent sit amet ornare lacus. Quisque blandit faucibus consequat. Curabitur dolor ligula, ultricies ut dapibus id, ullamcorper eget quam. Quisque vehicula massa ac magna imperdiet, molestie eleifend metus elementum. Mauris tempor ex orci, ut tempor lorem pellentesque laoreet. Sed aliquet ligula ut risus consectetur, ut venenatis neque dictum. Nulla facilisi. Nullam neque mi, faucibus nec egestas sit amet, luctus a nunc. + +Maecenas sed magna ut nisl sagittis viverra vitae nec orci. Nullam dapibus justo facilisis viverra placerat. Curabitur laoreet erat eu vulputate vestibulum. Nulla consectetur, quam nec ullamcorper lacinia, ipsum libero convallis enim, ac rutrum erat lectus nec massa. Proin placerat posuere tellus. Pellentesque vel metus vestibulum, vestibulum velit vel, mattis mauris. Quisque rhoncus sapien quam, id pellentesque neque interdum sit amet. Praesent aliquam lobortis magna sit amet lobortis. + +Maecenas quis libero erat. Nullam pharetra augue eget lacinia cursus. Donec id tortor pretium, placerat risus in, finibus libero. Mauris ac orci in turpis fermentum volutpat. Cras cursus massa est, quis sodales nulla vulputate quis. Etiam nec diam interdum, semper diam at, blandit nunc. Sed porta dolor at eros eleifend sagittis. Duis maximus eros sed risus viverra pretium. In hac habitasse platea dictumst. + +Vestibulum mollis, metus a sodales porttitor, erat odio volutpat purus, in cursus mauris lorem a velit. Ut non faucibus sapien. Quisque efficitur varius justo non porttitor. Curabitur malesuada non diam quis egestas. Cras mattis rhoncus neque quis viverra. Morbi eu iaculis lacus. Fusce eget diam quis ipsum pharetra sodales. Mauris volutpat lectus non ullamcorper ornare. Integer finibus commodo efficitur. Duis sit amet dui id metus condimentum hendrerit. Suspendisse et elit nulla. Integer lacinia egestas quam, dictum ullamcorper enim laoreet at. Sed lacinia neque et sapien convallis molestie. + +Praesent lectus turpis, imperdiet sit amet euismod sit amet, aliquam vitae libero. Proin imperdiet purus rutrum neque ultricies volutpat. Aenean dignissim at sem et laoreet. Nulla blandit nisl nec condimentum egestas. Vivamus feugiat viverra scelerisque. Maecenas molestie vulputate turpis, eu vestibulum urna malesuada in. Quisque porttitor quam ante. Aenean eu efficitur diam. Aenean purus justo, ultricies luctus orci posuere, dapibus placerat eros. Suspendisse hendrerit molestie libero quis blandit. Nullam dapibus urna vitae aliquet facilisis. Etiam ligula libero, interdum vel lorem non, aliquet auctor tortor. Nullam tincidunt nulla eget nunc pulvinar, non congue sapien gravida. Aliquam finibus quam sit amet scelerisque pharetra. + +Etiam at ornare metus, id sodales lorem. In nec sollicitudin mauris. Donec turpis tellus, sodales nec luctus in, vestibulum vel tortor. Curabitur luctus lorem at tellus eleifend consectetur. Sed facilisis libero in tincidunt consectetur. Vivamus nulla dolor, posuere et turpis at, fringilla blandit mi. Aenean tincidunt lorem vitae tellus semper, ut finibus turpis imperdiet. Aliquam ac diam sapien. Integer ultricies ullamcorper varius. Etiam pellentesque, lacus quis lacinia varius, massa lectus tempor turpis, id imperdiet nunc elit in purus. Sed fringilla ipsum eget velit eleifend imperdiet. Donec et enim erat. Aliquam sed orci tincidunt, porttitor lacus sit amet, fermentum neque. Fusce aliquet eros non faucibus hendrerit. In consectetur neque sem, id viverra nibh ultricies eget. + +Morbi tristique eu arcu ac laoreet. Ut orci tellus, gravida quis neque ac, auctor rutrum neque. Vivamus vitae risus nibh. Sed mollis vel ante et egestas. Aliquam eget bibendum orci. Proin ultricies mauris purus, vel mattis orci eleifend quis. Duis et eros ut tellus vulputate feugiat. Suspendisse potenti. + +Nam in urna quis est ornare semper at nec urna. Morbi ex lorem, hendrerit quis mauris vel, elementum hendrerit lorem. Maecenas ac euismod justo. Sed leo ante, sollicitudin sed leo sed, tristique laoreet lacus. In hac habitasse platea dictumst. Nam rutrum sagittis lectus. Vivamus aliquet maximus nisl, nec mollis sapien pellentesque vitae. Fusce sit amet lectus nisi. Curabitur egestas gravida aliquam. Cras venenatis lobortis faucibus. Curabitur sit amet rhoncus mauris. Maecenas nec ante suscipit erat tempus vehicula. Nunc eleifend nibh imperdiet urna euismod sagittis. Aenean imperdiet id sem vitae semper. + +Curabitur tristique porta ullamcorper. Cras at enim massa. Suspendisse ac rhoncus ante, in lobortis est. Etiam sit amet ullamcorper odio. Praesent volutpat vulputate lectus non faucibus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam congue sed orci vitae laoreet. + +Etiam elit ligula, hendrerit non finibus in, pulvinar eu lectus. Quisque pretium maximus augue sit amet lobortis. Pellentesque condimentum, nulla vitae dignissim pretium, diam neque semper purus, vel tincidunt ante neque a eros. Phasellus ac finibus tellus. In vel aliquet nisl. Nulla a orci a leo ultricies rutrum sit amet vitae dolor. Proin et faucibus tortor, quis hendrerit purus. Quisque maximus eleifend massa, vel facilisis ligula interdum eget. + +Phasellus varius gravida urna, in lacinia nisl posuere in. Aliquam iaculis sapien nisl, eu vehicula nisi hendrerit sit amet. Nam molestie, metus vitae maximus vestibulum, arcu est fermentum nisi, sit amet lobortis ante velit sit amet neque. Nulla vitae ultricies arcu. Pellentesque tincidunt tellus nibh, gravida vulputate justo vulputate quis. Maecenas ornare ante felis, et fermentum elit pretium eu. Quisque tellus sem, dignissim a ex vel, vestibulum porta nibh. Morbi pharetra iaculis dictum. Curabitur pharetra odio sed tincidunt congue. Fusce pellentesque nec felis sodales luctus. Fusce rutrum vitae ligula non sodales. Etiam aliquam suscipit neque, ut eleifend libero. + +Aenean sed euismod lorem. Sed pulvinar ex cursus, hendrerit lectus at, viverra urna. Cras at ligula eu lectus congue viverra. Ut eget pretium risus, non scelerisque enim. Integer eu venenatis risus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus nec pellentesque mauris. Aenean dapibus tempus nisi in pellentesque. Praesent mattis placerat nulla at blandit. Nulla ac consequat eros. Maecenas risus libero, hendrerit vitae dui quis, efficitur pretium nisl. Morbi in quam aliquet, mattis arcu a, rutrum purus. Donec ac sapien bibendum, elementum diam in, ornare felis. Nulla in volutpat felis. + +Nunc tempor ultricies massa, eu fringilla nisl molestie vitae. Vestibulum in pharetra lacus. Aenean nec tortor egestas, elementum risus interdum, suscipit lacus. Nam quis efficitur mauris. Duis egestas nunc semper urna euismod fermentum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque a quam turpis. In varius mauris sed iaculis lacinia. Nam ut nisl vel sem interdum consequat nec id risus. Suspendisse vel varius libero. Praesent vel cursus dolor, sed venenatis nunc. Cras justo tortor, accumsan eget tincidunt sit amet, lacinia vitae elit. Sed suscipit est risus, ornare tincidunt dolor interdum molestie. Etiam sit amet nunc a tortor laoreet laoreet. + +Aliquam sed orci venenatis, efficitur turpis ac, egestas neque. Integer arcu justo, condimentum et fermentum vitae, congue sit amet est. Fusce scelerisque posuere dui sed pharetra. Donec id sem sit amet velit mollis facilisis. Morbi rhoncus libero sed tellus efficitur porttitor. Cras id lobortis dolor, in commodo quam. Pellentesque molestie, lacus sit amet dignissim auctor, dui massa vestibulum dolor, sit amet luctus massa mi eu massa. Nullam fringilla, arcu et placerat rutrum, augue tortor fermentum quam, vitae accumsan est enim nec justo. Quisque lobortis commodo sapien, vel venenatis lorem volutpat vehicula. Fusce porta nisi ac odio commodo, quis commodo mi scelerisque. Nunc a volutpat est. Vestibulum dictum feugiat turpis ut finibus. Sed vitae dictum sem. Praesent sollicitudin nulla ultrices ipsum bibendum vulputate. Maecenas tempor augue bibendum erat maximus porttitor. + +Vestibulum ut ipsum orci. Pellentesque non lacinia nisl. Nam sed velit tempor, malesuada diam id, lacinia lacus. Nam dictum rhoncus lectus ut porta. Pellentesque et turpis ac orci dictum sodales quis ut orci. Suspendisse eget mollis risus. Mauris fermentum tellus at neque luctus, sed tincidunt diam sollicitudin. + +Proin cursus odio et aliquet porta. Vestibulum a odio pulvinar, hendrerit orci condimentum, ornare risus. Quisque pulvinar, sem at placerat porttitor, leo sem malesuada augue, mattis finibus diam velit eget urna. Fusce cursus augue sit amet arcu faucibus scelerisque. Sed nec ullamcorper ipsum, vitae tincidunt dui. Integer eget eros leo. Suspendisse eleifend lorem nec fringilla semper. Etiam elementum ipsum eget nibh vulputate, vitae consequat ligula porta. Nulla pharetra augue sit amet magna tincidunt sodales sit amet vitae eros. Etiam euismod rutrum ligula et sodales. Vestibulum ultrices arcu quis lobortis consequat. Vestibulum fringilla mattis arcu et pharetra. Nunc enim metus, efficitur imperdiet vestibulum sed, pulvinar eget arcu. Ut est odio, condimentum a scelerisque ut, tempor ac erat. + +Aliquam diam nulla, aliquet non mi eget, dignissim eleifend risus. In a gravida turpis. Duis blandit justo vitae tempus lacinia. Cras placerat, ipsum eu rutrum placerat, massa lectus ullamcorper nibh, ut facilisis lacus massa a ligula. Praesent vulputate, massa at consectetur eleifend, ante magna rutrum orci, ac interdum risus lectus ut metus. Donec eu leo nisi. Cras vulputate aliquam lacus vitae tempor. Quisque dolor nibh, tristique et imperdiet vitae, bibendum ut lorem. Nulla vel orci in ante dictum dictum a eget turpis. Vestibulum eget lorem sit amet nunc scelerisque consectetur vitae ut diam. Sed aliquam sagittis ante quis lobortis. Aliquam a elit fringilla, laoreet eros sed, accumsan est. Nullam vitae sollicitudin ex. + +Sed nibh lorem, eleifend quis gravida vel, posuere sed mi. Nullam eget enim lacinia, gravida leo nec, viverra felis. Aenean ac euismod mi. Duis congue, turpis in lacinia dapibus, eros mauris rutrum odio, a congue nunc enim sit amet mauris. Sed in lacus sed velit tempor congue. Suspendisse potenti. Nam et justo lorem. Vivamus dictum sapien eu sapien fermentum, nec finibus augue ultricies. Nunc sodales, urna vitae fringilla scelerisque, quam felis consequat sapien, ut venenatis elit magna vitae lectus. Donec porta condimentum leo eget feugiat. Fusce vulputate mauris tellus, ac vehicula sapien viverra ut. Nullam ac cursus tortor. Maecenas nec facilisis sem. Pellentesque dapibus sed libero vitae cursus. Vestibulum a semper quam, nec finibus tortor. + +Fusce consequat odio eu est aliquam dictum. Aenean ut blandit lacus. Donec pulvinar, mauris et euismod aliquam, metus mauris aliquam ex, a convallis lacus mi a lorem. Aenean eleifend mattis nulla, nec facilisis mi feugiat sed. Maecenas vitae interdum nisl. Vivamus vel mi ac nibh finibus congue. Sed tristique enim ut sollicitudin pulvinar. Maecenas quis accumsan felis. Quisque eget pulvinar quam. Suspendisse pellentesque velit ipsum, in pharetra ligula rutrum ac. Vivamus mattis sollicitudin condimentum. + +Maecenas eu metus vestibulum, sodales tortor vel, aliquet arcu. Integer lorem velit, fringilla facilisis blandit vel, interdum quis massa. Morbi non dui quam. Donec ante diam, tempor nec pharetra nec, ultricies at tortor. Donec ut nibh nibh. Mauris eu orci eget mi convallis porta in sed metus. Suspendisse potenti. Phasellus ullamcorper, purus et rutrum facilisis, quam turpis euismod tellus, nec rhoncus enim risus at ex. Ut tincidunt tempus eros non ornare. Mauris eu vehicula velit, quis posuere urna. Donec lectus est, blandit id rutrum non, accumsan nec justo. Mauris ut mollis tortor, sit amet ornare est. + +Phasellus rhoncus fermentum mauris, in pulvinar arcu rhoncus ut. Curabitur id pharetra orci, sed semper lorem. Cras convallis tempus nibh sit amet sollicitudin. Integer nec sollicitudin dui, non ultrices metus. Ut aliquet ex non arcu dignissim venenatis. Mauris elit massa, pellentesque ac tristique nec, porttitor eget nisi. Nunc at libero nisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; + +Sed pharetra sagittis interdum. Vestibulum sit amet mauris nec nunc mollis malesuada quis vitae nulla. Vestibulum consequat felis ac lorem tincidunt, ut ullamcorper leo posuere. Etiam commodo augue sit amet lacus congue mattis. Aenean nibh nunc, dignissim pulvinar arcu quis, venenatis placerat est. Proin tellus nibh, vestibulum id facilisis iaculis, facilisis in justo. Mauris libero erat, consequat eget finibus ut, tristique nec magna. Etiam quis mi non tellus feugiat fringilla. Ut pulvinar nibh nulla, ac viverra massa dictum semper. Ut non sollicitudin dui. + +Mauris convallis sem a eros suscipit, ut mattis quam pretium. Vestibulum sed elit dapibus, ullamcorper risus faucibus, pharetra felis. Proin libero massa, fermentum a imperdiet scelerisque, dapibus ut sem. Fusce id arcu nec leo bibendum laoreet eget sed sem. Nunc ac elementum ipsum. Nullam felis magna, sollicitudin quis justo vel, bibendum eleifend neque. Phasellus vestibulum nulla ac suscipit pharetra. Praesent rutrum odio id leo malesuada aliquet. Aliquam lorem lacus, feugiat non ultrices nec, venenatis varius ipsum. Proin a metus vitae felis ullamcorper auctor. Proin vitae blandit massa. Ut at tellus interdum, pretium mi id, ultrices augue. Nam rutrum risus tristique dui eleifend, non venenatis turpis dictum. Suspendisse nec mattis nulla. Nunc id enim orci. + +Nullam et sollicitudin ex. Ut iaculis consectetur lacus, eu luctus libero fringilla vel. Praesent aliquet libero at erat mollis facilisis. Vivamus tristique posuere diam, vitae interdum tortor accumsan a. Donec arcu est, bibendum eu dictum et, fringilla ac dui. Duis vel erat elit. Fusce fermentum vitae lacus ac auctor. Suspendisse potenti. Donec viverra tortor orci. Sed tempor ultricies sapien, at sollicitudin nunc aliquam eu. + +Nullam eleifend semper justo, at feugiat ex hendrerit sit amet. In vitae ipsum odio. Quisque pellentesque molestie quam, non feugiat quam mollis sed. Etiam accumsan, neque id placerat aliquet, risus tellus tincidunt orci, ut consequat tortor massa vel arcu. Phasellus sed erat et elit iaculis imperdiet. Mauris felis ante, venenatis quis lobortis eget, mollis non ipsum. Donec semper sodales ex vel sollicitudin. Nam ipsum lorem, hendrerit ac euismod non, cursus a tellus. + +Etiam auctor turpis eget lorem malesuada imperdiet et interdum ligula. Nunc dapibus finibus ante, in aliquet nulla. Proin quis ante odio. Mauris eu laoreet neque. Proin varius est sed lacus mollis tempus. In maximus sed nisl at posuere. Vestibulum accumsan urna quis faucibus blandit. Curabitur ornare egestas ipsum ac elementum. Nulla ac justo non enim posuere ornare. Fusce a hendrerit nisl. Fusce laoreet, felis eu mollis blandit, urna elit bibendum felis, ut imperdiet mauris leo ac massa. Fusce fringilla, quam et dictum commodo, dui tellus blandit mauris, sed eleifend dui est ut mauris. Pellentesque ut elit sollicitudin, placerat quam a, pharetra diam. Ut egestas velit ac lacinia sodales. Ut ullamcorper velit non erat suscipit, vel lobortis est ultrices. + +Fusce tristique eros eu mi tincidunt, at vulputate neque tempor. Aenean sit amet arcu a arcu porttitor semper id sit amet nulla. Pellentesque posuere lobortis lorem sed porta. Nullam nibh justo, finibus vitae varius sed, fermentum ut mauris. Nam sed vulputate ante. Suspendisse tristique libero in diam egestas, at varius sapien pulvinar. Vestibulum eu elit nec magna convallis lobortis. Duis a nisi odio. Quisque erat felis, molestie ut hendrerit pretium, consectetur ut risus. Phasellus malesuada maximus lacus vitae scelerisque. Nulla facilisis urna non ipsum mattis fermentum. Etiam semper quam ut ipsum euismod luctus. + +Ut sed feugiat ipsum. Nam quis bibendum enim, quis sollicitudin urna. Ut pharetra, leo ac feugiat pellentesque, libero diam tempus sapien, et pretium ex lacus a eros. Vestibulum sed augue nisl. Nunc id malesuada neque, quis rhoncus purus. Suspendisse nulla dui, sagittis luctus sapien quis, iaculis feugiat odio. Sed venenatis accumsan neque, sit amet tempus leo sodales id. Etiam eleifend, magna vel rutrum porta, sem quam ornare eros, vel tincidunt arcu ex a ligula. Ut a consequat dui. Aliquam vestibulum id felis a aliquet. Nullam sit amet arcu a orci lobortis tincidunt sed eget ante. In interdum, metus aliquet posuere lobortis, lectus tellus tristique elit, ultricies dictum erat ex a leo. Nulla lacinia, neque id volutpat pharetra, ex neque luctus tellus, eu blandit turpis magna mollis ipsum. + +Suspendisse nec maximus dui. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas felis justo, hendrerit eget turpis sit amet, dignissim hendrerit libero. Maecenas a leo nunc. Donec sit amet sem pellentesque, eleifend risus a, rutrum dui. Praesent diam libero, egestas a eros non, posuere varius augue. Integer ipsum eros, dictum viverra lectus a, condimentum aliquam orci. Ut tristique quam non mollis mollis. Vivamus a placerat tellus, vel vehicula orci. Praesent ac tempus felis, laoreet venenatis eros. + +Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam turpis nunc, posuere et arcu ut, lacinia pellentesque sapien. Quisque sagittis sit amet erat sed tincidunt. Curabitur id tempus eros. Sed suscipit a nibh vitae interdum. Mauris sapien velit, cursus in justo eu, sollicitudin dapibus tellus. Vivamus et feugiat massa. Phasellus mattis vulputate imperdiet. In ut gravida massa. In eu elit diam. Cras nec urna tincidunt, ornare lorem at, aliquet magna. Sed maximus tortor ipsum, quis maximus nunc sagittis eu. Cras pellentesque eu nulla nec mattis. Morbi suscipit sed neque sed auctor. Pellentesque dignissim tellus vel neque gravida, nec vestibulum nulla eleifend. + +Fusce tristique gravida purus. Curabitur laoreet augue nec metus auctor, ut mollis nisl suscipit. Nullam eget commodo erat. Quisque vitae lobortis lorem. In hac habitasse platea dictumst. Etiam eu orci facilisis, efficitur eros eget, posuere ante. Quisque in risus in orci convallis porttitor. Cras eleifend fringilla dictum. Pellentesque ut orci leo. Aliquam tincidunt condimentum dapibus. Donec vitae leo sed dolor tempor sagittis id ut odio. Aenean mollis tristique commodo. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque pretium viverra magna, eu feugiat tellus porttitor in. Nulla erat felis, sagittis quis dolor ac, aliquet pharetra metus. + +Etiam nec viverra lacus, nec gravida metus. Phasellus ipsum ex, malesuada sed pretium eu, ornare nec tortor. Ut eu leo sit amet elit euismod placerat. In porta ante et accumsan porta. Donec hendrerit ac libero sed facilisis. Proin bibendum justo vel vulputate tincidunt. Vestibulum molestie neque tortor, at elementum leo pulvinar in. Sed rhoncus malesuada risus, ut sagittis odio posuere vel. Vestibulum faucibus rhoncus nibh ut porta. Donec elementum urna consequat, scelerisque tortor in, bibendum lacus. Nulla erat nunc, lacinia at lobortis a, maximus eu dolor. Fusce viverra, erat semper placerat egestas, sapien diam lobortis urna, sit amet semper mauris est in risus. Cras eget porttitor massa. + +Fusce eget cursus neque. Donec erat elit, mattis sit amet faucibus in, dignissim eget arcu. Praesent sem erat, porttitor ut hendrerit sed, fermentum sed nisl. Suspendisse efficitur facilisis condimentum. In efficitur purus tortor, a pulvinar dolor venenatis quis. Proin consequat, risus nec condimentum placerat, quam massa dignissim mauris, at semper purus lorem et nunc. Phasellus luctus dictum ante, quis vestibulum eros auctor eu. Proin quis nisi quis ligula convallis rhoncus. Suspendisse id eros vitae neque efficitur malesuada. Praesent sit amet tincidunt lectus. In ante elit, blandit vel faucibus quis, aliquet euismod purus. Duis eu purus volutpat, porta ante sit amet, efficitur augue. Donec congue a risus quis malesuada. Aenean sed est sollicitudin, efficitur enim nec, viverra quam. + +Sed vel iaculis leo. In lobortis accumsan lacus sit amet sollicitudin. Donec vel porta purus, vel vulputate est. Maecenas volutpat nisl id accumsan pellentesque. Vestibulum posuere id lorem sit amet faucibus. Aenean dictum lectus lacus, varius semper dolor cursus nec. Aliquam a tortor nisl. Maecenas sit amet diam fringilla, sodales nulla vel, iaculis lectus. + +Cras pulvinar mattis faucibus. Pellentesque semper, felis vel elementum porttitor, mi ex vestibulum libero, a rhoncus ante libero at dolor. Pellentesque maximus lorem vel massa venenatis cursus. Maecenas sed facilisis orci, vel consectetur ligula. Sed porttitor tellus magna, in placerat enim tristique sit amet. Curabitur leo lectus, fringilla dignissim augue quis, scelerisque posuere nunc. Ut sollicitudin massa ac facilisis dictum. Proin et nulla gravida, auctor ante ut, accumsan massa. + +Vestibulum faucibus lectus eget eleifend tristique. Aliquam tristique felis quis metus pretium, sed egestas sem mattis. Pellentesque ac enim at mi fermentum lacinia non eget tellus. Proin lacus enim, imperdiet et turpis sed, viverra auctor leo. Nam augue ante, tristique a neque ut, ullamcorper tempor tellus. Curabitur porttitor ornare lectus vel commodo. Nunc luctus, purus et cursus viverra, dolor magna condimentum libero, maximus tristique lacus felis vel ligula. Phasellus lacinia faucibus leo, id pretium ipsum suscipit quis. Fusce mollis enim sed augue bibendum vehicula. Nunc mollis lorem vel erat molestie, non hendrerit id. diff --git a/bdd/features/e2e/E2E-013-topic.feature b/bdd/features/e2e/E2E-013-topic.feature index fffab66e7..baaacef1d 100644 --- a/bdd/features/e2e/E2E-013-topic.feature +++ b/bdd/features/e2e/E2E-013-topic.feature @@ -97,3 +97,29 @@ The tests check topic functionalities, where we send and receive data from /topi Then confirm data defined as "hulk-nl" will be received And host is still running + @ci_api + Scenario: E2E-013 TC-009 Create and delete topic + Given host is running + And topic "RegularTopic" is created + Then confirm topics contain "RegularTopic" + Then remove topic "RegularTopic" + Then confirm topics are empty + + @ci_api + Scenario: E2E-013 TC-010 Create and delete persisting topic + Given host is running + And sequence "../packages/csv-transform.tar.gz" named "TestSequence" is send to host + And persisting topic "PersistingTopic" is created with sequence "TestSequence" + Then confirm topics contain "PersistingTopic" + Then confirm instances are not empty + Then remove topic "PersistingTopic" + Then confirm topics are empty + # TODO: Then confirm instances are empty + + @ci_api + Scenario: E2E-013 TC-011 Persistent topic keeps data on disconnections + Given host is running + And sequence "../bdd/data/sequences/persistentSeq.tar.gz" named "backupingSequence" is send to host + And persisting topic "PersistingTopic" is created with sequence "backupingSequence" + Then send data from file "../bdd/data/test-data/loremIpsum.txt" to topic "PersistingTopic" and pipe-unpipe every one fifth of data read + And host is still running \ No newline at end of file diff --git a/bdd/step-definitions/e2e/host-steps.ts b/bdd/step-definitions/e2e/host-steps.ts index bbbcd7759..5bfccc80d 100644 --- a/bdd/step-definitions/e2e/host-steps.ts +++ b/bdd/step-definitions/e2e/host-steps.ts @@ -4,7 +4,7 @@ import { Given, When, Then, Before, After, BeforeAll, AfterAll } from "@cucumber/cucumber"; import { strict as assert } from "assert"; import { removeBoundaryQuotes, defer, waitUntilStreamEquals } from "../../lib/utils"; -import fs, { createReadStream, existsSync, ReadStream } from "fs"; +import fs, { createReadStream, createWriteStream, existsSync, ReadStream, accessSync, constants } from "fs"; import { HostClient, InstanceOutputStream } from "@scramjet/api-client"; import { HostUtils } from "../../lib/host-utils"; import { PassThrough, Readable, Stream, Writable } from "stream"; @@ -14,10 +14,11 @@ import Dockerode from "dockerode"; import { CustomWorld } from "../world"; import findPackage from "find-package-json"; -import { readFile } from "fs/promises"; +import { FileHandle, open, readFile } from "fs/promises"; import { BufferStream } from "scramjet"; import { expectedResponses } from "./expectedResponses"; import { exec } from "child_process"; +import { resolve } from "path"; let hostClient: HostClient; let actualHealthResponse: any; @@ -793,3 +794,106 @@ Then("confirm json {string} will be received", async function(this: CustomWorld, assert.equal(response, data); }); + +Given("topic {string} is created", async function(this: CustomWorld, topicId: string) { + await hostClient.createTopic(topicId, "text/plain"); +}); + +Given("persisting topic {string} is created with sequence {string}", async function(this: CustomWorld, topicId: string, sequenceName: string) { + await hostClient.createTopic(topicId, "text/plain", sequenceName); +}); + +Then("confirm topics contain {string}", async function(this: CustomWorld, topicId: string) { + const topics = await hostClient.getTopics(); + + const topic = topics.find(topicElement => topicElement.topicName === topicId); + + assert.notEqual(topic, undefined); +}); + +Then("remove topic {string}", async function(this: CustomWorld, topicId: string) { + await hostClient.deleteTopic(topicId); +}); + +Then("confirm topics are empty", async function(this: CustomWorld) { + const topics = await hostClient.getTopics(); + + assert.equal(topics.length, 0); +}); + +Given("sequence {string} named {string} is send to host", async function(this: CustomWorld, sequencePackagePath: string, sequenceName: string) { + if (!sequencePackagePath || !sequenceName) throw new Error("Missing params"); + const resolvedSequencePath = resolve(process.cwd(), sequencePackagePath); + + accessSync(resolvedSequencePath, constants.F_OK); + const sequenceStream = createReadStream(resolvedSequencePath); + const sendSequence = await hostClient.sendSequence(sequenceStream, { headers: { "x-name": sequenceName } }); + const sequences = await hostClient.listSequences(); + const sequence = sequences.find(seq => seq.id === sendSequence.id); + + assert.notEqual(sequence, undefined); +}); + +Then("confirm instances are not empty", async function() { + const instances = await hostClient.listInstances(); + + assert.notEqual(instances.length, 0); +}); + +Then("confirm instances are empty", async function() { + const instances = await hostClient.listInstances(); + + assert.equal(instances.length, 0); +}); + +const waitForFileToReachSize = async (file: FileHandle, size: number, timeout: number) => { + let timeoutOccured = false; + const timeoutFn = setTimeout(() => { timeoutOccured = true; }, timeout); + + while (!timeoutOccured) { + const stats = await file.stat(); + + if (stats.size === size) break; + } + clearTimeout(timeoutFn); +}; + +Then("send data from file {string} to topic {string} and pipe-unpipe every one fifth of data read", async function(this: CustomWorld, path: string, topicId: string) { + const sourcePath = resolve(process.cwd(), path); + const outputPath = resolve(process.cwd(), "./data/test-data/topicOutput.txt"); + const [source, output] = await Promise.all([open(sourcePath, "r"), open(outputPath, "w+")]); + const sourceSize = (await source.stat()).size; + + const provider = createReadStream(sourcePath, { highWaterMark: 50, emitClose: false }); + const consumer = createWriteStream(outputPath, { flags: "w+" }); + + const topicOutStream = await hostClient.getNamedData(topicId); + + let readLen = 0; + let piped = true; + let switchLenght = sourceSize / 5; + + provider.on("data", (chunk) => { + readLen += chunk.length; + + if (readLen > switchLenght) { + // eslint-disable-next-line no-unused-expressions + piped ? topicOutStream.unpipe() : topicOutStream.pipe(consumer); + piped = !piped; + switchLenght += sourceSize / 5; + } + }); + + topicOutStream.pipe(consumer); + await hostClient.sendNamedData(topicId, provider, {}, "text/plain", false); + + await waitForFileToReachSize(output, sourceSize, 1000); + + const [sourceBuff, outputBuff] = await Promise.all([source.readFile(), output.readFile()]); + + const equals = sourceBuff.equals(outputBuff); + + assert.equal(equals, true); + + await Promise.all([source.close(), output.close()]); +}); diff --git a/packages/api-client/src/host-client.ts b/packages/api-client/src/host-client.ts index 21e06de3a..467d268bd 100644 --- a/packages/api-client/src/host-client.ts +++ b/packages/api-client/src/host-client.ts @@ -186,6 +186,14 @@ export class HostClient implements ClientProvider { return this.client.getStream(`topic/${topic}`, requestInit); } + async createTopic(id: string, contentType: string, persistentSequence?: string): Promise<{ topicName: string }> { + return this.client.post("topics", { id, "content-type": contentType, persistentSequence }, undefined, { json: true, parse: "json" }); + } + + async deleteTopic(id: string): Promise<{ message: string }> { + return this.client.delete(`topics/${id}`); + } + async getTopics(): Promise { return this.client.get("topics"); } diff --git a/packages/host/jest.config.js b/packages/host/jest.config.js new file mode 100644 index 000000000..35e4ea56d --- /dev/null +++ b/packages/host/jest.config.js @@ -0,0 +1,194 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/tmp/jest_rw", + + // Automatically clear mock calls, instances, contexts and results before every test + // clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + // collectCoverage: true, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + coverageDirectory: "coverage", + + // An array of regexp pattern strings used to skip coverage collection + coveragePathIgnorePatterns: [ + "/node_modules/", + "/dist/" + ], + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: "v8", + + // A list of reporter names that Jest uses when writing coverage reports + coverageReporters: [ + // "json", + "text", + // "lcov", + // "clover" + ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + errorOnDeprecated: true, + + // The default configuration for fake timers + // fakeTimers: { + // "enableGlobally": false + // }, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "mjs", + // "cjs", + // "jsx", + // "ts", + // "tsx", + // "json", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + preset: 'ts-jest', + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state before every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state and implementation before every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + testEnvironment: 'node', + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + testMatch: [ + "**/__tests__/**/*.[jt]s?(x)", + "**/test/**/*.[jt]s?(x)", + "**/?(*.)+(spec|test).[tj]s?(x)" + ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + testPathIgnorePatterns: [ + "/node_modules/", + "/dist/", + ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", + + // A map from regular expressions to paths to transformers + // transform: undefined, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\.pnp\\.[^\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; \ No newline at end of file diff --git a/packages/host/package.json b/packages/host/package.json index b3bcc10df..67551495b 100644 --- a/packages/host/package.json +++ b/packages/host/package.json @@ -9,8 +9,9 @@ "build:docs": "typedoc", "clean": "rm -rf ./dist .bic_cache", "cloc": "cloc src --fullpath --include-lang TypeScript --not-match-d \"(node_modules|test|dist|bdd)\" --by-percent cm", - "test": "npm run test:ava", + "test": "npm run test:jest", "test:ava": "ava", + "test:jest": "jest --verbose", "prebuild": "yarn savehash", "savehash": "node ../../scripts/hash-to-file.js ./src/" }, @@ -40,8 +41,11 @@ "devDependencies": { "@scramjet/types": "^0.33.5", "@types/find-package-json": "^1.2.3", + "@types/jest": "^29.4.4", "@types/node": "15.12.5", "ava": "^3.15.0", + "jest": "^29.5.0", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", "typedoc": "^0.23.17", "typedoc-plugin-markdown": "^3.13.6", diff --git a/packages/host/src/index.ts b/packages/host/src/index.ts index 32c41811b..3c5a03f22 100644 --- a/packages/host/src/index.ts +++ b/packages/host/src/index.ts @@ -3,6 +3,6 @@ export * from "./lib/cpm-connector"; export * from "./lib/csi-controller"; export * from "./lib/host"; export * from "./lib/instance-store"; -export * from "./lib/sd-adapter"; +export * from "./lib/serviceDiscovery/sd-adapter"; export * from "./lib/socket-server"; export * from "./lib/start-host"; diff --git a/packages/host/src/lib/csi-controller.ts b/packages/host/src/lib/csi-controller.ts index b92bfc095..2b4423738 100644 --- a/packages/host/src/lib/csi-controller.ts +++ b/packages/host/src/lib/csi-controller.ts @@ -804,7 +804,7 @@ export class CSIController extends TypedEmitter { } getLogStream(): Readable { - return this.upStreams![CC.LOG]; + return this.upStreams![CC.LOG] as Duplex; } // @TODO discuss this diff --git a/packages/host/src/lib/host.ts b/packages/host/src/lib/host.ts index c138bcf0c..4dd660525 100644 --- a/packages/host/src/lib/host.ts +++ b/packages/host/src/lib/host.ts @@ -31,7 +31,7 @@ import { CSIController } from "./csi-controller"; import { CommonLogsPipe } from "./common-logs-pipe"; import { InstanceStore } from "./instance-store"; -import { ServiceDiscovery } from "./sd-adapter"; +import { ServiceDiscovery } from "./serviceDiscovery/sd-adapter"; import { SocketServer } from "./socket-server"; import { DataStream } from "scramjet"; import { optionsMiddleware } from "./middlewares/options"; @@ -46,6 +46,10 @@ import { cpus, totalmem } from "os"; import { S3Client } from "./s3-client"; import { DuplexStream } from "@scramjet/api-server"; import { readFileSync } from "fs"; +import TopicId from "./serviceDiscovery/topicId"; +import TopicRouter from "./serviceDiscovery/topicRouter"; +import { ContentType } from "./serviceDiscovery/contentType"; +import SequenceStore from "./sequenceStore"; const buildInfo = readJsonFile("build.info", __dirname, ".."); const packageFile = findPackage(__dirname).next(); @@ -110,7 +114,7 @@ export class Host implements IComponent { /** * Sequences store. */ - sequencesStore = new Map(); + sequenceStore = new SequenceStore(); /** * Instance of class providing logging utilities. @@ -125,7 +129,7 @@ export class Host implements IComponent { /** * Service to handle topics. */ - serviceDiscovery = new ServiceDiscovery(); + serviceDiscovery: ServiceDiscovery; commonLogsPipe = new CommonLogsPipe(); @@ -140,11 +144,7 @@ export class Host implements IComponent { */ s3Client?: S3Client; - private instanceProxy = { - onInstanceRequest: (socket: Duplex) => { - this.api.server.emit("connection", socket); - } - }; + private instanceProxy = { onInstanceRequest: (socket: Duplex) => { this.api.server.emit("connection", socket); } }; /** * Sets listener for connections to socket server. @@ -204,7 +204,11 @@ export class Host implements IComponent { this.config.host.id ||= this.getId(); this.logger.updateBaseLog({ id: this.config.host.id }); - this.serviceDiscovery.logger.pipe(this.logger); + + const startSequenceCb = + async (seqence: SequenceInfo) => { return this.startCSIController(seqence, { appConfig: {} }); }; + + this.serviceDiscovery = new ServiceDiscovery(this.logger, this.config.host.hostname, startSequenceCb); if (sthConfig.telemetry.environment) this.telemetryEnvironmentName = sthConfig.telemetry.environment; @@ -404,7 +408,7 @@ export class Host implements IComponent { await DataStream.from(startupConfig) .setOptions({ maxParallel: PARALLEL_SEQUENCE_STARTUP }) .map(async (seqenceConfig: StartSequenceDTO) => { - const sequence = this.sequencesStore.get(seqenceConfig.id); + const sequence = this.sequenceStore.getById(seqenceConfig.id); if (!sequence) { this.logger.warn("Sequence id not found for startup config", seqenceConfig); @@ -493,9 +497,9 @@ export class Host implements IComponent { this.api.get(`${this.apiBase}/config`, () => this.publicConfig); this.api.get(`${this.apiBase}/status`, () => this.getStatus()); - this.api.get(`${this.apiBase}/topics`, () => this.serviceDiscovery.getTopics()); - this.api.use(this.topicsBase, (req, res, next) => this.topicsMiddleware(req, res, next)); + new TopicRouter(this.logger, this.api, this.apiBase, this.serviceDiscovery, this.sequenceStore); + this.api.upstream(`${this.apiBase}/log`, () => this.commonLogsPipe.getOut()); this.api.duplex(`${this.apiBase}/platform`, (duplex: Duplex, headers: IncomingHttpHeaders) => { this.logger.debug("Platform request"); @@ -542,12 +546,6 @@ export class Host implements IComponent { return next(); } - topicsMiddleware(req: ParsedMessage, res: ServerResponse, next: NextCallback) { - req.url = req.url?.substring(this.topicsBase.length); - - return this.serviceDiscovery.router.lookup(req, res, next); - } - /** * Handles delete Sequence request. * Removes Sequence from the store and sends notification to Manager if connected. @@ -562,7 +560,7 @@ export class Host implements IComponent { this.logger.trace("Deleting Sequence...", id); - const sequenceInfo = this.sequencesStore.get(id) || this.getSequenceByName(id); + const sequenceInfo = this.sequenceStore.getByNameOrId(id); if (!sequenceInfo) { return { @@ -591,7 +589,7 @@ export class Host implements IComponent { const sequenceAdapter = getSequenceAdapter(this.adapterName, this.config); await sequenceAdapter.remove(sequenceInfo.config); - this.sequencesStore.delete(id); + this.sequenceStore.delete(id); this.logger.trace("Sequence removed:", id); @@ -664,7 +662,7 @@ export class Host implements IComponent { for (const config of configs) { this.logger.trace(`Sequence identified: ${config.id}`); - this.sequencesStore.set(config.id, { id: config.id, config: config, instances: new Set() }); + this.sequenceStore.set({ id: config.id, config: config, instances: new Set() }); } this.logger.info(` ${configs.length} sequences identified`); } catch (e: any) { @@ -693,7 +691,7 @@ export class Host implements IComponent { await sequenceAdapter.init(); if (sequenceName) { - const existingSequence = this.getSequenceByName(sequenceName as string); + const existingSequence = this.sequenceStore.getByName(sequenceName as string); if (existingSequence) { if (stream.method === "post") { @@ -713,7 +711,7 @@ export class Host implements IComponent { config.packageSize = stream.socket?.bytesRead; - this.sequencesStore.set(id, { id, config, instances: new Set(), name: sequenceName }); + this.sequenceStore.set({ id, config, instances: new Set(), name: sequenceName }); this.logger.info("Sequence identified", config); @@ -740,25 +738,19 @@ export class Host implements IComponent { stream.params ||= {}; const seqQuery = stream.params.id_name as string; - const existingSequence = this.sequencesStore.get(seqQuery) || this.getSequenceByName(seqQuery); + const existingSequence = this.sequenceStore.getByNameOrId(seqQuery); - if (existingSequence) { - if (existingSequence.instances.size) { - return { - opStatus: ReasonPhrases.CONFLICT, - error: `Sequence with name ${seqQuery} already exists` - }; - } - - this.logger.debug("Overriding sequence", existingSequence.name, existingSequence.id); + if (!existingSequence) { + return { opStatus: ReasonPhrases.NOT_FOUND, error: `Sequence with name ${seqQuery} not found` }; + } - return this.handleIncomingSequence(stream, existingSequence.id); + if (existingSequence.instances.size) { + return { opStatus: ReasonPhrases.CONFLICT, error: "Can't update sequence with instances" }; } - return { - opStatus: ReasonPhrases.NOT_FOUND, - error: `Sequence with name ${seqQuery} not found` - }; + this.logger.debug("Overriding sequence", existingSequence.name, existingSequence.id); + + return this.handleIncomingSequence(stream, existingSequence.id); } /** @@ -775,7 +767,7 @@ export class Host implements IComponent { const sequenceName = stream.headers["x-name"] as string; if (sequenceName) { - const existingSequence = this.getSequenceByName(sequenceName); + const existingSequence = this.sequenceStore.getByNameOrId(sequenceName); if (existingSequence) { this.logger.debug("Method not allowed", sequenceName, existingSequence.id); @@ -790,19 +782,6 @@ export class Host implements IComponent { return this.handleIncomingSequence(stream, id); } - getSequenceByName(sequenceName: string): SequenceInfo | undefined { - let seq; - - for (const i of this.sequencesStore.values()) { - if (sequenceName === this.sequencesStore.get(i.id)?.name) { - seq = i; - break; - } - } - - return seq; - } - async getExternalSequence(id: string): Promise { let packageStream: IncomingMessage | undefined; @@ -825,7 +804,7 @@ export class Host implements IComponent { id )) as STHRestAPI.SendSequenceResponse; - return this.sequencesStore.get(result.id)!; + return this.sequenceStore.getById(result.id)!; } catch (e: any) { this.logger.error("Error requesting sequence", e.message); @@ -853,9 +832,7 @@ export class Host implements IComponent { const id = req.params?.id as string; const payload = req.body || ({} as STHRestAPI.StartSequencePayload); - let sequence = - this.sequencesStore.get(id) || - Array.from(this.sequencesStore.values()).find((seq: SequenceInfo) => seq.name === id); + let sequence = this.sequenceStore.getByNameOrId(id); if (this.cpmConnector?.connected) { sequence ||= await this.getExternalSequence(id).catch((error: ReasonPhrases) => { @@ -940,8 +917,8 @@ export class Host implements IComponent { this.logger.trace("Routing Sequence input to topic", data.requires); await this.serviceDiscovery.routeTopicToStream( - { topic: data.requires, contentType: data.contentType! }, - csic.getInputStream() + { topic: new TopicId(data.requires), contentType: data.contentType as ContentType }, + csic.getInputStream() as Writable ); csic.inputRouted = true; @@ -954,9 +931,9 @@ export class Host implements IComponent { if (data.provides && !csic.outputRouted) { this.logger.trace("Routing Sequence output to topic", data.requires); await this.serviceDiscovery.routeStreamToTopic( - csic.getOutputStream(), - { topic: data.provides, contentType: data.contentType! }, - csic.id + csic.getOutputStream() as Readable, + { topic: new TopicId(data.provides), contentType: data.contentType as ContentType }, + // csic.id ); csic.outputRouted = true; @@ -968,15 +945,12 @@ export class Host implements IComponent { }); csic.on("end", async (code) => { - this.logger.trace("CSIControlled ended", `Exit code: ${code}`); + this.logger.trace("CSIController ended", `Exit code: ${code}`); if (csic.provides && csic.provides !== "") { - csic.getOutputStream()!.unpipe(this.serviceDiscovery.getData( - { - topic: csic.provides, - contentType: "" - } - ) as Writable); + const topic = this.serviceDiscovery.getTopic(new TopicId(csic.provides)); + + if (topic) csic.getOutputStream()!.unpipe(topic); } csic.logger.unpipe(this.logger); @@ -995,11 +969,9 @@ export class Host implements IComponent { csic.once("terminated", (code) => { if (csic.requires && csic.requires !== "") { - (this.serviceDiscovery.getData({ - topic: csic.requires, - contentType: "", - }) as Readable - ).unpipe(csic.getInputStream()!); + const topic = this.serviceDiscovery.getTopic(new TopicId(csic.requires)); + + if (topic) topic.unpipe(csic.getInputStream()! as Writable); } this.auditor.auditInstance(id, InstanceMessageCode.INSTANCE_ENDED); @@ -1038,7 +1010,7 @@ export class Host implements IComponent { * @returns {STHRestAPI.GetSequenceResponse} Sequence info object. */ getSequence(id: string): OpResponse { - const sequence = this.sequencesStore.get(id); + const sequence = this.sequenceStore.getById(id); if (!sequence) { return { @@ -1064,12 +1036,7 @@ export class Host implements IComponent { getSequences(): STHRestAPI.GetSequencesResponse { this.logger.info("List Sequences"); - return Array.from(this.sequencesStore.values()).map((sequence) => ({ - id: sequence.id, - name: sequence.name, - config: sequence.config, - instances: Array.from(sequence.instances.values()), - })); + return this.sequenceStore.sequences; } /** @@ -1079,7 +1046,7 @@ export class Host implements IComponent { * @returns List of Instances. */ getSequenceInstances(sequenceId: string): STHRestAPI.GetSequenceInstancesResponse { - const sequence = this.sequencesStore.get(sequenceId); + const sequence = this.sequenceStore.getById(sequenceId); if (!sequence) { return { @@ -1135,7 +1102,7 @@ export class Host implements IComponent { await Promise.all(Object.values(instancesStore).map((csi) => csi.finalize())); this.instancesStore = {}; - this.sequencesStore = new Map(); + this.sequenceStore.clear(); this.logger.trace("Stopping API server"); diff --git a/packages/host/src/lib/sd-adapter.ts b/packages/host/src/lib/sd-adapter.ts deleted file mode 100644 index acff894b9..000000000 --- a/packages/host/src/lib/sd-adapter.ts +++ /dev/null @@ -1,273 +0,0 @@ - -import { APIRoute, ReadableStream } from "@scramjet/types"; -import { Duplex, PassThrough, Readable, Writable } from "stream"; - -import { CPMConnector } from "./cpm-connector"; -import { ObjLogger } from "@scramjet/obj-logger"; -import { getRouter } from "@scramjet/api-server"; -import { ReasonPhrases } from "http-status-codes"; - -/** - * TODO: Refactor types below. - */ -export type dataType = { - topic: string; - contentType: string; -} - -/** - * Topic stream type definition. - */ -export type streamType = { - contentType: string; - stream: Duplex; -} - -/** - * Topic details type definition. - */ -export type topicDataType = { - contentType: string, - stream: Duplex, - localProvider?: string, - cpmRequest?: boolean -} - -const NEWLINE_BYTE = "\n".charCodeAt(0); - -function pipeToTopic(source: Readable, target: topicDataType) { - source.pipe(target.stream, { end: false }); - - // for json streams, make sure that the last message will be ended with newline - if (target.contentType === "application/x-ndjson") { - let lastChunk = Buffer.from([]); - - source - .on("data", (chunk) => { - lastChunk = chunk as Buffer; - }) - .on("end", () => { - const lastByte = lastChunk[lastChunk.length - 1]; - - if (lastByte !== NEWLINE_BYTE) { - target.stream.write("\n"); - } - }); - } -} - -/** - * Service Discovery provides methods to manage topics. - * Its functionality covers creating, storing, removing topics - * and requesting Manager when Instance requires data but data is not available locally. - */ -export class ServiceDiscovery { - dataMap = new Map< - string, - topicDataType - >(); - - logger = new ObjLogger(this); - - cpmConnector?: CPMConnector; - - public router: APIRoute = getRouter(); - - constructor() { - this.createTopicsRouter(); - } - - createTopicsRouter() { - this.router.downstream("/:topic", async (req) => { - const contentType = req.headers["content-type"] || ""; - const { topic } = req.params || {}; - const { cpm } = req.headers; - - this.logger.debug(`Incoming topic '${topic}' request`); - let target = this.getByTopic(topic); - - req.on("close", () => { - //@TODO: Should remove this actor" - }); - - if (!target) { - target = this.addData( - { contentType, topic }, - "api" - ); - } else if (contentType !== target.contentType) { - return { opStatus: ReasonPhrases.UNSUPPORTED_MEDIA_TYPE, error: `Acceptable Content-Type for ${topic.name} is ${topic.contentType}` }; - } - - pipeToTopic(req, target); - - if (!cpm) { - await this.update({ - provides: topic, contentType: contentType, topicName: topic }); - } else { - this.logger.debug(`Incoming Downstream CPM request for topic '${topic}'`); - } - return {}; - }, { checkContentType: false }); - - this.router.upstream("/:topic", async (req) => { - //TODO: what should be the default content type and where to store this information? - const contentType = req.headers["content-type"] || "application/x-ndjson"; - const { topic } = req.params || {}; - const { cpm } = req.headers; - - if (!cpm) { - await this.update({ - requires: topic, contentType, topicName: topic }); - } else { - this.logger.debug(`Incoming Upstream CPM request for topic '${topic}'`); - } - - return this.getData({ topic, contentType }); - }); - } - - /** - * Sets the CPM connector. - * - * @param {CPMConnector} cpmConnector Manager connector Instance used to communicate with Manager. - */ - setConnector(cpmConnector: CPMConnector) { - this.cpmConnector = cpmConnector; - } - - /** - * Stores given topic. - * - * @param {dataType} config Topic configuration. - * @param {string} [localProvider] Provider identifier. It not set topic will be considered as external. - * @returns added topic data. - */ - addData(config: dataType, localProvider?: string) { - if (!this.dataMap.has(config.topic)) { - this.logger.trace("Adding data:", config, localProvider); - - const topicStream = new PassThrough(); - - this.dataMap.set(config.topic, { - contentType: config.contentType, - stream: topicStream, - localProvider - - }); - } else { - this.logger.trace("Routing data:", config); - } - - return this.dataMap.get(config.topic)!; - } - - /** - * @TODO: implement. - - * @returns All topics. - */ - getTopics() { - return Array.from(this.dataMap, ([key, value]) => ({ - contentType: value.contentType, - localProvider: value.localProvider, - topic: key, - topicName: key - })); - } - - /** - * Returns topic details for given topic. - * - * @param {string} topic Topic name. - * @returns {streamType|undefined} Topic details. - */ - getByTopic(topic: string): streamType | undefined { - if (this.dataMap.has(topic)) { - return this.dataMap.get(topic); - } - - return undefined; - } - - /** - * Unsets local provider for given topic. - * - * @param {string} topic Topic name. - */ - removeLocalProvider(topic: string) { - const d = this.dataMap.get(topic); - - if (d) { - this.dataMap.set(topic, { ...d, localProvider: undefined }); - } - } - - /** - * Returns topic details for given topic. - * If topic does not exist it will be created. - * If topic exists but is not local, data will be requested from Manager. - * - * @param {dataType} dataType Topic configuration. - * @returns Topic stream. - */ - getData(dataType: dataType): Duplex { - this.logger.debug("Get data:", dataType); - - if (this.dataMap.has(dataType.topic)) { - const topicData = this.dataMap.get(dataType.topic)!; - - this.logger.debug("Topic exists", dataType.topic); - - if (topicData?.localProvider) { - this.logger.trace("LocalProvider found topic, provider", dataType.topic, topicData.localProvider); - } else { - this.logger.trace("Local topic provider not found for:", dataType.topic); - - if (this.cpmConnector) { - this.dataMap.set(dataType.topic, topicData); - } - } - - return topicData?.stream.on("end", () => this.logger.debug("Topic ended", dataType)); - } - - this.addData(dataType); - - return this.getData(dataType); - } - - /** - * Removes store topic with given id. - * - * @param {string} topic Topic name. - */ - removeData(topic: string) { - if (this.dataMap.has(topic)) { - // eslint-disable-next-line no-extra-parens - (this.dataMap.get(topic)?.stream as ReadableStream).unpipe(); - this.dataMap.delete(topic); - } - } - - public async routeTopicToStream(topicData: dataType, target: Writable) { - this.getData(topicData).pipe(target); - - await this.cpmConnector?.sendTopicInfo({ requires: topicData.topic, topicName: topicData.topic, contentType: topicData.contentType }); - } - - public async routeStreamToTopic(source: Readable, topicData: dataType, localProvider?: string) { - const topic = this.addData(topicData, localProvider); - - pipeToTopic(source, topic); - await this.cpmConnector?.sendTopicInfo({ provides: topicData.topic, topicName: topicData.topic, contentType: topicData.contentType }); - } - - async update(data: { provides?: string, requires?: string, topicName: string, contentType: string }) { - this.logger.trace("Topic update. Send topic info to CPM", data); - - if (this.cpmConnector?.connected) { - await this.cpmConnector?.sendTopicInfo(data); - } - } -} diff --git a/packages/host/src/lib/sequenceStore.ts b/packages/host/src/lib/sequenceStore.ts new file mode 100644 index 000000000..5edddeeaa --- /dev/null +++ b/packages/host/src/lib/sequenceStore.ts @@ -0,0 +1,39 @@ +import { SequenceInfo } from "@scramjet/types"; + +class SequenceStore { + private store: Map; + + constructor() { + this.store = new Map(); + } + + get sequences() { + return Array.from(this.store, ([, sequence]) => ({ + id: sequence.id, + name: sequence.name, + config: sequence.config, + instances: Array.from(sequence.instances.values()), + })); + } + + getById(id: string): SequenceInfo | undefined { return this.store.get(id); } + + getByName(sequenceName: string): SequenceInfo | undefined { + for (const i of this.store.values()) { + if (i.name === sequenceName) return i; + } + return undefined; + } + + getByNameOrId(sequenceNameOrId: string) { + return this.getById(sequenceNameOrId) || this.getByName(sequenceNameOrId); + } + + set(sequence: SequenceInfo) { return this.store.set(sequence.id, sequence); } + + delete(sequenceId: string) { return this.store.delete(sequenceId); } + + clear() { this.store.clear(); } +} + +export default SequenceStore; diff --git a/packages/host/src/lib/serviceDiscovery/contentType.ts b/packages/host/src/lib/serviceDiscovery/contentType.ts new file mode 100644 index 000000000..e1501fa77 --- /dev/null +++ b/packages/host/src/lib/serviceDiscovery/contentType.ts @@ -0,0 +1,10 @@ +export type ContentType = "text/x-ndjson" | "application/x-ndjson" | "text/plain" | "application/octet-stream" + +export const isContentType = (contentType: string): contentType is ContentType => { + return [ + "text/x-ndjson", + "application/x-ndjson", + "text/plain", + "application/octet-stream" + ].includes(contentType); +}; diff --git a/packages/host/src/lib/serviceDiscovery/persistentTopic.ts b/packages/host/src/lib/serviceDiscovery/persistentTopic.ts new file mode 100644 index 000000000..3b916e845 --- /dev/null +++ b/packages/host/src/lib/serviceDiscovery/persistentTopic.ts @@ -0,0 +1,68 @@ +import { Readable, Writable } from "stream"; +import { ContentType } from "./contentType"; +import { ReadableState, StreamOrigin, WorkState, WritableState } from "./streamHandler"; +import { Topic, TopicStreamOptions } from "./topic"; +import TopicId from "./topicId"; +import { TopicState } from "./topicHandler"; + +class PersistentTopic extends Topic { + instanceInput: Writable; + instanceOutput: Readable; + + constructor(instanceInput: Writable, instanceOutput: Readable, id: TopicId, + contentType: ContentType, origin: StreamOrigin, + options?: TopicStreamOptions) { + super(id, contentType, origin, options); + + this.instanceInput = instanceInput; + this.instanceOutput = instanceOutput; + + this.instanceOutput.on("readable", () => { + this.pushFromOutStream(); + }); + + this.instanceInput.on("drain", () => this.updateState()); + this.instanceOutput.on("pause", () => this.updateState()); + this.instanceOutput.on("resume", () => this.updateState()); + const errorCb = (err: Error) => { + this._errored = err; + this.updateState(); + }; + + this.instanceInput.on("error", errorCb); + this.instanceOutput.on("error", errorCb); + this.on("error", errorCb); + } + // protected attachEventListeners() { + // this.on("pipe", this.addProvider); + // this.on("unpipe", this.removeProvider); + // this.on(TopicEvent.ProvidersChanged, () => this.updateState()); + // this.on(TopicEvent.ConsumersChanged, () => this.updateState()); + // } + state(): TopicState { + if (this._errored) return WorkState.Error; + if (this.instanceOutput.isPaused() + // || this.providers.size === 0 || this.consumers.size === 0 + ) + return ReadableState.Pause; + if (this.needDrain) return WritableState.Drain; + return WorkState.Flowing; + } + + _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null | undefined) => void): void { + this.needDrain = !this.instanceInput.write(chunk, encoding, callback); + } + _read(size: number): void { + this.instanceOutput.read(size); + } + private pushFromOutStream(size?: number) { + let chunk; + + while ((chunk = this.instanceOutput.read(size)) !== null) { + // console.log("READ", chunk.toString()); + if (!this.push(chunk)) break; + } + } +} + +export default PersistentTopic; diff --git a/packages/host/src/lib/serviceDiscovery/sd-adapter.ts b/packages/host/src/lib/serviceDiscovery/sd-adapter.ts new file mode 100644 index 000000000..23bb606b7 --- /dev/null +++ b/packages/host/src/lib/serviceDiscovery/sd-adapter.ts @@ -0,0 +1,203 @@ + +import { Duplex, Readable, Writable } from "stream"; +import { CPMConnector } from "../cpm-connector"; +import { ObjLogger } from "@scramjet/obj-logger"; +import TopicId from "./topicId"; +import TopicsMap from "./topicsController"; +import { Topic } from "./topic"; +import { ContentType } from "./contentType"; +import { StreamOrigin } from "./streamHandler"; +import PersistentTopic from "./persistentTopic"; +import { IObjectLogger, SequenceInfo } from "@scramjet/types"; +import { CSIController } from "../csi-controller"; +// import Consumer from "./serviceDiscovery/consumer"; +// import Provider from "./serviceDiscovery/provider"; + +export type DataType = { + topic: TopicId, + contentType: ContentType +} + +/** + * Topic stream type definition. + */ +export type StreamType = { + contentType: string; + stream: Duplex; +} + +/** + * Topic details type definition. + */ +export type TopicDataType = { + contentType: string, + stream: Duplex, + localProvider?: string, + cpmRequest?: boolean +} + +type StartSequenceCb = (seq: SequenceInfo) => Promise; +/** + * Service Discovery provides methods to manage topics. + * Its functionality covers creating, storing, removing topics + * and requesting Manager when Instance requires data but data is not available locally. + */ +export class ServiceDiscovery { + private logger = new ObjLogger(this); + private hostName: string; + private startSequenceCb: StartSequenceCb; + cpmConnector?: CPMConnector; + + // change to private + topicsController: TopicsMap; + + //FIXME: Get rid of startSequenceCb to avoid Circular Reference + constructor(logger: IObjectLogger, hostName: string, startSequenceCb: StartSequenceCb) { + this.topicsController = new TopicsMap(); + this.hostName = hostName; + this.logger.pipe(logger); + this.startSequenceCb = startSequenceCb; + } + + getTopic(id: TopicId): Topic | undefined { + return this.topicsController.get(id); + } + + createTopic(id: TopicId, contentType: ContentType) { + const topic = new Topic(id, contentType, { id: this.hostName, type: "hub" }); + + this.topicsController.set(id, topic); + return topic; + } + + async createPersistentTopic(id: TopicId, contentType: ContentType, sequence: SequenceInfo) { + const csic = await this.startSequenceCb(sequence); + + const input = csic.getInputStream(); + const output = csic.getOutputStream(); + + input.write(`Content-Type: ${contentType}\r\n`); + input.write("\r\n"); + + const origin: StreamOrigin = { id: this.hostName, type: "hub" }; + const topic = new PersistentTopic(input, output, id, contentType, origin); + + this.topicsController.set(id, topic); + return topic; + } + + deleteTopic(id: TopicId) { return this.topicsController.delete(id); } + + topics() { return this.topicsController.topics; } + + /** + * Sets the CPM connector. + * + * @param {CPMConnector} cpmConnector Manager connector Instance used to communicate with Manager. + */ + setConnector(cpmConnector: CPMConnector) { + this.cpmConnector = cpmConnector; + } + + /** + * Returns topic with given configuration, if not exists creates new one. + * + * @param {DataType} config Topic configuration. + * @param {string} [localProvider] Provider identifier. It not set topic will be considered as external. + * @returns added topic data. + */ + createTopicIfNotExist(config: DataType) { + const topicName = config.topic; + const topic = this.topicsController.get(topicName); // TODO: sprawdzanie content Type + + if (topic) { + this.logger.trace("Routing topic:", config); + return topic; + } + this.logger.trace("Adding topic:", config); + const origin: StreamOrigin = { id: "XXXX", type: "hub" }; + const newTopic = new Topic(topicName, config.contentType, origin); + + this.topicsController.set(topicName, newTopic); + return newTopic; + } + + /** + * @returns All topics. + */ + getTopics() { + return this.topicsController.topics.map((value) => ({ + contentType: value.contentType, + localProvider: "", + topic: value.id, + topicName: value.id + })); + // return this.topicsController.topics; + } + + /** + * Returns topic details for given topic. + * + * @param {string} topic Topic name. + * @returns {StreamType|undefined} Topic details. + */ + getByTopic(topic: TopicId): StreamType | undefined { + const foundTopic = this.topicsController.get(topic); + + if (!foundTopic) return; + + // eslint-disable-next-line consistent-return + return { + contentType: foundTopic.options().contentType, + stream: foundTopic + }; + } + + /** + * Returns topic details for given topic. + * If topic does not exist it will be created. + * If topic exists but is not local, data will be requested from Manager. + * + * @param {DataType} dataType Topic configuration. + * @returns Topic stream. + */ + getData(dataType: DataType): Duplex { + this.logger.debug("Get data:", dataType); + + const topic = this.createTopicIfNotExist(dataType); + + return topic; + } + + public async routeTopicToStream(topicData: DataType, target: Writable) { + const topic = this.createTopicIfNotExist(topicData); + + //FIXME: Writable wrapper for target + topic.pipe(target); + + await this.cpmConnector?.sendTopicInfo({ + requires: topicData.topic.toString(), + topicName: topicData.topic.toString(), + contentType: topicData.contentType + }); + } + + public async routeStreamToTopic(source: Readable, topicData: DataType) { + const topic = this.createTopicIfNotExist(topicData); + + source.pipe(topic, { end: false }); + await this.cpmConnector?.sendTopicInfo({ + provides: topicData.topic.toString(), + topicName: topicData.topic.toString(), + contentType: topicData.contentType + }); + } + + async update(data: { provides?: string, requires?: string, topicName: string, contentType: string }) { + this.logger.trace("Topic update. Send topic info to CPM", data); + + if (this.cpmConnector?.connected) { + await this.cpmConnector?.sendTopicInfo(data); + } + } +} diff --git a/packages/host/src/lib/serviceDiscovery/streamHandler.ts b/packages/host/src/lib/serviceDiscovery/streamHandler.ts new file mode 100644 index 000000000..7bd93705d --- /dev/null +++ b/packages/host/src/lib/serviceDiscovery/streamHandler.ts @@ -0,0 +1,42 @@ +export enum WorkState { + Flowing = "flowing", + Close = "close", + Error = "error" +} + +export enum WritableState { + Finish = "finish", + Writable = "writable", + Drain = "drain" +} + +export enum ReadableState { + Readable = "readable", + Pause = "pause", + End = "end" +} + +export type StreamState = WorkState | WritableState | ReadableState; + +export enum StreamType { + Instance = "instance", + Topic = "topic", + Api = "api" +} + +export type StreamOptions = Record; + +export type OriginType = "space" | "hub" + +export type StreamOrigin = { + type: OriginType + id: string; +} + +export interface StreamHandler { + id(): string + state(): StreamState + type(): StreamType + options(): StreamOptions + origin(): StreamOrigin +} diff --git a/packages/host/src/lib/serviceDiscovery/topic.ts b/packages/host/src/lib/serviceDiscovery/topic.ts new file mode 100644 index 000000000..07aaf0cf8 --- /dev/null +++ b/packages/host/src/lib/serviceDiscovery/topic.ts @@ -0,0 +1,197 @@ +import { Duplex, DuplexOptions, Readable } from "stream"; +import { WorkState, ReadableState, WritableState, StreamType, StreamOrigin } from "./streamHandler"; +import TopicId from "./topicId"; +// import WritableStreamWrapper from "../streamWrapper/writableStreamWrapper"; +// import ReadableStreamWrapper from "../streamWrapper/readableStreamWrapper"; +import TopicHandler, { TopicOptions, TopicState } from "./topicHandler"; +import { ContentType } from "./contentType"; + +export enum TopicEvent { + StateChanged = "stateChanged", + // ProvidersChanged = "providersChanged", + // ConsumersChanged = "consumersChanged" +} + +export type TopicStreamOptions = Pick + +export class Topic extends Duplex implements TopicHandler { + protected _id: TopicId; + protected _options: TopicOptions; + protected _origin: StreamOrigin; + protected _state: TopicState; + protected _errored?: Error; + protected needDrain: boolean; + // providers: Providers; + // consumers: Consumers; + + constructor(id: TopicId, contentType: ContentType, origin: StreamOrigin, options?: TopicStreamOptions) { + super({ ...options, highWaterMark: 0 }); + + this._id = id; + this._origin = origin; + this._state = ReadableState.Pause; + this._options = { contentType }; + this.needDrain = false; + // this.providers = new Map(); + // this.consumers = new Map(); + + this.attachEventListeners(); + } + + id() { return this._id.toString(); } + options() { return this._options; } + type() { return StreamType.Topic; } + state(): TopicState { + if (this._errored) return WorkState.Error; + if (this.isPaused() + // || this.providers.size === 0 || this.consumers.size === 0 + ) return ReadableState.Pause; + if (this.needDrain) return WritableState.Drain; + return WorkState.Flowing; + } + origin() { return this._origin; } + + _read(_size: number): void { } + _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null | undefined) => void): void { + this.needDrain = !this.push(chunk, encoding); + // console.log("CHUNK: ", chunk.toString(), this.needDrain); + callback(); + } + + // pipe>(destination: T, options?: { end?: boolean; }): T + // pipe(destination: T, options?: { end?: boolean; }): T + // pipe(destination: WritableStreamWrapper | NodeJS.WritableStream, + // options?: { end?: boolean; }): typeof destination { + // if (destination instanceof WritableStreamWrapper) + // destination = destination.stream(); + // // if (!(destination instanceof Writable)) + // // throw new Error("Streams not extending Writable are not supported"); + + // // this.addConsumer(destination); + // return super.pipe(destination, options); + // } + + // unpipe(destination?: WritableStreamWrapper | NodeJS.WritableStream): this { + // if (destination) { + // if (destination instanceof WritableStreamWrapper) + // destination = destination.stream(); + // // if (!(destination instanceof Writable)) + // // throw new Error("Streams not extending Writable are not supported"); + // // this.removeConsumer(destination); + // } + // // else this.removeAllConsumers(); + // // TODO: emit consumers change should go after unpipe + // return super.unpipe(destination); + // } + + end(cb?: (() => void) | undefined): this; + end(chunk: any, cb?: (() => void) | undefined): this; + end(chunk: any, encoding?: BufferEncoding | undefined, cb?: (() => void) | undefined): this; + end(_chunk?: unknown, _encoding?: unknown, _cb?: unknown): this { + throw new Error("Topics are not supporting end() method"); + } + + protected attachEventListeners() { + this.on("pipe", this.addXndjsonException); + // this.on("pipe", this.addProvider); + // this.on("unpipe", this.removeProvider); + this.on("drain", () => this.updateState()); + this.on("pause", () => this.updateState()); + this.on("resume", () => this.updateState()); + this.on("error", (err: Error) => { + this._errored = err; + this.updateState(); + }); + // this.on(TopicEvent.ProvidersChanged, () => this.updateState()); + // this.on(TopicEvent.ConsumersChanged, () => this.updateState()); + } + + protected updateState() { + const currentState = this.state(); + + if (this._state === currentState) return; + this._state = currentState; + this.emit(TopicEvent.StateChanged, currentState); + } + // protected emitProvidersChange() { this.emit(TopicEvent.ProvidersChanged); } + // protected emitConsumersChange() { this.emit(TopicEvent.ConsumersChanged); } + + // protected addProvider(source: T) { + // if (!(source instanceof Readable)) + // throw new Error("Streams not extending Readable are not supported"); + + // this.addXndjsonException(source); + + // if (!this.addStream(source, this.providers)) return; + // this.emitProvidersChange(); + // } + + protected addXndjsonException(source: Readable) { + if (this._options.contentType === "application/x-ndjson") { + const NEWLINE_BYTE = "\n".charCodeAt(0); + + let lastChunk = Buffer.from([]); + + source + .on("data", (chunk) => { lastChunk = chunk as Buffer; }) + .on("end", () => { + const lastByte = lastChunk[lastChunk.length - 1]; + + if (lastByte !== NEWLINE_BYTE) { + this.write("\n"); + } + }); + } + } + + // protected removeProvider(source: T) { + // if (!(source instanceof Readable)) + // throw new Error("Streams not extending Readable are not supported"); + + // if (!this.removeStream(source, this.providers)) return; + // this.emitProvidersChange(); + // } + + // protected addConsumer(destination: T) { + // if (!this.addStream(destination, this.consumers)) return; + // this.emitConsumersChange(); + // } + // protected removeConsumer(destination: T) { + // if (!this.removeStream(destination, this.consumers)) return; + // this.emitConsumersChange(); + // } + // protected removeAllConsumers() { + // if (this.consumers.size === 0) return; + // this.consumers.clear(); + // this.emitConsumersChange(); + // } + + // private addStream(stream: Writable, destination: Consumers): boolean + // private addStream(stream: Readable, destination: Providers): boolean + // private addStream(stream: Writable | Readable, destination: Consumers | Providers) { + // let streamHandler: StreamHandler; + + // if (stream instanceof Topic) streamHandler = stream; + // else if (stream instanceof Readable) streamHandler = ReadableStreamWrapper.retrive(stream); + // else if (stream instanceof Writable) streamHandler = WritableStreamWrapper.retrive(stream); + // else throw new Error("Unsupported stream type"); + + // const streamExist = destination.has(stream); + + // if (streamExist) return false; + // destination.set(stream, streamHandler); + // this.updateState(); + // return true; + // } + + // private removeStream(stream: Writable, destination: Consumers): boolean + // private removeStream(stream: Readable, destination: Providers): boolean + // private removeStream(stream: Writable | Readable, destination: Consumers | Providers) { + // const removed = destination.delete(stream); + + // if (removed) this.updateState(); + // return removed; + // } +} + +export default Topic; diff --git a/packages/host/src/lib/serviceDiscovery/topicHandler.ts b/packages/host/src/lib/serviceDiscovery/topicHandler.ts new file mode 100644 index 000000000..bcb0be834 --- /dev/null +++ b/packages/host/src/lib/serviceDiscovery/topicHandler.ts @@ -0,0 +1,20 @@ +import { Duplex } from "stream"; +import { ReadableState, StreamHandler, WorkState, WritableState } from "./streamHandler"; +import { ContentType } from "./contentType"; + +// export type Providers = Map +// export type Consumers = Map + +export type TopicOptions = { + contentType: ContentType +} + +export type TopicState = WorkState.Flowing | WorkState.Error | ReadableState.Pause | WritableState.Drain; + +interface TopicHandler extends Duplex, StreamHandler { + // providers: Providers + // consumers: Consumers + options(): TopicOptions +} + +export default TopicHandler; diff --git a/packages/host/src/lib/serviceDiscovery/topicId.ts b/packages/host/src/lib/serviceDiscovery/topicId.ts new file mode 100644 index 000000000..07a472203 --- /dev/null +++ b/packages/host/src/lib/serviceDiscovery/topicId.ts @@ -0,0 +1,19 @@ +class TopicId { + private topicName: string; + + constructor(name: string) { + this.topicName = name; + } + toString() { + return this.topicName; + } + isValid() { + return TopicId.validate(this.topicName); + } + static validate(topicName: string) { + if (topicName.match(/^[\\a-zA-Z0-9_+-]+$/)) return true; + return false; + } +} + +export default TopicId; diff --git a/packages/host/src/lib/serviceDiscovery/topicRouter.ts b/packages/host/src/lib/serviceDiscovery/topicRouter.ts new file mode 100644 index 000000000..e60628822 --- /dev/null +++ b/packages/host/src/lib/serviceDiscovery/topicRouter.ts @@ -0,0 +1,191 @@ +/* eslint-disable complexity */ +import { ObjLogger } from "@scramjet/obj-logger"; +import { APIExpose, IObjectLogger, OpResponse, SequenceInfo } from "@scramjet/types"; +import { ReasonPhrases } from "http-status-codes"; +import { ServiceDiscovery } from "./sd-adapter"; +import { IncomingMessage, ServerResponse } from "http"; +import { TopicState } from "./topicHandler"; +import { StreamOrigin } from "./streamHandler"; +import { ContentType, isContentType } from "./contentType"; +import TopicId from "./topicId"; +import { Topic } from "./topic"; +import { PassThrough } from "stream"; +import SequenceStore from "../sequenceStore"; + +type TopicsPostReq = IncomingMessage & { + body?: { + id?: string, + "content-type"?: string, + persistentSequence?: string + }; +}; +type TopicsPostRes = { + id: string + origin: StreamOrigin + state: TopicState + contentType: ContentType + // consumers: [] //TODO: fill type + // providers: [] //TODO: fill type +} +type TopicDeleteReq = IncomingMessage & { + params?: { topic?: string } +} +type TopicStreamReq = IncomingMessage & { + headers?: { + "content-type"?: string, + cpm?: string + }, + params?: { topic?: string } +} + +const missingBodyId = "Missing body param: id"; +const invalidContentTypeMsg = "Unsupported content-type"; +const invalidTopicIdMsg = "Topic id incorrect format"; + +class TopicRouter { + private logger = new ObjLogger(this); + private serviceDiscovery: ServiceDiscovery; + private sequenceStore: SequenceStore; + + constructor(logger: IObjectLogger, apiServer: APIExpose, + apiBaseUrl: string, serviceDiscovery: ServiceDiscovery, + sequenceStore: SequenceStore) { + this.serviceDiscovery = serviceDiscovery; + this.logger.pipe(logger); + this.sequenceStore = sequenceStore; + + apiServer.get(`${apiBaseUrl}/topics`, () => this.serviceDiscovery.getTopics()); + apiServer.op("post", `${apiBaseUrl}/topics`, (req) => this.topicsPost(req)); + apiServer.op("delete", `${apiBaseUrl}/topics/:topic`, (req) => this.deleteTopic(req)); + apiServer.downstream(`${apiBaseUrl}/topic/:topic`, (req) => this.topicDownstream(req), { checkContentType: false }); + apiServer.upstream(`${apiBaseUrl}/topic/:topic`, (req, res) => this.topicUpstream(req, res)); + } + + async topicsPost(req: TopicsPostReq): Promise> { + if (!req.body?.id) return { opStatus: ReasonPhrases.BAD_REQUEST, error: missingBodyId }; + if (!req.body?.["content-type"]) return { opStatus: ReasonPhrases.BAD_REQUEST, error: "Missing body param: content-type" }; + const { "content-type": contentType, id, persistentSequence } = req.body; + + if (!isContentType(contentType)) return { opStatus: ReasonPhrases.BAD_REQUEST, error: invalidContentTypeMsg }; + if (!TopicId.validate(id)) return { opStatus: ReasonPhrases.BAD_REQUEST, error: invalidTopicIdMsg }; + + const topicId = new TopicId(id); + const topicExist = this.serviceDiscovery.getTopic(topicId) !== undefined; + + if (topicExist) return { opStatus: ReasonPhrases.BAD_REQUEST, error: "Topic with given id already exist" }; + + let topic: Topic; + let sequence: SequenceInfo | undefined; + + if (persistentSequence) { + sequence = this.sequenceStore.getByNameOrId(persistentSequence); + if (!sequence) return { opStatus: ReasonPhrases.NOT_FOUND, error: `Couldn't find sequence ${persistentSequence}` }; + topic = await this.serviceDiscovery.createPersistentTopic(topicId, contentType, sequence); + } else + topic = this.serviceDiscovery.createTopic(topicId, contentType); + + return { + opStatus: ReasonPhrases.OK, + id: topic.id(), + origin: topic.origin(), + state: topic.state(), + contentType: topic.options().contentType, + // consumers: [], + // providers: [], + }; + } + + async deleteTopic(req: TopicDeleteReq) { + const { topic: id = "" } = req.params || {}; + + if (!TopicId.validate(id)) return { opStatus: ReasonPhrases.BAD_REQUEST, error: invalidTopicIdMsg }; + + const topicId = new TopicId(id); + const removed = this.serviceDiscovery.deleteTopic(topicId); + + if (!removed) + return { + opStatus: ReasonPhrases.NOT_FOUND, + error: `Topic ${topicId} not found` + }; + return { + opStatus: ReasonPhrases.OK, + message: `Topic ${topicId} removed` + }; + } + + async topicDownstream(req: TopicStreamReq) { + const { "content-type": contentType = "", cpm } = req.headers; + const { topic: id = "" } = req.params || {}; + + if (!isContentType(contentType)) return { opStatus: ReasonPhrases.BAD_REQUEST, error: invalidContentTypeMsg }; + if (!TopicId.validate(id)) return { opStatus: ReasonPhrases.BAD_REQUEST, error: invalidTopicIdMsg }; + + const topicId = new TopicId(id); + + this.logger.debug(`Incoming topic '${id}' request`); + + let topic = this.serviceDiscovery.getTopic(topicId); + + if (topic) { + const topicContentType = topic.options().contentType; + + if (contentType !== topicContentType) { + return { + opStatus: ReasonPhrases.UNSUPPORTED_MEDIA_TYPE, + error: `Acceptable Content-Type for ${id} is ${topicContentType}` + }; + } + } else { + // FIXME: Single responsibility rule validation + topic = this.serviceDiscovery.createTopic(topicId, contentType); + } + req.pipe(topic, { end: false }); + + if (!cpm) { + await this.serviceDiscovery.update({ + provides: topic.id(), contentType: contentType, topicName: topic.id() + }); + } else { + this.logger.debug(`Incoming Downstream CPM request for topic '${topic}'`); + } + return { opStatus: ReasonPhrases.OK }; + } + + async topicUpstream(req: TopicStreamReq, res: ServerResponse) { + // FIXME: this shuoldn't be default + const { "content-type": contentType = "application/x-ndjson", cpm } = req.headers; + const { topic: id = "" } = req.params || {}; + + // FIXME: fix types to make it work properly: + if (!isContentType(contentType)) { + res.end({ opStatus: ReasonPhrases.BAD_REQUEST, error: invalidContentTypeMsg }); + return new PassThrough(); + } + if (!TopicId.validate(id)) { + res.end({ opStatus: ReasonPhrases.BAD_REQUEST, error: invalidTopicIdMsg }); + return new PassThrough(); + } + + const topicId = new TopicId(id); + //TODO: what should be the default content type and where to store this information? + + if (!cpm) { + await this.serviceDiscovery.update({ + requires: id, contentType, topicName: topicId.toString() + }); + } else { + this.logger.debug(`Incoming Upstream CPM request for topic '${id}'`); + } + + return this.serviceDiscovery.createTopicIfNotExist({ topic: topicId, contentType }); + } + + protected persistentToBoolean(persistenString: string | undefined) { + if (persistenString === "true") return true; + if (persistenString !== "false") return null; + return false; + } +} + +export default TopicRouter; diff --git a/packages/host/src/lib/serviceDiscovery/topicsController.ts b/packages/host/src/lib/serviceDiscovery/topicsController.ts new file mode 100644 index 000000000..1f551fcd0 --- /dev/null +++ b/packages/host/src/lib/serviceDiscovery/topicsController.ts @@ -0,0 +1,50 @@ +import { Topic } from "./topic"; +import TopicId from "./topicId"; + +class TopicsMap { + private topicsMap: Map; + + constructor() { + this.topicsMap = new Map(); + } + + get topics() { + return Array.from(this.topicsMap, ([, topic]) => ({ + id: topic.id(), + contentType: topic.options().contentType, + state: topic.state(), + // providers: Array.from(topic.providers, ([, provider]) => ({ + // type: provider.type(), + // id: provider.id(), + // state: provider.state(), + // origin: provider.origin(), + // })), + // consumers: Array.from(topic.providers, ([, consumer]) => ({ + // type: consumer.type(), + // id: consumer.id(), + // state: consumer.state(), + // origin: consumer.origin() + // })) + })); + } + + set(id: TopicId, topic: Topic) { + this.topicsMap.set(id.toString(), topic); + } + has(id: TopicId) { + return this.topicsMap.has(id.toString()); + } + get(id: TopicId) { + return this.topicsMap.get(id.toString()); + } + delete(id: TopicId) { + const topic = this.topicsMap.get(id.toString()); + + if (!topic) return false; + // TODO: should be something like topic.disconnect() (both providers and consumers) + topic.unpipe(); + return this.topicsMap.delete(id.toString()); + } +} + +export default TopicsMap; diff --git a/packages/host/src/lib/streamWrapper/baseStreamWrapper.ts b/packages/host/src/lib/streamWrapper/baseStreamWrapper.ts new file mode 100644 index 000000000..4c16bd9c8 --- /dev/null +++ b/packages/host/src/lib/streamWrapper/baseStreamWrapper.ts @@ -0,0 +1,45 @@ +import { Stream } from "stream"; +import { StreamHandler, StreamOptions, StreamOrigin, StreamState, StreamType } from "../serviceDiscovery/streamHandler"; + +export type WrapperData = { + id: string, + type: StreamType, + origin: StreamOrigin, + options?: StreamOptions +} + +export abstract class BaseStreamWrapper implements StreamHandler { + protected _stream: WrappedStream; + + constructor(stream: WrappedStream, wrapperData: WrapperData) { + this._stream = stream; + this.saveWrapperData(wrapperData); + } + + id(): string { return (this._stream as any).wrapperData.id; } + options(): StreamOptions { return (this._stream as any).wrapperData.options || {}; } + origin(): StreamOrigin { return (this._stream as any).wrapperData.origin; } + abstract state(): StreamState + type(): StreamType { return (this._stream as any).wrapperData.type; } + stream() { return this._stream; } + + static hasWrapperData(stream: WrappedStream) { return "wrapperData" in stream; } + static retriveWrapperData(stream: WrappedStream): WrapperData { + // TODO: Add after KM, remove return || default values + // if (!this.hasWrapperData) throw new Error("Stream doesn't contain wrapper data"); + const wrappedData: WrapperData = (stream as any).wrapperData; + + return { + id: wrappedData?.id || "", + type: wrappedData?.type || "instance", + origin: wrappedData?.origin || { id: "", type: "hub" }, + options: wrappedData?.options || {}, + }; + } + + protected saveWrapperData(wrapperData: WrapperData) { + (this._stream as any).wrapperData = wrapperData; + } +} + +export default BaseStreamWrapper; diff --git a/packages/host/src/lib/streamWrapper/readableStreamWrapper.ts b/packages/host/src/lib/streamWrapper/readableStreamWrapper.ts new file mode 100644 index 000000000..4554370d2 --- /dev/null +++ b/packages/host/src/lib/streamWrapper/readableStreamWrapper.ts @@ -0,0 +1,30 @@ +import { BaseStreamWrapper } from "./baseStreamWrapper"; +import { ReadableState, StreamOptions, StreamOrigin, StreamType, WorkState } from "../serviceDiscovery/streamHandler"; +import { Readable } from "stream"; + +type ReadableStreamState = WorkState | ReadableState + +class ReadableStreamWrapper extends BaseStreamWrapper { + static create( + stream: WrappedStream, id: string, type: StreamType, + origin: StreamOrigin, options: StreamOptions + ) { + return new ReadableStreamWrapper(stream, { id, type, origin, options }); + } + static retrive(stream: WrappedStream) { + const wrappedData = BaseStreamWrapper.retriveWrapperData(stream); + + return new ReadableStreamWrapper(stream, wrappedData); + } + + state(): ReadableStreamState { + // if (this._stream.errored) return WorkState.Error; + // if (this._stream.closed) return WorkState.Close; + if (this._stream.readableEnded) return ReadableState.End; + if (this._stream.isPaused()) return ReadableState.Pause; + if (this._stream.readable) return ReadableState.Readable; + return WorkState.Flowing; + } +} + +export default ReadableStreamWrapper; diff --git a/packages/host/src/lib/streamWrapper/writableStreamWrapper.ts b/packages/host/src/lib/streamWrapper/writableStreamWrapper.ts new file mode 100644 index 000000000..22edb2972 --- /dev/null +++ b/packages/host/src/lib/streamWrapper/writableStreamWrapper.ts @@ -0,0 +1,27 @@ +import { Writable } from "stream"; +import { BaseStreamWrapper } from "./baseStreamWrapper"; +import { StreamOptions, StreamOrigin, StreamType, WorkState, WritableState } from "../serviceDiscovery/streamHandler"; + +type WritableStreamState = WorkState | WritableState + +class WritableStreamWrapper extends BaseStreamWrapper { + static create(stream: WrappedStream, id: string, + type: StreamType, origin: StreamOrigin, options: StreamOptions) { + return new WritableStreamWrapper(stream, { id, type, origin, options }); + } + static retrive(stream: WrappedStream) { + const wrappedData = BaseStreamWrapper.retriveWrapperData(stream); + + return new WritableStreamWrapper(stream, wrappedData); + } + state(): WritableStreamState { + // if (this._stream.errored) return WorkState.Error; + // if (this._stream.closed) return WorkState.Close; + if (this._stream.writableFinished) return WritableState.Finish; + if (this._stream.writable) return WritableState.Writable; + // if (this._stream.writableNeedDrain) return WritableState.Drain; + return WorkState.Flowing; + } +} + +export default WritableStreamWrapper; diff --git a/packages/host/test/common-logs-pipe.spec.ts b/packages/host/test/common-logs-pipe.spec.ts index ebe6091d1..59ef49dab 100644 --- a/packages/host/test/common-logs-pipe.spec.ts +++ b/packages/host/test/common-logs-pipe.spec.ts @@ -2,14 +2,13 @@ import { DataStream } from "scramjet"; import { PassThrough } from "stream"; import { CommonLogsPipe } from "../src/lib/common-logs-pipe"; -import test from "ava"; const lineLength = 20; const numberOfLogs = 1e4; const highWaterMark = lineLength * numberOfLogs / 1000; const commonLogsBufferLength = numberOfLogs / 1000; -test("10k logs pauses instances streams if commonLogsPipe is a PassThrough", async (t) => { +test("10k logs pauses instances streams if commonLogsPipe is a PassThrough", async () => { const commonLogsPipe = { outStream: new PassThrough({ highWaterMark }) }; const instances = [new PassThrough(), new PassThrough()]; @@ -33,10 +32,10 @@ test("10k logs pauses instances streams if commonLogsPipe is a PassThrough", asy }) .run(); - t.assert(instances.every(instance => instance.isPaused() === true)); + expect(instances.every(instance => instance.isPaused() === true)); }); -test("10k logs does not pause instances streams", async (t) => { +test("10k logs does not pause instances streams", async () => { const commonLogsPipe = new CommonLogsPipe(commonLogsBufferLength); const instances = [new PassThrough(), new PassThrough()]; @@ -60,10 +59,10 @@ test("10k logs does not pause instances streams", async (t) => { }) .run(); - t.assert(instances.every(instance => instance.isPaused() === false)); + expect(instances.every(instance => instance.isPaused() === false)); }); -test("instances streams will automatically resume after a pause", async (t) => { +test("instances streams will automatically resume after a pause", async () => { const commonLogsPipe = new CommonLogsPipe(1e3); const instances = [new PassThrough(), new PassThrough()]; @@ -91,6 +90,6 @@ test("instances streams will automatically resume after a pause", async (t) => { }) .run(); - t.assert(instances.every(instance => instance.isPaused() === false)); - t.assert(areStreamsPaused.every(isPaused => isPaused === false)); + expect(instances.every(instance => instance.isPaused() === false)); + expect(areStreamsPaused.every(isPaused => isPaused === false)); }); diff --git a/packages/host/test/pass.spec.ts b/packages/host/test/pass.spec.ts deleted file mode 100644 index 57dc6c738..000000000 --- a/packages/host/test/pass.spec.ts +++ /dev/null @@ -1,5 +0,0 @@ -import test from "ava"; - -test("Passing test", (t) => { - t.pass(); -}); diff --git a/packages/host/test/serviceDiscovery/persistentTopic.spec.ts b/packages/host/test/serviceDiscovery/persistentTopic.spec.ts new file mode 100644 index 000000000..11102a311 --- /dev/null +++ b/packages/host/test/serviceDiscovery/persistentTopic.spec.ts @@ -0,0 +1,169 @@ +import { Duplex, EventEmitter, PassThrough, Readable } from "stream"; +import { StreamOrigin, StreamType } from "../../src/lib/serviceDiscovery/streamHandler"; +import TopicId from "../../src/lib/serviceDiscovery/topicId"; +import ReadableStreamWrapper from "../../src/lib/streamWrapper/readableStreamWrapper"; +// import WritableStreamWrapper from "../../src/lib/streamWrapper/writableStreamWrapper"; +import PersistentTopic from "../../src/lib/serviceDiscovery/persistentTopic"; + +let persistentSequence: Duplex; +let testPersistentTopic: PersistentTopic; +const testOrigin: StreamOrigin = { id: "TestEviroment", type: "hub" }; + +beforeEach(() => { + testPersistentTopic = new PersistentTopic(new PassThrough(), new TopicId("TestTopic"), "text/plain", testOrigin, { encoding: "ascii" }); + persistentSequence = testPersistentTopic.persistingStream; +}); + +describe("Passing events thorugh persistent topic", () => { + const waitForEvent = (eventName: string, source: EventEmitter) => { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject("Timeout"), 100); + + source.on(eventName, () => { + clearTimeout(timeout); + resolve(); + }); + }); + }; + + test("Data event", async () => { + const eventOccured = waitForEvent("data", persistentSequence); + + persistentSequence.on("readable", () => { persistentSequence.read(); }); + testPersistentTopic.write("some text123"); + await expect(eventOccured).resolves; + }); + // test("Error event", async () => { + // const eventOccured = waitForEvent("error", persistentSequence); + // testPersistentTopic.destroy(new Error("Test Error")); + // await expect(eventOccured).resolves; + // }); + + test("Readable event", async () => { + const eventOccured = waitForEvent("readable", testPersistentTopic); + + testPersistentTopic.write("some text"); + await expect(eventOccured).resolves; + }); + test("Resume event", async () => { + const eventOccured = waitForEvent("resume", testPersistentTopic); + + testPersistentTopic.resume(); + await expect(eventOccured).resolves; + }); +}); + +describe("Data flow", () => { + const testText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + + const createWaitingPromise = (): [Promise, () => void, (_: any) => void] => { + let res = () => { }; + let rej = (_reason: any) => { }; + const promise = new Promise((resolve, reject) => { res = resolve; rej = reject; }); + + return [promise, res, rej]; + }; + + test("Basic flow", async () => { + testPersistentTopic = new PersistentTopic(new PassThrough({ highWaterMark: 0 }), new TopicId("TestTopic"), "text/plain", testOrigin, { encoding: "ascii" }); + const topicFinished = new Promise(resolve => testPersistentTopic.on("readable", () => { + resolve(testPersistentTopic.read()); + })); + + testPersistentTopic.write(testText); + const result = await topicFinished; + + expect(result).toBe(testText); + }); + // test("Piped flow", async () => { + // const testProvider = ReadableStreamWrapper.create(new PassThrough({ encoding: "ascii" }), "testReadStream", StreamType.Instance, testOrigin, {}); + // const testConsumer = WritableStreamWrapper.create(new PassThrough({ encoding: "ascii" }), "testWriteStream", StreamType.Instance, testOrigin, {}); + + // testProvider.stream().pipe(testPersistentTopic).pipe(testConsumer); + + // const readPromise = new Promise(resolve => testConsumer.stream().on("readable", () => { + // resolve(testConsumer.stream().read()); + // })); + + // testProvider.stream().push(testText); + // const readValue = await readPromise; + + // expect(readValue).toBe(testText); + // }); + test("Many Providers writing", async () => { + const [startGeneratingPromise, startGenerating] = createWaitingPromise(); + + async function* generator(from: number, to: number) { + let i = from; + + while (i <= to) { + await startGeneratingPromise; + yield Number(i++).toString(); + } + } + + const createStreamProvider = + (name: string, from: number, to: number): [ReadableStreamWrapper, Promise] => { + const gen = generator(from, to); + const provider = ReadableStreamWrapper.create(Readable.from(gen).setEncoding("ascii"), name, StreamType.Instance, testOrigin, {}); + const [streamEndPromise, streamEnd, streamError] = createWaitingPromise(); + + provider.stream().on("close", streamEnd).on("error", streamError); + return [provider, streamEndPromise]; + }; + + const [provider1, provider1End] = createStreamProvider("TestReadStream1", 1, 10); + const [provider2, provider2End] = createStreamProvider("TestReadStream2", 11, 20); + const [provider3, provider3End] = createStreamProvider("TestReadStream3", 21, 30); + + provider1.stream().pipe(testPersistentTopic, { end: false }); + provider2.stream().pipe(testPersistentTopic, { end: false }); + provider3.stream().pipe(testPersistentTopic, { end: false }); + + const result: number[] = []; + + testPersistentTopic.on("data", (chunk) => { result.push(Number(chunk)); }); + + startGenerating(); + await Promise.all([provider1End, provider2End, provider3End]); + result.sort((a: number, b: number) => a - b); + const expectedResult = [...Array(30).keys()].map(val => val + 1); + const match = result.length === expectedResult.length && + !expectedResult.some((value, index) => result[index] !== value); + + expect(match).toBe(true); + }); + // test("Many Consumers reading", async () => { + // const consumer1 = WritableStreamWrapper.create(new PassThrough({ encoding: "ascii" }), "TestWriteStream1", StreamType.Instance, testOrigin, {}); + // const consumer2 = WritableStreamWrapper.create(new PassThrough({ encoding: "ascii" }), "TestWriteStream1", StreamType.Instance, testOrigin, {}); + // const consumer3 = WritableStreamWrapper.create(new PassThrough({ encoding: "ascii" }), "TestWriteStream1", StreamType.Instance, testOrigin, {}); + + // const result = ["", "", ""]; + // const [readed1Promise, readed1] = createWaitingPromise(); + // const [readed2Promise, readed2] = createWaitingPromise(); + // const [readed3Promise, readed3] = createWaitingPromise(); + + // consumer1.stream().on("readable", () => { + // result[0] = consumer1.stream().read(); + // readed1(); + // }); + // consumer2.stream().on("readable", () => { + // result[1] = consumer2.stream().read(); + // readed2(); + // }); + // consumer3.stream().on("readable", () => { + // result[2] = consumer3.stream().read(); + // readed3(); + // }); + + // testPersistentTopic.pipe(consumer1); + // testPersistentTopic.pipe(consumer2); + // testPersistentTopic.pipe(consumer3); + // testPersistentTopic.write(testText); + + // await Promise.all([readed1Promise, readed2Promise, readed3Promise]); + // expect(result[0]).toBe(testText); + // expect(result[1]).toBe(testText); + // expect(result[2]).toBe(testText); + // }); +}); diff --git a/packages/host/test/serviceDiscovery/sd-discovery.spec.ts b/packages/host/test/serviceDiscovery/sd-discovery.spec.ts new file mode 100644 index 000000000..835337ec3 --- /dev/null +++ b/packages/host/test/serviceDiscovery/sd-discovery.spec.ts @@ -0,0 +1,124 @@ +import { DataType, ServiceDiscovery } from "../../src/lib/serviceDiscovery/sd-adapter"; +import { CPMConnector } from "../../src/lib/cpm-connector"; +import { PassThrough } from "stream"; +import TopicId from "../../src/lib/serviceDiscovery/topicId"; +import { ObjLogger } from "@scramjet/obj-logger"; + +let serviceDiscovery: ServiceDiscovery; +const testUUID = new TopicId("4fb4230f-5481-487d-a055-a99d20740e96"); +const testConfig: DataType = { + topic: testUUID, + contentType: "text/plain" +}; + +type sendTopicInfoArg = { provides?: string; requires?: string; topicName: string, contentType: string; }; +let topicInfo: sendTopicInfoArg; + +beforeEach(() => { + const mockLogger = new ObjLogger(this); + const mockCallback = () => { throw new Error("Mocked callback"); }; + + serviceDiscovery = new ServiceDiscovery(mockLogger, "MockHost", mockCallback); + serviceDiscovery.cpmConnector = { + sendTopicInfo: (data: sendTopicInfoArg): Promise => { + topicInfo = data; + return new Promise((resolve) => resolve()); + } + } as CPMConnector; +}); + +// getTopics() +describe("Return list of topics in SD", () => { + test("Empty list", () => { + const topics = serviceDiscovery.getTopics(); + + expect(topics.length === 0); + }); + + test("List with 5 elements", () => { + const topicsId = [ + new TopicId("1fb4230f-5481-487d-a055-a99d20740e96"), + new TopicId("2fb4230f-5481-487d-a055-a99d20740e96"), + new TopicId("3fb4230f-5481-487d-a055-a99d20740e96"), + new TopicId("4fb4230f-5481-487d-a055-a99d20740e96"), + new TopicId("5fb4230f-5481-487d-a055-a99d20740e96"), + ]; + + topicsId.forEach((topicId) => + serviceDiscovery.createTopicIfNotExist({ topic: topicId, contentType: "text/plain" })) + const topics = serviceDiscovery.getTopics(); + + expect(topics.length === 5); + }); + + test("List with only unique elements", () => { + for (let i = 0; i < 10; i++) + serviceDiscovery.createTopicIfNotExist({ topic: new TopicId("1fb4230f-5481-487d-a055-a99d20740e00"), contentType: "text/plain" }); + + const topics = serviceDiscovery.getTopics(); + + expect(topics.length === 1); + }); +}); + +// getByTopic(topic: string) +describe("Get topic details for given topic", () => { + test("Get existing topic", () => { + serviceDiscovery.createTopicIfNotExist(testConfig); + const returnedTopic = serviceDiscovery.getByTopic(testUUID); + + expect(returnedTopic).not.toBeUndefined(); + expect(returnedTopic!.contentType).toEqual(testConfig.contentType); + }); + test("Get not existing topic", () => { + const returnedTopic = serviceDiscovery.getByTopic(testUUID); + + expect(returnedTopic).toBeUndefined(); + }); +}); + +// getData(dataType: dataType) +test("Get topic details", () => { + serviceDiscovery.getData(testConfig); + // Unable to test + expect(true).toBeTruthy(); +}); + +// removeData(topic: string) +test("Remove stored topic with given id", () => { + serviceDiscovery.createTopicIfNotExist(testConfig); + expect(serviceDiscovery.getTopics().length === 1); + // serviceDiscovery.removeData(testUUID); + // expect(serviceDiscovery.getTopics().length === 0); +}); + +// routeTopicToStream(topicData: dataType, target: Writable) +test("Route topic to stream", async () => { + const testTarget = new PassThrough(); + + await serviceDiscovery.routeTopicToStream(testConfig, testTarget); + expect(topicInfo!).not.toBeUndefined(); + expect(topicInfo!.requires).toEqual(testConfig.topic.toString()); + expect(topicInfo!.contentType).toEqual(testConfig.contentType); +}); + +// routeStreamToTopic(source: Readable, topicData: dataType, localProvider?: string) +test("Route stream to topic", async () => { + const testSource = new PassThrough(); + + await serviceDiscovery.routeStreamToTopic(testSource, testConfig); + expect(topicInfo!).not.toBeUndefined(); + expect(topicInfo!.provides).toEqual(testConfig.topic.toString()); + expect(topicInfo!.contentType).toEqual(testConfig.contentType); +}); + +// update(data: { provides?: string, requires?: string, topicName: string, contentType: string }) +test("Update", async () => { + serviceDiscovery.cpmConnector!.connected = true; + await serviceDiscovery.update({ provides: "dummyProvides", requires: "dummyRequires", topicName: "dummyTopicName", contentType: "dummyContentType" }); + expect(topicInfo!).not.toBeUndefined(); + expect(topicInfo!.provides).toEqual("dummyProvides"); + expect(topicInfo!.requires).toEqual("dummyRequires"); + expect(topicInfo!.topicName).toEqual("dummyTopicName"); + expect(topicInfo!.contentType).toEqual("dummyContentType"); +}); diff --git a/packages/host/test/serviceDiscovery/topic.spec.ts b/packages/host/test/serviceDiscovery/topic.spec.ts new file mode 100644 index 000000000..22bc9fd7d --- /dev/null +++ b/packages/host/test/serviceDiscovery/topic.spec.ts @@ -0,0 +1,348 @@ +import { PassThrough, Readable, Stream } from "stream"; +import { StreamOrigin, StreamType } from "../../src/lib/serviceDiscovery/streamHandler"; +import { Topic } from "../../src/lib/serviceDiscovery/topic"; +import TopicId from "../../src/lib/serviceDiscovery/topicId"; +import ReadableStreamWrapper from "../../src/lib/streamWrapper/readableStreamWrapper"; +// import WritableStreamWrapper from "../../src/lib/streamWrapper/writableStreamWrapper"; + +let testTopic: Topic; +const testOrigin: StreamOrigin = { id: "TestEviroment", type: "hub" }; + +beforeEach(() => { + testTopic = new Topic(new TopicId("TestTopic"), "text/plain", testOrigin, { encoding: "ascii" }); +}); + +// describe("Provider management", () => { +// let testProvider: ReadableStreamWrapper; + +// beforeEach(() => { +// testProvider = ReadableStreamWrapper.create(new Readable({ read: () => { } }), "testReadStream", StreamType.Instance, testOrigin, {}); +// }); + +// test("Automaticly add provider on pipe", () => { +// expect(testTopic.providers.size).toBe(0); +// testProvider.stream().pipe(testTopic); +// expect(testTopic.providers.size).toBe(1); +// }); + +// test("Add only unique streams on pipe", () => { +// testProvider.stream().pipe(testTopic); +// testProvider.stream().pipe(testTopic); +// testProvider.stream().pipe(testTopic); +// expect(testTopic.providers.size).toBe(1); +// }); + +// test("Add multiple providers on pipe", () => { +// const testProvider1 = ReadableStreamWrapper.create(new Readable({ read: () => { } }), "testReadStream1", StreamType.Instance, testOrigin, {}); +// const testProvider2 = ReadableStreamWrapper.create(new Readable({ read: () => { } }), "testReadStream2", StreamType.Instance, testOrigin, {}); +// const testProvider3 = ReadableStreamWrapper.create(new Readable({ read: () => { } }), "testReadStream3", StreamType.Instance, testOrigin, {}); + +// testProvider1.stream().pipe(testTopic); +// testProvider2.stream().pipe(testTopic); +// testProvider3.stream().pipe(testTopic); + +// expect(testTopic.providers.size).toBe(3); +// }); + +// test("Add other topic as provider", () => { +// const otherTopic = new Topic(new TopicId("TestTopic"), "text/plain", testOrigin); + +// otherTopic.pipe(testTopic); +// expect(testTopic.providers.size).toBe(1); +// }); + +// test("Automaticly remove provider on unpipe(source)", () => { +// testProvider.stream().pipe(testTopic); +// expect(testTopic.providers.size).toBe(1); +// testProvider.stream().unpipe(testTopic); +// expect(testTopic.providers.size).toBe(0); +// }); +// }); + +// describe("Consumer management", () => { +// let testConsumer: WritableStreamWrapper; + +// beforeEach(() => { +// testConsumer = WritableStreamWrapper.create(new Writable({ write: () => { } }), "testWriteStream", StreamType.Instance, testOrigin, {}); +// }); + +// test("Automaticly add consumer on pipe", () => { +// expect(testTopic.consumers.size).toBe(0); +// testTopic.pipe(testConsumer); +// expect(testTopic.consumers.size).toBe(1); +// }); + +// test("Add only unique streams on pipe", () => { +// testTopic.pipe(testConsumer); +// testTopic.pipe(testConsumer); +// testTopic.pipe(testConsumer); +// expect(testTopic.consumers.size).toBe(1); +// }); + +// test("Add multiple consumer on pipe", () => { +// const testConsumer1 = WritableStreamWrapper.create(new Writable({ write: () => { } }), "testWriteStream1", StreamType.Instance, testOrigin, {}); +// const testConsumer2 = WritableStreamWrapper.create(new Writable({ write: () => { } }), "testWriteStream2", StreamType.Instance, testOrigin, {}); +// const testConsumer3 = WritableStreamWrapper.create(new Writable({ write: () => { } }), "testWriteStream3", StreamType.Instance, testOrigin, {}); + +// testTopic.pipe(testConsumer1); +// testTopic.pipe(testConsumer2); +// testTopic.pipe(testConsumer3); + +// expect(testTopic.consumers.size).toBe(3); +// }); + +// test("Add other topic as consumer", () => { +// const otherTopic = new Topic(new TopicId("TestTopic"), "text/plain", testOrigin); + +// testTopic.pipe(otherTopic); +// expect(testTopic.consumers.size).toBe(1); +// }); + +// test("Automaticly remove consumer on unpipe(source)", () => { +// testTopic.pipe(testConsumer.stream()); +// expect(testTopic.consumers.size).toBe(1); +// testTopic.unpipe(testConsumer.stream()); +// expect(testTopic.consumers.size).toBe(0); +// }); + +// test("Automaticly remove all consumers on unpipe()", () => { +// const testConsumer1 = WritableStreamWrapper.create(new Writable({ write: () => { } }), "testWriteStream1", StreamType.Instance, testOrigin, {}); +// const testConsumer2 = WritableStreamWrapper.create(new Writable({ write: () => { } }), "testWriteStream2", StreamType.Instance, testOrigin, {}); +// const testConsumer3 = WritableStreamWrapper.create(new Writable({ write: () => { } }), "testWriteStream3", StreamType.Instance, testOrigin, {}); + +// testTopic.pipe(testConsumer1); +// testTopic.pipe(testConsumer2); +// testTopic.pipe(testConsumer3); + +// expect(testTopic.consumers.size).toBe(3); +// testTopic.unpipe(); +// expect(testTopic.consumers.size).toBe(0); +// }); +// }); + +describe("Event flow", () => { + const waitForEvent = (eventName: string, source: Stream) => { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject("Timeout"), 100); + + source.on(eventName, () => { + clearTimeout(timeout); + resolve(true); + }); + }); + }; + + describe("Duplex events", () => { + test("Data event", async () => { + const eventOccured = waitForEvent("data", testTopic); + + testTopic.on("readable", () => { testTopic.read(); }); + testTopic.write("some text123"); + await expect(eventOccured).resolves.toBe(true); + }); + // test("Error event", async () => { + // const eventOccured = waitForEvent("error", testTopic); + + // testTopic.destroy(new Error("Test Error")); + // await expect(eventOccured).resolves.toBe(true); + // }); + test("Pause event", async () => { + const eventOccured = waitForEvent("pause", testTopic); + + testTopic.pause(); + await expect(eventOccured).resolves.toBe(true); + }); + test("Readable event", async () => { + const eventOccured = waitForEvent("readable", testTopic); + + testTopic.write("some text"); + await expect(eventOccured).resolves.toBe(true); + }); + test("Resume event", async () => { + const eventOccured = waitForEvent("resume", testTopic); + + testTopic.resume(); + await expect(eventOccured).resolves.toBe(true); + }); + }); + // describe("Topic events", () => { + // let testProvider: ReadableStreamWrapper; + // let testConsumer: WritableStreamWrapper; + + // beforeEach(() => { + // testProvider = ReadableStreamWrapper.create(new PassThrough({ encoding: "ascii" }), "testReadStream", StreamType.Instance, testOrigin, {}); + // testConsumer = WritableStreamWrapper.create(new PassThrough({ encoding: "ascii" }), "testWriteStream", StreamType.Instance, testOrigin, {}); + // }); + + // test("State when error", async () => { + // const eventOccured = waitForEvent("error", testTopic); + + // testTopic.destroy(new Error("Test Error")); + // await eventOccured; + // expect(testTopic.state()).toBe(WorkState.Error); + // }); + + // test("State flowing", async () => { + // testProvider.stream().pipe(testTopic); + // expect(testTopic.state()).toBe(ReadableState.Pause); + // const eventPromise = waitForEvent(TopicEvent.StateChanged, testTopic); + + // testTopic.pipe(testConsumer); + // await eventPromise; + // expect(testTopic.state()).toBe(WorkState.Flowing); + // }); + + // test("ProvidersChanged on add", async () => { + // const eventPromise = waitForEvent(TopicEvent.ProvidersChanged, testTopic); + + // testProvider.stream().pipe(testTopic); + // await eventPromise; + // expect(testTopic.providers.size).toBe(1); + // }); + // test("ProvidersChanged on remove", async () => { + // let eventPromise = waitForEvent(TopicEvent.ProvidersChanged, testTopic); + + // testProvider.stream().pipe(testTopic); + // await eventPromise; + // eventPromise = waitForEvent(TopicEvent.ProvidersChanged, testTopic); + // testProvider.stream().unpipe(testTopic); + // expect(testTopic.providers.size).toBe(0); + // }); + // test("ConsumersChanged on add", async () => { + // const eventPromise = waitForEvent(TopicEvent.ConsumersChanged, testTopic); + + // testTopic.pipe(testConsumer); + // await eventPromise; + // expect(testTopic.consumers.size).toBe(1); + // }); + // test("ConsumersChanged on remove", async () => { + // let eventPromise = waitForEvent(TopicEvent.ConsumersChanged, testTopic); + + // testTopic.pipe(testConsumer); + // await eventPromise; + // eventPromise = waitForEvent(TopicEvent.ConsumersChanged, testTopic); + // testTopic.unpipe(testConsumer); + // expect(testTopic.consumers.size).toBe(0); + // }); + // }); +}); + +describe("Data flow", () => { + const testText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + + const createWaitingPromise = (): [Promise, () => void, (_: any) => void] => { + let res = () => { }; + let rej = (_reason: any) => { }; + const promise = new Promise((resolve, reject) => { res = resolve; rej = reject; }); + + return [promise, res, rej]; + }; + + test("Basic flow", async () => { + const topicFinished = new Promise(resolve => testTopic.on("readable", () => { + resolve(testTopic.read()); + })); + + testTopic.write(testText); + const result = await topicFinished; + + expect(result).toBe(testText); + }); + test("Piped flow", async () => { + // const testProvider = ReadableStreamWrapper.create(new PassThrough({ encoding: "ascii" }), "testReadStream", StreamType.Instance, testOrigin, {}); + // const testConsumer = WritableStreamWrapper.create(new PassThrough({ encoding: "ascii" }), "testWriteStream", StreamType.Instance, testOrigin, {}); + + const testProvider = new PassThrough(); + const testConsumer = new PassThrough({ encoding: "utf-8" }); + + testProvider.pipe(testTopic).pipe(testConsumer); + + const readPromise = new Promise(resolve => testConsumer.on("readable", () => { + resolve(testConsumer.read()); + })); + + testProvider.push(testText); + const readValue = await readPromise; + + expect(readValue).toBe(testText); + }); + test("Many Providers writing", async () => { + const [startGeneratingPromise, startGenerating] = createWaitingPromise(); + + async function* generator(from: number, to: number) { + let i = from; + + while (i <= to) { + await startGeneratingPromise; + yield Number(i++).toString(); + } + } + + const createStreamProvider = + (name: string, from: number, to: number): [ReadableStreamWrapper, Promise] => { + const gen = generator(from, to); + const provider = ReadableStreamWrapper.create(Readable.from(gen).setEncoding("ascii"), name, StreamType.Instance, testOrigin, {}); + const [streamEndPromise, streamEnd, streamError] = createWaitingPromise(); + + provider.stream().on("close", streamEnd).on("error", streamError); + return [provider, streamEndPromise]; + }; + + const [provider1, provider1End] = createStreamProvider("TestReadStream1", 1, 10); + const [provider2, provider2End] = createStreamProvider("TestReadStream2", 11, 20); + const [provider3, provider3End] = createStreamProvider("TestReadStream3", 21, 30); + + provider1.stream().pipe(testTopic, { end: false }); + provider2.stream().pipe(testTopic, { end: false }); + provider3.stream().pipe(testTopic, { end: false }); + + const result: number[] = []; + + testTopic.on("data", (chunk) => { result.push(Number(chunk)); }); + + startGenerating(); + await Promise.all([provider1End, provider2End, provider3End]); + result.sort((a: number, b: number) => a - b); + const expectedResult = [...Array(30).keys()].map(val => val + 1); + const match = result.length === expectedResult.length && + !expectedResult.some((value, index) => result[index] !== value); + + expect(match).toBe(true); + }); + test("Many Consumers reading", async () => { + // const consumer1 = WritableStreamWrapper.create(new PassThrough({ encoding: "ascii" }), "TestWriteStream1", StreamType.Instance, testOrigin, {}); + // const consumer2 = WritableStreamWrapper.create(new PassThrough({ encoding: "ascii" }), "TestWriteStream1", StreamType.Instance, testOrigin, {}); + // const consumer3 = WritableStreamWrapper.create(new PassThrough({ encoding: "ascii" }), "TestWriteStream1", StreamType.Instance, testOrigin, {}); + const consumer1 = new PassThrough({ encoding: "ascii" }); + const consumer2 = new PassThrough({ encoding: "ascii" }); + const consumer3 = new PassThrough({ encoding: "ascii" }); + + const result = ["", "", ""]; + const [readed1Promise, readed1] = createWaitingPromise(); + const [readed2Promise, readed2] = createWaitingPromise(); + const [readed3Promise, readed3] = createWaitingPromise(); + + consumer1.on("readable", () => { + result[0] = consumer1.read(); + readed1(); + }); + consumer2.on("readable", () => { + result[1] = consumer2.read(); + readed2(); + }); + consumer3.on("readable", () => { + result[2] = consumer3.read(); + readed3(); + }); + + testTopic.pipe(consumer1); + testTopic.pipe(consumer2); + testTopic.pipe(consumer3); + testTopic.write(testText); + + await Promise.all([readed1Promise, readed2Promise, readed3Promise]); + expect(result[0]).toBe(testText); + expect(result[1]).toBe(testText); + expect(result[2]).toBe(testText); + }); +}); diff --git a/packages/obj-logger/src/obj-logger.ts b/packages/obj-logger/src/obj-logger.ts index ef2f77b76..ee488fce4 100644 --- a/packages/obj-logger/src/obj-logger.ts +++ b/packages/obj-logger/src/obj-logger.ts @@ -10,6 +10,22 @@ type ObjLogPipeOptions = { stringified?: boolean; }; +const getCircularReplacer = () => { + const seen = new WeakSet(); + + return (_key: string, value: any): any => { + if (typeof value === "object" && value !== null) { + if (seen.has(value)) { + return; + } + seen.add(value); + } + + // eslint-disable-next-line consistent-return + return value; + }; +}; + export class ObjLogger implements IObjectLogger { /** * Identifies if you can still write messages. @@ -166,8 +182,17 @@ export class ObjLogger implements IObjectLogger { get stringifiedOutput(): StringStream { if (!this._stringifiedOutput) - // eslint-disable-next-line no-console - this._stringifiedOutput = this.output.JSONStringify().catch((e: any) => { console.error(e); }); + this._stringifiedOutput = this.output + .stringify((chunk) => { + try { + return JSON.stringify(chunk) + "\n"; + } catch (e) { + return JSON.stringify(chunk, getCircularReplacer()) + "\n"; + } + }) + // eslint-disable-next-line no-console + .catch((e: any) => { console.error(e?.cause); }); + return this._stringifiedOutput; } diff --git a/packages/obj-logger/src/utils/streams.ts b/packages/obj-logger/src/utils/streams.ts index eaa7fe1e4..7caa8273b 100644 --- a/packages/obj-logger/src/utils/streams.ts +++ b/packages/obj-logger/src/utils/streams.ts @@ -31,8 +31,7 @@ export class JSONParserStream extends Transform { try { this.push(this.parser(chunk)); } catch (e: any) { - if (typeof e === "object") e.chunk = chunk; - this.emit("error", Object.assign(e, { chunk })); + this.emit("error", Object.assign(new Error("Cannot parse"), { originalMessage: e?.message, chunk, cause: e?.stack })); } } } @@ -54,8 +53,7 @@ export class JSONStringifierStream extends Transform { try { this.push(this.stringifier(chunk)); } catch (e: any) { - if (typeof e === "object") e.chunk = chunk; - this.emit("error", Object.assign(e, { chunk })); + this.emit("error", Object.assign(new Error("Cannot stringify"), { originalMessage: e?.message, chunk, cause: e?.stack })); } } } diff --git a/packages/types/src/rest-api-sth/get-topics.ts b/packages/types/src/rest-api-sth/get-topics.ts index 142b1a209..b4cb6a6e5 100644 --- a/packages/types/src/rest-api-sth/get-topics.ts +++ b/packages/types/src/rest-api-sth/get-topics.ts @@ -1,4 +1,6 @@ export type GetTopicsResponse = { - name: string; contentType: string; + localProvider: string, + topic: string, + topicName: string, }[];