#############################################################################################
#############################################################################################
##
## PROJECT-DEFINITIONS
##
#############################################################################################
#############################################################################################

COPYRIGHT_TEXT       := © 2021 schukai GmbH, Released under the AGPL 3.0 License.

#############################################################################################
#############################################################################################
##
## more general block with standard definitions
##
#############################################################################################
#############################################################################################

# get Makefile directory name: http://stackoverflow.com/a/5982798/376773
THIS_MAKEFILE_PATH:=$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
THIS_DIR:=$(shell cd $(dir $(THIS_MAKEFILE_PATH));pwd)/
THIS_MAKEFILE:=$(THIS_DIR)$(THIS_MAKEFILE_PATH)

# colors
BLACK        := $(shell tput -Txterm setaf 0)
RED          := $(shell tput -Txterm setaf 1)
GREEN        := $(shell tput -Txterm setaf 2)
YELLOW       := $(shell tput -Txterm setaf 3)
LIGHTPURPLE  := $(shell tput -Txterm setaf 4)
PURPLE       := $(shell tput -Txterm setaf 5)
BLUE         := $(shell tput -Txterm setaf 6)
WHITE        := $(shell tput -Txterm setaf 7)
RESET        := $(shell tput -Txterm sgr0)

INFO    := $(GREEN)
COMMENT := $(YELLOW)

# Output control and standard outputs
MARKER           := $(BLUE)[+]$(RESET)
ERRORMARKER      := $(RED)[-]$(RESET)
## Deactivate the QUIET mode by overwriting the value with space

ifndef DEBUG
    QUIET = @
else
    QUIET = 
endif

ifndef DONTOPENBROWSER
    OPENBROWSER = true
else
    OPENBROWSER = false
endif

ECHO             := @echo
ECHOMARKER       := @echo "$(MARKER) $0"
ECHOERRORMARKER  := @echo "$(ERRORMARKER) $0"

# Use bash instead of sh
## Sets the shell used
SHELL            =  bash

# path and binaries
AWK              := awk
CP               := cp
CD               := cd
KILL             := /bin/kill
M4               := m4
MV               := mv
RM               := rm -f
MKDIR            := mkdir -p
SED              := sed
FIND             := find
SORT             := sort
TOUCH            := touch
WGET             := wget
CHMOD            := chmod
RSYNC            := rsync
DOCKER           := docker
NPX              := npx
AWS              := aws
XARGS            := xargs
GREP             := grep
NPM              := npm
make             := make
GIT              := git
NPX              := npx
NODE             := node

# Executable Programs the Installed be have to
EXECUTABLES = $(AWK) $(CP) $(KILL) $(M4) $(MV) rm mkdir $(SED) $(SORT) $(TOUCH) $(WGET) $(CHMOD) $(NPX) $(FIND) $(XARGS) $(GREP) $(NPM) $(GIT) $(NPX); 
K := $(foreach exec,$(EXECUTABLES),\
        $(if $(shell which $(exec)),some string,$(error "Missing $(exec) in PATH; please install")))

check_defined = \
    $(strip $(foreach 1,$1, \
        $(call __check_defined,$1,$(strip $(value 2)),$3)))
__check_defined = \
    $(if $(value $1),, \
      $(ECHOERRORMARKER) $(if $2, $2, $1))
      

#############################################################################################
#############################################################################################
##
## DEFAULT-TARGETS
##
#############################################################################################
#############################################################################################

# @see .PHONY https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html#Phony-Targets

.DEFAULT_GOAL := help

.PHONY: print
print:
	$(ECHO) "THIS_MAKEFILE:      $(THIS_MAKEFILE)"
	$(ECHO) "THIS_MAKEFILE_PATH: $(THIS_MAKEFILE_PATH)"
	$(ECHO) "THIS_DIR:           $(THIS_DIR)"

