diff --git a/.env.example b/.env.example
new file mode 100755
index 0000000..cb6940d
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,29 @@
+# The environment Craft is currently running in ('dev', 'staging', 'production', etc.)
+ENVIRONMENT="dev"
+
+# The secure key Craft will use for hashing and encrypting data
+SECURITY_KEY=""
+
+# The database driver that will used ('mysql' or 'pgsql')
+DB_DRIVER="mysql"
+
+# The database server name or IP address (usually this is 'localhost' or '127.0.0.1')
+DB_SERVER="localhost"
+
+# The database username to connect with
+DB_USER="root"
+
+# The database password to connect with
+DB_PASSWORD=""
+
+# The name of the database to select
+DB_DATABASE=""
+
+# The database schema that will be used (PostgreSQL only)
+DB_SCHEMA="public"
+
+# The prefix that should be added to generated table names (only necessary if multiple things are sharing the same database)
+DB_TABLE_PREFIX=""
+
+# The port to connect to the database with. Will default to 5432 for PostgreSQL and 3306 for MySQL.
+DB_PORT=""
diff --git a/.gitignore b/.gitignore
new file mode 100755
index 0000000..b8ea745
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/.env
+/.idea
+/vendor
+.DS_Store
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100755
index 0000000..005050c
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,3 @@
+# vigetlabs/craft Change Log
+
+## TODO
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100755
index 0000000..3ca1d31
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Viget Labs, LLC.
+
+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 above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+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.
diff --git a/README.md b/README.md
new file mode 100755
index 0000000..00d7bdd
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+WIP
diff --git a/composer.json b/composer.json
new file mode 100755
index 0000000..3664149
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,52 @@
+{
+ "name": "jeremyfrank/craft",
+ "description": "Viget Craft 3 CMS scaffolding project",
+ "keywords": [
+ "craft",
+ "cms",
+ "craftcms",
+ "project"
+ ],
+ "license": "MIT",
+ "homepage": "https://craftcms.com/",
+ "type": "project",
+ "support": {
+ "email": "craft@viget.com",
+ "issues": "https://github.com/vigetlabs/craft/issues",
+ "source": "https://github.com/vigetlabs/craft",
+ "docs": "https://github.com/vigetlabs/craft"
+ },
+ "minimum-stability": "RC",
+ "require": {
+ "craftcms/cms": "^3.0.0-RC1",
+ "vlucas/phpdotenv": "^2.4.0",
+ "craftcms/redactor": "^1.0.0",
+ "mikestecker/craft-videoembedder": "^v1.0.0",
+ "pennebaker/craft-architect": "^2.2.0",
+ "rias/craft-position-fieldtype": "^v1.0",
+ "topshelfcraft/environment-label": "^3.1.1",
+ "verbb/super-table": "^2.0.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "modules\\": "modules/"
+ }
+ },
+ "config": {
+ "optimize-autoloader": true,
+ "sort-packages": true,
+ "platform": {
+ "php": "7.0"
+ }
+ },
+ "scripts": {
+ "post-root-package-install": [
+ "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
+ ],
+ "post-create-project-cmd": [
+ "@composer dump-autoload -o",
+ "@php craft setup/welcome",
+ "@php viget-setup welcome"
+ ]
+ }
+}
diff --git a/config/app.php b/config/app.php
new file mode 100755
index 0000000..da97795
--- /dev/null
+++ b/config/app.php
@@ -0,0 +1,25 @@
+ [
+ 'my-module' => \modules\Module::class,
+ ],
+ //'bootstrap' => ['my-module'],
+];
diff --git a/config/architect/setup.json b/config/architect/setup.json
new file mode 100644
index 0000000..1bf0d9a
--- /dev/null
+++ b/config/architect/setup.json
@@ -0,0 +1,386 @@
+{
+ "fieldGroups": [
+ "Common"
+ ],
+ "volumes": [
+ {
+ "name": "Placeholders",
+ "handle": "placeholders",
+ "type": "craft\\volumes\\Local",
+ "hasUrls": true,
+ "url": "@web\/placeholders",
+ "settings": {
+ "path": "placeholders"
+ },
+ "fieldLayout": []
+ }
+ ],
+ "sections": [
+ {
+ "name": "Homepage",
+ "handle": "homepage",
+ "type": "single",
+ "enableVersioning": true,
+ "siteSettings": [
+ {
+ "hasUrls": "1",
+ "uriFormat": "__home__",
+ "template": "index",
+ "enabledByDefault": true
+ }
+ ]
+ },
+ {
+ "name": "Page",
+ "handle": "page",
+ "type": "structure",
+ "enableVersioning": true,
+ "maxLevels": null,
+ "siteSettings": [
+ {
+ "hasUrls": "1",
+ "uriFormat": "page\/{slug}",
+ "template": "page\/_entry",
+ "enabledByDefault": true
+ }
+ ]
+ },
+ {
+ "name": "Parts Kit",
+ "handle": "partsKit",
+ "type": "structure",
+ "enableVersioning": true,
+ "maxLevels": null,
+ "siteSettings": [
+ {
+ "hasUrls": "1",
+ "uriFormat": "parts\/{slug}",
+ "template": "parts\/_entry",
+ "enabledByDefault": true
+ }
+ ]
+ }
+ ],
+ "fields": [
+ {
+ "group": "Common",
+ "name": "Hero",
+ "handle": "hero",
+ "instructions": "",
+ "type": "craft\\fields\\Assets",
+ "useSingleFolder": "",
+ "defaultUploadLocationSource": "placeholders",
+ "defaultUploadLocationSubpath": "",
+ "singleUploadLocationSource": "placeholders",
+ "singleUploadLocationSubpath": "",
+ "restrictFiles": "1",
+ "allowedKinds": [
+ "image"
+ ],
+ "sources": "*",
+ "viewMode": "large",
+ "limit": "1",
+ "selectionLabel": "",
+ "localizeRelations": false
+ },
+ {
+ "group": "Common",
+ "name": "Page Blocks",
+ "handle": "pageBlocks",
+ "instructions": "",
+ "type": "craft\\fields\\Matrix",
+ "minBlocks": "",
+ "maxBlocks": "",
+ "localizeBlocks": false,
+ "blockTypes": [
+ {
+ "name": "Text",
+ "handle": "text",
+ "fields": [
+ {
+ "required": true,
+ "name": "Text",
+ "handle": "text",
+ "instructions": "",
+ "type": "craft\\redactor\\Field",
+ "typesettings": {
+ "redactorConfig": "",
+ "purifierConfig": "",
+ "cleanupHtml": "1",
+ "purifyHtml": "1",
+ "columnType": "text",
+ "availableVolumes": "*",
+ "availableTransforms": "*"
+ }
+ }
+ ]
+ },
+ {
+ "name": "Image",
+ "handle": "image",
+ "fields": [
+ {
+ "required": true,
+ "name": "Image",
+ "handle": "image",
+ "instructions": "",
+ "type": "craft\\fields\\Assets",
+ "typesettings": {
+ "useSingleFolder": "",
+ "defaultUploadLocationSource": "placeholders",
+ "defaultUploadLocationSubpath": "",
+ "singleUploadLocationSource": "placeholders",
+ "singleUploadLocationSubpath": "",
+ "restrictFiles": "1",
+ "allowedKinds": [
+ "image"
+ ],
+ "sources": "*",
+ "viewMode": "list",
+ "limit": "1",
+ "selectionLabel": "",
+ "localizeRelations": false
+ }
+ },
+ {
+ "required": false,
+ "name": "Display",
+ "handle": "display",
+ "instructions": "",
+ "type": "rias\\positionfieldtype\\fields\\Position",
+ "typesettings": {
+ "options": {
+ "left": "1",
+ "center": "1",
+ "right": "1",
+ "full": "1",
+ "drop-left": "",
+ "drop-right": ""
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "Video",
+ "handle": "video",
+ "fields": [
+ {
+ "required": true,
+ "name": "Video URL",
+ "handle": "videoUrl",
+ "instructions": "",
+ "type": "craft\\fields\\Url",
+ "typesettings": []
+ },
+ {
+ "required": false,
+ "name": "Display",
+ "handle": "display",
+ "instructions": "",
+ "type": "rias\\positionfieldtype\\fields\\Position",
+ "typesettings": {
+ "options": {
+ "left": "1",
+ "center": "1",
+ "right": "1",
+ "full": "",
+ "drop-left": "",
+ "drop-right": ""
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "Quote",
+ "handle": "quote",
+ "fields": [
+ {
+ "required": true,
+ "name": "Quote",
+ "handle": "quote",
+ "instructions": "",
+ "type": "craft\\redactor\\Field",
+ "typesettings": {
+ "redactorConfig": "Simple.json",
+ "purifierConfig": "",
+ "cleanupHtml": "1",
+ "purifyHtml": "1",
+ "columnType": "text",
+ "availableVolumes": "*",
+ "availableTransforms": "*"
+ }
+ },
+ {
+ "required": false,
+ "name": "Attribution",
+ "handle": "attribution",
+ "instructions": "",
+ "type": "craft\\fields\\PlainText",
+ "typesettings": {
+ "placeholder": "",
+ "multiline": "",
+ "initialRows": "4",
+ "charLimit": "",
+ "columnType": "string"
+ }
+ },
+ {
+ "required": false,
+ "name": "Display",
+ "handle": "display",
+ "instructions": "",
+ "type": "rias\\positionfieldtype\\fields\\Position",
+ "typesettings": {
+ "options": {
+ "left": "1",
+ "center": "1",
+ "right": "1",
+ "full": "",
+ "drop-left": "",
+ "drop-right": ""
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "Two Column Text",
+ "handle": "twoColumnText",
+ "fields": [
+ {
+ "required": true,
+ "name": "Column 1",
+ "handle": "column1",
+ "instructions": "",
+ "type": "craft\\redactor\\Field",
+ "typesettings": {
+ "redactorConfig": "",
+ "purifierConfig": "",
+ "cleanupHtml": "1",
+ "purifyHtml": "1",
+ "columnType": "text",
+ "availableVolumes": "*",
+ "availableTransforms": "*"
+ }
+ },
+ {
+ "required": true,
+ "name": "Column 2",
+ "handle": "column2",
+ "instructions": "",
+ "type": "craft\\redactor\\Field",
+ "typesettings": {
+ "redactorConfig": "",
+ "purifierConfig": "",
+ "cleanupHtml": "1",
+ "purifyHtml": "1",
+ "columnType": "text",
+ "availableVolumes": "*",
+ "availableTransforms": "*"
+ }
+ }
+ ]
+ },
+ {
+ "name": "Two Column Image & Caption",
+ "handle": "twoColumnImageCaption",
+ "fields": [
+ {
+ "required": false,
+ "name": "Columns",
+ "handle": "columns",
+ "instructions": "",
+ "type": "verbb\\supertable\\fields\\SuperTableField",
+ "typesettings": {
+ "minRows": "2",
+ "maxRows": "2",
+ "localizeBlocks": false,
+ "staticField": "",
+ "fieldLayout": "row",
+ "selectionLabel": "",
+ "blockTypes": [
+ {
+ "name": "Image",
+ "handle": "image",
+ "instructions": "",
+ "type": "craft\\fields\\Assets",
+ "typesettings": {
+ "useSingleFolder": "",
+ "defaultUploadLocationSource": "placeholders",
+ "defaultUploadLocationSubpath": "",
+ "singleUploadLocationSource": "placeholders",
+ "singleUploadLocationSubpath": "",
+ "restrictFiles": "1",
+ "allowedKinds": [
+ "image"
+ ],
+ "sources": "*",
+ "viewMode": "list",
+ "limit": "1",
+ "selectionLabel": "",
+ "localizeRelations": false
+ }
+ },
+ {
+ "name": "Caption",
+ "handle": "caption",
+ "instructions": "",
+ "type": "craft\\fields\\PlainText",
+ "typesettings": {
+ "placeholder": "",
+ "multiline": "",
+ "initialRows": "4",
+ "charLimit": "",
+ "columnType": "string"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "entryTypes": [
+ {
+ "sectionHandle": "homepage",
+ "name": "Homepage",
+ "handle": "homepage",
+ "hasTitleField": false,
+ "titleLabel": "",
+ "titleFormat": "{section.name|raw}",
+ "fieldLayout": []
+ },
+ {
+ "sectionHandle": "page",
+ "name": "Page",
+ "handle": "page",
+ "hasTitleField": true,
+ "titleLabel": "Title",
+ "titleFormat": "",
+ "fieldLayout": {
+ "Content": [
+ "hero",
+ "pageBlocks"
+ ]
+ }
+ },
+ {
+ "sectionHandle": "partsKit",
+ "name": "Parts Kit",
+ "handle": "partsKit",
+ "hasTitleField": true,
+ "titleLabel": "Title",
+ "titleFormat": "",
+ "fieldLayout": {
+ "Content": [
+ "hero",
+ "pageBlocks"
+ ]
+ }
+ }
+ ]
+}
diff --git a/config/db.php b/config/db.php
new file mode 100755
index 0000000..2f30e47
--- /dev/null
+++ b/config/db.php
@@ -0,0 +1,18 @@
+ getenv('DB_DRIVER'),
+ 'server' => getenv('DB_SERVER'),
+ 'user' => getenv('DB_USER'),
+ 'password' => getenv('DB_PASSWORD'),
+ 'database' => getenv('DB_DATABASE'),
+ 'schema' => getenv('DB_SCHEMA'),
+ 'tablePrefix' => getenv('DB_TABLE_PREFIX'),
+ 'port' => getenv('DB_PORT')
+];
diff --git a/config/environment-label.php b/config/environment-label.php
new file mode 100644
index 0000000..58f505d
--- /dev/null
+++ b/config/environment-label.php
@@ -0,0 +1,8 @@
+ getenv('CRAFT_ENV_SHOW_LABEL'),
+ 'labelText' => getenv('CRAFT_ENV_LABEL_TEXT'),
+
+];
diff --git a/config/general.php b/config/general.php
new file mode 100755
index 0000000..e50df68
--- /dev/null
+++ b/config/general.php
@@ -0,0 +1,48 @@
+ [
+ // Default Week Start Day (0 = Sunday, 1 = Monday...)
+ 'defaultWeekStartDay' => 0,
+
+ // Enable CSRF Protection (recommended)
+ 'enableCsrfProtection' => true,
+
+ // Whether "index.php" should be visible in URLs
+ 'omitScriptNameInUrls' => true,
+
+ // Control Panel trigger word
+ 'cpTrigger' => 'admin',
+
+ // The secure key Craft will use for hashing and encrypting data
+ 'securityKey' => getenv('SECURITY_KEY'),
+ ],
+
+ // Dev environment settings
+ 'dev' => [
+ // Base site URL
+ 'siteUrl' => null,
+
+ // Dev Mode (see https://craftcms.com/support/dev-mode)
+ 'devMode' => true,
+ ],
+
+ // Staging environment settings
+ 'staging' => [
+ // Base site URL
+ 'siteUrl' => null,
+ ],
+
+ // Production environment settings
+ 'production' => [
+ // Base site URL
+ 'siteUrl' => null,
+ ],
+];
diff --git a/config/redactor/Simple.json b/config/redactor/Simple.json
new file mode 100755
index 0000000..f0ded2c
--- /dev/null
+++ b/config/redactor/Simple.json
@@ -0,0 +1,4 @@
+{
+ "buttons": ["bold", "italic"],
+ "toolbarFixed": true
+}
diff --git a/config/redactor/Standard.json b/config/redactor/Standard.json
new file mode 100755
index 0000000..5ba4565
--- /dev/null
+++ b/config/redactor/Standard.json
@@ -0,0 +1,5 @@
+{
+ "buttons": ["formatting", "bold", "italic", "unorderedlist", "orderedlist", "link", "image", "video"],
+ "plugins": ["source", "fullscreen", "video"],
+ "toolbarFixed": true
+}
diff --git a/config/routes.php b/config/routes.php
new file mode 100755
index 0000000..c3c332f
--- /dev/null
+++ b/config/routes.php
@@ -0,0 +1,23 @@
+' => ['template' => 'blog/_archive'],
+ *
+ * That example would match URIs such as `/blog/archive/2012`, and pass the
+ * request along to the `blog/_archive` template, providing it a `year` variable
+ * set to the value `2012`.
+ */
+
+return [
+
+];
diff --git a/craft b/craft
new file mode 100755
index 0000000..13cc74c
--- /dev/null
+++ b/craft
@@ -0,0 +1,23 @@
+#!/usr/bin/env php
+load();
+}
+
+// Load and run Craft
+define('CRAFT_ENVIRONMENT', getenv('ENVIRONMENT') ?: 'production');
+$app = require CRAFT_VENDOR_PATH.'/craftcms/cms/bootstrap/console.php';
+$exitCode = $app->run();
+exit($exitCode);
diff --git a/craft.bat b/craft.bat
new file mode 100755
index 0000000..f8bf519
--- /dev/null
+++ b/craft.bat
@@ -0,0 +1,15 @@
+@echo off
+
+rem -------------------------------------------------------------
+rem Craft command line bootstrap script for Windows
+rem -------------------------------------------------------------
+
+@setlocal
+
+set CRAFT_PATH=%~dp0
+
+if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe
+
+"%PHP_COMMAND%" "%CRAFT_PATH%craft" %*
+
+@endlocal
diff --git a/modules/Module.php b/modules/Module.php
new file mode 100755
index 0000000..6a12a5b
--- /dev/null
+++ b/modules/Module.php
@@ -0,0 +1,35 @@
+getModule('my-module')`.
+ *
+ * You can change its module ID ("my-module") to something else from
+ * config/app.php.
+ *
+ * If you want the module to get loaded on every request, uncomment this line
+ * in config/app.php:
+ *
+ * 'bootstrap' => ['my-module']
+ *
+ * Learn more about Yii module development in Yii's documentation:
+ * http://www.yiiframework.com/doc-2.0/guide-structure-modules.html
+ */
+class Module extends \yii\base\Module
+{
+ /**
+ * Initializes the module.
+ */
+ public function init()
+ {
+ Craft::setAlias('@modules', __DIR__);
+ parent::init();
+
+ // Custom initialization code goes here...
+ }
+}
diff --git a/storage/.gitignore b/storage/.gitignore
new file mode 100755
index 0000000..96f517c
--- /dev/null
+++ b/storage/.gitignore
@@ -0,0 +1,3 @@
+backups
+logs
+runtime
diff --git a/templates/.gitkeep b/templates/.gitkeep
new file mode 100755
index 0000000..e69de29
diff --git a/viget-setup b/viget-setup
new file mode 100755
index 0000000..27e4ab0
--- /dev/null
+++ b/viget-setup
@@ -0,0 +1,186 @@
+#!/usr/bin/env php
+load();
+}
+
+// By default, run the setup script
+if (empty($argv[1])) {
+ setupVigetCraft();
+} else {
+ // See what command we were passed in
+ switch ($argv[1]) {
+ case 'welcome':
+ // Display a welcome message
+ welcomeVigetCraft();
+ break;
+ default:
+ // Set up all the things!
+ setupVigetCraft();
+ break;
+ }
+}
+
+/**
+ * Display a welcome message
+ */
+function welcomeVigetCraft()
+{
+ $cdCommand = 'cd '.basename(__DIR__); // cd to the project directory where this file is located
+ $craftSetupCommand = './craft setup'; // runs the craft setup command
+ $vigetSetupCommand = './'.basename(__FILE__); // runs the viget setup command
+
+ outputString(PHP_EOL.'ATTENTION: Instead of running the command above, run the command below to setup Craft from your terminal.', Console::FG_YELLOW);
+ outputString(PHP_EOL.'It performs the setup steps in the Craft setup command, followed by some additional setup steps specific to Viget.', Console::FG_YELLOW);
+ outputString(PHP_EOL.' '.$cdCommand.' && '.$craftSetupCommand.' && '.$vigetSetupCommand, Console::FG_GREEN);
+ outputString(PHP_EOL.'Your setup is not complete until you run these two commands.', Console::FG_YELLOW);
+}
+
+/**
+ * Set up all the things!
+ */
+function setupVigetCraft()
+{
+ // Say hello
+ outputString(PHP_EOL.'Welcome to viget-setup', Console::FG_YELLOW);
+ // Install the default plugins
+ installPlugins();
+ // Run migrations to set up volumes, fields, sections and entry types
+ runMigrations();
+ // Include any final instructions
+ finalInstructions();
+ // Say goodbye
+ outputString(PHP_EOL.'Setup complete. Have a nice day!', Console::FG_YELLOW);
+}
+
+/**
+ * Install the default plugins
+ */
+function installPlugins()
+{
+ outputString(PHP_EOL.'Installing plugins', Console::FG_YELLOW);
+ $installPluginCmd = './craft install/plugin ';
+ foreach (INSTALL_PLUGINS as $pluginHandle) {
+ outputString('- installing plugin '.$pluginHandle);
+ executeShellCommand($installPluginCmd . $pluginHandle);
+ }
+}
+
+/**
+ * Run all migrations
+ */
+function runMigrations()
+{
+ // TODO Implement Craft content migrations.
+ // Architect's import command (./craft architect/import)
+ // doesn't currently do anything. Then we can remove
+ // this plugin from the project and rely on migrations.
+
+ // executeShellCommand('./craft migrate/all');
+}
+
+/**
+ * Any final instructions
+ */
+function finalInstructions() {
+ outputString(PHP_EOL.'Final instructions', Console::FG_YELLOW);
+ outputString(PHP_EOL.'1. Setup content models. Until migrations have been implemented, you’ll need to do this via the Craft admin. Click on Architect then copy and paste the contents of config/architect/setup.json and click the import button.', Console::FG_YELLOW);
+}
+
+/**
+ * Output a string to the console, using optional $args to color it, if supported
+ *
+ * @param string $string
+ *
+ * @return mixed
+ */
+function outputString($string)
+{
+ // DEBUG: streamSupportsAnsiColors below not working properly
+ // when run from composer script.
+ // $stream = \STDOUT;
+ // if (Console::streamSupportsAnsiColors($stream)) {
+ $args = func_get_args();
+ array_shift($args);
+ $string = Console::ansiFormat($string, $args);
+ // }
+
+ return Console::stdout($string.PHP_EOL);
+}
+
+/**
+ * Execute a shell command
+ *
+ * @param string $command
+ *
+ * @return string
+ */
+function executeShellCommand(string $command): string
+{
+ // Create the shell command
+ $shellCommand = new ShellCommand();
+ $shellCommand->setCommand($command);
+
+ // If we don't have proc_open, maybe we've got exec
+ if (!function_exists('proc_open') && function_exists('exec')) {
+ $shellCommand->useExec = true;
+ }
+
+ // Return the result of the command's output or error
+ if ($shellCommand->execute()) {
+ $result = $shellCommand->getOutput();
+ } else {
+ $result = $shellCommand->getError();
+ }
+
+ return $result;
+}
+
+/**
+ * Return whether a shell command exists or not
+ *
+ * @param string $command
+ *
+ * @return bool
+ */
+function shellCommandExists(string $command): bool
+{
+ $result = executeShellCommand('which '.$command);
+
+ return !empty($result);
+}
diff --git a/web/.htaccess b/web/.htaccess
new file mode 100755
index 0000000..712b922
--- /dev/null
+++ b/web/.htaccess
@@ -0,0 +1,9 @@
+
+ RewriteEngine On
+
+ # Send would-be 404 requests to Craft
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
+ RewriteRule (.+) index.php?p=$1 [QSA,L]
+
diff --git a/web/cpresources/.gitignore b/web/cpresources/.gitignore
new file mode 100755
index 0000000..d6b7ef3
--- /dev/null
+++ b/web/cpresources/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/web/index.php b/web/index.php
new file mode 100755
index 0000000..4e9d2f8
--- /dev/null
+++ b/web/index.php
@@ -0,0 +1,21 @@
+load();
+}
+
+// Load and run Craft
+define('CRAFT_ENVIRONMENT', getenv('ENVIRONMENT') ?: 'production');
+$app = require CRAFT_VENDOR_PATH.'/craftcms/cms/bootstrap/web.php';
+$app->run();
diff --git a/web/placeholders/fpo-1-1600x1200.png b/web/placeholders/fpo-1-1600x1200.png
new file mode 100644
index 0000000..49c01b2
Binary files /dev/null and b/web/placeholders/fpo-1-1600x1200.png differ
diff --git a/web/placeholders/fpo-2-1600x1200.jpg b/web/placeholders/fpo-2-1600x1200.jpg
new file mode 100644
index 0000000..8ab2259
Binary files /dev/null and b/web/placeholders/fpo-2-1600x1200.jpg differ
diff --git a/web/web.config b/web/web.config
new file mode 100755
index 0000000..4274da5
--- /dev/null
+++ b/web/web.config
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+