1
0
mirror of https://github.com/mgerb/mywebsite synced 2026-01-12 10:52:47 +00:00

updated bunch of file paths and changed the way posts are loaded

This commit is contained in:
2016-01-05 12:28:04 -06:00
parent 719ae331ae
commit c96a84d0ff
13249 changed files with 317868 additions and 2101398 deletions

20
node_modules/mailcomposer/.jshintrc generated vendored Normal file
View File

@@ -0,0 +1,20 @@
{
"indent": 4,
"node": true,
"globalstrict": true,
"evil": true,
"unused": true,
"undef": true,
"newcap": true,
"esnext": true,
"curly": true,
"eqeqeq": true,
"expr": true,
"predef": [
"describe",
"it",
"beforeEach",
"afterEach"
]
}

2
node_modules/mailcomposer/.npmignore generated vendored Normal file
View File

@@ -0,0 +1,2 @@
.travis.yml
test

30
node_modules/mailcomposer/Gruntfile.js generated vendored Normal file
View File

@@ -0,0 +1,30 @@
'use strict';
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
jshint: {
all: ['lib/*.js', 'test/*.js'],
options: {
jshintrc: '.jshintrc'
}
},
mochaTest: {
all: {
options: {
reporter: 'spec'
},
src: ['test/*-test.js']
}
}
});
// Load the plugin(s)
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-mocha-test');
// Tasks
grunt.registerTask('default', ['jshint', 'mochaTest']);
};

16
node_modules/mailcomposer/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,16 @@
Copyright (c) 2012-2015 Andris Reinman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

252
node_modules/mailcomposer/README.md generated vendored Normal file
View File