# Add a comment to the public targets so that it appears
# in this help Use two # characters for a help comment
.PHONY: help
help:
	@printf "${COMMENT}Usage:${RESET}\n"
	@printf " make [target] [arg=\"val\"...]\n\n"
	@printf "${COMMENT}Available targets:${RESET}\n"
	@awk '/^[a-zA-Z\-_0-9\.@]+:/ { \
		helpMessage = match(lastLine, /^## (.*)/); \
		if (helpMessage) { \
			helpCommand = substr($$1, 0, index($$1, ":")); \
			helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
			printf " ${INFO}%-22s${RESET} %s\n", helpCommand, helpMessage; \
		} \
	} \
	{ lastLine = $$0 }' $(MAKEFILE_LIST)
	@printf "\n${COMMENT}Available arguments:${RESET}\n"
	@printf "\n ${INFO}DONTOPENBROWSER${RESET}        disable open chrome"
	@printf "\n ${INFO}NEXTVERSION${RESET}            see target release => 0 – major, 1 – minor (default), 2 – patch\n"
	@awk '/^(([a-zA-Z\-_0-9\.@]+)\s=)/ { \
		helpMessage = match(lastLine, /^## (.*)/); \
		if (helpMessage) { \
			helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
			printf " ${INFO}%-22s${RESET} %s (Default: %s)\n", $$1, helpMessage, $$3; \
		} \
	} \
	{ lastLine = $$0 }' $(MAKEFILE_LIST)
	@printf "\n"

.PHONY: variables
## Print all Variables
variables:
	@$(foreach v, $(.VARIABLES), $(if $(filter file,$(origin $(v))), $(info $(INFO)$(v)$(RESET)=$($(v))$(RESET))))

#############################################################################################
#############################################################################################
##
## DIRECTORIES
##
#############################################################################################
#############################################################################################

SCRIPT_PATH          :=   $(THIS_DIR)scripts/

#############################################################################################
#############################################################################################
##
## GIT-TARGETS
##
#############################################################################################
#############################################################################################

## Current Branch-Tag
TAG := -

## Git Commit Message for git-push
MESSAGE := current status

.PHONY: git-branch
## create new branch (use TAG-Variable)
git-branch:

ifeq (, $(shell command -v uuidgen))
	$(error "No uuidgen in PATH, consider doing apt-get install uuidgen")
endif

	$(QUIET) export BRANCH="MONSTER/$(TAG)/$(shell uuidgen --random)" ; \
	$(GIT) checkout -b $${BRANCH} && \
	RESULT=$$($(GIT) push origin $$BRANCH 2>&1) && \
    RESULT2=$$($(GIT) branch --set-upstream-to=origin/$$BRANCH $$BRANCH) && \
	GITLABURL=$$(echo "$$RESULT" | tr '\n' '\#' | grep -o 'remote\:\s*https:\/\/gitlab\.schukai\.com[^ ]*' | cut -d " " -f2-9 | sed -e 's/^[ \t]*//') && \
	if $(OPENBROWSER) ; then google-chrome --profile-directory="Default" $$GITLABURL ; fi


.PHONY: git-to-master
## git checkout master, fetch and merge
git-to-master:
	$(GIT) checkout master && $(GIT) fetch -pP && $(GIT) merge


.PHONY: git-push-to-server
## git push changes to server
git-push-to-server:
	$(GIT) add -A
	$(GIT) commit -m"$(MESSAGE)"
	$(GIT) push

.PHONY: git-push
## git create branch and push changes to server
git-push: git-branch git-push-to-server

.PHONY: git-tag
## git create version tag
git-tag:
	$(GIT) tag -a "$(MONSTER_CORE_VERSION)" -m "release $(MONSTER_CORE_VERSION)"

#############################################################################################
#############################################################################################
##
## DEFAULT-DEFINITIONS
##
#############################################################################################
#############################################################################################

NODE_MODULES_DIR := $(THIS_DIR)node_modules/
NODE_MODULES_BIN_DIR := $(NODE_MODULES_DIR).bin/

WEBPACK       := $(NODE_MODULES_BIN_DIR)webpack
BABEL         := $(NODE_MODULES_BIN_DIR)babel
EXORCIST      := $(NODE_MODULES_BIN_DIR)exorcist
UGLIFYJS      := $(NODE_MODULES_BIN_DIR)uglifyjs
C8            := $(NODE_MODULES_BIN_DIR)c8
MOCHA         := $(NODE_MODULES_BIN_DIR)mocha
JSDOC         := $(NODE_MODULES_BIN_DIR)jsdoc

$(NODE_MODULES_DIR): $(THIS_DIR)package.json
	$(QUIET) $(NPM) install 


