VimUnDo3AEڂn[]43߉Z_ YX _0ggVX]/05_WffVXЭW[WY5_Y!iiVXXZ7 * Read the contents at path and respond appropriately.5_Y6iiVXXZ7 * Read the contents at path and write to the response.5_Y iiVXY[ * approprX[> * Read the contents at path and write to the response object.5_ZjjVXYZ * appropriate headers.5_Y*iiVXY[ * apprX[H * Read the file at the provided path and respond with it along with the5_Y?jjVXXZK * Read the file at the provided path and write to the response, along with5_YFjjVXX[J * Read the file at the provided path and write to the response along with5_ZkkVXY[ * with * appropriate headers.5_ZjjVXY[ * with * appropriate headers.5_ZjjVXY[ * with appropriate headers.5_ZjjVXY[ * with appropriate headers.5_ Z jjVXZ\5_  [kkVXZ[ *5_   `jjVX)cf * otherwibe * respons`d`b5_   dooVX~ce: * otherwise the a template listing the files is rendered.5_   dooVX~ce9 * otherwise the template listing the files is rendered.5_  d ooVXce8 * otherwise the template listing the files is rendered.5_ DooVXѢDGDF5_EqqVXѺDE/**5_EppVXѺDE * Return true if t5_22DVX12Basync function listContents (path: string): Promise { const directories = []; const files = [];! const fullPath = resolve(path);+ const contents = await readdir(fullPath);/ await map(contents, async (file: string) => {4 const stats = await lstat(join(fullPath, file)); if (stats.isFile()) {# files.push(join(path, file)); } else {) directories.push(join(path, file)); } }); return { directories, files };}5_M22VXMaMN5_M22VXOQ * filesMQMO5_OG22VXNQJ * Read the files in the directory and return a list of subdirectories and5_P22VXOQ * and * files.5_P22VXOQ * and * files.5_P22VXOQ * and files.5_P 22VXOR * and files.5_OOP VXNOF * Read the files in the directory and return a list of subdirectories * and files.5_NOO VXNP * NP5_OPP VXNP * Return 5_O4PP VXNP5 * Return a list of files and subdirectories at path.5_Y3PP VXIY[ Y[5_\PP VXT[]# files.push(join(path, file));5_ ^PP VXW]_) directories.push(join(path, file));5_! [PP VXbZ\ if (stats.isFile()) {5_ "!^PP VXf]^ directories.push(name);5_!#"[PP VXg[][\5_"$#]PP VXh\] files.push(name);5_#%$]PP VXh]_]^5_$&%J PP VXҺJL JL5_%'&KQQ VXJK console.log('handling', path);5_&('UPP VXUWUV5_')(VPP VXUV console.log('handling', path);5_(*)j!PP VXjljk5_)+*kPP VXjk console.log('handling', path);5_*,+{PP VX{}{|5_+-,|PP VX {| console.log('handling', path);5_,.-{PP VX {}{|5_-/.PP VX 5_.0/PP VX(, console.log('what is', path, stats, error)5_/10|PP VX){| console.log('handling', path);5_021 PP VXA 5_132; PP VXS;= ;=5_243<QQ VXW;< console.log('oki5_3846PP VXo69 685_49587RR VX}68 if (path) {5_8:97RR VX~7: 795_9;:8TT VXӁ8: 8:5_:<;9UU VXӊ8: {5_;=<9"UU VXә8:# 'Content-Type': defaultValue;5_<>=9"UU VXӚ8:# 'Content-Type': defaultValue,5_=?>8 UU VXӚ79 return {" 'Content-Type': defaultValue5_>@?8 TT VXӛ79) return { 'Content-Type': defaultValue }5_?A@8+SS VXӜ79+ return { 'Content-Type': defaultValue }5_@BA6+SS VXӝ68 685_ACB;8TT VXӫ:<T const contentType = getContentType(basename(path)) || 'text/plain; charset=utf-8';5_BDC<TT VX;=) return { 'Content-Type': contentType };5_CED;TT VX:<E const contentType = getContentType(basename(path)) || defaultValue;5_DFE<TT VX;= return { 'Content-Type': <=5_EGF<JTT VX;=J return { 'Content-Type': getContentType(basename(path)) || defaultValue;5_FHG;TT VX:; const contentType = 5_GIH:SS VX:<5_HJI;TT VX:;5_IKJ7SS VX7: 795_JLK9UU VX9;5_KML8VV VX8:5_LNM8WW VX8:895_MON9XX VX8:, return { 'Content-Type': defaultValue };5_NPO:XX VX9:5_OQP9#WW VX8:# 'Content-Type': defaultValue };5_PRQ9:WW VX8:I 'Content-Type': path ? getContentType(basename(path)) : defaultValue,5_QSR;;?IVIX:; if (!path) {, return { 'Content-Type': defaultValue }; }L return { 'Content-Type': getContentType(basename(path)) || defaultValue };5_RYS;;IVIX console.log('hello', path);5_SZUY9;;IVIXm8:Y 'Content-Type': path ? getContentType(basename(path)) || defaultValue : defaultValue,5_Y[Z9J;;IVIXo8:Z 'Content-Type': path ? (getContentType(basename(path)) || defaultValue : defaultValue,5_Z\[72;;IVIXy79 795_[]\8<<IVIX}8:895_\^]9==IVIX~8:[ 'Content-Type': path ? (getContentType(basename(path)) || defaultValue) : defaultValue,5_]_^9==IVIXԀ8:P pe': path ? (getContentType(basename(path)) || defaultValue) : defaultValue,5_^`_8==IVIXԀ79 const contentType = K path ? (getContentType(basename(path)) || defaultValue) : defaultValue,5__a`8]<<IVIXԂ79] const contentType = path ? (getContentType(basename(path)) || defaultValue) : defaultValue,5_`ba9 <<IVIXԋ8: return {[ 'Content-Type': path ? (getContentType(basename(path)) || defaultValue) : defaultValue,5_acb9;;IVIXԍ8:b return { 'Content-Type': path ? (getContentType(basename(path)) || defaultValue) : defaultValue,5_bdc:;;IVIXԒ9: };5_ced225VX12;function hasIndexTemplate (files: Array): boolean {L return files.some((file: string): boolean => !!file.match(/index.html$/));}5_dfe`22VX`e`a5_egf`22VX`b5_fhge22VXde5_giha22VXadac5_hjic22VXbc * Return true if the array 5_ikjb22VXab/**5_jlk22VX/ lstat as _lstat5_kml22VX= lstat as _lstat,5_lom11VX>5_mqnoVXZ lstat as _lstat, readdir as _readdir, readFile as _readFile, realpath as _realpath,5_orpq 5v5XՁ5_qsr 5v5XՅ5_rtsbbeVXՔab;function hasIndexTemplate (files: Array): boolean {L return files.some((file: string): boolean => !!file.match(/index.html$/));}5_sut0bbVX՘05015_tvu4ffVX՚345_uwv0eeVX՜025_vyw.24VXv-/ error: ReadError;5_wzxySX#RT const directories = [];5_y{zT X+SU const files = [];5_z|{X5_{}|X 5_|~}XcreateButlerServer5_}~Xfunction createButlerServer5_~X5_X 5_X% 5_X* 5_%X5'function createButlerServer (options) {5_&X8,function createButlerServer (options):void {5_$X9-function createButlerServer (options): void {5_X?5_XA interface5_/XC/3/15_1 XJ02interface ServerOptions {5_1XL135_2XN135_X`5_Xc5_3Xq4// Configure globals required throughout the module;5_ Xy let OPTIONS;5_4 X݆35 directory: string;5_ X݋let OPTIONS = {};5_Xݏ let OPTIONS: ButlerOptions = {};5_Xݠ let OPTIONS: ButlerOptions = {};5_Xݰ5function createButlerServer (options: Object): void {5_#Xݵ2function createButlerServer (opts: Object): void {5_Xݹ if (options) {5_Xݻ OPTIONS = options;5_Xݼ options = options;5_X9function createButlerServer (opts: ButlerOptions): void {5_X if (opts) {5_X options = opts;5_X options = options;5_X createServer(requestHandler);5_X5_X let options: ButlerOptions = {};5_Xlet opts: ButlerOptions = {};5_(XEimport { createServer, IncomingMessage, ServerResponse } from 'http';5_6Xfunction createButlerServer (options: ButlerOptions): Server {5_X8"export default createButlerServer;5_EXe Mexport default function createButlerServer (options: ButlerOptions): Server {5_CXpJexport default function createButlerServer (options: ButlerOptions): any {5_CXpIexport default function createButlerServer (options: ButlerOptions) any {5_CXpHexport default function createButlerServer (options: ButlerOptions)any {5_CXqGexport default function createButlerServer (options: ButlerOptions)ny {5_CXq Fexport default function createButlerServer (options: ButlerOptions)y {5_&X߁ 5_&Xߊ Mimport { createServer, IncomingMessage, Server, ServerResponse } from 'http';5_CXߑ Eexport default function createButlerServer (options: ButlerOptions) {5_Ximport { Server } from 'net';5_(X'Eimport { createServer, IncomingMessage, ServerResponse } from 'http';5_EX8Mexport default function createButlerServer (options: ButlerOptions): Server {5_3XbQexport default function createButlerServer (options: ButlerOptions): HttpServer {5_Xs5_Xy5_VXinterface HttpServer { listen: Function;}5_&VXFMimport { createServer, IncomingMessage, Server, ServerResponse } from 'http';5_6VXXBexport default function createButlerServer (options): HttpServer {5_VXr& return createServer(requestHandler);5_VXr% eturn createServer(requestHandler);5_VXr$ turn createServer(requestHandler);5_VXr# urn createServer(requestHandler);5_VXr" rn createServer(requestHandler);5_VXs! n createServer(requestHandler);5_VXs createServer(requestHandler);5_6VX~>export default function createButlerServer (options): Server {5_VX createServer(requestHandler);5_3VX const root = opts.directory ? resolve(opts.directory) : '.';5_$&%e'eHVLX:? const root = opts.directory ? resolve(opts.directory) : './';5_%'& e'eHVLX< directory?: string;5_&('d6e'eHVLX2=df df5_')(cf'fHVLXce5_(*)dg'gHVLX>cd5_)+*cf'fHVLXce ce5_*,+dg'gHVLXcd trim = 5_+-,cf'fHVLXce5_,.-cg'gHVLXce ce5_-/.d5h'hHVLXce: const trimLength = resolve(opts.directory).length + 1;5_.0/d5h'hHVLXce9 const trimLength = resolve(opts.directory).length+ 1;5_/10d5h'hHVLXce8 const trimLength = resolve(opts.directory).length 1;5_021d5h'hHVLXce7 const trimLength = resolve(opts.directory).length1;5_132dh'hHVLXce6 const trimLength = resolve(opts.directory).length;5_243ch'hHVLXce5_354ei'iHVLXeh eg5_465fk'kHVLXeg if (trimLength === 1) {5_576fk'kHVLX?fh fh5_687j)l'lHVLX AikM const name = join(path, file).substr(resolve(opts.directory).length + 1);5_7:8hl'lHVLXCgj }5_8;9:hm'mHVLX Dgh } else {5_:<; l'lHVLXoE 9import { basename, join, relative, resolve } from 'path';5_;=<_l'lHVLXF^_1 console.log('hello', path, fullPath, contents);5_<>=bk'kHVLXab2 console.log('hi', path, file, opts.directory);5_=?>ij'jHVLXGhi console.log('name', name);5_>@?zi'iHVLXHyz* console.log('dirs', directories, files);5_?A@i'iHVLXJ5_@BAi'iHVLX5_ACBi'iHVLXK5_BDCi'iHVLX&( let path = join(root, decodeURI(url));5_CEDi'iHVLX0M' const root = resolve(opts.directory);5_DFEfi'iHVLX=fh fh5_EGFgj'jHVLXAgi gi5_FHGhk'kHVLXMgh let trim5_GIHccfVXNbc4 let trimLength = resolve(opts.directory).length; if (trimLength !== 1) { trimLength += 1; }5_HJIcccVXOchcd5_IKJgccVXPgi gi5_JLKjccVX`ij5 const name = join(path, file).substr(trimLength);5_KMLbccVXbbd bd5_LNMcddVXhbc // 5_MONTccVXTWTV5_NPOV eeVXUWfunction trimmedName (5_OQPVeeVX)UXfunction getTrimmedFilename (5_PRQVffVXQNVX VX5_QSRfggVX\fh fh5_RTSW&hhVXeVX6 console.log('gettrimm', path, file, opts.directory);5_SUTW&hhVXeVX5 console.log('gettrimm', path, file, pts.directory);5_TVUW&hhVXeVX4 console.log('gettrimm', path, file, ts.directory);5_UWVW&hhVXfVX3 console.log('gettrimm', path, file, s.directory);5_VXWW&hhVXgVX2 console.log('gettrimm', path, file, .directory);5_WYXV)hhVXiOUW:function getTrimmedFilename (path, file, opts.directory) {5_XZYV!hhVXUW0function getTrimmedFilename (path, file, root) {5_Y[ZV/hhVXUW8function getTrimmedFilename (path: string, file, root) {5_Z\[V=hhVXPUW@function getTrimmedFilename (path: string, file: string, root) {5_[]\W*hhVXQVX, console.log('gettrimm', path, file, root);5_\a]m"hhVX Tmo mo5_]b^aUgnXWY * nameUYUW5_acbXDjqXXZ * XZ5_bdcYkrXXYA * - If the root directory was set to the current directory (./),5_cedXEjqXWYE * names and not an absolute path or only the filename. For instance:5_dfeX>jqXWYE * names and not an absolute path or only the filename. TODO Eexpand.5_egfXCjqXWYD * names and not an absolute path or only the filename. TODO Expand.5_fhgYjqXXYHfunction getTrimmedFilename (path: string, file: string, root: string) {5_gihXipXXZ * XZ5_hjiZjqXYZ; console.log('gettrimm', path, file, root, resolve(root));5_ikjhipXhj hj5_jlkijqXhj const name = get5_kmlijqXhj const name = 3 getTrimmedFilename(path, file, opts.directory);5_lnmYipXY\Y[5_mon[krXZ[}5_npoZ!jqXY[8function getTrimmedFilename (path, file, rootDirectory {5_oqpZ/jqXY[@function getTrimmedFilename (path: string, file, rootDirectory {5_prqZFjqXY[Hfunction getTrimmedFilename (path: string, file: string, rootDirectory {5_qsrZNjqX Y[Pfunction getTrimmedFilename (path: string, file: string, rootDirectory: string {5_rtsZOjqX Y[Qfunction getTrimmedFilename (path: string, file: string, rootDirectory: string) {5_sutZVjqX Y[Xfunction getTrimmedFilename (path: string, file: string, rootDirectory: string): strin {5_tvuZVjqXZ\ Z\5_uwv[krX$Z[ c5_vxwZjqX$Z\5_wyxllrVX+kl let name = join(path, file);4 let trimLength = resolve(opts.directory).length; if (trimLength !== 1) { trimLength += 1; }# name = name.substr(trimLength); console.log('n name', name);5_xzyZllVX-ZbZ[5_y{zZssVX/Z\ Z\5_z|{\ttVX9[\ let name = join(path, file);5_{}|[ssVX9[]5_|~}]]bVX;\c4 let trimLength = resolve(opts.directory).length; if (trimLength !== 1) { trimLength += 1; }# name = name.substr(trimLength); console.log('n name', name);5_}~b]bVX<ab console.log('n name', name);5_~b]bVX=bd bd5_c]bVX@bc return name;5_b]bVXAab5_a]bVXB`b! name = name.substr(trimLength);5_a]bVXC`b# return = name.substr(trimLength);5_a]bVXD`b" return= name.substr(trimLength);5_`]bVXD`b5_\]cVXG[\5_`\bVXHU_`5__\aVX_a _a5_`\bVX_a' console.log('debug:', opts.directory)5_`/\bVXV_a/ console.log('debug:', resolve(opts.directory)5_\1\bVX\_ \^5_^\dVX]^ //5_]\cVX\^ //5_]'\cVX\^( // Handle system root directory ("/").5_a\cVX`aQ console.log('debug:', resolve(opts.directory), resolve(opts.directory).length);5_`\bVX`b5_\\cVXW\^5_[\dVXXZ\ let name = join(path, file);5_r\dVX7qr5_s\dVX9Yrs5_b\dVXDZab5_a\cVXE[ac5_W.WXVXyVXK * Trim the filename so that it only includes any relative parent directory5_W;WXVX~WY * pathVY; * Trim the filename so that it only includes a relative pa5_W.WYVXWY * directoVYK * Trim the filename so that it only includes a relative parent directory's5_XIWZVXXZ5_ZZ[VXYZ * pathname. For instanceL * names and not an absolute path or only the filename. TODO Expand on this.5_XZZVXY[ * direcX[ * XZ5_Y\\VXXZJ * given a root directory of /Users/butler and the contents being a single5_Y+\\VXXZK * given a root directory of "/Users/butler and the contents being a single5_Z \\VXY[ * directory5_Z\\VXY[ * directory "example"5_Y+\\VXXZL * given a root directory of "/Users/butler" and the contents being a single5_Z\\VXY[ * directory "example/"5_Z%\\VX Y[% * directory "/Users/butler/example/"5_Z:\\VX"Y[F * directory "/Users/butler/example/" with a file called "example.txt"5_Z:\\VX#Y[? * directory "/Users/butler/example/" with a file called ".txt"5_Z\\VX9Y[F * directory "/Users/butler/example/" with a file called "example.txt"5_Z\\VX:Y[E * directory "Users/butler/example/" with a file called "example.txt"5_Z\\VX:Y[D * directory "sers/butler/example/" with a file called "example.txt"5_Z\\VX:Y[C * directory "ers/butler/example/" with a file called "example.txt"5_Z\\VX:Y[B * directory "rs/butler/example/" with a file called "example.txt"5_Z\\VX:Y[A * directory "s/butler/example/" with a file called "example.txt"5_Z\\VX:Y[@ * directory "/butler/example/" with a file called "example.txt"5_Z\\VX:Y[? * directory "butler/example/" with a file called "example.txt"5_Z\\VX:Y[> * directory "utler/example/" with a file called "example.txt"5_Z\\VX:Y[= * directory "tler/example/" with a file called "example.txt"5_Z\\VX:Y[< * directory "ler/example/" with a file called "example.txt"5_Z\\VX:Y[; * directory "er/example/" with a file called "example.txt"5_Z\\VX:Y[: * directory "r/example/" with a file called "example.txt"5_Z\\VX;Y[9 * directory "/example/" with a file called "example.txt"5_Z8\\VX<Y\8 * directory "example/" with a file called "example.txt"5_\]]VXc[\ *5_[N\\VXpZ\O * return "example/example.txt" instead of "/Users/butler/example/example.txt".5_X=\\VXWZJ * directory as part of the pathname, not the absolute path. For instance,5_Z]]VXXZ * Example:Jgiven a root directory of "/Users/butler/" and the contents being a singleY[M * given a root directory of "/Users/butler/" and the contents being a single5_Y \\VXXZV * Example: given a root directory of "/Users/butler/" and the contents being a single5_YN\\VXX[V * Example: Given a root directory of "/Users/butler/" and the contents being a single5_Z]]VXY[ * a singleM * directory "example/" with a file called "example.txt", the function should5_Z \\VXY[X * a single * directory "example/" with a file called "example.txt", the function should5_Z \\VXY[W * a single directory "example/" with a file called "example.txt", the function should5_Z-\\VXY[V * a single directory "example/" with a file called "example.txt", the function should5_Y\\VXXZM * Example: Given a root directory of "/Users/butler/" and the contents beingO * a single directory "example/" with a file "example.txt", the function should5_YN[[VXXZ * Example: Given a root directory of "/Users/butler/" and the contents being * a single directory "example/" with a file "example.txt", the function should5_YN[[VXXZ * Example: Given a root directory of "/Users/butler/" and the contents being a single directory "example/" with a file "example.txt", the function should5_YP[[VX`X[ * Example: Given a root directory of "/Users/butler/" and the contents being a single directory "example/" with a file "example.txt", the function should5_XR 5_XYa5_Xg5_ Xl import chalk5_Xoimport chalk from 'chalk';5_ Xpb  5_Xy console.log('serving', path);5_*X~c* console.log(chalk.cyan('serving', path);5_ Xd import chalk from 'chalk';5_X 5_X%3 console.log('ip', req.conconnection.remoteAddress5_X', console.log('ip', connection.remoteAddress5_0X(e0 console.log('ip', req.connection.remoteAddress5_X 5_X ip = ip.substr(7)}#if (ip.substr(0, 7) == "::ffff:") {5_XJ var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;5_Xf2 console.log('ip', req.connection.remoteAddress);5_X ip = ip.substr(7)5_X% if (ip.substr(0, 7) == "::ffff:") {5_!X% if (ip.substr(0, 7) == '::ffff:") {5_ X% if (ip.substr(0, 7) == '::ffff:') {5_ X$ if (ip.ubstr(0, 7) == '::ffff:') {5_ X# if (ip.bstr(0, 7) == '::ffff:') {5_ X" if (ip.str(0, 7) == '::ffff:') {5_ X! if (ip.tr(0, 7) == '::ffff:') {5_ X if (ip.r(0, 7) == '::ffff:') {5_ X if (ip.(0, 7) == '::ffff:') {5_ X if (ip.0, 7) == '::ffff:') {5_ X if (ip., 7) == '::ffff:') {5_ X if (ip. 7) == '::ffff:') {5_ X if (ip.7) == '::ffff:') {5_ X if (ip.) == '::ffff:') {5_ X if (ip. == '::ffff:') {5_ X if (ip.== '::ffff:') {5_ X if (ip.= '::ffff:') {5_ X if (ip. '::ffff:') {5_ X if (ip.'::ffff:') {5_X  if (ip.startsWith('::ffff:') {5_X 5_X 5_ X 5_ X 5_Xc var datestring = ("0" + d.getDate()).slice(-2) + "-" + ("0"+(d.getMonth()+1)).slice(-2) + "-" +5_X return R ("0" + d.getDate()).slice(-2) + "-" + ("0"+(d.getMonth()+1)).slice(-2) + "-" +5_X$ var d = new Date();5_ X& const d = new Date();5_ X) 5_ X4 const date.getDate5_X5 const day = date.getDate5_/X<5_X= 5_XL& const month = date.getMonth() + 1)5_'XO' const month = (date.getMonth() + 1)5_XW0 const month = (date.getMonth() + 1).padStart5_X[0 const month = `date.getMonth() + 1).padStart5_(X^2 const month = `${date.getMonth() + 1).padStart5_)X_3 const month = `${date.getMonth() + 1}).padStart5_)X_2 const month = `${date.getMonth() + 1}.padStart5_3Xa3 const month = `${date.getMonth() + 1}`.padStart5_;Xe 5_#Xu 5_1X5_ X2 const hour = date.getHours().padStart(2, ' ');5_X5 const minutes = date.getHours().padStart(2, ' ');5_ X2 const hour = date.getHours().padStart(2, ' ');5_6X 5_ X return `5_X return `${day}-${month}-5_6X5_  X7 const minutes = date.getMinutes().padStart(2, ' ');5_  X7 const seconds = date.getMinutes().padStart(2, ' ');5_   7X7 return `${day}-${month}-${year} ${hours}:${minutes}5_   X const getDate () => {5_   VXY return ("0" + d.getDate()).slice(-2) + "-" + ("0"+(d.getMonth()+1)).slice(-2) + "-" +d d.getFullYear() + " " + ("0" + d.getHours()).slice(-2) + ":" + ("0" + d.getMinutes()).slice(-2);5_  VX5_ VX5_VX console.log('ip', ip);5_VXg console.log('time', ip);5_VXh const getDate (): string => {5_VXW0 const day = date.getDate().padStart(2, ' ');5_"VX\3 const hours = date.getHours().padStart(2, ' ');5_&VX^7 const minutes = date.getMinutes().padStart(2, ' ');5_&VX`i7 const seconds = date.getSeconds().padStart(2, ' ');5_ X   5_X 5_X console.5_VX ! const getDate = (): string => { const date = new Date();; const day = date.getDate().toString().padStart(2, ' ');< const month = `${date.getMonth() + 1}`.padStart(2, ' ');$ const year = date.getFullYear();> const hours = date.getHours().toString().padStart(2, ' ');B const minutes = date.getMinutes().toString().padStart(2, ' ');B const seconds = date.getSeconds().toString().padStart(2, ' ');D return `${day}-${month}-${year} ${hours}:${minutes}:${seconds}`; };5_VXj! console.log('time', getDate());5_ VXK import formt from 'date-fns';5_ VXMk import { formt from 'date-fns';5_ VXVl !import { formt } from 'date-fns';5_ ,VXb? console.log('time', format(new Date(), 'DD-MM-YY HH:MM:SS'));5_! /VXdm? console.log('time', format(new Date(), 'DD/MM-YY HH:MM:SS'));5_ "!VX 5_!#",VXG console.log('Served ', chalk.cyan(path), 'to', chalk.cyan(ip), 'at', 5_"$#/VXH console.log('Served ', chalk.cyan(path), ' to', chalk.cyan(ip), 'at', 5_#%$DVXI console.log('Served ', chalk.cyan(path), ' to ', chalk.cyan(ip), 'at', 5_$&%GVXJ console.log('Served ', chalk.cyan(path), ' to ', chalk.cyan(ip), ' at', 5_%(&KVXK console.log('Served ', chalk.cyan(path), ' to ', chalk.cyan(ip), ' at ', 5_&)'(VX? console.log('time', format(new Date(), 'DD/MM/YY HH:MM:SS'));5_(*)8VX8 const time = format(new Date(), 'DD/MM/YY HH:MM:SS'));5_)+*VX console.log('ip', ip);5_*,+VXn+ console.log(chalk.cyan('serving', path));5_+-, VX 5_,.-VX 5_-/.VX chalk.blue(time);5_.0/ VX 5_/10VX5_021VX7 const time = format(new Date(), 'DD/MM/YY HH:MM:SS');5_132VX5_243VX] console.log('Served ', chalk.cyan(path), ' to ', chalk.cyan(ip), ' at ', chalk.cyan(time));5_354VX5_465VX chalk.white(time);5_576VX! console.log(`chalk.white(time);5_687#VX# console.log(`${chalk.white(time);5_798"VX# console.log(`${chalk.white(time)} chalk.blue(path);5_8:9#VX5 console.log(`${chalk.white(time)} chalk.blue(path);5_9;:#VX4 console.log(`${chalk.white(time)}chalk.blue(path);5_:<;6VX6 console.log(`${chalk.white(time)}${chalk.blue(path);5_;=<5VX6 console.log(`${chalk.white(time)}${chalk.blue(path)} chalk.red(ip);5_<>=6VXE console.log(`${chalk.white(time)}${chalk.blue(path)} chalk.red(ip);5_=?>7VXE console.log(`${chalk.white(time)}${chalk.blue(path)}$chalk.red(ip);5_>@?FVXF console.log(`${chalk.white(time)}${chalk.blue(path)}${chalk.red(ip);5_?A@VX5_@BA#VXI console.log(`${chalk.white(time)}${chalk.blue(path)}${chalk.red(ip)}`);5_ACB7VXoJ console.log(`${chalk.white(time)} ${chalk.blue(path)}${chalk.red(ip)}`);5_BDCVX HK console.log(`${chalk.white(time)} ${chalk.blue(path)} ${chalk.red(ip)}`);5_CEDFVX SpZ console.log(`${chalk.red} @ ${chalk.white(time)} ${chalk.blue(path)} ${chalk.red(ip)}`);5_DFEVX bqI console.log(`${chalk.red} @ ${chalk.white(time)} ${chalk.blue(path)}`);5_EGF7VX sM console.log(`${chalk.red(ip)} @ ${chalk.white(time)} ${chalk.blue(path)}`);5_FHG VX O console.log(`${chalk.red(ip)} @ ${chalk.white(time)} > ${chalk.blue(path)}`);5_GIH*VX _ console.log(`${chalk.red(ip)} ${chalk.organge(@ ${chalk.white(time)} > ${chalk.blue(path)}`);5_HJI0VX ^ console.log(`${chalk.red(ip)} ${chalk.orange(@ ${chalk.white(time)} > ${chalk.blue(path)}`);5_IKJHVX ` console.log(`${chalk.red(ip)} ${chalk.orange(@)} ${chalk.white(time)} > ${chalk.blue(path)}`);5_JLKWVX o console.log(`${chalk.red(ip)} ${chalk.orange(@)} ${chalk.white(time)} ${chalk.orange(> ${chalk.blue(path)}`);5_KML/VX o console.log(`${chalk.red(ip)} ${chalk.orange(@)} ${chalk.white(time)} ${chalk.orange(> ${chalk.blue(path)}`);5_LNM1VX p console.log(`${chalk.red(ip)} ${chalk.orange('@)} ${chalk.white(time)} ${chalk.orange(> ${chalk.blue(path)}`);5_MONYVX q console.log(`${chalk.red(ip)} ${chalk.orange('@')} ${chalk.white(time)} ${chalk.orange(> ${chalk.blue(path)}`);5_NPO[VX r console.log(`${chalk.red(ip)} ${chalk.orange('@')} ${chalk.white(time)} ${chalk.orange('> ${chalk.blue(path)}`);5_OQP]VX tt console.log(`${chalk.red(ip)} ${chalk.orange('@')} ${chalk.white(time)} ${chalk.orange('>') ${chalk.blue(path)}`);5_PRQRVX u console.log(`${chalk.red(ip)} ${chalk.orange('@')} ${chalk.white(time)} ${chalk.orange('>')} ${chalk.blue(path)}`);5_QSR(VX uu console.log(`${chalk.red(ip)} ${chalk.orange('@')} ${chalk.white(time)} ${chalk.yellow('>')} ${chalk.blue(path)}`);5_RTSVX u console.log(`${chalk.red(ip)} ${chalk.yellow('@')} ${chalk.white(time)} ${chalk.yellow('>')} ${chalk.blue(path)}`);5_SUT*VX w console.log(`${chalk.white(ip)} ${chalk.yellow('@')} ${chalk.white(time)} ${chalk.yellow('>')} ${chalk.blue(path)}`);5_TVUQVX #vt console.log(`${chalk.white(ip)} ${chalk.red('@')} ${chalk.white(time)} ${chalk.yellow('>')} ${chalk.blue(path)}`);5_UWVVX 4q console.log(`${chalk.white(ip)} ${chalk.red('@')} ${chalk.white(time)} ${chalk.red('>')} ${chalk.blue(path)}`);5_VXW;VX 6wp console.log(`${chalk.gray(ip)} ${chalk.red('@')} ${chalk.white(time)} ${chalk.red('>')} ${chalk.blue(path)}`);5_WYXVX Yo console.log(`${chalk.gray(ip)} ${chalk.red('@')} ${chalk.gray(time)} ${chalk.red('>')} ${chalk.blue(path)}`);5_XZY<VX [p console.log(`${chalk.white(ip)} ${chalk.red('@')} ${chalk.gray(time)} ${chalk.red('>')} ${chalk.blue(path)}`);5_Y[Z*VX ^p console.log(`${chalk.white(ip)} ${chalk.red('@')} ${chalk.hite(time)} ${chalk.red('>')} ${chalk.blue(path)}`);5_Z\[=VX aq console.log(`${chalk.white(ip)} ${chalk.bold('@')} ${chalk.hite(time)} ${chalk.red('>')} ${chalk.blue(path)}`);5_[]\RVX cxr console.log(`${chalk.white(ip)} ${chalk.bold('@')} ${chalk.white(time)} ${chalk.red('>')} ${chalk.blue(path)}`);5_\^]RVX {s console.log(`${chalk.white(ip)} ${chalk.bold('@')} ${chalk.white(time)} ${chalk.bold('>')} ${chalk.blue(path)}`);5_]_^*VX ~yr console.log(`${chalk.white(ip)} ${chalk.bold('@')} ${chalk.white(time)} ${chalk.red('>')} ${chalk.blue(path)}`);5_^`_VX z 5__a`$VX * console.log('serving files from', path);5_`ba)VX + console.log('serving files from', opts.);5_acb$VX 4 console.log('serving files from', opts.directory);5_bdc:VX |< console.log('serving files from', resolve(opts.directory);5_ced:VX } 5_dfeVX 4- console.log(req.url, path, opts.directory);5_egf3VX 6~5 console.log(req.url, path, resolve(opts.directory);5_fhg3VX ;5_gihVX G 5_hji!VX Q! console.log(getTrimmedFilename(5_ikj'VX a' console.log(getTrimmedFilename(path, 5_jlk0VX i0 console.log(getTrimmedFilename(path, req.url, 5_kmlVX J console.log(getTrimmedFilename(path, req.url, resolve(opts.directory)));5_lnmVX 6 console.log(req.url, path, resolve(opts.directory));5_monVX = console.log('serving files from', resolve(opts.directory));5_npohVX q console.log(`${chalk.white(ip)} ${chalk.red('@')} ${chalk.white(time)} ${chalk.red('>')} ${chalk.blue(path)}`);5_oqpVX  5_prqVX 5_qsrVX 5_rtsVX 7 const time = format(new Date(), 'DD/MM/YY HH:MM:SS');J let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;! if (ip.startsWith('::ffff:')) { ip = ip.substr(7); }t console.log(`${chalk.white(ip)} ${chalk.red('@')} ${chalk.white(time)} ${chalk.red('>')} ${chalk.blue(req.url)}`);5_sutVX 5_tvuVX 5_uwvVX }5_vxwVX 5_wyxVX 5_xzyVX 5_y{zVX  5_z|{VX / 5_{}|VX 4 5_|~}VX 8 5_}~VX It console.log(`${chalk.white(ip)} ${chalk.red('@')} ${chalk.white(time)} ${chalk.red('>')} ${chalk.blue(req.url)}`);5_~VX J 5_VX V logRequest(req);5_VX X5_VX Y5_VX [5_VX _5_VX u ckalk.red('>'),5_VX | console.log(time.join(' '));5_VX  5_VX  5_VX 5_VX  chalk.white(ip), chalk.red('@'), chalk.white(time), chalk.red('>'), chalk.blue(req.url),5_VX 5_VX 5_VX  const items = [ ]; console.log(items.join(' '));5_VX  5_VX. chalk.blue(req.url),5_VX5( chalk.blue(req.headers.hostreq.url),5_"VX;+ chalk.blue(`${req.headers.hostreq.url),5_,VX>. chalk.blue(`${req.headers.host}${req.url),5_VXE console.log(req);5_VXi 5_VXw! chalk.white(req.headers.host)5_$VXz$ `${chalk.white(req.headers.host)5_VX0 chalk.blue(`${req.headers.host}${req.url}`),5_VX 5_VX console.log(req);5_VX 5_VXP$ console.log(req.socket.bytesRead);5_X    5_X  path: string;5_X 5_X~ 5_Xj console.log('yo', req.url);5_Xk 5_X5_X }5_X 5_X5_VX } else { notFoundHandler(res); }5_VX5_VX5_X  if (error) {X return error.code === 'ENOENT' && notFoundHandler(res) || internalErrorHandler(res); } if (stats.isFile()) { fileHandler(res, path);# } else if (stats.isDirectory()) { directoryHandler(res, path); } else { internalErrorHandler(res); }= const { path, stats, error } = await getPathStats(req.url);5_X5_X5_X 5_6X? const { path, stats, error } = await getPathStats(req.url);5_6X> const { path, stats, error } = await getPathStats(eq.url);5_6X= const { path, stats, error } = await getPathStats(q.url);5_6X< const { path, stats, error } = await getPathStats(.url);5_'X) if (req.url.startsWith(opts.basePath) {5_X0 const url = req.url.substr(basePath.length);5_X 5_X res.redirect(5_X 5_X6 5_X> 5_XM 5_XQ notFoundHandler(res);5_'X|( Location: opts.basePath + req.url,5_X // redirect?5_X //notFoundHandler(res);5_X console.log('yo', opts);5_NXfNRNP5_PXpPR5_Xs 5_X| redirectHandler(res)5_X~ redirectHandler(req, res)5_VX res.writeHead(302, {2 Location: opts.basePath + req.url.substr(1), }); res.end();5_P VXPUPQ5_QQTVXPU res.writeHead(302, {2 Location: opts.basePath + req.url.substr(1), }); res.end();5_UQTVXTU5_PQTVXOQ0function redirectHandler (res: ServerResponse) {5_PDQTVXOQFfunction redirectHandler (req: IncomingMessage, res: ServerResponse) {5_K3QTVXJL5function internalErrorHandler (res: ServerResponse) {5_F.QTVXEG0function notFoundHandler (res: ServerResponse) {5_RQTVXQS0 Location: opts.basePath + req.url.substr(1),5_RQTVXQS3 Location: `${opts.basePath + req.url.substr(1),5_RQTVXQS4 Location: `${opts.basePath} + req.url.substr(1),5_RQTVXQS3 Location: `${opts.basePath}+ req.url.substr(1),5_RQTVXQS2 Location: `${opts.basePath} req.url.substr(1),5_RQTVXQS1 Location: `${opts.basePath}req.url.substr(1),5_R3QTVXQS3 Location: `${opts.basePath}${req.url.substr(1),5_QQTVXPR res.writeHead(302, {5 Location: `${opts.basePath}${req.url.substr(1)}`,5_QQSVXPRH res.writeHead(302, { Location: `${opts.basePath}${req.url.substr(1)}`, });5_QGQRVXPRL res.writeHead(302, { Location: `${opts.basePath}${req.url.substr(1)}`, });5_QRVX  5_QRVX(5_QRVX*5_QRVX, redirectHandler(req, res);5_QRVX.5_QRVX/5_QRVX0 5_ QRVX1 return redirectHandler(req, res);5_QRVX:* if (req.url.startsWith(opts.basePath)) {5_PCQRVX\OQLfunction redirectHandler (req: IncomingMessage, res: ServerResponse): void {5_Q!QRVXfPRK res.writeHead(302, { Location: `${opts.basePath}${req.url.substr(1)}` });5_Q-QRVXqPRW res.writeHead(302, { Location: redirectUrl `${opts.basePath}${req.url.substr(1)}` });5_Q-QRVXsPR- res.writeHead(302, { Location: redirectUrl 5_ QRVXy 5_QRVX{ https://240c6f3f.ngrok.io/5_GQRVX|5_QRVX|5_QRVX}H https://240c6f3f.ngrok.io/`${opts.basePath}${req.url.substr(1)}` });5_QRVX~*`${opts.basePath}${req.url.substr(1)}` });5_QRVX/ d`${opts.basePath}${req.url.substr(1)}` });5_QRVX. `${opts.basePath}${req.url.substr(1)}` });5_QRVX5_%QRVX% return redirectHandler(req, res);5_$QRVX% return redirectHandler(req, res, 5_#QRVX$ return redirectHandler(req, res,. `${opts.basePath}${req.url.substr(1)}` });5_OQRVXO return redirectHandler(req, res, `${opts.basePath}${req.url.substr(1)}` });5_NQRVXP return redirectHandler(req, res, `${opts.basePath}${req.url.substr(1)}` }));5_VX5 const url = req.url.substr(opts.basePath.length);; const { path, stats, error } = await getPathStats(url); if (error) {Z return error.code === 'ENOENT' && notFoundHandler(res) || internalErrorHandler(res); } if (stats.isFile()) { fileHandler(res, path);% } else if (stats.isDirectory()) {" directoryHandler(res, path); } else { internalErrorHandler(res); }5_VX } else {5_VX }5_JVXO return redirectHandler(req, res, `${opts.basePath}${req.url.substr(1)}` });5_JVXN return redirectHandler(req, res, `${opts.basePath}${req.url.substr(1)} });5_JVXM return redirectHandler(req, res, `${opts.basePath}${req.url.substr(1)}});5_JVXL return redirectHandler(req, res, `${opts.basePath}${req.url.substr(1)});5_VX5_/VX"7 const time = format(new Date(), 'DD/MM/YY HH:MM:SS');5_2VX#7 const time = format(new Date(), 'DD/MM/YY HH:mm:SS');5_<X;;=;function hasIndexTemplate (files: Array): boolean {5_@X=*?A9function createHeaders (path?: string): ResponseHeaders {5_FX>kEG6function notFoundHandler (res: ServerResponse): void {5_X>M return redirectHandler(req, res, `${opts.basePath}${req.url.substr(1)}`);5_X>L return redirectHandler(eq, res, `${opts.basePath}${req.url.substr(1)}`);5_X>K return redirectHandler(q, res, `${opts.basePath}${req.url.substr(1)}`);5_X>J return redirectHandler(, res, `${opts.basePath}${req.url.substr(1)}`);5_X>I return redirectHandler( res, `${opts.basePath}${req.url.substr(1)}`);5_PX>OQafunction redirectHandler (req: IncomingMessage, res: ServerResponse, redirectUrl: string): void {5_PX>OQ`function redirectHandler (eq: IncomingMessage, res: ServerResponse, redirectUrl: string): void {5_PX>OQ_function redirectHandler (q: IncomingMessage, res: ServerResponse, redirectUrl: string): void {5_ PX>OQ^function redirectHandler (: IncomingMessage, res: ServerResponse, redirectUrl: string): void {5_! PX>OQ]function redirectHandler ( IncomingMessage, res: ServerResponse, redirectUrl: string): void {5_ "!PX>OQ\function redirectHandler (IncomingMessage, res: ServerResponse, redirectUrl: string): void {5_!#"PX>OQ[function redirectHandler (ncomingMessage, res: ServerResponse, redirectUrl: string): void {5_"$#PX>OQZfunction redirectHandler (comingMessage, res: ServerResponse, redirectUrl: string): void {5_#%$PX>OQYfunction redirectHandler (omingMessage, res: ServerResponse, redirectUrl: string): void {5_$&%PX>OQXfunction redirectHandler (mingMessage, res: ServerResponse, redirectUrl: string): void {5_%'&PX>OQWfunction redirectHandler (ingMessage, res: ServerResponse, redirectUrl: string): void {5_&('PX>OQVfunction redirectHandler (ngMessage, res: ServerResponse, redirectUrl: string): void {5_')(PX>OQUfunction redirectHandler (gMessage, res: ServerResponse, redirectUrl: string): void {5_(*)PX>OQTfunction redirectHandler (Message, res: ServerResponse, redirectUrl: string): void {5_)+*PX>OQSfunction redirectHandler (essage, res: ServerResponse, redirectUrl: string): void {5_*,+PX>OQRfunction redirectHandler (ssage, res: ServerResponse, redirectUrl: string): void {5_+-,PX>OQQfunction redirectHandler (sage, res: ServerResponse, redirectUrl: string): void {5_,.-PX>OQPfunction redirectHandler (age, res: ServerResponse, redirectUrl: string): void {5_-/.PX>OQOfunction redirectHandler (ge, res: ServerResponse, redirectUrl: string): void {5_.0/PX>OQNfunction redirectHandler (e, res: ServerResponse, redirectUrl: string): void {5_/10PX>OQMfunction redirectHandler (, res: ServerResponse, redirectUrl: string): void {5_021PX>OQLfunction redirectHandler ( res: ServerResponse, redirectUrl: string): void {5_132KXDJL;function internalErrorHandler (res: ServerResponse): void {5_243PXDOQKfunction redirectHandler (res: ServerResponse, redirectUrl: string): void {5_354HXDGI" res.end('404 - File not found');5_465HXDGI" res.end('404 - File Not found');5_576YXHXZ@async function fileHandler (res: ServerResponse, path: string) {5_687eXL*dfYfunction getTrimmedFilename (path: string, file: string, rootDirectory: string): string {5_798eX=!eg eg5_8S9fX=4ef0 console.log('gtf', path, file, rootDirectory);5_9T:SgX@fh2 let trimLength = resolve(opts.directory).length;5_SUTe'XAteg eg5_TVUmXAmo mo5_U`VnXAmo console.log(trimLength);5_VaX`hjnXCCgi1 let trimLength = resolve(rootDirectory).length;5_`bafjnXCEef/ console.log('hi', path, file, rootDirectory);5_acbmiiVXCKlm console.log(trimLength, name);5_bdcjjlXCOjm trimLength += 1; }ik if (trimLength !== 1) {5_cedjjlXC[im //if (trimLength !== 1) { // trimLength += 1; //}5_dfejjlXC\im /if (trimLength !== 1) { / trimLength += 1; /}5_egfgjlXCjfh3 const trimLength = resolve(rootDirectory).length;5_fhggjlXC}gi gi5_gvhmkmXCmomn5_hwivnkmXDQmn" console.log('prev', trimLength);5_vxwhkmXDRgh" console.log('prev', trimLength);5_wyxg0jlXDfh1 let trimLength = resolve(rootDirectory).length;5_xzyiilXDim if (trimLength !== 1) { trimLength += 1; }hj2 // Handle system root directory ("/") edge case.5_y{zfilXDfh fh5_z|{gjmXEfh console.log('n', name);5_{}|jjmXE;ik4 //// Handle system root directory ("/") edge case.5_|~}jjmXE;ik3 /// Handle system root directory ("/") edge case.5_}~kkmXE<jn //if (trimLength !== 1) { // trimLength += 1; //}5_~kkmXE=jn /if (trimLength !== 1) { / trimLength += 1; /}5_kkmXEAjl if (trimLength !== 1) {5_lkmXEFkm trimLength += 1;5_lkmXEFkm trimLength = 1;5_lkmXEFkm trimLength 1;5_lkmXEHkm trimLength - 1;5_kkmXEjl if (trimLength === 1) {5_lkmXEkm trimLength -= 1;5_j(kmXEik2 // Handle system root directory ("/") edge case.5_gkmXEfgN console.log('n', resolve(rootDirectory), resolve(rootDirectory).length + 1);5_i jlXEhj8 // Handle system root directory ("/") paths edge case.5_ijlXEhjF // Handle edge case for system root directory ("/") paths edge case.5_i9jlXEhjJ // Handle edge case for the system root directory ("/") paths edge case.5_i9jlXEhj9 // Handle edge case for the system root directory ("/")5_tjlXEsuBasync function listContents (path: string): Promise {5_}jlXG>} }5_~jlXGB} console.log('n', name),5_yjlXGny{ y{5_jlXG~ console.log('n', name);5_XP 5_XP( console.log('hi', directories, files);5_XQ* 5_XQ0 5_ XQ45_XQB console.log('ret'),5_XQa~! console.log('n', file, name);5_fXQfh fh5_hXQhj hj5_nXQnp np5_pXQpr pr5_fXQeg const name = join(path, file);5_f XQeg( const name = join(resolve(path, file);5_gXR8fg console.log('gt', name);5_hXR9gh console.log('gt', trimLength);5_mXR:lm console.log(trimLength);5_nXR:mn. console.log('res', name.substr(trimLength));5_zXR?yz& console.log('path', path, fullPath);5_~XR@}~= console.log('n', file, name, path, file, opts.directory);5_XR@~ console.log('push');5_XRA console.log('push');5_XRB console.log('ret');5_XREasync function directoryHandler (res: ServerResponse, path: string) {5_XU 5_XU console.log('hi', res, path);5_XU5_XU console.log('hi', res, path);5_XU@ 5_ XUD 5_XU}" console.log(directories, files);5_XU~ console.log('tru');5_XW console.log('fa');5_XX?async function getPathStats (url: string): Promise {5_X[ 5_X[ console.log('yep');5_X[ 5_X[ console.log('now', path),5_X[ 5_X\ console.log('now', path);5_X\ console.log('wat', err);5_X\ console.log('yep', path);5_X]2function logRequest (req: IncomingMessage): void {5_X]Zasync function requestHandler (req: IncomingMessage, res: ServerResponse): Promise {5_X_n 5_X_ console.log(req.headers);5_X_ 5_X` 5_X` console.5_Xa@ 5_XaJ console.log('should be...');5_Xa% console.log('should be...', req);5_VXi4  console.log('ipppp', ip);5_VXEimport { createServer, IncomingMessage, ServerResponse } from 'http';import { readFileSync, lstat as _lstat, readFile as _readFile, readdir as _readdir, realpath as _realpath, } from 'fs';/import { basename, join, resolve } from 'path';import * as chalk from 'chalk';"import { format } from 'date-fns';import { compile } from 'ejs';;import { contentType as getContentType } from 'mime-types';*import { map, promisify } from 'bluebird';@// Promisify callback-style methods as promises for async/await.$const readdir = promisify(_readdir);&const readFile = promisify(_readFile);&const realpath = promisify(_realpath); const lstat = promisify(_lstat);4// Configure globals required throughout the module.let opts: ButlerOptions;Qconst template = compile(readFileSync(join(__dirname, 'template.ejs'), 'utf-8')); export interface ButlerOptions { port: string; directory: string; basePath: string;}interface DirContents { directories: Array; files: Array;}interface ResponseHeaders { 'Content-Type': string;}interface FileStats { isFile(): boolean; isDirectory(): boolean; isSymbolicLink(): boolean;}interface ReadError { code: string;}interface PathStats { path: string; stats: FileStats; error?: ReadError;}Bexport function hasIndexTemplate (files: Array): boolean {L return files.some((file: string): boolean => !!file.match(/index.html$/));}@export function createHeaders (path?: string): ResponseHeaders {3 const defaultValue = 'text/plain; charset=utf-8';] const contentType = path ? (getContentType(basename(path)) || defaultValue) : defaultValue;) return { 'Content-Type': contentType };}=export function notFoundHandler (res: ServerResponse): void {& res.writeHead(404, createHeaders());" res.end('404 - File Not Found');}Bexport function internalErrorHandler (res: ServerResponse): void {& res.writeHead(500, createHeaders());) res.end('500 - Internal Server Error');}Rexport function redirectHandler (res: ServerResponse, redirectUrl: string): void {0 res.writeHead(302, { Location: redirectUrl }); res.end();}/**E * Read the file at the provided path and write to the response along * with the appropriate headers. */Gexport async function fileHandler (res: ServerResponse, path: string) {* res.writeHead(200, createHeaders(path)); res.end(await readFile(path));}/**H * Trim the filename so that it only includes subdirectories of the root< * directory as part of the pathname, not the absolute path.O * Example: Given a root directory of "/Users/butler/" and the contents being aM * single directory "example/" with a file "example.txt", the function shouldO * return "example/example.txt" instead of "/Users/butler/example/example.txt". */`export function getTrimmedFilename (path: string, file: string, rootDirectory: string): string {) const name = join(resolve(path), file);5 let trimLength = resolve(rootDirectory).length + 1;: // Handle edge case for the system root directory ("/"). if (trimLength === 2) { trimLength = 1; }! return name.substr(trimLength);}/**? * Return a list of files and subdirectories at the given path. */Iexport async function listContents (path: string): Promise {( const directories: Array = [];" const files: Array = [];! const fullPath = resolve(path);+ const contents = await readdir(fullPath);/ await map(contents, async (file: string) => {4 const stats = await lstat(join(fullPath, file));@ const name = getTrimmedFilename(path, file, opts.directory); if (stats.isDirectory()) { directories.push(name); } else { files.push(name); } }); return { directories, files };}/**H * Read the files in the directory at the provided path and write to theH * response as appropriate; if there is an index.html file it is served,6 * otherwise a template listing the files is rendered. */Lexport async function directoryHandler (res: ServerResponse, path: string) {: const { directories, files } = await listContents(path); if (hasIndexTemplate(files)) {9 res.end(await readFile(resolve(path, 'index.html'))); } else {4 res.end(template({ directories, files, path })); }}/**> * Parse the provided URL into a path and read the file there.> * Return the path, the path stats and any errors encountered. */Fexport async function getPathStats (url: string): Promise {; let path = join(resolve(opts.directory), decodeURI(url)); let stats; let error; try { stats = await lstat(path);* // Follow symbolic link when required.! if (stats.isSymbolicLink()) {, path = await realpath(path) as string; stats = await lstat(path); } } catch (err) { error = err; } return { path, stats, error };}/** * Parse and log the request. */9export function logRequest (req: IncomingMessage): void {7 const time = format(new Date(), 'DD/MM/YY HH:mm:ss');J let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;! if (ip.startsWith('::ffff:')) { ip = ip.substr(7); } console.log( chalk.white(ip), chalk.red('@'), chalk.white(time), chalk.red('>'),= `${chalk.white(req.headers.host)}${chalk.blue(req.url)}`, );}/**G * Handle server requests by delegating to other functions that examineJ * the URL and then serve a response for files, folders, symbolic links or * errors as appropriate. */aexport async function requestHandler (req: IncomingMessage, res: ServerResponse): Promise { logRequest(req);+ if (!req.url.startsWith(opts.basePath)) {H return redirectHandler(res, `${opts.basePath}${req.url.substr(1)}`); }3 const url = req.url.substr(opts.basePath.length);9 const { path, stats, error } = await getPathStats(url); if (error) {X return error.code === 'ENOENT' && notFoundHandler(res) || internalErrorHandler(res); } if (stats.isFile()) { fileHandler(res, path);# } else if (stats.isDirectory()) { directoryHandler(res, path); } else { internalErrorHandler(res); }}_export default function createButlerServer (options: ButlerOptions, callback: Function): void { if (options) { opts = options; }4 createServer(requestHandler).listen(options.port); callback();}5_Xbexport testing 5_Xbexport const testing 5_Xbexport const testing = {}5_Xb  requestHandler,5_VXi/ uequestHandler,5_Xc directoryHandler,5_VXd5_VXds  console.log('wataaa');5_VXd5_VXd  console.log('2');5_VXd  console.log('1');5_VXe console.log('2');5_VXe console.log('2');5_VXe console.log('3');5_ VXe console.log('3');5_VXe console.log('4');5_VXe console.log('3');5_VXe console.log('5');5_VXe console.log('3');5_VXe4 res.end(template({ directories, files, path }));5_VXe, template({ directories, files, path }));5_VXe> console.log('4'); template({ directories, files, path }));5_VXe= console.log('4'; template({ directories, files, path }));5_VXe< console.log('4' template({ directories, files, path }));5_VXe; console.log('4'template({ directories, files, path }));5_VXe= console.log('4', template({ directories, files, path }));5_=VXe= console.log('4', template({ directories, files, path }));5_;VXf,F console.log('4', template({ directories, files, path }), res.end);5_VXd'& await directoryHandler(res, path);5_hpvinkmXCmo" console.log('post', trimLength);5_iqjpg0hnXD fh5 let trimLength = resolve(rootDirectory).length + 1;5_prqhhnXDgi$ //console.log('prev', trimLength);ho4 //// Handle system root directory ("/") edge case. //if (trimLength !== 1) { // trimLength += 1; //}$ //console.log('post', trimLength);5_qsrg3h#n$VNXD,fhQ let trimLength = resolve(rootDirectory).length + rootDirectory === '/' ? 0 : 1;5_rtshh#h$VNXD<go5_sutgh#h$VNXD>fhS const trimLength = resolve(rootDirectory).length + rootDirectory === '/' ? 0 : 1;5_tuhh#h$VNXD?gi5_impjg0kmXCfh5 let trimLength = resolve(rootDirectory).length + 1;5_jnkmhjlXCgi5_mong1jlXCfh2 let trimLength = resolve(rootDirectory).length ;5_nog0jlXCfh1 let trimLength = resolve(rootDirectory).length;5_jlmkghoVXCfh7 const trimLength = resolve(rootDirectory).length + 1;5_klhhhVXCgp5_VYW`XjjoVXBuik4 //// Handle system root directory ("/") edge case.jo //if (trimLength !== 1) { // trimLength += 1; //}" //console.log(trimLength, name);5_XZYjjjVXBip5_Y[ZjjjVXBik4 return name.substr(resolve(rootDirectory).length);5_Z\[hiiVXBgi5_[]\fhhVXBeg5_\^]gggVXBfh5_]_^g ggVXBfh@ return join(path, file).substr(resolve(rootDirectory).length);5_^_fffVXBeg5_VXWjjnXAik4 //// Handle system root directory ("/") edge case.jo //if (trimLength !== 1) { // trimLength += 1; //}" //console.log(trimLength, name);5_9;S:mX=5mnmn0 console.log('gtf', path, file, rootDirectory);5_:<;nX=7nono! return name.substr(trimLength);5_;=<oX=8np eturn name.substr(trimLength);5_<>=oX=8np turn name.substr(trimLength);5_=?>oX=8np urn name.substr(trimLength);5_>@?oX=9np rn name.substr(trimLength);5_?A@oX=9np n name.substr(trimLength);5_@BAoX=9np name.substr(trimLength);5_ACBoX=9np name.substr(trimLength);5_BDCoX=:np& console.log(name.substr(trimLength);5_CEDo&X=<np' console.log(name.substr(trimLength));5_DFEoX=@np5_EGFnX=@no np let ret = 5_FHGo X=Enq+ let ret = return name.substr(trimLength);5_GIHo X=Fnp& let ret = n name.substr(trimLength);5_HJIo X=Gnp% let ret = name.substr(trimLength);5_IKJo X=Gnp$ let ret = name.substr(trimLength);5_JLKo X=Gop oq return ret;5_KMLo X=Iop oq con5_LNMpX=Koq5_MONoX=Lnp5_NPOmX=Lmnmn$ let ret = name.substr(trimLength);5_OQPo.X=Mnp5 console.log('gtf', path, file, rootDirectory, ret);5_PRQo0X=Qnp; console.log('gtf', path, file, rootDirectory, '=>', ret);5_QRgX?fh1 let trimLength = resolve(rootDirectory).length;5_VX5_VX3 const url = req.url.substr(opts.basePath.length);5_9VX4 const { path, stats, error } = await getPathStats(5_3VXf const { path, stats, error } = await getPathStats( const url = req.url.substr(opts.basePath.length);5_4VXe const { path, stats, error } = await getPathStats(const url = req.url.substr(opts.basePath.length);5_4VXd const { path, stats, error } = await getPathStats(onst url = req.url.substr(opts.basePath.length);5_4VXc const { path, stats, error } = await getPathStats(nst url = req.url.substr(opts.basePath.length);5_ 4VXb const { path, stats, error } = await getPathStats(st url = req.url.substr(opts.basePath.length);5_  4VXa const { path, stats, error } = await getPathStats(t url = req.url.substr(opts.basePath.length);5_   4VX` const { path, stats, error } = await getPathStats( url = req.url.substr(opts.basePath.length);5_   4VX_ const { path, stats, error } = await getPathStats(url = req.url.substr(opts.basePath.length);5_   4VX^ const { path, stats, error } = await getPathStats(rl = req.url.substr(opts.basePath.length);5_  4VX] const { path, stats, error } = await getPathStats(l = req.url.substr(opts.basePath.length);5_ 4VX\ const { path, stats, error } = await getPathStats( = req.url.substr(opts.basePath.length);5_4VX[ const { path, stats, error } = await getPathStats(= req.url.substr(opts.basePath.length);5_4VXZ const { path, stats, error } = await getPathStats( req.url.substr(opts.basePath.length);5_4VXY const { path, stats, error } = await getPathStats(req.url.substr(opts.basePath.length);5_QRVXzH https://240c6f3f.ngrok.io/`${opts.basePath}${req.url.substr(1)}` });5_Q-QRVXnPR- res.writeHead(302, { Location: redirectUrl 5_Q-QRVXlPR4 res.writeHead(302, { Location: redirectUrl )}` });5_Q-QRVXiPRG res.writeHead(302, { Location: redirectUrl }${req.url.substr(1)}` });5_X55_ VX  chalk.gray('@'),5_ VX  chalk.gray('>'),5_VX  ip,5_VX  time,5_&('VX co5_.VX_B const seconds = date.getSeconds().padStarttoString().(2, ' ');5_]_a^ggnXEfh5 //getTrimmedFilename(path, file, opts.directory);go" //let name = join(path, file);6 //let trimLength = resolve(opts.directory).length; //if (trimLength !== 1) { // trimLength += 1; //}% //name = name.substr(trimLength);" //console.log('n name', name);5_^`_qgnXHpr directories.push(file);5__`sgnXJSrt files.push(file);5_8:9hn'nHVLXBhi hj trimLength = 0;5_"c)d'dHVLXbdL const name = join(path, file).substr(esolve(opts.directory).length + 1);5_c)d'dHVLXbdK const name = join(path, file).substr(solve(opts.directory).length + 1);5_ c)d'dHVLXbdJ const name = join(path, file).substr(olve(opts.directory).length + 1);5_  c)d'dHVLXbdI const name = join(path, file).substr(lve(opts.directory).length + 1);5_   c)d'dHVLXbdH const name = join(path, file).substr(ve(opts.directory).length + 1);5_   c)d'dHVLXbdG const name = join(path, file).substr(e(opts.directory).length + 1);5_   c)d'dHVLXbdF const name = join(path, file).substr((opts.directory).length + 1);5_  c)d'dHVLXbdE const name = join(path, file).substr(opts.directory).length + 1);5_ c)d'dHVLXbdD const name = join(path, file).substr(pts.directory).length + 1);5_c)d'dHVLXbdC const name = join(path, file).substr(ts.directory).length + 1);5_c)d'dHVLXbdB const name = join(path, file).substr(s.directory).length + 1);5_c)d'dHVLXbdA const name = join(path, file).substr(.directory).length + 1);5_c)d'dHVLXbd@ const name = join(path, file).substr(directory).length + 1);5_c)d'dHVLXbd? const name = join(path, file).substr(irectory).length + 1);5_c)d'dHVLXbd> const name = join(path, file).substr(rectory).length + 1);5_c)d'dHVLXbd= const name = join(path, file).substr(ectory).length + 1);5_c)d'dHVLXbd< const name = join(path, file).substr(ctory).length + 1);5_c)d'dHVLXbd; const name = join(path, file).substr(tory).length + 1);5_c)d'dHVLXbd: const name = join(path, file).substr(ory).length + 1);5_c)d'dHVLXbd9 const name = join(path, file).substr(ry).length + 1);5_c)d'dHVLXbd8 const name = join(path, file).substr(y).length + 1);5_c)d'dHVLXbd7 const name = join(path, file).substr().length + 1);5_c)d'dHVLXbd6 const name = join(path, file).substr(.length + 1);5_c)d'dHVLXbd5 const name = join(path, file).substr(length + 1);5_c)d'dHVLXbd4 const name = join(path, file).substr(ength + 1);5_ c)d'dHVLXbd3 const name = join(path, file).substr(ngth + 1);5_! c)d'dHVLXbd2 const name = join(path, file).substr(gth + 1);5_ !c)d'dHVLXbd1 const name = join(path, file).substr(th + 1);5_f88VXveg* directories.push(relative(pathfile);5_VXlet opts: ButlerOptions = {d};5_DOOvOX/Xexport default function createButlerServer (options: ButlerOptions, (callback: ): void {5_OOOvOX4]export default function createButlerServer (options: ButlerOptions, (callback: void)): void {5_&VX/Eimport { createServer, IncomingMessage, ServerResponse } from 'http';5_%XS0 return createServer(requestHandler) as Server;5_Xlet OPTS Ö ButlerOptions = {};5_wyxSXRT( const directories = []: Array;5_oqp =v=XlLimport { zasdf, createServer, IncomingMessage, ServerResponse } from 'http';5_monVXM lstat as _lstat, readFile as _readFile, readFileSync, readdir as _readdir, realpath as _realpath,5_SVTYU7<<IVIX+78 79L const contentType = path ? getContentType(basename(path)) || defaultValue;5_UWV8<<IVIXQ79K const contentType = path getContentType(basename(path)) || defaultValue;5_VXW8<<IVIXR79M const contentType = path && getContentType(basename(path)) || defaultValue;5_WX8==IVIXU89 8: return { 'Content-Type'5_SUT8<<IVIX*895_46858QQ VXt795_576989Xt9:9: }5_67889Xv79V const contentType = getContentType(basename(path)) || 'text/plain; charset=utf-8';8:+ return { 'Content-Type': contentType };5