summaryrefslogtreecommitdiff
path: root/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands
diff options
context:
space:
mode:
authorBenjamin Sanders <ben@Benjamins-MacBook-Pro.local>2025-10-11 10:34:24 -0400
committerBenjamin Sanders <ben@Benjamins-MacBook-Pro.local>2025-10-11 10:34:24 -0400
commit5571dc766e2143e39762ff0b47c41d1c2e154f4c (patch)
treef4f124d314a7e76c04484515aa0fd1f2e271a601 /vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands
parent359f3309c97fc894b63e0a295c76ab298504d635 (diff)
Vendor bundled gems for deployment
Diffstat (limited to 'vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands')
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/build.rb82
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/clean.rb44
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/doctor.rb177
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/help.rb34
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new.rb168
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new_theme.rb39
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve.rb372
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/live_reload_reactor.rb119
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/livereload_assets/livereload.js1183
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/mime_types_charset.json71
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/servlet.rb206
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/websockets.rb81
12 files changed, 2576 insertions, 0 deletions
diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/build.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/build.rb
new file mode 100644
index 0000000..204b2a1
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/build.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+module Jekyll
+ module Commands
+ class Build < Command
+ class << self
+ # Create the Mercenary command for the Jekyll CLI for this Command
+ def init_with_program(prog)
+ prog.command(:build) do |c|
+ c.syntax "build [options]"
+ c.description "Build your site"
+ c.alias :b
+
+ add_build_options(c)
+
+ c.action do |_, options|
+ options["serving"] = false
+ process_with_graceful_fail(c, options, self)
+ end
+ end
+ end
+
+ # Build your jekyll site
+ # Continuously watch if `watch` is set to true in the config.
+ def process(options)
+ # Adjust verbosity quickly
+ Jekyll.logger.adjust_verbosity(options)
+
+ options = configuration_from_options(options)
+ site = Jekyll::Site.new(options)
+
+ if options.fetch("skip_initial_build", false)
+ Jekyll.logger.warn "Build Warning:",
+ "Skipping the initial build. This may result in an out-of-date site."
+ else
+ build(site, options)
+ end
+
+ if options.fetch("detach", false)
+ Jekyll.logger.info "Auto-regeneration:",
+ "disabled when running server detached."
+ elsif options.fetch("watch", false)
+ watch(site, options)
+ else
+ Jekyll.logger.info "Auto-regeneration:", "disabled. Use --watch to enable."
+ end
+ end
+
+ # Build your Jekyll site.
+ #
+ # site - the Jekyll::Site instance to build
+ # options - A Hash of options passed to the command
+ #
+ # Returns nothing.
+ def build(site, options)
+ t = Time.now
+ source = File.expand_path(options["source"])
+ destination = File.expand_path(options["destination"])
+ incremental = options["incremental"]
+ Jekyll.logger.info "Source:", source
+ Jekyll.logger.info "Destination:", destination
+ Jekyll.logger.info "Incremental build:",
+ (incremental ? "enabled" : "disabled. Enable with --incremental")
+ Jekyll.logger.info "Generating..."
+ process_site(site)
+ Jekyll.logger.info "", "done in #{(Time.now - t).round(3)} seconds."
+ end
+
+ # Private: Watch for file changes and rebuild the site.
+ #
+ # site - A Jekyll::Site instance
+ # options - A Hash of options passed to the command
+ #
+ # Returns nothing.
+ def watch(site, options)
+ External.require_with_graceful_fail "jekyll-watch"
+ Jekyll::Watcher.watch(options, site)
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/clean.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/clean.rb
new file mode 100644
index 0000000..9b657a4
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/clean.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+module Jekyll
+ module Commands
+ class Clean < Command
+ class << self
+ def init_with_program(prog)
+ prog.command(:clean) do |c|
+ c.syntax "clean [subcommand]"
+ c.description "Clean the site (removes site output and metadata file) without building."
+
+ add_build_options(c)
+
+ c.action do |_, options|
+ Jekyll::Commands::Clean.process(options)
+ end
+ end
+ end
+
+ def process(options)
+ options = configuration_from_options(options)
+ destination = options["destination"]
+ metadata_file = File.join(options["source"], ".jekyll-metadata")
+ cache_dir = File.join(options["source"], options["cache_dir"])
+ sass_cache = ".sass-cache"
+
+ remove(destination, :checker_func => :directory?)
+ remove(metadata_file, :checker_func => :file?)
+ remove(cache_dir, :checker_func => :directory?)
+ remove(sass_cache, :checker_func => :directory?)
+ end
+
+ def remove(filename, checker_func: :file?)
+ if File.public_send(checker_func, filename)
+ Jekyll.logger.info "Cleaner:", "Removing #{filename}..."
+ FileUtils.rm_rf(filename)
+ else
+ Jekyll.logger.info "Cleaner:", "Nothing to do for #{filename}."
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/doctor.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/doctor.rb
new file mode 100644
index 0000000..eec7133
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/doctor.rb
@@ -0,0 +1,177 @@
+# frozen_string_literal: true
+
+module Jekyll
+ module Commands
+ class Doctor < Command
+ class << self
+ def init_with_program(prog)
+ prog.command(:doctor) do |c|
+ c.syntax "doctor"
+ c.description "Search site and print specific deprecation warnings"
+ c.alias(:hyde)
+
+ c.option "config", "--config CONFIG_FILE[,CONFIG_FILE2,...]", Array,
+ "Custom configuration file"
+
+ c.action do |_, options|
+ Jekyll::Commands::Doctor.process(options)
+ end
+ end
+ end
+
+ def process(options)
+ site = Jekyll::Site.new(configuration_from_options(options))
+ site.reset
+ site.read
+ site.generate
+
+ if healthy?(site)
+ Jekyll.logger.info "Your test results", "are in. Everything looks fine."
+ else
+ abort
+ end
+ end
+
+ def healthy?(site)
+ [
+ fsnotify_buggy?(site),
+ !deprecated_relative_permalinks(site),
+ !conflicting_urls(site),
+ !urls_only_differ_by_case(site),
+ proper_site_url?(site),
+ properly_gathered_posts?(site),
+ ].all?
+ end
+
+ def properly_gathered_posts?(site)
+ return true if site.config["collections_dir"].empty?
+
+ posts_at_root = site.in_source_dir("_posts")
+ return true unless File.directory?(posts_at_root)
+
+ Jekyll.logger.warn "Warning:",
+ "Detected '_posts' directory outside custom `collections_dir`!"
+ Jekyll.logger.warn "",
+ "Please move '#{posts_at_root}' into the custom directory at " \
+ "'#{site.in_source_dir(site.config["collections_dir"])}'"
+ false
+ end
+
+ def deprecated_relative_permalinks(site)
+ if site.config["relative_permalinks"]
+ Jekyll::Deprecator.deprecation_message "Your site still uses relative permalinks, " \
+ "which was removed in Jekyll v3.0.0."
+ true
+ end
+ end
+
+ def conflicting_urls(site)
+ conflicting_urls = false
+ destination_map(site).each do |dest, paths|
+ next unless paths.size > 1
+
+ conflicting_urls = true
+ Jekyll.logger.warn "Conflict:",
+ "The following destination is shared by multiple files."
+ Jekyll.logger.warn "", "The written file may end up with unexpected contents."
+ Jekyll.logger.warn "", dest.to_s.cyan
+ paths.each { |path| Jekyll.logger.warn "", " - #{path}" }
+ Jekyll.logger.warn ""
+ end
+ conflicting_urls
+ end
+
+ def fsnotify_buggy?(_site)
+ return true unless Utils::Platforms.osx?
+
+ if Dir.pwd != `pwd`.strip
+ Jekyll.logger.error <<~STR
+ We have detected that there might be trouble using fsevent on your
+ operating system, you can read https://github.com/thibaudgg/rb-fsevent/wiki/no-fsevents-fired-(OSX-bug)
+ for possible workarounds or you can work around it immediately
+ with `--force-polling`.
+ STR
+
+ false
+ end
+
+ true
+ end
+
+ def urls_only_differ_by_case(site)
+ urls_only_differ_by_case = false
+ urls = case_insensitive_urls(site.pages + site.docs_to_write, site.dest)
+ urls.each_value do |real_urls|
+ next unless real_urls.uniq.size > 1
+
+ urls_only_differ_by_case = true
+ Jekyll.logger.warn "Warning:", "The following URLs only differ by case. On a " \
+ "case-insensitive file system one of the URLs will be " \
+ "overwritten by the other: #{real_urls.join(", ")}"
+ end
+ urls_only_differ_by_case
+ end
+
+ def proper_site_url?(site)
+ url = site.config["url"]
+ [
+ url_exists?(url),
+ url_valid?(url),
+ url_absolute(url),
+ ].all?
+ end
+
+ private
+
+ def destination_map(site)
+ {}.tap do |result|
+ site.each_site_file do |thing|
+ next if allow_used_permalink?(thing)
+
+ dest_path = thing.destination(site.dest)
+ (result[dest_path] ||= []) << thing.path
+ end
+ end
+ end
+
+ def allow_used_permalink?(item)
+ defined?(JekyllRedirectFrom) && item.is_a?(JekyllRedirectFrom::RedirectPage)
+ end
+
+ def case_insensitive_urls(things, destination)
+ things.each_with_object({}) do |thing, memo|
+ dest = thing.destination(destination)
+ (memo[dest.downcase] ||= []) << dest
+ end
+ end
+
+ def url_exists?(url)
+ return true unless url.nil? || url.empty?
+
+ Jekyll.logger.warn "Warning:", "You didn't set an URL in the config file, you may " \
+ "encounter problems with some plugins."
+ false
+ end
+
+ def url_valid?(url)
+ Addressable::URI.parse(url)
+ true
+ # Addressable::URI#parse only raises a TypeError
+ # https://github.com/sporkmonger/addressable/blob/0a0e96acb17225f9b1c9cab0bad332b448934c9a/lib/addressable/uri.rb#L103
+ rescue TypeError
+ Jekyll.logger.warn "Warning:", "The site URL does not seem to be valid, " \
+ "check the value of `url` in your config file."
+ false
+ end
+
+ def url_absolute(url)
+ return true if url.is_a?(String) && Addressable::URI.parse(url).absolute?
+
+ Jekyll.logger.warn "Warning:", "Your site URL does not seem to be absolute, " \
+ "check the value of `url` in your config file."
+ false
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/help.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/help.rb
new file mode 100644
index 0000000..90403df
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/help.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Jekyll
+ module Commands
+ class Help < Command
+ class << self
+ def init_with_program(prog)
+ prog.command(:help) do |c|
+ c.syntax "help [subcommand]"
+ c.description "Show the help message, optionally for a given subcommand."
+
+ c.action do |args, _|
+ cmd = (args.first || "").to_sym
+ if args.empty?
+ Jekyll.logger.info prog.to_s
+ elsif prog.has_command? cmd
+ Jekyll.logger.info prog.commands[cmd].to_s
+ else
+ invalid_command(prog, cmd)
+ abort
+ end
+ end
+ end
+ end
+
+ def invalid_command(prog, cmd)
+ Jekyll.logger.error "Error:",
+ "Hmm... we don't know what the '#{cmd}' command is."
+ Jekyll.logger.info "Valid commands:", prog.commands.keys.join(", ")
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new.rb
new file mode 100644
index 0000000..161a3dd
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new.rb
@@ -0,0 +1,168 @@
+# frozen_string_literal: true
+
+require "erb"
+
+module Jekyll
+ module Commands
+ class New < Command
+ class << self
+ def init_with_program(prog)
+ prog.command(:new) do |c|
+ c.syntax "new PATH"
+ c.description "Creates a new Jekyll site scaffold in PATH"
+
+ c.option "force", "--force", "Force creation even if PATH already exists"
+ c.option "blank", "--blank", "Creates scaffolding but with empty files"
+ c.option "skip-bundle", "--skip-bundle", "Skip 'bundle install'"
+
+ c.action do |args, options|
+ Jekyll::Commands::New.process(args, options)
+ end
+ end
+ end
+
+ def process(args, options = {})
+ raise ArgumentError, "You must specify a path." if args.empty?
+
+ new_blog_path = File.expand_path(args.join(" "), Dir.pwd)
+ FileUtils.mkdir_p new_blog_path
+ if preserve_source_location?(new_blog_path, options)
+ Jekyll.logger.error "Conflict:", "#{new_blog_path} exists and is not empty."
+ Jekyll.logger.abort_with "", "Ensure #{new_blog_path} is empty or else try again " \
+ "with `--force` to proceed and overwrite any files."
+ end
+
+ if options["blank"]
+ create_blank_site new_blog_path
+ else
+ create_site new_blog_path
+ end
+
+ after_install(new_blog_path, options)
+ end
+
+ def blank_template
+ File.expand_path("../../blank_template", __dir__)
+ end
+
+ def create_blank_site(path)
+ FileUtils.cp_r blank_template + "/.", path
+ FileUtils.chmod_R "u+w", path
+
+ Dir.chdir(path) do
+ FileUtils.mkdir(%w(_data _drafts _includes _posts))
+ end
+ end
+
+ def scaffold_post_content
+ ERB.new(File.read(File.expand_path(scaffold_path, site_template))).result
+ end
+
+ # Internal: Gets the filename of the sample post to be created
+ #
+ # Returns the filename of the sample post, as a String
+ def initialized_post_name
+ "_posts/#{Time.now.strftime("%Y-%m-%d")}-welcome-to-jekyll.markdown"
+ end
+
+ private
+
+ def gemfile_contents
+ <<~RUBY
+ source "https://rubygems.org"
+ # Hello! This is where you manage which Jekyll version is used to run.
+ # When you want to use a different version, change it below, save the
+ # file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
+ #
+ # bundle exec jekyll serve
+ #
+ # This will help ensure the proper Jekyll version is running.
+ # Happy Jekylling!
+ gem "jekyll", "~> #{Jekyll::VERSION}"
+ # This is the default theme for new Jekyll sites. You may change this to anything you like.
+ gem "minima", "~> 2.5"
+ # If you want to use GitHub Pages, remove the "gem "jekyll"" above and
+ # uncomment the line below. To upgrade, run `bundle update github-pages`.
+ # gem "github-pages", group: :jekyll_plugins
+ # If you have any plugins, put them here!
+ group :jekyll_plugins do
+ gem "jekyll-feed", "~> 0.12"
+ end
+
+ # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
+ # and associated library.
+ platforms :mingw, :x64_mingw, :mswin, :jruby do
+ gem "tzinfo", ">= 1", "< 3"
+ gem "tzinfo-data"
+ end
+
+ # Performance-booster for watching directories on Windows
+ gem "wdm", "~> 0.1", :platforms => [:mingw, :x64_mingw, :mswin]
+
+ # Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem
+ # do not have a Java counterpart.
+ gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby]
+ RUBY
+ end
+
+ def create_site(new_blog_path)
+ create_sample_files new_blog_path
+
+ File.write(File.expand_path(initialized_post_name, new_blog_path), scaffold_post_content)
+
+ File.write(File.expand_path("Gemfile", new_blog_path), gemfile_contents)
+ end
+
+ def preserve_source_location?(path, options)
+ !options["force"] && !Dir["#{path}/**/*"].empty?
+ end
+
+ def create_sample_files(path)
+ FileUtils.cp_r site_template + "/.", path
+ FileUtils.chmod_R "u+w", path
+ FileUtils.rm File.expand_path(scaffold_path, path)
+ end
+
+ def site_template
+ File.expand_path("../../site_template", __dir__)
+ end
+
+ def scaffold_path
+ "_posts/0000-00-00-welcome-to-jekyll.markdown.erb"
+ end
+
+ # After a new blog has been created, print a success notification and
+ # then automatically execute bundle install from within the new blog dir
+ # unless the user opts to generate a blank blog or skip 'bundle install'.
+
+ def after_install(path, options = {})
+ unless options["blank"] || options["skip-bundle"]
+ begin
+ require "bundler"
+ bundle_install path
+ rescue LoadError
+ Jekyll.logger.info "Could not load Bundler. Bundle install skipped."
+ end
+ end
+
+ Jekyll.logger.info "New jekyll site installed in #{path.cyan}."
+ Jekyll.logger.info "Bundle install skipped." if options["skip-bundle"]
+ end
+
+ def bundle_install(path)
+ Jekyll.logger.info "Running bundle install in #{path.cyan}..."
+ Dir.chdir(path) do
+ exe = Gem.bin_path("bundler", "bundle")
+ process, output = Jekyll::Utils::Exec.run("ruby", exe, "install")
+
+ output.to_s.each_line do |line|
+ Jekyll.logger.info("Bundler:".green, line.strip) unless line.to_s.empty?
+ end
+
+ raise SystemExit unless process.success?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new_theme.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new_theme.rb
new file mode 100644
index 0000000..3419d17
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new_theme.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require "erb"
+
+module Jekyll
+ module Commands
+ class NewTheme < Jekyll::Command
+ class << self
+ def init_with_program(prog)
+ prog.command(:"new-theme") do |c|
+ c.syntax "new-theme NAME"
+ c.description "Creates a new Jekyll theme scaffold"
+ c.option "code_of_conduct", "-c", "--code-of-conduct",
+ "Include a Code of Conduct. (defaults to false)"
+
+ c.action do |args, opts|
+ Jekyll::Commands::NewTheme.process(args, opts)
+ end
+ end
+ end
+
+ def process(args, opts)
+ if !args || args.empty?
+ raise Jekyll::Errors::InvalidThemeName, "You must specify a theme name."
+ end
+
+ new_theme_name = args.join("_")
+ theme = Jekyll::ThemeBuilder.new(new_theme_name, opts)
+ Jekyll.logger.abort_with "Conflict:", "#{theme.path} already exists." if theme.path.exist?
+
+ theme.create!
+ Jekyll.logger.info "Your new Jekyll theme, #{theme.name.cyan}, " \
+ "is ready for you in #{theme.path.to_s.cyan}!"
+ Jekyll.logger.info "For help getting started, read #{theme.path}/README.md."
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve.rb
new file mode 100644
index 0000000..6abd893
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve.rb
@@ -0,0 +1,372 @@
+# frozen_string_literal: true
+
+module Jekyll
+ module Commands
+ class Serve < Command
+ # Similar to the pattern in Utils::ThreadEvent except we are maintaining the
+ # state of @running instead of just signaling an event. We have to maintain this
+ # state since Serve is just called via class methods instead of an instance
+ # being created each time.
+ @mutex = Mutex.new
+ @run_cond = ConditionVariable.new
+ @running = false
+
+ class << self
+ COMMAND_OPTIONS = {
+ "ssl_cert" => ["--ssl-cert [CERT]", "X.509 (SSL) certificate."],
+ "host" => ["host", "-H", "--host [HOST]", "Host to bind to"],
+ "open_url" => ["-o", "--open-url", "Launch your site in a browser"],
+ "detach" => ["-B", "--detach",
+ "Run the server in the background",],
+ "ssl_key" => ["--ssl-key [KEY]", "X.509 (SSL) Private Key."],
+ "port" => ["-P", "--port [PORT]", "Port to listen on"],
+ "show_dir_listing" => ["--show-dir-listing",
+ "Show a directory listing instead of loading " \
+ "your index file.",],
+ "skip_initial_build" => ["skip_initial_build", "--skip-initial-build",
+ "Skips the initial site build which occurs before " \
+ "the server is started.",],
+ "livereload" => ["-l", "--livereload",
+ "Use LiveReload to automatically refresh browsers",],
+ "livereload_ignore" => ["--livereload-ignore GLOB1[,GLOB2[,...]]",
+ Array,
+ "Files for LiveReload to ignore. " \
+ "Remember to quote the values so your shell " \
+ "won't expand them",],
+ "livereload_min_delay" => ["--livereload-min-delay [SECONDS]",
+ "Minimum reload delay",],
+ "livereload_max_delay" => ["--livereload-max-delay [SECONDS]",
+ "Maximum reload delay",],
+ "livereload_port" => ["--livereload-port [PORT]", Integer,
+ "Port for LiveReload to listen on",],
+ }.freeze
+
+ DIRECTORY_INDEX = %w(
+ index.htm
+ index.html
+ index.rhtml
+ index.xht
+ index.xhtml
+ index.cgi
+ index.xml
+ index.json
+ ).freeze
+
+ LIVERELOAD_PORT = 35_729
+ LIVERELOAD_DIR = File.join(__dir__, "serve", "livereload_assets")
+
+ attr_reader :mutex, :run_cond, :running
+ alias_method :running?, :running
+
+ def init_with_program(prog)
+ prog.command(:serve) do |cmd|
+ cmd.description "Serve your site locally"
+ cmd.syntax "serve [options]"
+ cmd.alias :server
+ cmd.alias :s
+
+ add_build_options(cmd)
+ COMMAND_OPTIONS.each do |key, val|
+ cmd.option key, *val
+ end
+
+ cmd.action do |_, opts|
+ opts["serving"] = true
+ opts["watch"] = true unless opts.key?("watch")
+
+ # Set the reactor to nil so any old reactor will be GCed.
+ # We can't unregister a hook so while running tests we don't want to
+ # inadvertently keep using a reactor created by a previous test.
+ @reload_reactor = nil
+
+ config = configuration_from_options(opts)
+ config["url"] = default_url(config) if Jekyll.env == "development"
+
+ process_with_graceful_fail(cmd, config, Build, Serve)
+ end
+ end
+ end
+
+ #
+
+ def process(opts)
+ opts = configuration_from_options(opts)
+ destination = opts["destination"]
+ if opts["livereload"]
+ opts["livereload_port"] ||= LIVERELOAD_PORT
+ validate_options(opts)
+ register_reload_hooks(opts)
+ end
+ setup(destination)
+
+ start_up_webrick(opts, destination)
+ end
+
+ def shutdown
+ @server.shutdown if running?
+ end
+
+ # Perform logical validation of CLI options
+
+ private
+
+ def validate_options(opts)
+ if opts["livereload"]
+ if opts["detach"]
+ Jekyll.logger.warn "Warning:", "--detach and --livereload are mutually exclusive. " \
+ "Choosing --livereload"
+ opts["detach"] = false
+ end
+ if opts["ssl_cert"] || opts["ssl_key"]
+ # This is not technically true. LiveReload works fine over SSL, but
+ # EventMachine's SSL support in Windows requires building the gem's
+ # native extensions against OpenSSL and that proved to be a process
+ # so tedious that expecting users to do it is a non-starter.
+ Jekyll.logger.abort_with "Error:", "LiveReload does not support SSL"
+ end
+ unless opts["watch"]
+ # Using livereload logically implies you want to watch the files
+ opts["watch"] = true
+ end
+ elsif %w(livereload_min_delay
+ livereload_max_delay
+ livereload_ignore
+ livereload_port).any? { |o| opts[o] }
+ Jekyll.logger.abort_with "--livereload-min-delay, --livereload-max-delay, " \
+ "--livereload-ignore, and --livereload-port require " \
+ "the --livereload option."
+ end
+ end
+
+ def register_reload_hooks(opts)
+ require_relative "serve/live_reload_reactor"
+ @reload_reactor = LiveReloadReactor.new
+
+ Jekyll::Hooks.register(:site, :post_render) do |site|
+ @changed_pages = []
+ site.each_site_file do |item|
+ @changed_pages << item if site.regenerator.regenerate?(item)
+ end
+ end
+
+ # A note on ignoring files: LiveReload errs on the side of reloading when it
+ # comes to the message it gets. If, for example, a page is ignored but a CSS
+ # file linked in the page isn't, the page will still be reloaded if the CSS
+ # file is contained in the message sent to LiveReload. Additionally, the
+ # path matching is very loose so that a message to reload "/" will always
+ # lead the page to reload since every page starts with "/".
+ Jekyll::Hooks.register(:site, :post_write) do
+ if @changed_pages && @reload_reactor && @reload_reactor.running?
+ ignore, @changed_pages = @changed_pages.partition do |p|
+ Array(opts["livereload_ignore"]).any? do |filter|
+ File.fnmatch(filter, p.relative_path)
+ end
+ end
+ Jekyll.logger.debug "LiveReload:", "Ignoring #{ignore.map(&:relative_path)}"
+ @reload_reactor.reload(@changed_pages)
+ end
+ @changed_pages = nil
+ end
+ end
+
+ # Do a base pre-setup of WEBRick so that everything is in place
+ # when we get ready to party, checking for an setting up an error page
+ # and making sure our destination exists.
+ #
+ # rubocop:disable Security/IoMethods
+ def setup(destination)
+ require_relative "serve/servlet"
+
+ FileUtils.mkdir_p(destination)
+ if File.exist?(File.join(destination, "404.html"))
+ WEBrick::HTTPResponse.class_eval do
+ def create_error_page
+ @header["Content-Type"] = "text/html; charset=UTF-8"
+ @body = IO.read(File.join(@config[:DocumentRoot], "404.html"))
+ end
+ end
+ end
+ end
+ # rubocop:enable Security/IoMethods
+
+ def webrick_opts(opts)
+ opts = {
+ :JekyllOptions => opts,
+ :DoNotReverseLookup => true,
+ :MimeTypes => mime_types,
+ :MimeTypesCharset => mime_types_charset,
+ :DocumentRoot => opts["destination"],
+ :StartCallback => start_callback(opts["detach"]),
+ :StopCallback => stop_callback(opts["detach"]),
+ :BindAddress => opts["host"],
+ :Port => opts["port"],
+ :DirectoryIndex => DIRECTORY_INDEX,
+ }
+
+ opts[:DirectoryIndex] = [] if opts[:JekyllOptions]["show_dir_listing"]
+
+ enable_ssl(opts)
+ enable_logging(opts)
+ opts
+ end
+
+ def start_up_webrick(opts, destination)
+ @reload_reactor.start(opts) if opts["livereload"]
+
+ @server = WEBrick::HTTPServer.new(webrick_opts(opts)).tap { |o| o.unmount("") }
+ @server.mount(opts["baseurl"].to_s, Servlet, destination, file_handler_opts)
+
+ Jekyll.logger.info "Server address:", server_address(@server, opts)
+ launch_browser @server, opts if opts["open_url"]
+ boot_or_detach @server, opts
+ end
+
+ # Recreate NondisclosureName under utf-8 circumstance
+ def file_handler_opts
+ WEBrick::Config::FileHandler.merge(
+ :FancyIndexing => true,
+ :NondisclosureName => [
+ ".ht*", "~*",
+ ]
+ )
+ end
+
+ def server_address(server, options = {})
+ format_url(
+ server.config[:SSLEnable],
+ server.config[:BindAddress],
+ server.config[:Port],
+ options["baseurl"]
+ )
+ end
+
+ def format_url(ssl_enabled, address, port, baseurl = nil)
+ format("%<prefix>s://%<address>s:%<port>i%<baseurl>s",
+ :prefix => ssl_enabled ? "https" : "http",
+ :address => address,
+ :port => port,
+ :baseurl => baseurl ? "#{baseurl}/" : "")
+ end
+
+ def default_url(opts)
+ config = configuration_from_options(opts)
+ format_url(
+ config["ssl_cert"] && config["ssl_key"],
+ config["host"] == "127.0.0.1" ? "localhost" : config["host"],
+ config["port"]
+ )
+ end
+
+ def launch_browser(server, opts)
+ address = server_address(server, opts)
+ return system "start", address if Utils::Platforms.windows?
+ return system "xdg-open", address if Utils::Platforms.linux?
+ return system "open", address if Utils::Platforms.osx?
+
+ Jekyll.logger.error "Refusing to launch browser. Platform launcher unknown."
+ end
+
+ # Keep in our area with a thread or detach the server as requested
+ # by the user. This method determines what we do based on what you
+ # ask us to do.
+ def boot_or_detach(server, opts)
+ if opts["detach"]
+ pid = Process.fork do
+ # Detach the process from controlling terminal
+ $stdin.reopen("/dev/null", "r")
+ $stdout.reopen("/dev/null", "w")
+ $stderr.reopen("/dev/null", "w")
+ server.start
+ end
+
+ Process.detach(pid)
+ Jekyll.logger.info "Server detached with pid '#{pid}'.",
+ "Run `pkill -f jekyll' or `kill -9 #{pid}' to stop the server."
+
+ # Exit without running `at_exit` inherited by the forked process.
+ Process.exit! 0
+ else
+ t = Thread.new { server.start }
+ trap("INT") { server.shutdown }
+ t.join
+ end
+ end
+
+ # Make the stack verbose if the user requests it.
+ def enable_logging(opts)
+ opts[:AccessLog] = []
+ level = WEBrick::Log.const_get(opts[:JekyllOptions]["verbose"] ? :DEBUG : :WARN)
+ opts[:Logger] = WEBrick::Log.new($stdout, level)
+ end
+
+ # Add SSL to the stack if the user triggers --enable-ssl and they
+ # provide both types of certificates commonly needed. Raise if they
+ # forget to add one of the certificates.
+ def enable_ssl(opts)
+ cert, key, src =
+ opts[:JekyllOptions].values_at("ssl_cert", "ssl_key", "source")
+
+ return if cert.nil? && key.nil?
+ raise "Missing --ssl_cert or --ssl_key. Both are required." unless cert && key
+
+ require "openssl"
+ require "webrick/https"
+
+ opts[:SSLCertificate] = OpenSSL::X509::Certificate.new(read_file(src, cert))
+ begin
+ opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(read_file(src, key))
+ rescue StandardError
+ if defined?(OpenSSL::PKey::EC)
+ opts[:SSLPrivateKey] = OpenSSL::PKey::EC.new(read_file(src, key))
+ else
+ raise
+ end
+ end
+ opts[:SSLEnable] = true
+ end
+
+ def start_callback(detached)
+ unless detached
+ proc do
+ mutex.synchronize do
+ # Block until EventMachine reactor starts
+ @reload_reactor&.started_event&.wait
+ @running = true
+ Jekyll.logger.info("Server running...", "press ctrl-c to stop.")
+ @run_cond.broadcast
+ end
+ end
+ end
+ end
+
+ def stop_callback(detached)
+ unless detached
+ proc do
+ mutex.synchronize do
+ unless @reload_reactor.nil?
+ @reload_reactor.stop
+ @reload_reactor.stopped_event.wait
+ end
+ @running = false
+ @run_cond.broadcast
+ end
+ end
+ end
+ end
+
+ def mime_types
+ file = File.expand_path("../mime.types", __dir__)
+ WEBrick::HTTPUtils.load_mime_types(file)
+ end
+
+ def mime_types_charset
+ SafeYAML.load_file(File.expand_path("serve/mime_types_charset.json", __dir__))
+ end
+
+ def read_file(source_dir, file_path)
+ File.read(Jekyll.sanitized_path(source_dir, file_path))
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/live_reload_reactor.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/live_reload_reactor.rb
new file mode 100644
index 0000000..78f9408
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/live_reload_reactor.rb
@@ -0,0 +1,119 @@
+# frozen_string_literal: true
+
+require "em-websocket"
+
+require_relative "websockets"
+
+module Jekyll
+ module Commands
+ class Serve
+ class LiveReloadReactor
+ attr_reader :started_event, :stopped_event, :thread
+
+ def initialize
+ @websockets = []
+ @connections_count = 0
+ @started_event = Utils::ThreadEvent.new
+ @stopped_event = Utils::ThreadEvent.new
+ end
+
+ def stop
+ # There is only one EventMachine instance per Ruby process so stopping
+ # it here will stop the reactor thread we have running.
+ EM.stop if EM.reactor_running?
+ Jekyll.logger.debug "LiveReload Server:", "halted"
+ end
+
+ def running?
+ EM.reactor_running?
+ end
+
+ def handle_websockets_event(websocket)
+ websocket.onopen { |handshake| connect(websocket, handshake) }
+ websocket.onclose { disconnect(websocket) }
+ websocket.onmessage { |msg| print_message(msg) }
+ websocket.onerror { |error| log_error(error) }
+ end
+
+ def start(opts)
+ @thread = Thread.new do
+ # Use epoll if the kernel supports it
+ EM.epoll
+ EM.run do
+ EM.error_handler { |e| log_error(e) }
+
+ EM.start_server(
+ opts["host"],
+ opts["livereload_port"],
+ HttpAwareConnection,
+ opts
+ ) do |ws|
+ handle_websockets_event(ws)
+ end
+
+ # Notify blocked threads that EventMachine has started or shutdown
+ EM.schedule { @started_event.set }
+ EM.add_shutdown_hook { @stopped_event.set }
+
+ Jekyll.logger.info "LiveReload address:",
+ "http://#{opts["host"]}:#{opts["livereload_port"]}"
+ end
+ end
+ @thread.abort_on_exception = true
+ end
+
+ # For a description of the protocol see
+ # http://feedback.livereload.com/knowledgebase/articles/86174-livereload-protocol
+ def reload(pages)
+ pages.each do |p|
+ json_message = JSON.dump(
+ :command => "reload",
+ :path => p.url,
+ :liveCSS => true
+ )
+
+ Jekyll.logger.debug "LiveReload:", "Reloading URL #{p.url.inspect}"
+ @websockets.each { |ws| ws.send(json_message) }
+ end
+ end
+
+ private
+
+ def connect(websocket, handshake)
+ @connections_count += 1
+ if @connections_count == 1
+ message = "Browser connected"
+ message += " over SSL/TLS" if handshake.secure?
+ Jekyll.logger.info "LiveReload:", message
+ end
+ websocket.send(
+ JSON.dump(
+ :command => "hello",
+ :protocols => ["http://livereload.com/protocols/official-7"],
+ :serverName => "jekyll"
+ )
+ )
+
+ @websockets << websocket
+ end
+
+ def disconnect(websocket)
+ @websockets.delete(websocket)
+ end
+
+ def print_message(json_message)
+ msg = JSON.parse(json_message)
+ # Not sure what the 'url' command even does in LiveReload. The spec is silent
+ # on its purpose.
+ Jekyll.logger.info "LiveReload:", "Browser URL: #{msg["url"]}" if msg["command"] == "url"
+ end
+
+ def log_error(error)
+ Jekyll.logger.error "LiveReload experienced an error. " \
+ "Run with --trace for more information."
+ raise error
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/livereload_assets/livereload.js b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/livereload_assets/livereload.js
new file mode 100644
index 0000000..eee60ec
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/livereload_assets/livereload.js
@@ -0,0 +1,1183 @@
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+(function() {
+ var Connector, PROTOCOL_6, PROTOCOL_7, Parser, Version, _ref;
+
+ _ref = require('./protocol'), Parser = _ref.Parser, PROTOCOL_6 = _ref.PROTOCOL_6, PROTOCOL_7 = _ref.PROTOCOL_7;
+
+ Version = '2.2.2';
+
+ exports.Connector = Connector = (function() {
+ function Connector(options, WebSocket, Timer, handlers) {
+ this.options = options;
+ this.WebSocket = WebSocket;
+ this.Timer = Timer;
+ this.handlers = handlers;
+ this._uri = "ws" + (this.options.https ? "s" : "") + "://" + this.options.host + ":" + this.options.port + "/livereload";
+ this._nextDelay = this.options.mindelay;
+ this._connectionDesired = false;
+ this.protocol = 0;
+ this.protocolParser = new Parser({
+ connected: (function(_this) {
+ return function(protocol) {
+ _this.protocol = protocol;
+ _this._handshakeTimeout.stop();
+ _this._nextDelay = _this.options.mindelay;
+ _this._disconnectionReason = 'broken';
+ return _this.handlers.connected(protocol);
+ };
+ })(this),
+ error: (function(_this) {
+ return function(e) {
+ _this.handlers.error(e);
+ return _this._closeOnError();
+ };
+ })(this),
+ message: (function(_this) {
+ return function(message) {
+ return _this.handlers.message(message);
+ };
+ })(this)
+ });
+ this._handshakeTimeout = new Timer((function(_this) {
+ return function() {
+ if (!_this._isSocketConnected()) {
+ return;
+ }
+ _this._disconnectionReason = 'handshake-timeout';
+ return _this.socket.close();
+ };
+ })(this));
+ this._reconnectTimer = new Timer((function(_this) {
+ return function() {
+ if (!_this._connectionDesired) {
+ return;
+ }
+ return _this.connect();
+ };
+ })(this));
+ this.connect();
+ }
+
+ Connector.prototype._isSocketConnected = function() {
+ return this.socket && this.socket.readyState === this.WebSocket.OPEN;
+ };
+
+ Connector.prototype.connect = function() {
+ this._connectionDesired = true;
+ if (this._isSocketConnected()) {
+ return;
+ }
+ this._reconnectTimer.stop();
+ this._disconnectionReason = 'cannot-connect';
+ this.protocolParser.reset();
+ this.handlers.connecting();
+ this.socket = new this.WebSocket(this._uri);
+ this.socket.onopen = (function(_this) {
+ return function(e) {
+ return _this._onopen(e);
+ };
+ })(this);
+ this.socket.onclose = (function(_this) {
+ return function(e) {
+ return _this._onclose(e);
+ };
+ })(this);
+ this.socket.onmessage = (function(_this) {
+ return function(e) {
+ return _this._onmessage(e);
+ };
+ })(this);
+ return this.socket.onerror = (function(_this) {
+ return function(e) {
+ return _this._onerror(e);
+ };
+ })(this);
+ };
+
+ Connector.prototype.disconnect = function() {
+ this._connectionDesired = false;
+ this._reconnectTimer.stop();
+ if (!this._isSocketConnected()) {
+ return;
+ }
+ this._disconnectionReason = 'manual';
+ return this.socket.close();
+ };
+
+ Connector.prototype._scheduleReconnection = function() {
+ if (!this._connectionDesired) {
+ return;
+ }
+ if (!this._reconnectTimer.running) {
+ this._reconnectTimer.start(this._nextDelay);
+ return this._nextDelay = Math.min(this.options.maxdelay, this._nextDelay * 2);
+ }
+ };
+
+ Connector.prototype.sendCommand = function(command) {
+ if (this.protocol == null) {
+ return;
+ }
+ return this._sendCommand(command);
+ };
+
+ Connector.prototype._sendCommand = function(command) {
+ return this.socket.send(JSON.stringify(command));
+ };
+
+ Connector.prototype._closeOnError = function() {
+ this._handshakeTimeout.stop();
+ this._disconnectionReason = 'error';
+ return this.socket.close();
+ };
+
+ Connector.prototype._onopen = function(e) {
+ var hello;
+ this.handlers.socketConnected();
+ this._disconnectionReason = 'handshake-failed';
+ hello = {
+ command: 'hello',
+ protocols: [PROTOCOL_6, PROTOCOL_7]
+ };
+ hello.ver = Version;
+ if (this.options.ext) {
+ hello.ext = this.options.ext;
+ }
+ if (this.options.extver) {
+ hello.extver = this.options.extver;
+ }
+ if (this.options.snipver) {
+ hello.snipver = this.options.snipver;
+ }
+ this._sendCommand(hello);
+ return this._handshakeTimeout.start(this.options.handshake_timeout);
+ };
+
+ Connector.prototype._onclose = function(e) {
+ this.protocol = 0;
+ this.handlers.disconnected(this._disconnectionReason, this._nextDelay);
+ return this._scheduleReconnection();
+ };
+
+ Connector.prototype._onerror = function(e) {};
+
+ Connector.prototype._onmessage = function(e) {
+ return this.protocolParser.process(e.data);
+ };
+
+ return Connector;
+
+ })();
+
+}).call(this);
+
+},{"./protocol":6}],2:[function(require,module,exports){
+(function() {
+ var CustomEvents;
+
+ CustomEvents = {
+ bind: function(element, eventName, handler) {
+ if (element.addEventListener) {
+ return element.addEventListener(eventName, handler, false);
+ } else if (element.attachEvent) {
+ element[eventName] = 1;
+ return element.attachEvent('onpropertychange', function(event) {
+ if (event.propertyName === eventName) {
+ return handler();
+ }
+ });
+ } else {
+ throw new Error("Attempt to attach custom event " + eventName + " to something which isn't a DOMElement");
+ }
+ },
+ fire: function(element, eventName) {
+ var event;
+ if (element.addEventListener) {
+ event = document.createEvent('HTMLEvents');
+ event.initEvent(eventName, true, true);
+ return document.dispatchEvent(event);
+ } else if (element.attachEvent) {
+ if (element[eventName]) {
+ return element[eventName]++;
+ }
+ } else {
+ throw new Error("Attempt to fire custom event " + eventName + " on something which isn't a DOMElement");
+ }
+ }
+ };
+
+ exports.bind = CustomEvents.bind;
+
+ exports.fire = CustomEvents.fire;
+
+}).call(this);
+
+},{}],3:[function(require,module,exports){
+(function() {
+ var LessPlugin;
+
+ module.exports = LessPlugin = (function() {
+ LessPlugin.identifier = 'less';
+
+ LessPlugin.version = '1.0';
+
+ function LessPlugin(window, host) {
+ this.window = window;
+ this.host = host;
+ }
+
+ LessPlugin.prototype.reload = function(path, options) {
+ if (this.window.less && this.window.less.refresh) {
+ if (path.match(/\.less$/i)) {
+ return this.reloadLess(path);
+ }
+ if (options.originalPath.match(/\.less$/i)) {
+ return this.reloadLess(options.originalPath);
+ }
+ }
+ return false;
+ };
+
+ LessPlugin.prototype.reloadLess = function(path) {
+ var link, links, _i, _len;
+ links = (function() {
+ var _i, _len, _ref, _results;
+ _ref = document.getElementsByTagName('link');
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ if (link.href && link.rel.match(/^stylesheet\/less$/i) || (link.rel.match(/stylesheet/i) && link.type.match(/^text\/(x-)?less$/i))) {
+ _results.push(link);
+ }
+ }
+ return _results;
+ })();
+ if (links.length === 0) {
+ return false;
+ }
+ for (_i = 0, _len = links.length; _i < _len; _i++) {
+ link = links[_i];
+ link.href = this.host.generateCacheBustUrl(link.href);
+ }
+ this.host.console.log("LiveReload is asking LESS to recompile all stylesheets");
+ this.window.less.refresh(true);
+ return true;
+ };
+
+ LessPlugin.prototype.analyze = function() {
+ return {
+ disable: !!(this.window.less && this.window.less.refresh)
+ };
+ };
+
+ return LessPlugin;
+
+ })();
+
+}).call(this);
+
+},{}],4:[function(require,module,exports){
+(function() {
+ var Connector, LiveReload, Options, Reloader, Timer,
+ __hasProp = {}.hasOwnProperty;
+
+ Connector = require('./connector').Connector;
+
+ Timer = require('./timer').Timer;
+
+ Options = require('./options').Options;
+
+ Reloader = require('./reloader').Reloader;
+
+ exports.LiveReload = LiveReload = (function() {
+ function LiveReload(window) {
+ var k, v, _ref;
+ this.window = window;
+ this.listeners = {};
+ this.plugins = [];
+ this.pluginIdentifiers = {};
+ this.console = this.window.console && this.window.console.log && this.window.console.error ? this.window.location.href.match(/LR-verbose/) ? this.window.console : {
+ log: function() {},
+ error: this.window.console.error.bind(this.window.console)
+ } : {
+ log: function() {},
+ error: function() {}
+ };
+ if (!(this.WebSocket = this.window.WebSocket || this.window.MozWebSocket)) {
+ this.console.error("LiveReload disabled because the browser does not seem to support web sockets");
+ return;
+ }
+ if ('LiveReloadOptions' in window) {
+ this.options = new Options();
+ _ref = window['LiveReloadOptions'];
+ for (k in _ref) {
+ if (!__hasProp.call(_ref, k)) continue;
+ v = _ref[k];
+ this.options.set(k, v);
+ }
+ } else {
+ this.options = Options.extract(this.window.document);
+ if (!this.options) {
+ this.console.error("LiveReload disabled because it could not find its own <SCRIPT> tag");
+ return;
+ }
+ }
+ this.reloader = new Reloader(this.window, this.console, Timer);
+ this.connector = new Connector(this.options, this.WebSocket, Timer, {
+ connecting: (function(_this) {
+ return function() {};
+ })(this),
+ socketConnected: (function(_this) {
+ return function() {};
+ })(this),
+ connected: (function(_this) {
+ return function(protocol) {
+ var _base;
+ if (typeof (_base = _this.listeners).connect === "function") {
+ _base.connect();
+ }
+ _this.log("LiveReload is connected to " + _this.options.host + ":" + _this.options.port + " (protocol v" + protocol + ").");
+ return _this.analyze();
+ };
+ })(this),
+ error: (function(_this) {
+ return function(e) {
+ if (e instanceof ProtocolError) {
+ if (typeof console !== "undefined" && console !== null) {
+ return console.log("" + e.message + ".");
+ }
+ } else {
+ if (typeof console !== "undefined" && console !== null) {
+ return console.log("LiveReload internal error: " + e.message);
+ }
+ }
+ };
+ })(this),
+ disconnected: (function(_this) {
+ return function(reason, nextDelay) {
+ var _base;
+ if (typeof (_base = _this.listeners).disconnect === "function") {
+ _base.disconnect();
+ }
+ switch (reason) {
+ case 'cannot-connect':
+ return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + ", will retry in " + nextDelay + " sec.");
+ case 'broken':
+ return _this.log("LiveReload disconnected from " + _this.options.host + ":" + _this.options.port + ", reconnecting in " + nextDelay + " sec.");
+ case 'handshake-timeout':
+ return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + " (handshake timeout), will retry in " + nextDelay + " sec.");
+ case 'handshake-failed':
+ return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + " (handshake failed), will retry in " + nextDelay + " sec.");
+ case 'manual':
+ break;
+ case 'error':
+ break;
+ default:
+ return _this.log("LiveReload disconnected from " + _this.options.host + ":" + _this.options.port + " (" + reason + "), reconnecting in " + nextDelay + " sec.");
+ }
+ };
+ })(this),
+ message: (function(_this) {
+ return function(message) {
+ switch (message.command) {
+ case 'reload':
+ return _this.performReload(message);
+ case 'alert':
+ return _this.performAlert(message);
+ }
+ };
+ })(this)
+ });
+ this.initialized = true;
+ }
+
+ LiveReload.prototype.on = function(eventName, handler) {
+ return this.listeners[eventName] = handler;
+ };
+
+ LiveReload.prototype.log = function(message) {
+ return this.console.log("" + message);
+ };
+
+ LiveReload.prototype.performReload = function(message) {
+ var _ref, _ref1;
+ this.log("LiveReload received reload request: " + (JSON.stringify(message, null, 2)));
+ return this.reloader.reload(message.path, {
+ liveCSS: (_ref = message.liveCSS) != null ? _ref : true,
+ liveImg: (_ref1 = message.liveImg) != null ? _ref1 : true,
+ originalPath: message.originalPath || '',
+ overrideURL: message.overrideURL || '',
+ serverURL: "http://" + this.options.host + ":" + this.options.port
+ });
+ };
+
+ LiveReload.prototype.performAlert = function(message) {
+ return alert(message.message);
+ };
+
+ LiveReload.prototype.shutDown = function() {
+ var _base;
+ if (!this.initialized) {
+ return;
+ }
+ this.connector.disconnect();
+ this.log("LiveReload disconnected.");
+ return typeof (_base = this.listeners).shutdown === "function" ? _base.shutdown() : void 0;
+ };
+
+ LiveReload.prototype.hasPlugin = function(identifier) {
+ return !!this.pluginIdentifiers[identifier];
+ };
+
+ LiveReload.prototype.addPlugin = function(pluginClass) {
+ var plugin;
+ if (!this.initialized) {
+ return;
+ }
+ if (this.hasPlugin(pluginClass.identifier)) {
+ return;
+ }
+ this.pluginIdentifiers[pluginClass.identifier] = true;
+ plugin = new pluginClass(this.window, {
+ _livereload: this,
+ _reloader: this.reloader,
+ _connector: this.connector,
+ console: this.console,
+ Timer: Timer,
+ generateCacheBustUrl: (function(_this) {
+ return function(url) {
+ return _this.reloader.generateCacheBustUrl(url);
+ };
+ })(this)
+ });
+ this.plugins.push(plugin);
+ this.reloader.addPlugin(plugin);
+ };
+
+ LiveReload.prototype.analyze = function() {
+ var plugin, pluginData, pluginsData, _i, _len, _ref;
+ if (!this.initialized) {
+ return;
+ }
+ if (!(this.connector.protocol >= 7)) {
+ return;
+ }
+ pluginsData = {};
+ _ref = this.plugins;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ plugin = _ref[_i];
+ pluginsData[plugin.constructor.identifier] = pluginData = (typeof plugin.analyze === "function" ? plugin.analyze() : void 0) || {};
+ pluginData.version = plugin.constructor.version;
+ }
+ this.connector.sendCommand({
+ command: 'info',
+ plugins: pluginsData,
+ url: this.window.location.href
+ });
+ };
+
+ return LiveReload;
+
+ })();
+
+}).call(this);
+
+},{"./connector":1,"./options":5,"./reloader":7,"./timer":9}],5:[function(require,module,exports){
+(function() {
+ var Options;
+
+ exports.Options = Options = (function() {
+ function Options() {
+ this.https = false;
+ this.host = null;
+ this.port = 35729;
+ this.snipver = null;
+ this.ext = null;
+ this.extver = null;
+ this.mindelay = 1000;
+ this.maxdelay = 60000;
+ this.handshake_timeout = 5000;
+ }
+
+ Options.prototype.set = function(name, value) {
+ if (typeof value === 'undefined') {
+ return;
+ }
+ if (!isNaN(+value)) {
+ value = +value;
+ }
+ return this[name] = value;
+ };
+
+ return Options;
+
+ })();
+
+ Options.extract = function(document) {
+ var element, keyAndValue, m, mm, options, pair, src, _i, _j, _len, _len1, _ref, _ref1;
+ _ref = document.getElementsByTagName('script');
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ element = _ref[_i];
+ if ((src = element.src) && (m = src.match(/^[^:]+:\/\/(.*)\/z?livereload\.js(?:\?(.*))?$/))) {
+ options = new Options();
+ options.https = src.indexOf("https") === 0;
+ if (mm = m[1].match(/^([^\/:]+)(?::(\d+))?$/)) {
+ options.host = mm[1];
+ if (mm[2]) {
+ options.port = parseInt(mm[2], 10);
+ }
+ }
+ if (m[2]) {
+ _ref1 = m[2].split('&');
+ for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
+ pair = _ref1[_j];
+ if ((keyAndValue = pair.split('=')).length > 1) {
+ options.set(keyAndValue[0].replace(/-/g, '_'), keyAndValue.slice(1).join('='));
+ }
+ }
+ }
+ return options;
+ }
+ }
+ return null;
+ };
+
+}).call(this);
+
+},{}],6:[function(require,module,exports){
+(function() {
+ var PROTOCOL_6, PROTOCOL_7, Parser, ProtocolError,
+ __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
+
+ exports.PROTOCOL_6 = PROTOCOL_6 = 'http://livereload.com/protocols/official-6';
+
+ exports.PROTOCOL_7 = PROTOCOL_7 = 'http://livereload.com/protocols/official-7';
+
+ exports.ProtocolError = ProtocolError = (function() {
+ function ProtocolError(reason, data) {
+ this.message = "LiveReload protocol error (" + reason + ") after receiving data: \"" + data + "\".";
+ }
+
+ return ProtocolError;
+
+ })();
+
+ exports.Parser = Parser = (function() {
+ function Parser(handlers) {
+ this.handlers = handlers;
+ this.reset();
+ }
+
+ Parser.prototype.reset = function() {
+ return this.protocol = null;
+ };
+
+ Parser.prototype.process = function(data) {
+ var command, e, message, options, _ref;
+ try {
+ if (this.protocol == null) {
+ if (data.match(/^!!ver:([\d.]+)$/)) {
+ this.protocol = 6;
+ } else if (message = this._parseMessage(data, ['hello'])) {
+ if (!message.protocols.length) {
+ throw new ProtocolError("no protocols specified in handshake message");
+ } else if (__indexOf.call(message.protocols, PROTOCOL_7) >= 0) {
+ this.protocol = 7;
+ } else if (__indexOf.call(message.protocols, PROTOCOL_6) >= 0) {
+ this.protocol = 6;
+ } else {
+ throw new ProtocolError("no supported protocols found");
+ }
+ }
+ return this.handlers.connected(this.protocol);
+ } else if (this.protocol === 6) {
+ message = JSON.parse(data);
+ if (!message.length) {
+ throw new ProtocolError("protocol 6 messages must be arrays");
+ }
+ command = message[0], options = message[1];
+ if (command !== 'refresh') {
+ throw new ProtocolError("unknown protocol 6 command");
+ }
+ return this.handlers.message({
+ command: 'reload',
+ path: options.path,
+ liveCSS: (_ref = options.apply_css_live) != null ? _ref : true
+ });
+ } else {
+ message = this._parseMessage(data, ['reload', 'alert']);
+ return this.handlers.message(message);
+ }
+ } catch (_error) {
+ e = _error;
+ if (e instanceof ProtocolError) {
+ return this.handlers.error(e);
+ } else {
+ throw e;
+ }
+ }
+ };
+
+ Parser.prototype._parseMessage = function(data, validCommands) {
+ var e, message, _ref;
+ try {
+ message = JSON.parse(data);
+ } catch (_error) {
+ e = _error;
+ throw new ProtocolError('unparsable JSON', data);
+ }
+ if (!message.command) {
+ throw new ProtocolError('missing "command" key', data);
+ }
+ if (_ref = message.command, __indexOf.call(validCommands, _ref) < 0) {
+ throw new ProtocolError("invalid command '" + message.command + "', only valid commands are: " + (validCommands.join(', ')) + ")", data);
+ }
+ return message;
+ };
+
+ return Parser;
+
+ })();
+
+}).call(this);
+
+},{}],7:[function(require,module,exports){
+(function() {
+ var IMAGE_STYLES, Reloader, numberOfMatchingSegments, pathFromUrl, pathsMatch, pickBestMatch, splitUrl;
+
+ splitUrl = function(url) {
+ var hash, index, params;
+ if ((index = url.indexOf('#')) >= 0) {
+ hash = url.slice(index);
+ url = url.slice(0, index);
+ } else {
+ hash = '';
+ }
+ if ((index = url.indexOf('?')) >= 0) {
+ params = url.slice(index);
+ url = url.slice(0, index);
+ } else {
+ params = '';
+ }
+ return {
+ url: url,
+ params: params,
+ hash: hash
+ };
+ };
+
+ pathFromUrl = function(url) {
+ var path;
+ url = splitUrl(url).url;
+ if (url.indexOf('file://') === 0) {
+ path = url.replace(/^file:\/\/(localhost)?/, '');
+ } else {
+ path = url.replace(/^([^:]+:)?\/\/([^:\/]+)(:\d*)?\//, '/');
+ }
+ return decodeURIComponent(path);
+ };
+
+ pickBestMatch = function(path, objects, pathFunc) {
+ var bestMatch, object, score, _i, _len;
+ bestMatch = {
+ score: 0
+ };
+ for (_i = 0, _len = objects.length; _i < _len; _i++) {
+ object = objects[_i];
+ score = numberOfMatchingSegments(path, pathFunc(object));
+ if (score > bestMatch.score) {
+ bestMatch = {
+ object: object,
+ score: score
+ };
+ }
+ }
+ if (bestMatch.score > 0) {
+ return bestMatch;
+ } else {
+ return null;
+ }
+ };
+
+ numberOfMatchingSegments = function(path1, path2) {
+ var comps1, comps2, eqCount, len;
+ path1 = path1.replace(/^\/+/, '').toLowerCase();
+ path2 = path2.replace(/^\/+/, '').toLowerCase();
+ if (path1 === path2) {
+ return 10000;
+ }
+ comps1 = path1.split('/').reverse();
+ comps2 = path2.split('/').reverse();
+ len = Math.min(comps1.length, comps2.length);
+ eqCount = 0;
+ while (eqCount < len && comps1[eqCount] === comps2[eqCount]) {
+ ++eqCount;
+ }
+ return eqCount;
+ };
+
+ pathsMatch = function(path1, path2) {
+ return numberOfMatchingSegments(path1, path2) > 0;
+ };
+
+ IMAGE_STYLES = [
+ {
+ selector: 'background',
+ styleNames: ['backgroundImage']
+ }, {
+ selector: 'border',
+ styleNames: ['borderImage', 'webkitBorderImage', 'MozBorderImage']
+ }
+ ];
+
+ exports.Reloader = Reloader = (function() {
+ function Reloader(window, console, Timer) {
+ this.window = window;
+ this.console = console;
+ this.Timer = Timer;
+ this.document = this.window.document;
+ this.importCacheWaitPeriod = 200;
+ this.plugins = [];
+ }
+
+ Reloader.prototype.addPlugin = function(plugin) {
+ return this.plugins.push(plugin);
+ };
+
+ Reloader.prototype.analyze = function(callback) {
+ return results;
+ };
+
+ Reloader.prototype.reload = function(path, options) {
+ var plugin, _base, _i, _len, _ref;
+ this.options = options;
+ if ((_base = this.options).stylesheetReloadTimeout == null) {
+ _base.stylesheetReloadTimeout = 15000;
+ }
+ _ref = this.plugins;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ plugin = _ref[_i];
+ if (plugin.reload && plugin.reload(path, options)) {
+ return;
+ }
+ }
+ if (options.liveCSS) {
+ if (path.match(/\.css$/i)) {
+ if (this.reloadStylesheet(path)) {
+ return;
+ }
+ }
+ }
+ if (options.liveImg) {
+ if (path.match(/\.(jpe?g|png|gif)$/i)) {
+ this.reloadImages(path);
+ return;
+ }
+ }
+ return this.reloadPage();
+ };
+
+ Reloader.prototype.reloadPage = function() {
+ return this.window.document.location.reload();
+ };
+
+ Reloader.prototype.reloadImages = function(path) {
+ var expando, img, selector, styleNames, styleSheet, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _results;
+ expando = this.generateUniqueString();
+ _ref = this.document.images;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ img = _ref[_i];
+ if (pathsMatch(path, pathFromUrl(img.src))) {
+ img.src = this.generateCacheBustUrl(img.src, expando);
+ }
+ }
+ if (this.document.querySelectorAll) {
+ for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) {
+ _ref1 = IMAGE_STYLES[_j], selector = _ref1.selector, styleNames = _ref1.styleNames;
+ _ref2 = this.document.querySelectorAll("[style*=" + selector + "]");
+ for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
+ img = _ref2[_k];
+ this.reloadStyleImages(img.style, styleNames, path, expando);
+ }
+ }
+ }
+ if (this.document.styleSheets) {
+ _ref3 = this.document.styleSheets;
+ _results = [];
+ for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
+ styleSheet = _ref3[_l];
+ _results.push(this.reloadStylesheetImages(styleSheet, path, expando));
+ }
+ return _results;
+ }
+ };
+
+ Reloader.prototype.reloadStylesheetImages = function(styleSheet, path, expando) {
+ var e, rule, rules, styleNames, _i, _j, _len, _len1;
+ try {
+ rules = styleSheet != null ? styleSheet.cssRules : void 0;
+ } catch (_error) {
+ e = _error;
+ }
+ if (!rules) {
+ return;
+ }
+ for (_i = 0, _len = rules.length; _i < _len; _i++) {
+ rule = rules[_i];
+ switch (rule.type) {
+ case CSSRule.IMPORT_RULE:
+ this.reloadStylesheetImages(rule.styleSheet, path, expando);
+ break;
+ case CSSRule.STYLE_RULE:
+ for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) {
+ styleNames = IMAGE_STYLES[_j].styleNames;
+ this.reloadStyleImages(rule.style, styleNames, path, expando);
+ }
+ break;
+ case CSSRule.MEDIA_RULE:
+ this.reloadStylesheetImages(rule, path, expando);
+ }
+ }
+ };
+
+ Reloader.prototype.reloadStyleImages = function(style, styleNames, path, expando) {
+ var newValue, styleName, value, _i, _len;
+ for (_i = 0, _len = styleNames.length; _i < _len; _i++) {
+ styleName = styleNames[_i];
+ value = style[styleName];
+ if (typeof value === 'string') {
+ newValue = value.replace(/\burl\s*\(([^)]*)\)/, (function(_this) {
+ return function(match, src) {
+ if (pathsMatch(path, pathFromUrl(src))) {
+ return "url(" + (_this.generateCacheBustUrl(src, expando)) + ")";
+ } else {
+ return match;
+ }
+ };
+ })(this));
+ if (newValue !== value) {
+ style[styleName] = newValue;
+ }
+ }
+ }
+ };
+
+ Reloader.prototype.reloadStylesheet = function(path) {
+ var imported, link, links, match, style, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1;
+ links = (function() {
+ var _i, _len, _ref, _results;
+ _ref = this.document.getElementsByTagName('link');
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ if (link.rel.match(/^stylesheet$/i) && !link.__LiveReload_pendingRemoval) {
+ _results.push(link);
+ }
+ }
+ return _results;
+ }).call(this);
+ imported = [];
+ _ref = this.document.getElementsByTagName('style');
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ style = _ref[_i];
+ if (style.sheet) {
+ this.collectImportedStylesheets(style, style.sheet, imported);
+ }
+ }
+ for (_j = 0, _len1 = links.length; _j < _len1; _j++) {
+ link = links[_j];
+ this.collectImportedStylesheets(link, link.sheet, imported);
+ }
+ if (this.window.StyleFix && this.document.querySelectorAll) {
+ _ref1 = this.document.querySelectorAll('style[data-href]');
+ for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
+ style = _ref1[_k];
+ links.push(style);
+ }
+ }
+ this.console.log("LiveReload found " + links.length + " LINKed stylesheets, " + imported.length + " @imported stylesheets");
+ match = pickBestMatch(path, links.concat(imported), (function(_this) {
+ return function(l) {
+ return pathFromUrl(_this.linkHref(l));
+ };
+ })(this));
+ if (match) {
+ if (match.object.rule) {
+ this.console.log("LiveReload is reloading imported stylesheet: " + match.object.href);
+ this.reattachImportedRule(match.object);
+ } else {
+ this.console.log("LiveReload is reloading stylesheet: " + (this.linkHref(match.object)));
+ this.reattachStylesheetLink(match.object);
+ }
+ } else {
+ this.console.log("LiveReload will reload all stylesheets because path '" + path + "' did not match any specific one");
+ for (_l = 0, _len3 = links.length; _l < _len3; _l++) {
+ link = links[_l];
+ this.reattachStylesheetLink(link);
+ }
+ }
+ return true;
+ };
+
+ Reloader.prototype.collectImportedStylesheets = function(link, styleSheet, result) {
+ var e, index, rule, rules, _i, _len;
+ try {
+ rules = styleSheet != null ? styleSheet.cssRules : void 0;
+ } catch (_error) {
+ e = _error;
+ }
+ if (rules && rules.length) {
+ for (index = _i = 0, _len = rules.length; _i < _len; index = ++_i) {
+ rule = rules[index];
+ switch (rule.type) {
+ case CSSRule.CHARSET_RULE:
+ continue;
+ case CSSRule.IMPORT_RULE:
+ result.push({
+ link: link,
+ rule: rule,
+ index: index,
+ href: rule.href
+ });
+ this.collectImportedStylesheets(link, rule.styleSheet, result);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ };
+
+ Reloader.prototype.waitUntilCssLoads = function(clone, func) {
+ var callbackExecuted, executeCallback, poll;
+ callbackExecuted = false;
+ executeCallback = (function(_this) {
+ return function() {
+ if (callbackExecuted) {
+ return;
+ }
+ callbackExecuted = true;
+ return func();
+ };
+ })(this);
+ clone.onload = (function(_this) {
+ return function() {
+ _this.console.log("LiveReload: the new stylesheet has finished loading");
+ _this.knownToSupportCssOnLoad = true;
+ return executeCallback();
+ };
+ })(this);
+ if (!this.knownToSupportCssOnLoad) {
+ (poll = (function(_this) {
+ return function() {
+ if (clone.sheet) {
+ _this.console.log("LiveReload is polling until the new CSS finishes loading...");
+ return executeCallback();
+ } else {
+ return _this.Timer.start(50, poll);
+ }
+ };
+ })(this))();
+ }
+ return this.Timer.start(this.options.stylesheetReloadTimeout, executeCallback);
+ };
+
+ Reloader.prototype.linkHref = function(link) {
+ return link.href || link.getAttribute('data-href');
+ };
+
+ Reloader.prototype.reattachStylesheetLink = function(link) {
+ var clone, parent;
+ if (link.__LiveReload_pendingRemoval) {
+ return;
+ }
+ link.__LiveReload_pendingRemoval = true;
+ if (link.tagName === 'STYLE') {
+ clone = this.document.createElement('link');
+ clone.rel = 'stylesheet';
+ clone.media = link.media;
+ clone.disabled = link.disabled;
+ } else {
+ clone = link.cloneNode(false);
+ }
+ clone.href = this.generateCacheBustUrl(this.linkHref(link));
+ parent = link.parentNode;
+ if (parent.lastChild === link) {
+ parent.appendChild(clone);
+ } else {
+ parent.insertBefore(clone, link.nextSibling);
+ }
+ return this.waitUntilCssLoads(clone, (function(_this) {
+ return function() {
+ var additionalWaitingTime;
+ if (/AppleWebKit/.test(navigator.userAgent)) {
+ additionalWaitingTime = 5;
+ } else {
+ additionalWaitingTime = 200;
+ }
+ return _this.Timer.start(additionalWaitingTime, function() {
+ var _ref;
+ if (!link.parentNode) {
+ return;
+ }
+ link.parentNode.removeChild(link);
+ clone.onreadystatechange = null;
+ return (_ref = _this.window.StyleFix) != null ? _ref.link(clone) : void 0;
+ });
+ };
+ })(this));
+ };
+
+ Reloader.prototype.reattachImportedRule = function(_arg) {
+ var href, index, link, media, newRule, parent, rule, tempLink;
+ rule = _arg.rule, index = _arg.index, link = _arg.link;
+ parent = rule.parentStyleSheet;
+ href = this.generateCacheBustUrl(rule.href);
+ media = rule.media.length ? [].join.call(rule.media, ', ') : '';
+ newRule = "@import url(\"" + href + "\") " + media + ";";
+ rule.__LiveReload_newHref = href;
+ tempLink = this.document.createElement("link");
+ tempLink.rel = 'stylesheet';
+ tempLink.href = href;
+ tempLink.__LiveReload_pendingRemoval = true;
+ if (link.parentNode) {
+ link.parentNode.insertBefore(tempLink, link);
+ }
+ return this.Timer.start(this.importCacheWaitPeriod, (function(_this) {
+ return function() {
+ if (tempLink.parentNode) {
+ tempLink.parentNode.removeChild(tempLink);
+ }
+ if (rule.__LiveReload_newHref !== href) {
+ return;
+ }
+ parent.insertRule(newRule, index);
+ parent.deleteRule(index + 1);
+ rule = parent.cssRules[index];
+ rule.__LiveReload_newHref = href;
+ return _this.Timer.start(_this.importCacheWaitPeriod, function() {
+ if (rule.__LiveReload_newHref !== href) {
+ return;
+ }
+ parent.insertRule(newRule, index);
+ return parent.deleteRule(index + 1);
+ });
+ };
+ })(this));
+ };
+
+ Reloader.prototype.generateUniqueString = function() {
+ return 'livereload=' + Date.now();
+ };
+
+ Reloader.prototype.generateCacheBustUrl = function(url, expando) {
+ var hash, oldParams, originalUrl, params, _ref;
+ if (expando == null) {
+ expando = this.generateUniqueString();
+ }
+ _ref = splitUrl(url), url = _ref.url, hash = _ref.hash, oldParams = _ref.params;
+ if (this.options.overrideURL) {
+ if (url.indexOf(this.options.serverURL) < 0) {
+ originalUrl = url;
+ url = this.options.serverURL + this.options.overrideURL + "?url=" + encodeURIComponent(url);
+ this.console.log("LiveReload is overriding source URL " + originalUrl + " with " + url);
+ }
+ }
+ params = oldParams.replace(/(\?|&)livereload=(\d+)/, function(match, sep) {
+ return "" + sep + expando;
+ });
+ if (params === oldParams) {
+ if (oldParams.length === 0) {
+ params = "?" + expando;
+ } else {
+ params = "" + oldParams + "&" + expando;
+ }
+ }
+ return url + params + hash;
+ };
+
+ return Reloader;
+
+ })();
+
+}).call(this);
+
+},{}],8:[function(require,module,exports){
+(function() {
+ var CustomEvents, LiveReload, k;
+
+ CustomEvents = require('./customevents');
+
+ LiveReload = window.LiveReload = new (require('./livereload').LiveReload)(window);
+
+ for (k in window) {
+ if (k.match(/^LiveReloadPlugin/)) {
+ LiveReload.addPlugin(window[k]);
+ }
+ }
+
+ LiveReload.addPlugin(require('./less'));
+
+ LiveReload.on('shutdown', function() {
+ return delete window.LiveReload;
+ });
+
+ LiveReload.on('connect', function() {
+ return CustomEvents.fire(document, 'LiveReloadConnect');
+ });
+
+ LiveReload.on('disconnect', function() {
+ return CustomEvents.fire(document, 'LiveReloadDisconnect');
+ });
+
+ CustomEvents.bind(document, 'LiveReloadShutDown', function() {
+ return LiveReload.shutDown();
+ });
+
+}).call(this);
+
+},{"./customevents":2,"./less":3,"./livereload":4}],9:[function(require,module,exports){
+(function() {
+ var Timer;
+
+ exports.Timer = Timer = (function() {
+ function Timer(func) {
+ this.func = func;
+ this.running = false;
+ this.id = null;
+ this._handler = (function(_this) {
+ return function() {
+ _this.running = false;
+ _this.id = null;
+ return _this.func();
+ };
+ })(this);
+ }
+
+ Timer.prototype.start = function(timeout) {
+ if (this.running) {
+ clearTimeout(this.id);
+ }
+ this.id = setTimeout(this._handler, timeout);
+ return this.running = true;
+ };
+
+ Timer.prototype.stop = function() {
+ if (this.running) {
+ clearTimeout(this.id);
+ this.running = false;
+ return this.id = null;
+ }
+ };
+
+ return Timer;
+
+ })();
+
+ Timer.start = function(timeout, func) {
+ return setTimeout(func, timeout);
+ };
+
+}).call(this);
+
+},{}]},{},[8]);
diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/mime_types_charset.json b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/mime_types_charset.json
new file mode 100644
index 0000000..017469b
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/mime_types_charset.json
@@ -0,0 +1,71 @@
+{
+ "application/javascript": "UTF-8",
+ "application/json": "UTF-8",
+ "application/manifest+json": "UTF-8",
+ "application/vnd.syncml+xml": "UTF-8",
+ "application/vnd.syncml.dm+wbxml": "UTF-8",
+ "application/vnd.syncml.dm+xml": "UTF-8",
+ "application/vnd.syncml.dmddf+xml": "UTF-8",
+ "application/vnd.wap.wbxml": "UTF-8",
+ "text/cache-manifest": "UTF-8",
+ "text/calendar": "UTF-8",
+ "text/coffeescript": "UTF-8",
+ "text/css": "UTF-8",
+ "text/csv": "UTF-8",
+ "text/html": "UTF-8",
+ "text/jade": "UTF-8",
+ "text/jsx": "UTF-8",
+ "text/less": "UTF-8",
+ "text/markdown": "UTF-8",
+ "text/mathml": "UTF-8",
+ "text/mdx": "UTF-8",
+ "text/n3": "UTF-8",
+ "text/plain": "UTF-8",
+ "text/prs.lines.tag": "UTF-8",
+ "text/richtext": "UTF-8",
+ "text/sgml": "UTF-8",
+ "text/shex": "UTF-8",
+ "text/slim": "UTF-8",
+ "text/spdx": "UTF-8",
+ "text/stylus": "UTF-8",
+ "text/tab-separated-values": "UTF-8",
+ "text/troff": "UTF-8",
+ "text/turtle": "UTF-8",
+ "text/uri-list": "UTF-8",
+ "text/vcard": "UTF-8",
+ "text/vnd.curl": "UTF-8",
+ "text/vnd.curl.dcurl": "UTF-8",
+ "text/vnd.curl.mcurl": "UTF-8",
+ "text/vnd.curl.scurl": "UTF-8",
+ "text/vnd.familysearch.gedcom": "UTF-8",
+ "text/vnd.fly": "UTF-8",
+ "text/vnd.fmi.flexstor": "UTF-8",
+ "text/vnd.graphviz": "UTF-8",
+ "text/vnd.in3d.3dml": "UTF-8",
+ "text/vnd.in3d.spot": "UTF-8",
+ "text/vnd.sun.j2me.app-descriptor": "UTF-8",
+ "text/vnd.wap.wml": "UTF-8",
+ "text/vnd.wap.wmlscript": "UTF-8",
+ "text/vtt": "UTF-8",
+ "text/x-asm": "UTF-8",
+ "text/x-c": "UTF-8",
+ "text/x-component": "UTF-8",
+ "text/x-fortran": "UTF-8",
+ "text/x-handlebars-template": "UTF-8",
+ "text/x-java-source": "UTF-8",
+ "text/x-lua": "UTF-8",
+ "text/x-markdown": "UTF-8",
+ "text/x-nfo": "UTF-8",
+ "text/x-opml": "UTF-8",
+ "text/x-pascal": "UTF-8",
+ "text/x-processing": "UTF-8",
+ "text/x-sass": "UTF-8",
+ "text/x-scss": "UTF-8",
+ "text/x-setext": "UTF-8",
+ "text/x-sfv": "UTF-8",
+ "text/x-suse-ymp": "UTF-8",
+ "text/x-uuencode": "UTF-8",
+ "text/x-vcalendar": "UTF-8",
+ "text/x-vcard": "UTF-8",
+ "text/yaml": "UTF-8"
+}
diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/servlet.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/servlet.rb
new file mode 100644
index 0000000..c8895e5
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/servlet.rb
@@ -0,0 +1,206 @@
+# frozen_string_literal: true
+
+require "webrick"
+
+module Jekyll
+ module Commands
+ class Serve
+ # This class is used to determine if the Servlet should modify a served file
+ # to insert the LiveReload script tags
+ class SkipAnalyzer
+ BAD_USER_AGENTS = [%r!MSIE!].freeze
+
+ def self.skip_processing?(request, response, options)
+ new(request, response, options).skip_processing?
+ end
+
+ def initialize(request, response, options)
+ @options = options
+ @request = request
+ @response = response
+ end
+
+ def skip_processing?
+ !html? || chunked? || inline? || bad_browser?
+ end
+
+ def chunked?
+ @response["Transfer-Encoding"] == "chunked"
+ end
+
+ def inline?
+ @response["Content-Disposition"].to_s.start_with?("inline")
+ end
+
+ def bad_browser?
+ BAD_USER_AGENTS.any? { |pattern| pattern.match?(@request["User-Agent"]) }
+ end
+
+ def html?
+ @response["Content-Type"].to_s.include?("text/html")
+ end
+ end
+
+ # This class inserts the LiveReload script tags into HTML as it is served
+ class BodyProcessor
+ HEAD_TAG_REGEX = %r!<head>|<head[^(er)][^<]*>!.freeze
+
+ attr_reader :content_length, :new_body, :livereload_added
+
+ def initialize(body, options)
+ @body = body
+ @options = options
+ @processed = false
+ end
+
+ def processed?
+ @processed
+ end
+
+ # rubocop:disable Metrics/MethodLength
+ def process!
+ @new_body = []
+ # @body will usually be a File object but Strings occur in rare cases
+ if @body.respond_to?(:each)
+ begin
+ @body.each { |line| @new_body << line.to_s }
+ ensure
+ @body.close
+ end
+ else
+ @new_body = @body.lines
+ end
+
+ @content_length = 0
+ @livereload_added = false
+
+ @new_body.each do |line|
+ if !@livereload_added && line["<head"]
+ line.gsub!(HEAD_TAG_REGEX) do |match|
+ %(#{match}#{template.result(binding)})
+ end
+
+ @livereload_added = true
+ end
+
+ @content_length += line.bytesize
+ @processed = true
+ end
+ @new_body = @new_body.join
+ end
+ # rubocop:enable Metrics/MethodLength
+
+ def template
+ # Unclear what "snipver" does. Doc at
+ # https://github.com/livereload/livereload-js states that the recommended
+ # setting is 1.
+
+ # Complicated JavaScript to ensure that livereload.js is loaded from the
+ # same origin as the page. Mostly useful for dealing with the browser's
+ # distinction between 'localhost' and 127.0.0.1
+ @template ||= ERB.new(<<~TEMPLATE)
+ <script>
+ document.write(
+ '<script src="' + location.protocol + '//' +
+ (location.host || 'localhost').split(':')[0] +
+ ':<%=@options["livereload_port"] %>/livereload.js?snipver=1<%= livereload_args %>"' +
+ '></' +
+ 'script>');
+ </script>
+ TEMPLATE
+ end
+
+ def livereload_args
+ # XHTML standard requires ampersands to be encoded as entities when in
+ # attributes. See http://stackoverflow.com/a/2190292
+ src = ""
+ if @options["livereload_min_delay"]
+ src += "&amp;mindelay=#{@options["livereload_min_delay"]}"
+ end
+ if @options["livereload_max_delay"]
+ src += "&amp;maxdelay=#{@options["livereload_max_delay"]}"
+ end
+ src += "&amp;port=#{@options["livereload_port"]}" if @options["livereload_port"]
+ src
+ end
+ end
+
+ class Servlet < WEBrick::HTTPServlet::FileHandler
+ DEFAULTS = {
+ "Cache-Control" => "private, max-age=0, proxy-revalidate, " \
+ "no-store, no-cache, must-revalidate",
+ }.freeze
+
+ def initialize(server, root, callbacks)
+ # So we can access them easily.
+ @jekyll_opts = server.config[:JekyllOptions]
+ @mime_types_charset = server.config[:MimeTypesCharset]
+ set_defaults
+ super
+ end
+
+ def search_index_file(req, res)
+ super ||
+ search_file(req, res, ".html") ||
+ search_file(req, res, ".xhtml")
+ end
+
+ # Add the ability to tap file.html the same way that Nginx does on our
+ # Docker images (or on GitHub Pages.) The difference is that we might end
+ # up with a different preference on which comes first.
+
+ def search_file(req, res, basename)
+ # /file.* > /file/index.html > /file.html
+ super ||
+ super(req, res, "#{basename}.html") ||
+ super(req, res, "#{basename}.xhtml")
+ end
+
+ # rubocop:disable Naming/MethodName
+ def do_GET(req, res)
+ rtn = super
+
+ if @jekyll_opts["livereload"]
+ return rtn if SkipAnalyzer.skip_processing?(req, res, @jekyll_opts)
+
+ processor = BodyProcessor.new(res.body, @jekyll_opts)
+ processor.process!
+ res.body = processor.new_body
+ res.content_length = processor.content_length.to_s
+
+ if processor.livereload_added
+ # Add a header to indicate that the page content has been modified
+ res["X-Rack-LiveReload"] = "1"
+ end
+ end
+
+ conditionally_inject_charset(res)
+ res.header.merge!(@headers)
+ rtn
+ end
+ # rubocop:enable Naming/MethodName
+
+ private
+
+ # Inject charset based on Jekyll config only if our mime-types database contains
+ # the charset metadata.
+ #
+ # Refer `script/vendor-mimes` in the repository for further details.
+ def conditionally_inject_charset(res)
+ typ = res.header["content-type"]
+ return unless @mime_types_charset.key?(typ)
+ return if %r!;\s*charset=!.match?(typ)
+
+ res.header["content-type"] = "#{typ}; charset=#{@jekyll_opts["encoding"]}"
+ end
+
+ def set_defaults
+ hash_ = @jekyll_opts.fetch("webrick", {}).fetch("headers", {})
+ DEFAULTS.each_with_object(@headers = hash_) do |(key, val), hash|
+ hash[key] = val unless hash.key?(key)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/websockets.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/websockets.rb
new file mode 100644
index 0000000..6aa522c
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/websockets.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+require "http/parser"
+
+module Jekyll
+ module Commands
+ class Serve
+ # The LiveReload protocol requires the server to serve livereload.js over HTTP
+ # despite the fact that the protocol itself uses WebSockets. This custom connection
+ # class addresses the dual protocols that the server needs to understand.
+ class HttpAwareConnection < EventMachine::WebSocket::Connection
+ attr_reader :reload_body, :reload_size
+
+ def initialize(_opts)
+ # If EventMachine SSL support on Windows ever gets better, the code below will
+ # set up the reactor to handle SSL
+ #
+ # @ssl_enabled = opts["ssl_cert"] && opts["ssl_key"]
+ # if @ssl_enabled
+ # em_opts[:tls_options] = {
+ # :private_key_file => Jekyll.sanitized_path(opts["source"], opts["ssl_key"]),
+ # :cert_chain_file => Jekyll.sanitized_path(opts["source"], opts["ssl_cert"])
+ # }
+ # em_opts[:secure] = true
+ # end
+
+ # This is too noisy even for --verbose, but uncomment if you need it for
+ # a specific WebSockets issue. Adding ?LR-verbose=true onto the URL will
+ # enable logging on the client side.
+ # em_opts[:debug] = true
+
+ em_opts = {}
+ super(em_opts)
+
+ reload_file = File.join(Serve.singleton_class::LIVERELOAD_DIR, "livereload.js")
+
+ @reload_body = File.read(reload_file)
+ @reload_size = @reload_body.bytesize
+ end
+
+ # rubocop:disable Metrics/MethodLength
+ def dispatch(data)
+ parser = Http::Parser.new
+ parser << data
+
+ # WebSockets requests will have a Connection: Upgrade header
+ if parser.http_method != "GET" || parser.upgrade?
+ super
+ elsif parser.request_url.start_with?("/livereload.js")
+ headers = [
+ "HTTP/1.1 200 OK",
+ "Content-Type: application/javascript",
+ "Content-Length: #{reload_size}",
+ "",
+ "",
+ ].join("\r\n")
+ send_data(headers)
+
+ # stream_file_data would free us from keeping livereload.js in memory
+ # but JRuby blocks on that call and never returns
+ send_data(reload_body)
+ close_connection_after_writing
+ else
+ body = "This port only serves livereload.js over HTTP.\n"
+ headers = [
+ "HTTP/1.1 400 Bad Request",
+ "Content-Type: text/plain",
+ "Content-Length: #{body.bytesize}",
+ "",
+ "",
+ ].join("\r\n")
+ send_data(headers)
+ send_data(body)
+ close_connection_after_writing
+ end
+ end
+ # rubocop:enable Metrics/MethodLength
+ end
+ end
+ end
+end