#############################################################################################
## UNTILITIES ###############################################################################
#############################################################################################

.PHONY: new-package
## init new package structure
new-package:
	$(QUIET) $(call check_defined, NAME, the variable NAME must be set)
	$(QUIET) if [ ! -n "$(NAME)" ] ; then exit 3 ; fi
	$(QUIET) $(MKDIR) $(THIS_DIR)packages/$(NAME)/
	$(QUIET) $(CP) -r $(THIS_DIR)templates/* $(THIS_DIR)packages/$(NAME)/
	$(QUIET) $(GREP) -rl '%%NAME%%' $(THIS_DIR)packages/$(NAME)/ | xargs sed -i 's/%%NAME%%/$(NAME)/g'
	

#############################################################################################
## MONSTER CORE #############################################################################
#############################################################################################

## Name of the subpackage; ex. dom 
SUBPACKAGE = 

ifneq ($(strip $(PACKAGE)),)
SUBPACKAGE=-$(PACKAGE)
endif

MONSTER_CORE_DIR                           := $(THIS_DIR)packages/monster/
							           
MONSTER_DIR                                := $(THIS_DIR)packages/monster$(SUBPACKAGE)/
MONSTER_TUTORIAL_DIR                       := $(THIS_DIR)tutorials/
MONSTER_SOURCE_DIR                         := $(MONSTER_DIR)source/
MONSTER_SOURCE_FILES                       := $(shell find $(MONSTER_SOURCE_DIR) -name '*.js')
MONSTER_RELATIVE_SOURCE_FILES              := $(shell find $(MONSTER_SOURCE_DIR) -name '*.js' -exec realpath --relative-to $(THIS_DIR) {} \;   )
MONSTER_DIST_DIR                           := $(MONSTER_DIR)dist/
MONSTER_DIST_MODULE_DIR                    := $(MONSTER_DIST_DIR)modules/
MONSTER_DIST_MODULES_FILES                 := $(subst $(MONSTER_SOURCE_DIR), $(MONSTER_DIST_MODULE_DIR), $(MONSTER_SOURCE_FILES))
MONSTER_TEST_DIR                           := $(MONSTER_DIR)test/
MONSTER_TEST_CASE_DIR                      := $(MONSTER_TEST_DIR)cases/
MONSTER_BUILD_TEST_BROWSER_DIR             := $(SCRIPT_PATH)builds/monster/test-browser/
MONSTER_BUILD_LIB_DIR                      := $(SCRIPT_PATH)builds/monster/library/
MONSTER_BUILD_LIB_DEV_DIR                  := $(SCRIPT_PATH)builds/monster/library-dev/
MONSTER_TUTORIALS_FILES_WITHVERSION        := $(shell grep -l -r -E "monster($(SUBPACKAGE))?@[0-9]+\.[0-9]+\.[0-9]+" $(MONSTER_TUTORIAL_DIR))
MONSTER_FILES_WITHVERSION                  := $(shell grep -l -r -E "monster($(SUBPACKAGE))?@[0-9]+\.[0-9]+\.[0-9]+" $(MONSTER_SOURCE_FILES)) $(MONSTER_TEST_CASE_DIR)monster.js $(MONSTER_DIR)README.md $(MONSTER_TUTORIALS_FILES_WITHVERSION) $(MONSTER_SOURCE_DIR)/types/version.js

MONSTER_CORE_VERSION                       := $(shell jq -r ".version" $(MONSTER_CORE_DIR)package.json)
MONSTER_VERSION                            := $(shell jq -r ".version" $(MONSTER_DIR)package.json)
LICENSE_C_COMMENT                          := Monster $(MONSTER_VERSION), $(COPYRIGHT_TEXT)

$(MONSTER_DIST_DIR): 
	$(ECHOMARKER) "make directory $(MONSTER_DIST_DIR)"
	$(QUIET) $(MKDIR) $(MONSTER_DIST_DIR)	


$(MONSTER_BUILD_TEST_BROWSER_DIR)node_modules/: $(MONSTER_BUILD_TEST_BROWSER_DIR)/package.json
	$(QUIET) $(CD) $(MONSTER_BUILD_TEST_BROWSER_DIR) ; $(NPM) install ; cd - 

$(MONSTER_BUILD_LIB_DIR)node_modules/: $(MONSTER_BUILD_LIB_DIR)/package.json
	$(QUIET) $(CD) $(MONSTER_BUILD_LIB_DIR) ; $(NPM) install ; cd - 

$(MONSTER_BUILD_LIB_DEV_DIR)node_modules/: $(MONSTER_BUILD_LIB_DEV_DIR)/package.json
	$(QUIET) $(CD) $(MONSTER_BUILD_LIB_DEV_DIR) ; $(NPM) install ; cd - 

.PHONY: version-monster
version-monster: $(MONSTER_TEST_CASE_DIR)monster.js $(MONSTER_SOURCE_DIR)/types/version.js $(MONSTER_DIR)README.md $(MONSTER_FILES_WITHVERSION) $(MONSTER_TUTORIALS_FILES_WITHVERSION)

$(MONSTER_FILES_WITHVERSION): $(MONSTER_DIR)package.json $(MONSTER_CORE_DIR)package.json 
	$(ECHOMARKER) "write $@ monster version $(MONSTER_VERSION) and monster core version $(MONSTER_CORE_VERSION)"
	$(QUIET) $(SED) -i -E "s/(\/monster$(SUBPACKAGE)@)([0-9]+\.[0-9]+\.[0-9]+)\//\1$(MONSTER_VERSION)\//gi" $@
	$(QUIET) $(SED) -i -E "s/(\/monster@)([0-9]+\.[0-9]+\.[0-9]+)\//\1$(MONSTER_CORE_VERSION)\//gi" $@
	$(QUIET) $(SED) -i -E "s/(monsterjs\.org\/en\/doc\/)([0-9]+\.[0-9]+\.[0-9]+)\//\1$(MONSTER_CORE_VERSION)\//gi" $@
	$(QUIET) $(AWK) -i inplace -v start='/**#@+' -v end='/**#@-*/' -v repl="    /**#@+ dont touch, replaced by make with package.json version */\n    monsterVersion = new Version('$(MONSTER_VERSION)')\n    /**#@-*/" '$$1 == start{del=2} $$1 == end{$$1 = repl; del=0} !del' $@

