Webpack how to cache bust angular-translate with $translatePartialLoader?
"webpack": "^2.7.0"
I'm trying to add a hash to our translation files in order to cache bust when deploying. I've managed to extract the json and add a hash and output it to a folder and is good with the world.
But, my unhashed json is still under there original folders after building. I understand that we don't need to add a loader for json as it already has means of handling importing, so my question would be how do I clean out the json that's already been processed?
my folder structure is as follows
src/
app/
module-name/
/translations
en.json
fn.json
module-name/
/translations
en.json
fn.json
//ect...
I used the CopyWebpackPlugin to get the json and hash is there maybe an option ive missed that cleans out the process'd files? or maybe i'm approaching this the incorrect way.
const webpack = require('webpack');
const conf = require('./gulp.conf');
const path = require('path');
const VersionFile = require('webpack-version-file');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const pkg = require('../package.json');
const autoprefixer = require('autoprefixer');
module.exports =
module:
loaders: [
test: /.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre'
,
scss)$/,
loaders: ExtractTextPlugin.extract(
fallback: 'style-loader',
use: 'css-loader?minimize!resolve-url-loader!sass-loader?sourceMap!postcss-loader'
)
,
test: /.(jpe?g,
test: /.js$/,
exclude: /node_modules/,
loaders: [
'ng-annotate-loader',
'babel-loader'
]
,
test: /.html$/,
loaders: [
'html-loader'
]
]
,
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new HtmlWebpackPlugin(
template: conf.path.src('index.html')
),
new webpack.optimize.UglifyJsPlugin(
output: comments: false,
compress: unused: true, dead_code: true, warnings: false // eslint-disable-line camelcase
),
new ExtractTextPlugin('index-[contenthash].css'),
new webpack.optimize.CommonsChunkPlugin(name: 'vendor'),
new webpack.LoaderOptionsPlugin(
options:
postcss: () => [autoprefixer]
),
new webpack.HashedModuleIdsPlugin(),
new CopyWebpackPlugin([
from: 'src/app/**/*.json',
to: 'translations/[name]-[hash].[ext]'
]),
new VersionFile(
output: `$conf.paths.dist/version.txt`,
verbose: true
)
],
output:
path: path.join(process.cwd(), conf.paths.dist),
filename: '[name]-[hash].js'
,
entry:
app: [`./$conf.path.src('app/app.module.js')`],
vendor: Object.keys(pkg.dependencies)
,
node:
fs: 'empty',
/* eslint-disable camelcase */
child_process: 'empty'
;
Or to similfy the question, how can i add a hash to json files? and the following code doesn't seem to do anything.
test: /.json$/,
loader: 'file-loader',
options:
name: '[name]-[hash].[ext]'
EDIT:
so it seems like my json loader doesnt pick up the translation files as they're dynamicly imported like so how:
$translateProvider.useLoader('$translatePartialLoader',
urlTemplate: 'app/part/translations/lang.json'
);
do you handle cases like this?
javascript json webpack
|
show 1 more comment
"webpack": "^2.7.0"
I'm trying to add a hash to our translation files in order to cache bust when deploying. I've managed to extract the json and add a hash and output it to a folder and is good with the world.
But, my unhashed json is still under there original folders after building. I understand that we don't need to add a loader for json as it already has means of handling importing, so my question would be how do I clean out the json that's already been processed?
my folder structure is as follows
src/
app/
module-name/
/translations
en.json
fn.json
module-name/
/translations
en.json
fn.json
//ect...
I used the CopyWebpackPlugin to get the json and hash is there maybe an option ive missed that cleans out the process'd files? or maybe i'm approaching this the incorrect way.
const webpack = require('webpack');
const conf = require('./gulp.conf');
const path = require('path');
const VersionFile = require('webpack-version-file');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const pkg = require('../package.json');
const autoprefixer = require('autoprefixer');
module.exports =
module:
loaders: [
test: /.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre'
,
scss)$/,
loaders: ExtractTextPlugin.extract(
fallback: 'style-loader',
use: 'css-loader?minimize!resolve-url-loader!sass-loader?sourceMap!postcss-loader'
)
,
test: /.(jpe?g,
test: /.js$/,
exclude: /node_modules/,
loaders: [
'ng-annotate-loader',
'babel-loader'
]
,
test: /.html$/,
loaders: [
'html-loader'
]
]
,
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new HtmlWebpackPlugin(
template: conf.path.src('index.html')
),
new webpack.optimize.UglifyJsPlugin(
output: comments: false,
compress: unused: true, dead_code: true, warnings: false // eslint-disable-line camelcase
),
new ExtractTextPlugin('index-[contenthash].css'),
new webpack.optimize.CommonsChunkPlugin(name: 'vendor'),
new webpack.LoaderOptionsPlugin(
options:
postcss: () => [autoprefixer]
),
new webpack.HashedModuleIdsPlugin(),
new CopyWebpackPlugin([
from: 'src/app/**/*.json',
to: 'translations/[name]-[hash].[ext]'
]),
new VersionFile(
output: `$conf.paths.dist/version.txt`,
verbose: true
)
],
output:
path: path.join(process.cwd(), conf.paths.dist),
filename: '[name]-[hash].js'
,
entry:
app: [`./$conf.path.src('app/app.module.js')`],
vendor: Object.keys(pkg.dependencies)
,
node:
fs: 'empty',
/* eslint-disable camelcase */
child_process: 'empty'
;
Or to similfy the question, how can i add a hash to json files? and the following code doesn't seem to do anything.
test: /.json$/,
loader: 'file-loader',
options:
name: '[name]-[hash].[ext]'
EDIT:
so it seems like my json loader doesnt pick up the translation files as they're dynamicly imported like so how:
$translateProvider.useLoader('$translatePartialLoader',
urlTemplate: 'app/part/translations/lang.json'
);
do you handle cases like this?
javascript json webpack
In CopyWebpackPlugin you can specify the pathto: path.join(process.cwd(), conf.path.dist, 'translations/[name]-[hash].[ext]')
it will provide an absolute path to the plugin instead of the current relative path per entry. This will create atranslations
folder at the root of your dist directory
– Asten Mies
Nov 13 '18 at 18:34
Yes I can create the translations folder with the hashes just fine will your method remove the old entries?
– Joe Warner
Nov 13 '18 at 19:08
@astenmies Thanks for having a look
– Joe Warner
Nov 13 '18 at 19:09
To remove the old entries you can just delete the dist folder and build again
– Asten Mies
Nov 13 '18 at 19:10
No so the JSON copied still remains in there original path shown In the screen shot ofc I could do something like exec('-rm /dist/app') or something to that flavour but I was hoping it could be done with the build step if not that's cool
– Joe Warner
Nov 13 '18 at 19:13
|
show 1 more comment
"webpack": "^2.7.0"
I'm trying to add a hash to our translation files in order to cache bust when deploying. I've managed to extract the json and add a hash and output it to a folder and is good with the world.
But, my unhashed json is still under there original folders after building. I understand that we don't need to add a loader for json as it already has means of handling importing, so my question would be how do I clean out the json that's already been processed?
my folder structure is as follows
src/
app/
module-name/
/translations
en.json
fn.json
module-name/
/translations
en.json
fn.json
//ect...
I used the CopyWebpackPlugin to get the json and hash is there maybe an option ive missed that cleans out the process'd files? or maybe i'm approaching this the incorrect way.
const webpack = require('webpack');
const conf = require('./gulp.conf');
const path = require('path');
const VersionFile = require('webpack-version-file');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const pkg = require('../package.json');
const autoprefixer = require('autoprefixer');
module.exports =
module:
loaders: [
test: /.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre'
,
scss)$/,
loaders: ExtractTextPlugin.extract(
fallback: 'style-loader',
use: 'css-loader?minimize!resolve-url-loader!sass-loader?sourceMap!postcss-loader'
)
,
test: /.(jpe?g,
test: /.js$/,
exclude: /node_modules/,
loaders: [
'ng-annotate-loader',
'babel-loader'
]
,
test: /.html$/,
loaders: [
'html-loader'
]
]
,
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new HtmlWebpackPlugin(
template: conf.path.src('index.html')
),
new webpack.optimize.UglifyJsPlugin(
output: comments: false,
compress: unused: true, dead_code: true, warnings: false // eslint-disable-line camelcase
),
new ExtractTextPlugin('index-[contenthash].css'),
new webpack.optimize.CommonsChunkPlugin(name: 'vendor'),
new webpack.LoaderOptionsPlugin(
options:
postcss: () => [autoprefixer]
),
new webpack.HashedModuleIdsPlugin(),
new CopyWebpackPlugin([
from: 'src/app/**/*.json',
to: 'translations/[name]-[hash].[ext]'
]),
new VersionFile(
output: `$conf.paths.dist/version.txt`,
verbose: true
)
],
output:
path: path.join(process.cwd(), conf.paths.dist),
filename: '[name]-[hash].js'
,
entry:
app: [`./$conf.path.src('app/app.module.js')`],
vendor: Object.keys(pkg.dependencies)
,
node:
fs: 'empty',
/* eslint-disable camelcase */
child_process: 'empty'
;
Or to similfy the question, how can i add a hash to json files? and the following code doesn't seem to do anything.
test: /.json$/,
loader: 'file-loader',
options:
name: '[name]-[hash].[ext]'
EDIT:
so it seems like my json loader doesnt pick up the translation files as they're dynamicly imported like so how:
$translateProvider.useLoader('$translatePartialLoader',
urlTemplate: 'app/part/translations/lang.json'
);
do you handle cases like this?
javascript json webpack
"webpack": "^2.7.0"
I'm trying to add a hash to our translation files in order to cache bust when deploying. I've managed to extract the json and add a hash and output it to a folder and is good with the world.
But, my unhashed json is still under there original folders after building. I understand that we don't need to add a loader for json as it already has means of handling importing, so my question would be how do I clean out the json that's already been processed?
my folder structure is as follows
src/
app/
module-name/
/translations
en.json
fn.json
module-name/
/translations
en.json
fn.json
//ect...
I used the CopyWebpackPlugin to get the json and hash is there maybe an option ive missed that cleans out the process'd files? or maybe i'm approaching this the incorrect way.
const webpack = require('webpack');
const conf = require('./gulp.conf');
const path = require('path');
const VersionFile = require('webpack-version-file');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const pkg = require('../package.json');
const autoprefixer = require('autoprefixer');
module.exports =
module:
loaders: [
test: /.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre'
,
scss)$/,
loaders: ExtractTextPlugin.extract(
fallback: 'style-loader',
use: 'css-loader?minimize!resolve-url-loader!sass-loader?sourceMap!postcss-loader'
)
,
test: /.(jpe?g,
test: /.js$/,
exclude: /node_modules/,
loaders: [
'ng-annotate-loader',
'babel-loader'
]
,
test: /.html$/,
loaders: [
'html-loader'
]
]
,
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new HtmlWebpackPlugin(
template: conf.path.src('index.html')
),
new webpack.optimize.UglifyJsPlugin(
output: comments: false,
compress: unused: true, dead_code: true, warnings: false // eslint-disable-line camelcase
),
new ExtractTextPlugin('index-[contenthash].css'),
new webpack.optimize.CommonsChunkPlugin(name: 'vendor'),
new webpack.LoaderOptionsPlugin(
options:
postcss: () => [autoprefixer]
),
new webpack.HashedModuleIdsPlugin(),
new CopyWebpackPlugin([
from: 'src/app/**/*.json',
to: 'translations/[name]-[hash].[ext]'
]),
new VersionFile(
output: `$conf.paths.dist/version.txt`,
verbose: true
)
],
output:
path: path.join(process.cwd(), conf.paths.dist),
filename: '[name]-[hash].js'
,
entry:
app: [`./$conf.path.src('app/app.module.js')`],
vendor: Object.keys(pkg.dependencies)
,
node:
fs: 'empty',
/* eslint-disable camelcase */
child_process: 'empty'
;
Or to similfy the question, how can i add a hash to json files? and the following code doesn't seem to do anything.
test: /.json$/,
loader: 'file-loader',
options:
name: '[name]-[hash].[ext]'
EDIT:
so it seems like my json loader doesnt pick up the translation files as they're dynamicly imported like so how:
$translateProvider.useLoader('$translatePartialLoader',
urlTemplate: 'app/part/translations/lang.json'
);
do you handle cases like this?
javascript json webpack
javascript json webpack
edited Nov 19 '18 at 15:08
Joe Warner
asked Nov 13 '18 at 16:27
Joe WarnerJoe Warner
1,9321522
1,9321522
In CopyWebpackPlugin you can specify the pathto: path.join(process.cwd(), conf.path.dist, 'translations/[name]-[hash].[ext]')
it will provide an absolute path to the plugin instead of the current relative path per entry. This will create atranslations
folder at the root of your dist directory
– Asten Mies
Nov 13 '18 at 18:34
Yes I can create the translations folder with the hashes just fine will your method remove the old entries?
– Joe Warner
Nov 13 '18 at 19:08
@astenmies Thanks for having a look
– Joe Warner
Nov 13 '18 at 19:09
To remove the old entries you can just delete the dist folder and build again
– Asten Mies
Nov 13 '18 at 19:10
No so the JSON copied still remains in there original path shown In the screen shot ofc I could do something like exec('-rm /dist/app') or something to that flavour but I was hoping it could be done with the build step if not that's cool
– Joe Warner
Nov 13 '18 at 19:13
|
show 1 more comment
In CopyWebpackPlugin you can specify the pathto: path.join(process.cwd(), conf.path.dist, 'translations/[name]-[hash].[ext]')
it will provide an absolute path to the plugin instead of the current relative path per entry. This will create atranslations
folder at the root of your dist directory
– Asten Mies
Nov 13 '18 at 18:34
Yes I can create the translations folder with the hashes just fine will your method remove the old entries?
– Joe Warner
Nov 13 '18 at 19:08
@astenmies Thanks for having a look
– Joe Warner
Nov 13 '18 at 19:09
To remove the old entries you can just delete the dist folder and build again
– Asten Mies
Nov 13 '18 at 19:10
No so the JSON copied still remains in there original path shown In the screen shot ofc I could do something like exec('-rm /dist/app') or something to that flavour but I was hoping it could be done with the build step if not that's cool
– Joe Warner
Nov 13 '18 at 19:13
In CopyWebpackPlugin you can specify the path
to: path.join(process.cwd(), conf.path.dist, 'translations/[name]-[hash].[ext]')
it will provide an absolute path to the plugin instead of the current relative path per entry. This will create a translations
folder at the root of your dist directory– Asten Mies
Nov 13 '18 at 18:34
In CopyWebpackPlugin you can specify the path
to: path.join(process.cwd(), conf.path.dist, 'translations/[name]-[hash].[ext]')
it will provide an absolute path to the plugin instead of the current relative path per entry. This will create a translations
folder at the root of your dist directory– Asten Mies
Nov 13 '18 at 18:34
Yes I can create the translations folder with the hashes just fine will your method remove the old entries?
– Joe Warner
Nov 13 '18 at 19:08
Yes I can create the translations folder with the hashes just fine will your method remove the old entries?
– Joe Warner
Nov 13 '18 at 19:08
@astenmies Thanks for having a look
– Joe Warner
Nov 13 '18 at 19:09
@astenmies Thanks for having a look
– Joe Warner
Nov 13 '18 at 19:09
To remove the old entries you can just delete the dist folder and build again
– Asten Mies
Nov 13 '18 at 19:10
To remove the old entries you can just delete the dist folder and build again
– Asten Mies
Nov 13 '18 at 19:10
No so the JSON copied still remains in there original path shown In the screen shot ofc I could do something like exec('-rm /dist/app') or something to that flavour but I was hoping it could be done with the build step if not that's cool
– Joe Warner
Nov 13 '18 at 19:13
No so the JSON copied still remains in there original path shown In the screen shot ofc I could do something like exec('-rm /dist/app') or something to that flavour but I was hoping it could be done with the build step if not that's cool
– Joe Warner
Nov 13 '18 at 19:13
|
show 1 more comment
1 Answer
1
active
oldest
votes
The main goal you're trying to do here is telling the browser its a new file when releasing a new version and we can do this fairly easily without having to force webpack to know what files are being used.
in your webpack config add this
const pkg = require('../package.json');
//...
new webpack.DefinePlugin(
__VERSION__: JSON.stringify(pkg.version)
)
and where you add your translation files this allows for the browser to know where has been a new release and should update translation files.
$translateProvider.useLoader('$translatePartialLoader',
urlTemplate: `app/part/translations/lang.json?v=$__VERSION__`
);
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53285407%2fwebpack-how-to-cache-bust-angular-translate-with-translatepartialloader%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The main goal you're trying to do here is telling the browser its a new file when releasing a new version and we can do this fairly easily without having to force webpack to know what files are being used.
in your webpack config add this
const pkg = require('../package.json');
//...
new webpack.DefinePlugin(
__VERSION__: JSON.stringify(pkg.version)
)
and where you add your translation files this allows for the browser to know where has been a new release and should update translation files.
$translateProvider.useLoader('$translatePartialLoader',
urlTemplate: `app/part/translations/lang.json?v=$__VERSION__`
);
add a comment |
The main goal you're trying to do here is telling the browser its a new file when releasing a new version and we can do this fairly easily without having to force webpack to know what files are being used.
in your webpack config add this
const pkg = require('../package.json');
//...
new webpack.DefinePlugin(
__VERSION__: JSON.stringify(pkg.version)
)
and where you add your translation files this allows for the browser to know where has been a new release and should update translation files.
$translateProvider.useLoader('$translatePartialLoader',
urlTemplate: `app/part/translations/lang.json?v=$__VERSION__`
);
add a comment |
The main goal you're trying to do here is telling the browser its a new file when releasing a new version and we can do this fairly easily without having to force webpack to know what files are being used.
in your webpack config add this
const pkg = require('../package.json');
//...
new webpack.DefinePlugin(
__VERSION__: JSON.stringify(pkg.version)
)
and where you add your translation files this allows for the browser to know where has been a new release and should update translation files.
$translateProvider.useLoader('$translatePartialLoader',
urlTemplate: `app/part/translations/lang.json?v=$__VERSION__`
);
The main goal you're trying to do here is telling the browser its a new file when releasing a new version and we can do this fairly easily without having to force webpack to know what files are being used.
in your webpack config add this
const pkg = require('../package.json');
//...
new webpack.DefinePlugin(
__VERSION__: JSON.stringify(pkg.version)
)
and where you add your translation files this allows for the browser to know where has been a new release and should update translation files.
$translateProvider.useLoader('$translatePartialLoader',
urlTemplate: `app/part/translations/lang.json?v=$__VERSION__`
);
answered Nov 19 '18 at 17:57
Joe WarnerJoe Warner
1,9321522
1,9321522
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53285407%2fwebpack-how-to-cache-bust-angular-translate-with-translatepartialloader%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
In CopyWebpackPlugin you can specify the path
to: path.join(process.cwd(), conf.path.dist, 'translations/[name]-[hash].[ext]')
it will provide an absolute path to the plugin instead of the current relative path per entry. This will create atranslations
folder at the root of your dist directory– Asten Mies
Nov 13 '18 at 18:34
Yes I can create the translations folder with the hashes just fine will your method remove the old entries?
– Joe Warner
Nov 13 '18 at 19:08
@astenmies Thanks for having a look
– Joe Warner
Nov 13 '18 at 19:09
To remove the old entries you can just delete the dist folder and build again
– Asten Mies
Nov 13 '18 at 19:10
No so the JSON copied still remains in there original path shown In the screen shot ofc I could do something like exec('-rm /dist/app') or something to that flavour but I was hoping it could be done with the build step if not that's cool
– Joe Warner
Nov 13 '18 at 19:13