@@ -0,0 +1,252 @@
# mailcomposer
**mailcomposer** is a Node.JS module for generating e-mail messages that can be streamed to SMTP or file.
> **NB!** This module is not backwards compatible with versions 0.x
[![Build Status](https://secure.travis-ci.org/andris9/mailcomposer.png)](http://travis-ci.org/andris9/mailcomposer)
## Support mailcomposer development
[![Donate to author](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DB26KWR2BQX5W)
## Installation
Install through NPM
npm install mailcomposer
## Usage
### Include mailcomposer module
```javascript
var mailcomposer = require("mailcomposer");
```
### Create a new `MailComposer` instance
```javascript
var mail = mailcomposer(mailOptions);
```
Where `mailOptions` is an object that defines the components of the message, see below
## API
### createReadStream
To create a stream that outputs a raw rfc822 message from the defined input, use `createReadStream()`
```javascript
var mail = mailcomposer({from: '...', ...});
var stream = mail.createReadStream();
stream.pipe(process.stdout);
```
### build
To generate the message and return it with a callback use `build()`
```javascript
var mail = mailcomposer({from: '...', ...});
mail.build(function(err, message){
process.stdout.write(message);
});
```
### E-mail message fields
The following are the possible fields of an e-mail message:
- **from** - The e-mail address of the sender. All e-mail addresses can be plain `'sender@server.com'` or formatted `'Sender Name <sender@server.com>'`, see [here](#address-formatting) for details
- **sender** - An e-mail address that will appear on the *Sender:* field
- **to** - Comma separated list or an array of recipients e-mail addresses that will appear on the *To:* field
- **cc** - Comma separated list or an array of recipients e-mail addresses that will appear on the *Cc:* field
- **bcc** - Comma separated list or an array of recipients e-mail addresses that will appear on the *Bcc:* field
- **replyTo** - An e-mail address that will appear on the *Reply-To:* field
- **inReplyTo** - The message-id this message is replying
- **references** - Message-id list (an array or space separated string)
- **subject** - The subject of the e-mail
- **text** - The plaintext version of the message as an Unicode string, Buffer, Stream or an object *{path: '...'}*
- **html** - The HTML version of the message as an Unicode string, Buffer, Stream or an object *{path: '...'}*
- **watchHtml** - Apple Watch specific HTML version of the message (*experimental*)
- **headers** - An object or array of additional header fields (e.g. *{"X-Key-Name": "key value"}* or *[{key: "X-Key-Name", value: "val1"}, {key: "X-Key-Name", value: "val2"}]*)
- **attachments** - An array of attachment objects (see [below](#attachments) for details)
- **alternatives** - An array of alternative text contents (in addition to text and html parts) (see [below](#alternatives) for details)
- **envelope** - optional SMTP envelope, if auto generated envelope is not suitable (see [below](#smtp-envelope) for details)
- **messageId** - optional Message-Id value, random value will be generated if not set
- **date** - optional Date value, current UTC string will be used if not set
- **encoding** - optional transfer encoding for the textual parts
All text fields (e-mail addresses, plaintext body, html body) use UTF-8 as the encoding.
Attachments are streamed as binary.
### Attachments
Attachment object consists of the following properties:
* **filename** - filename to be reported as the name of the attached file, use of unicode is allowed
* **cid** - optional content id for using inline images in HTML message source
* **content** - String, Buffer or a Stream contents for the attachment
* **encoding** - If set and `content` is string, then encodes the content to a Buffer using the specified encoding. Example values: `base64`, `hex`, `binary` etc. Useful if you want to use binary attachments in a JSON formatted e-mail object
* **path** - path to a file or an URL (data uris are allowed as well) if you want to stream the file instead of including it (better for larger attachments)
* **contentType** - optional content type for the attachment, if not set will be derived from the `filename` property
* **contentTransferEncoding** - optional transfer encoding for the attachment, if not set it will be derived from the `contentType` property. Example values: `quoted-printable`, `base64`
* **contentDisposition** - optional content disposition type for the attachment, defaults to 'attachment'
Attachments can be added as many as you want.
```javascript
var mailOptions = {
...
attachments: [
{ // utf-8 string as an attachment
filename: 'text1.txt',
content: 'hello world!'
},
{ // binary buffer as an attachment
filename: 'text2.txt',
content: new Buffer('hello world!','utf-8')
},
{ // file on disk as an attachment
filename: 'text3.txt',
path: '/path/to/file.txt' // stream this file
},
{ // filename and content type is derived from path
path: '/path/to/file.txt'
},
{ // stream as an attachment
filename: 'text4.txt',
content: fs.createReadStream('file.txt')
},
{ // define custom content type for the attachment
filename: 'text.bin',
content: 'hello world!',
contentType: 'text/plain'
},
{ // use URL as an attachment
filename: 'license.txt',
path: 'https://raw.github.com/andris9/Nodemailer/master/LICENSE'
},
{ // encoded string as an attachment
filename: 'text1.txt',
content: 'aGVsbG8gd29ybGQh',
encoding: 'base64'
},
{ // data uri as an attachment
path: 'data:text/plain;base64,aGVsbG8gd29ybGQ='
}
]
}
```
### Alternatives
In addition to text and HTML, any kind of data can be inserted as an alternative content of the main body - for example a word processing document with the same text as in the HTML field. It is the job of the e-mail client to select and show the best fitting alternative to the reader. Usually this field is used for calendar events and such.
Alternative objects use the same options as [attachment objects](#attachments). The difference between an attachment and an alternative is the fact that attachments are placed into *multipart/mixed* or *multipart/related* parts of the message white alternatives are placed into *multipart/alternative* part.
**Usage example:**
```javascript
var mailOptions = {
...
html: '<b>Hello world!</b>',
alternatives: [
{
contentType: 'text/x-web-markdown',
content: '**Hello world!**'
}
]
}
```
Alternatives can be added as many as you want.
### Address Formatting
All the e-mail addresses can be plain e-mail addresses
```
foobar@blurdybloop.com
```
or with formatted name (includes unicode support)
```
"Ноде Майлер" <foobar@blurdybloop.com>
```
> Notice that all address fields (even `from`) are comma separated lists, so if you want to use a comma in the name part, make sure you enclose the name in double quotes: `"Майлер, Ноде" <foobar@blurdybloop.com>`
or as an address object (in this case you do not need to worry about the formatting, no need to use quotes etc.)
```
{
name: 'Майлер, Ноде',
address: 'foobar@blurdybloop.com'
}
```
All address fields accept comma separated list of e-mails or an array of
e-mails or an array of comma separated list of e-mails or address objects - use it as you like.
Formatting can be mixed.
```
...,
to: 'foobar@blurdybloop.com, "Ноде Майлер" <bar@blurdybloop.com>, "Name, User" <baz@blurdybloop.com>',
cc: ['foobar@blurdybloop.com', '"Ноде Майлер" <bar@blurdybloop.com>, "Name, User" <baz@blurdybloop.com>'],
bcc: ['foobar@blurdybloop.com', {name: 'Майлер, Ноде', address: 'foobar@blurdybloop.com'}]
...
```
You can even use unicode domains, these are automatically converted to punycode
```
'"Unicode Domain" <info@müriaad-polüteism.info>'
```
### SMTP envelope
SMTP envelope is usually auto generated from `from`, `to`, `cc` and `bcc` fields but
if for some reason you want to specify it yourself, you can do it with `envelope` property.
`envelope` is an object with the following params: `from`, `to`, `cc` and `bcc` just like
with regular mail options. You can also use the regular address format, unicode domains etc.
```javascript
mailOptions = {
...,
from: 'mailer@kreata.ee',
to: 'daemon@kreata.ee',
envelope: {
from: 'Daemon <deamon@kreata.ee>',
to: 'mailer@kreata.ee, Mailer <mailer2@kreata.ee>'
}
}
```
> Not all transports can use the `envelope` object, for example SES ignores it and uses the data from the From:, To: etc. headers.
### Using Embedded Images
Attachments can be used as embedded images in the HTML body. To use this feature, you need to set additional property of the attachment - `cid` (unique identifier of the file) which is a reference to the attachment file. The same `cid` value must be used as the image URL in HTML (using `cid:` as the URL protocol, see example below).
**NB!** the cid value should be as unique as possible!
```javascript
var mailOptions = {
...
html: 'Embedded image: <img src="cid:unique@kreata.ee"/>',
attachments: [{
filename: 'image.png',
path: '/path/to/file',
cid: 'unique@kreata.ee' //same cid value as in the html img src
}]
}
```
## License
**MIT**

421
node_modules/mailcomposer/lib/mailcomposer.js generated vendored Normal file
View File

@@ -0,0 +1,421 @@
'use strict';
var BuildMail = require('buildmail');
var libmime = require('libmime');
module.exports = function(mail) {
return new MailComposer(mail).compile();
};
module.exports.MailComposer = MailComposer;
/**
* Creates the object for composing a BuildMail instance out from the mail options
*
* @constructor
* @param {Object} mail Mail options
*/
function MailComposer(mail) {
if (!(this instanceof MailComposer)) {
return new MailComposer(mail);
}
this.mail = mail || {};
this.message = false;
}
/**
* Builds BuildMail instance
*/
MailComposer.prototype.compile = function() {
this._alternatives = this._getAlternatives();
this._htmlNode = this._alternatives.filter(function(alternative) {
return /^text\/html\b/i.test(alternative.contentType);
}).pop();
this._attachments = this._getAttachments(!!this._htmlNode);
this._useRelated = !!(this._htmlNode && this._attachments.related.length);
this._useAlternative = this._alternatives.length > 1;
this._useMixed = this._attachments.attached.length > 1 || (this._alternatives.length && this._attachments.attached.length === 1);
// Compose MIME tree
if (this._useMixed) {
this.message = this._createMixed();
} else if (this._useAlternative) {
this.message = this._createAlternative();
} else if (this._useRelated) {
this.message = this._createRelated();
} else {
this.message = this._createContentNode(false, [].concat(this._alternatives || []).concat(this._attachments.attached || []).shift() || {
contentType: 'text/plain',
content: ''
});
}
// Add headers to the root node
[
'from',
'sender',
'to',
'cc',
'bcc',
'reply-to',
'in-reply-to',
'references',
'subject',
'message-id',
'date'
].forEach(function(header) {
var key = header.replace(/-(\w)/g, function(o, c) {
return c.toUpperCase();
});
if (this.mail[key]) {
this.message.setHeader(header, this.mail[key]);
}
}.bind(this));
// Add custom headers
if (this.mail.headers) {
this.message.addHeader(this.mail.headers);
}
// Sets custom envelope
if (this.mail.envelope) {
this.message.setEnvelope(this.mail.envelope);
}
return this.message;
};
/**
* Builds multipart/mixed node. It should always contain different type of elements on the same level
* eg. text + attachments
*
* @param {Object} parentNode Parent for this note. If it does not exist, a root node is created
* @returns {Object} BuildMail node element
*/
MailComposer.prototype._createMixed = function(parentNode) {
var node;
if (!parentNode) {
node = new BuildMail('multipart/mixed', {
baseBoundary: this.mail.baseBoundary
});
} else {
node = parentNode.createChild('multipart/mixed');
}
if (this._useAlternative) {
this._createAlternative(node);
} else if (this._useRelated) {
this._createRelated(node);
}
[].concat(!this._useAlternative && this._alternatives || []).concat(this._attachments.attached || []).forEach(function(element) {
// if the element is a html node from related subpart then ignore it
if (!this._useRelated || element !== this._htmlNode) {
this._createContentNode(node, element);
}
}.bind(this));
return node;
};
/**
* Builds multipart/alternative node. It should always contain same type of elements on the same level
* eg. text + html view of the same data
*
* @param {Object} parentNode Parent for this note. If it does not exist, a root node is created
* @returns {Object} BuildMail node element
*/
MailComposer.prototype._createAlternative = function(parentNode) {
var node;
if (!parentNode) {
node = new BuildMail('multipart/alternative', {
baseBoundary: this.mail.baseBoundary
});
} else {
node = parentNode.createChild('multipart/alternative');
}
this._alternatives.forEach(function(alternative) {
if (this._useRelated && this._htmlNode === alternative) {
this._createRelated(node);
} else {
this._createContentNode(node, alternative);
}
}.bind(this));
return node;
};
/**
* Builds multipart/related node. It should always contain html node with related attachments
*
* @param {Object} parentNode Parent for this note. If it does not exist, a root node is created
* @returns {Object} BuildMail node element
*/
MailComposer.prototype._createRelated = function(parentNode) {
var node;
if (!parentNode) {
node = new BuildMail('multipart/related; type="text/html"', {
baseBoundary: this.mail.baseBoundary
});
} else {
node = parentNode.createChild('multipart/related; type="text/html"');
}
this._createContentNode(node, this._htmlNode);
this._attachments.related.forEach(function(alternative) {
this._createContentNode(node, alternative);
}.bind(this));
return node;
};
/**
* Creates a regular node with contents
*
* @param {Object} parentNode Parent for this note. If it does not exist, a root node is created
* @param {Object} element Node data
* @returns {Object} BuildMail node element
*/
MailComposer.prototype._createContentNode = function(parentNode, element) {
element = element || {};
element.content = element.content || '';
var node;
var encoding = (element.encoding || 'utf8')
.toString()
.toLowerCase()
.replace(/[-_\s]/g, '');
if (!parentNode) {
node = new BuildMail(element.contentType, {
filename: element.filename,
baseBoundary: this.mail.baseBoundary
});
} else {
node = parentNode.createChild(element.contentType, {
filename: element.filename
});
}
if (element.cid) {
node.setHeader('Content-Id', '<' + element.cid.replace(/[<>]/g, '') + '>');
}
if (element.contentTransferEncoding) {
node.setHeader('Content-Transfer-Encoding', element.contentTransferEncoding);
} else if (this.mail.encoding && /^text\//i.test(element.contentType)) {
node.setHeader('Content-Transfer-Encoding', this.mail.encoding);
}
if (!/^text\//i.test(element.contentType) || element.contentDisposition) {
node.setHeader('Content-Disposition', element.contentDisposition || 'attachment');
}
if (typeof element.content === 'string' && ['utf8', 'usascii', 'ascii'].indexOf(encoding) < 0) {
element.content = new Buffer(element.content, encoding);
}
node.setContent(element.content);
return node;
};
/**
* List all attachments. Resulting attachment objects can be used as input for BuildMail nodes
*
* @param {Boolean} findRelated If true separate related attachments from attached ones
* @returns {Object} An object of arrays (`related` and `attached`)
*/
MailComposer.prototype._getAttachments = function(findRelated) {
var attachments = [].concat(this.mail.attachments || []).map(function(attachment, i) {
var data;
if (/^data:/i.test(attachment.path || attachment.href)) {
attachment = this._processDataUrl(attachment);
}
data = {
contentType: attachment.contentType ||
libmime.detectMimeType(attachment.filename || attachment.path || attachment.href || 'bin'),
contentDisposition: attachment.contentDisposition || 'attachment',
contentTransferEncoding: attachment.contentTransferEncoding
};
if (attachment.filename) {
data.filename = attachment.filename;
} else {
data.filename = (attachment.path || attachment.href || '').split('/').pop() || 'attachment-' + (i + 1);
if (data.filename.indexOf('.') < 0) {
data.filename += '.' + libmime.detectExtension(data.contentType);
}
}
if (/^https?:\/\//i.test(attachment.path)) {
attachment.href = attachment.path;
attachment.path = undefined;
}
if (attachment.cid) {
data.cid = attachment.cid;
}
if (attachment.path) {
data.content = {
path: attachment.path
};
} else if (attachment.href) {
data.content = {
href: attachment.href
};
} else {
data.content = attachment.content || '';
}
if (attachment.encoding) {
data.encoding = attachment.encoding;
}
return data;
}.bind(this));
if (!findRelated) {
return {
attached: attachments,
related: []
};
} else {
return {
attached: attachments.filter(function(attachment) {
return !attachment.cid;
}),
related: attachments.filter(function(attachment) {
return !!attachment.cid;
})
};
}
};
/**
* List alternatives. Resulting objects can be used as input for BuildMail nodes
*
* @returns {Array} An array of alternative elements. Includes the `text` and `html` values as well
*/
MailComposer.prototype._getAlternatives = function() {
var alternatives = [],
text, html, watchHtml;
if (this.mail.text) {
if (typeof this.mail.text === 'object' && this.mail.text.content || this.mail.text.path || this.mail.text.href) {
text = this.mail.text;
} else {
text = {
content: this.mail.text
};
}
text.contentType = 'text/plain' + (!text.encoding && libmime.isPlainText(text.content) ? '' : '; charset=utf-8');
}
if (this.mail.watchHtml) {
if (typeof this.mail.watchHtml === 'object' && this.mail.watchHtml.content || this.mail.watchHtml.path || this.mail.watchHtml.href) {
watchHtml = this.mail.watchHtml;
} else {
watchHtml = {
content: this.mail.watchHtml
};
}
watchHtml.contentType = 'text/watch-html' + (!watchHtml.encoding && libmime.isPlainText(watchHtml.content) ? '' : '; charset=utf-8');
}
if (this.mail.html) {
if (typeof this.mail.html === 'object' && this.mail.html.content || this.mail.html.path || this.mail.html.href) {
html = this.mail.html;
} else {
html = {
content: this.mail.html
};
}
html.contentType = 'text/html' + (!html.encoding && libmime.isPlainText(html.content) ? '' : '; charset=utf-8');
}
[].concat(text || []).concat(watchHtml || []).concat(html || []).concat(this.mail.alternatives || []).forEach(function(alternative) {
var data;
if (/^data:/i.test(alternative.path || alternative.href)) {
alternative = this._processDataUrl(alternative);
}
data = {
contentType: alternative.contentType ||
libmime.detectMimeType(alternative.filename || alternative.path || alternative.href || 'txt'),
contentTransferEncoding: alternative.contentTransferEncoding
};
if (alternative.filename) {
data.filename = alternative.filename;
}
if (/^https?:\/\//i.test(alternative.path)) {
alternative.href = alternative.path;
alternative.path = undefined;
}
if (alternative.path) {
data.content = {
path: alternative.path
};
} else if (alternative.href) {
data.content = {
href: alternative.href
};
} else {
data.content = alternative.content || '';
}
if (alternative.encoding) {
data.encoding = alternative.encoding;
}
alternatives.push(data);
}.bind(this));
return alternatives;
};
/**
* Parses data uri and converts it to a Buffer
*
* @param {Object} element Content element
* @return {Object} Parsed element
*/
MailComposer.prototype._processDataUrl = function(element) {
var parts = (element.path || element.href).match(/^data:((?:[^;]*;)*(?:[^,]*)),(.*)$/i);
if (!parts) {
return element;
}
element.content = /\bbase64$/i.test(parts[1]) ? new Buffer(parts[2], 'base64') : new Buffer(decodeURIComponent(parts[2]));
if ('path' in element) {
element.path = false;
}
if ('href' in element) {
element.href = false;
}
parts[1].split(';').forEach(function(item) {
if (/^\w+\/[^\/]+$/i.test(item)) {
element.contentType = element.contentType || item.toLowerCase();
}
});
return element;
};

89
node_modules/mailcomposer/package.json generated vendored Normal file
View File

@@ -0,0 +1,89 @@
{
"_args": [
[
"mailcomposer@^2.1.0",
"/home/mitchell/Desktop/test-mywebsite/mywebsite/node_modules/nodemailer"
]
],
"_from": "mailcomposer@>=2.1.0 <3.0.0",
"_id": "mailcomposer@2.1.0",
"_inCache": true,
"_installable": true,
"_location": "/mailcomposer",
"_nodeVersion": "4.1.1",
"_npmUser": {
"email": "andris@kreata.ee",
"name": "andris"
},
"_npmVersion": "2.14.4",
"_phantomChildren": {},
"_requested": {
"name": "mailcomposer",
"raw": "mailcomposer@^2.1.0",
"rawSpec": "^2.1.0",
"scope": null,
"spec": ">=2.1.0 <3.0.0",
"type": "range"
},
"_requiredBy": [
"/nodemailer"
],
"_resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-2.1.0.tgz",
"_shasum": "a6531822899614fee899c92226d81e2b9cbb183d",
"_shrinkwrap": null,
"_spec": "mailcomposer@^2.1.0",
"_where": "/home/mitchell/Desktop/test-mywebsite/mywebsite/node_modules/nodemailer",
"author": {
"name": "Andris Reinman"
},
"bugs": {
"url": "https://github.com/andris9/mailcomposer/issues"
},
"dependencies": {
"buildmail": "^2.0.0",
"libmime": "^1.2.0"
},
"description": "Compose E-Mail messages",
"devDependencies": {
"chai": "^3.3.0",
"grunt": "^0.4.5",
"grunt-contrib-jshint": "^0.11.3",
"grunt-mocha-test": "^0.12.7",
"mocha": "^2.3.3",
"sinon": "^1.17.1"
},
"directories": {},
"dist": {
"shasum": "a6531822899614fee899c92226d81e2b9cbb183d",
"tarball": "http://registry.npmjs.org/mailcomposer/-/mailcomposer-2.1.0.tgz"
},
"engine": {
"node": ">=0.12"
},
"gitHead": "9860c0ea52a7f678805c4d0f9bde027feed1db68",
"homepage": "https://github.com/andris9/mailcomposer#readme",
"keywords": [
"e-mail",
"mime",
"parser"
],
"license": "MIT",
"main": "./lib/mailcomposer",
"maintainers": [
{
"name": "andris",
"email": "andris@node.ee"
}
],
"name": "mailcomposer",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/andris9/mailcomposer.git"
},
"scripts": {
"test": "grunt"
},
"version": "2.1.0"
}