$(MONSTER_DIST_DIR)monster.dev.js:  $(MONSTER_SOURCE_FILES)
	$(QUIET) if [ -f $(MONSTER_DIST_DIR)monster.dev.js ] ; then $(RM) $(MONSTER_DIST_DIR)monster.dev.js ; fi;
	$(QUIET) $(CD) $(MONSTER_BUILD_LIB_DEV_DIR); $(WEBPACK) ; $(CD) -
	$(QUIET) $(SED) -i '1 i /** $(LICENSE_C_COMMENT) */' $(MONSTER_DIST_DIR)monster.dev.js 

$(MONSTER_DIST_MODULES_FILES): $(MONSTER_SOURCE_FILES)
	$(QUIET) $(BABEL) --config-file $(THIS_DIR).babelrc.json --no-comments --out-file $@ --minified --presets @babel/preset-modules $(subst $(MONSTER_DIST_MODULE_DIR), $(MONSTER_SOURCE_DIR), $@)
	$(QUIET) $(SED) -i '1 i /** $(LICENSE_C_COMMENT) */' $@

.PHONY: uglifyjs-monster
uglifyjs-monster: $(MONSTER_DIST_MODULES_FILES)
	$(ECHOMARKER) "uglifyjs monster modules"
	$(QUIET) $(UGLIFYJS) --validate --compress --mangle --comments 'schukai' --in-situ  $(MONSTER_DIST_MODULES_FILES)	
     
$(MONSTER_DIST_DIR)monster.js: $(MONSTER_SOURCE_FILES)
	$(ECHOMARKER) "build monster"
	 $(CD) $(MONSTER_BUILD_LIB_DIR); $(WEBPACK) ; $(CD) - 
	$(QUIET) $(SED) -i '1 i /** $(LICENSE_C_COMMENT) */' $(MONSTER_DIST_DIR)monster.js

.PHONY: build-monster
## create packages
build-monster: $(MONSTER_BUILD_LIB_DEV_DIR)node_modules/ $(MONSTER_BUILD_LIB_DIR)node_modules/ $(NODE_MODULES_DIR) version-monster $(MONSTER_DIST_DIR) $(MONSTER_DIST_DIR)monster.js $(MONSTER_DIST_DIR)monster.dev.js $(MONSTER_DIST_MODULES_FILES)

.PHONY: test-browser-monster
## create test-browser-monster
test-browser-monster: $(MONSTER_BUILD_TEST_BROWSER_DIR)node_modules/ create-polyfill-monster
	$(ECHOMARKER) "create browser test and start chrome"
	$(QUIET) $(FIND) $(MONSTER_TEST_CASE_DIR) -type f | $(SED) "s|^$(MONSTER_TEST_CASE_DIR)||" > $(MONSTER_TEST_DIR)web/import.js
	$(QUIET) $(SED) -i 's|^|import "../cases/|' $(MONSTER_TEST_DIR)web/import.js
	$(QUIET) $(SED) -i 's|$$|";|' $(MONSTER_TEST_DIR)web/import.js 
	$(QUIET) $(SED) -i "1 i import \"./prepare.js\";"  $(MONSTER_TEST_DIR)web/import.js
	$(QUIET) $(SED) -i "1 i /** this file was created automatically by the make target test-browser-monster */"  $(MONSTER_TEST_DIR)web/import.js
	$(QUIET) $(CD) $(MONSTER_BUILD_TEST_BROWSER_DIR); $(WEBPACK) ; $(CD) - 
	$(QUIET) $(SED) -i -E "/<h1/s_.*_  <h1 style='margin-bottom: 0.1em;'>Monster $(MONSTER_CORE_VERSION)</h1>_" $(MONSTER_TEST_DIR)web/test.html $(MONSTER_TEST_DIR)web/monster.html $(MONSTER_TEST_DIR)web/monster-dev.html 
	$(QUIET) $(SED) -i -E "/id=\"lastupdate\"/s_.*_  <div id=\"lastupdate\" style='font-size:0.7em'>last update $(shell date)</div>_" $(MONSTER_TEST_DIR)web/test.html $(MONSTER_TEST_DIR)web/monster.html $(MONSTER_TEST_DIR)web/monster-dev.html   
	$(QUIET) $(SED) -i -E "s_src=\"([\"]*)\.js.*\"_src=\"\1.js?r=$(shell date +"%T")\"_" $(MONSTER_TEST_DIR)web/test.html $(MONSTER_TEST_DIR)web/monster.html $(MONSTER_TEST_DIR)web/monster-dev.html
	$(QUIET) $(SED) -i -E "s_dist/([0-9]+\.[0-9]+\.[0-9]+)*/dist/monster_dist/$(MONSTER_CORE_VERSION)/dist/monster_" $(MONSTER_TEST_DIR)web/monster.html $(MONSTER_TEST_DIR)web/monster-dev.html
	$(QUIET) if $(OPENBROWSER) ; then google-chrome --profile-directory="Default" $(MONSTER_TEST_DIR)web/test.html ; fi

.PHONY: test-monster
## test library
test-monster: build-monster
	$(ECHOMARKER) "test monster"
	$(QUIET) $(NPX) flow      
	$(QUIET) $(MOCHA)  --recursive $(MONSTER_TEST_CASE_DIR)**

.PHONY: coverage-monster
## coverage library
coverage-monster: test-monster
	$(ECHOMARKER) "coverage monster"
	$(QUIET) $(C8) --config=$(MONSTER_DIR).c8rc.json $(MOCHA) $(MONSTER_TEST_CASE_DIR)** 
	$(QUIET) if $(OPENBROWSER) ; then google-chrome --profile-directory="Default" $(MONSTER_DIR)coverage/index.html ; fi

.PHONY: npm-publish-monster
## publish library to npm
npm-publish-monster: build-monster
	$(ECHOMARKER) "publish monster"
	$(QUIET) $(CD) $(MONSTER_DIR) ; \
		$(NPM) publish --access public ; \
		$(CD) -

.PHONY: clean-monster
## clean repos
clean-monster:
	$(QUIET) $(RM) --recursive $(MONSTER_DIST_DIR)

.PHONY: clean-all-monster
## clean repos complete
clean-all-monster:
	$(QUIET) $(RM) --recursive $(MONSTER_DIST_DIR)
	$(QUIET) $(RM) --recursive $(MONSTER_DIST_MODULES_FILES) 
	$(QUIET) $(RM) --recursive $(MONSTER_BUILD_TEST_BROWSER_DIR)node_modules/ 
	$(QUIET) $(RM) --recursive $(MONSTER_BUILD_LIB_DIR)node_modules/ 
	$(QUIET) $(RM) --recursive $(MONSTER_BUILD_LIB_DEV_DIR)node_modules/

.PHONY: transfer-monster
## transfer-monster to aws
transfer-monster:
	$(ECHOMARKER) "upload aws"
	$(QUIET) $(AWS) s3 --only-show-errors cp --recursive $(MONSTER_DIR)/ s3://monsterjs.org/dist/$(MONSTER_CORE_VERSION)/

.PHONY: release-monster
## release monster repos with new version (use NEXTVERSION)
release-monster:
	$(ECHOMARKER) "release monster"
	$(QUIET) $(SCRIPT_PATH)increase-version.sh "$(MONSTER_CORE_DIR)package.json" $(MONSTER_CORE_VERSION) $(NEXTVERSION)  
	$(QUIET) $(MAKE) clean
	$(QUIET) $(MAKE) build-monster
	$(QUIET) $(MAKE) uglifyjs-monster
	$(QUIET) $(MAKE) test-monster
	$(QUIET) $(MAKE) coverage-monster DONTOPENBROWSER=true
	$(QUIET) $(MAKE) test-browser-monster DONTOPENBROWSER=true
	$(QUIET) $(MAKE) doc-2-aws
	$(QUIET) $(MAKE) doc-build-versions-dropdown
	$(QUIET) $(MAKE) git-tag
	$(QUIET) $(MAKE) transfer-monster
	$(QUIET) $(MAKE) npm-publish-monster
	
.PHONY: create-polyfill-monster
## create polyfill.io url
create-polyfill-monster: $(MONSTER_SOURCE_FILES)
	$(ECHOMARKER) "create and replace polyfill"
	$(QUIET) $(SCRIPT_PATH)create-polyfill.sh $(MONSTER_RELATIVE_SOURCE_FILES)

#############################################################################################

.PHONY: clean
## clean 
clean:
	$(QUIET) $(RM) --recursive $(THIS_DIR)docs/
	$(QUIET) $(MAKE) clean-monster

.PHONY: clean-all
## clean-all
clean-all:
	$(QUIET) $(RM) --recursive $(NODE_MODULES_DIR)
	$(QUIET) $(RM) --recursive $(THIS_DIR)docs/
	$(QUIET) $(MAKE) clean-all-monster


.PHONY: build
## create all packages
build:
	$(QUIET) $(MAKE) build-monster
## make build-monster PACKAGE=dom

.PHONY: test
## test all packages
test: 
	$(QUIET) $(MAKE) test-monster

.PHONY: coverage
## coverage all packages
coverage: 
	$(QUIET) $(MAKE) coverage-monster

.PHONY: release
## release all packages
release: 
	$(QUIET) $(MAKE) release-monster

.PHONY: doc
## generate docs
doc: test create-polyfill-monster $(THIS_DIR)jsdoc.json
	$(ECHOMARKER) "create doc"
	$(QUIET) $(JSDOC) --tutorials $(THIS_DIR)tutorials/ -c $(THIS_DIR)jsdoc.json $(THIS_DIR)README.md
#	$(QUIET) $(GREP) -rl 'Documentation generated by' $(THIS_DIR)docs/ | $(XARGS) sed -i '/Documentation generated by/d'

doc-2-aws: doc doc-build-versions-dropdown
	$(QUIET) $(AWS) s3 --only-show-errors cp --recursive $(THIS_DIR)docs/ s3://monsterjs.org/en/doc/$(MONSTER_CORE_VERSION)/

.PHONY: doc-build-versions-dropdown	
doc-build-versions-dropdown: $(THIS_DIR)docs/monster-versions.js

$(THIS_DIR)docs/monster-versions.js: $(THIS_DIR)package.json $(MONSTER_CORE_DIR)package.json
	$(QUIET) $(NODE) $(SCRIPT_PATH)build-versions-dropdown.js 
	$(QUIET) $(AWS) s3 --only-show-errors cp $(THIS_DIR)docs/monster-versions.js s3://monsterjs.org/js/doc/monster-versions.js