bridgetown-core 0.15.0.beta3 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +14 -0
  3. data/bridgetown-core.gemspec +3 -0
  4. data/lib/bridgetown-core.rb +6 -1
  5. data/lib/bridgetown-core/commands/concerns/actions.rb +29 -23
  6. data/lib/bridgetown-core/commands/console.rb +12 -2
  7. data/lib/bridgetown-core/commands/serve.rb +5 -0
  8. data/lib/bridgetown-core/concerns/data_accessible.rb +19 -0
  9. data/lib/bridgetown-core/concerns/layout_placeable.rb +17 -0
  10. data/lib/bridgetown-core/concerns/liquid_renderable.rb +20 -0
  11. data/lib/bridgetown-core/concerns/publishable.rb +10 -0
  12. data/lib/bridgetown-core/concerns/site/configurable.rb +62 -31
  13. data/lib/bridgetown-core/concerns/site/content.rb +88 -29
  14. data/lib/bridgetown-core/concerns/site/extensible.rb +15 -12
  15. data/lib/bridgetown-core/concerns/site/processable.rb +12 -10
  16. data/lib/bridgetown-core/concerns/site/renderable.rb +22 -2
  17. data/lib/bridgetown-core/concerns/site/writable.rb +16 -2
  18. data/lib/bridgetown-core/concerns/validatable.rb +59 -0
  19. data/lib/bridgetown-core/configuration.rb +1 -0
  20. data/lib/bridgetown-core/converter.rb +34 -0
  21. data/lib/bridgetown-core/converters/erb_templates.rb +78 -0
  22. data/lib/bridgetown-core/converters/markdown.rb +6 -23
  23. data/lib/bridgetown-core/converters/smartypants.rb +0 -10
  24. data/lib/bridgetown-core/document.rb +8 -52
  25. data/lib/bridgetown-core/drops/document_drop.rb +9 -1
  26. data/lib/bridgetown-core/errors.rb +2 -0
  27. data/lib/bridgetown-core/excerpt.rb +1 -6
  28. data/lib/bridgetown-core/filters.rb +2 -0
  29. data/lib/bridgetown-core/layout.rb +24 -1
  30. data/lib/bridgetown-core/liquid_renderer/file_system.rb +1 -1
  31. data/lib/bridgetown-core/page.rb +34 -25
  32. data/lib/bridgetown-core/plugin_manager.rb +14 -5
  33. data/lib/bridgetown-core/regenerator.rb +1 -1
  34. data/lib/bridgetown-core/renderer.rb +38 -12
  35. data/lib/bridgetown-core/ruby_template_view.rb +98 -0
  36. data/lib/bridgetown-core/tags/class_map.rb +90 -0
  37. data/lib/bridgetown-core/tags/include.rb +2 -0
  38. data/lib/bridgetown-core/tags/render_content.rb +11 -1
  39. data/lib/bridgetown-core/tags/webpack_path.rb +19 -22
  40. data/lib/bridgetown-core/utils.rb +53 -0
  41. data/lib/bridgetown-core/version.rb +2 -2
  42. data/lib/site_template/bridgetown.config.yml +5 -3
  43. data/lib/site_template/src/_components/{footer.html → footer.liquid} +0 -0
  44. data/lib/site_template/src/_components/{head.html → head.liquid} +0 -0
  45. data/lib/site_template/src/_components/{navbar.html → navbar.liquid} +0 -0
  46. data/lib/site_template/src/_layouts/{default.html → default.liquid} +1 -1
  47. data/lib/site_template/src/_layouts/{home.html → home.liquid} +0 -0
  48. data/lib/site_template/src/_layouts/{page.html → page.liquid} +0 -0
  49. data/lib/site_template/src/_layouts/{post.html → post.liquid} +0 -0
  50. metadata +59 -10
  51. data/lib/bridgetown-core/concerns/convertible.rb +0 -235
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+ require "active_support/core_ext/hash/keys"
5
+
6
+ module Bridgetown
7
+ class RubyTemplateView
8
+ class Helpers
9
+ include Bridgetown::Filters
10
+
11
+ Context = Struct.new(:registers)
12
+
13
+ def initialize(site)
14
+ @site = site
15
+
16
+ # duck typing for Liquid context
17
+ @context = Context.new({ site: @site })
18
+ end
19
+
20
+ def webpack_path(asset_type)
21
+ Bridgetown::Utils.parse_webpack_manifest_file(@site, asset_type.to_s)
22
+ end
23
+ end
24
+
25
+ attr_reader :layout, :page, :site, :content
26
+
27
+ def initialize(convertible)
28
+ if convertible.is_a?(Layout)
29
+ @layout = convertible
30
+ @page = layout.current_document
31
+ @content = layout.current_document_output
32
+ else
33
+ @page = convertible
34
+ end
35
+ @site = page.site
36
+ end
37
+
38
+ def partial(_partial_name, _options = {})
39
+ raise "Must be implemented in a subclass"
40
+ end
41
+
42
+ def site_drop
43
+ site.site_payload.site
44
+ end
45
+
46
+ def liquid_render(component, options = {})
47
+ render_statement = _render_statement(component, options)
48
+
49
+ template = site.liquid_renderer.file(
50
+ "#{page.path}.#{Digest::SHA2.hexdigest(render_statement)}"
51
+ ).parse(render_statement)
52
+ template.warnings.each do |e|
53
+ Bridgetown.logger.warn "Liquid Warning:",
54
+ LiquidRenderer.format_error(e, path || document.relative_path)
55
+ end
56
+ template.render!(options.deep_stringify_keys, _liquid_context)
57
+ end
58
+
59
+ def helpers
60
+ @helpers ||= Helpers.new(@site)
61
+ end
62
+
63
+ def method_missing(method, *args, &block)
64
+ if helpers.respond_to?(method.to_sym)
65
+ helpers.send method.to_sym, *args, &block
66
+ else
67
+ super
68
+ end
69
+ end
70
+
71
+ def respond_to_missing?(method, include_private = false)
72
+ helpers.respond_to?(method.to_sym, include_private) || super
73
+ end
74
+
75
+ private
76
+
77
+ def _render_statement(component, options)
78
+ render_statement = ["{% render \"#{component}\""]
79
+ unless options.empty?
80
+ render_statement << ", " + options.keys.map { |k| "#{k}: #{k}" }.join(", ")
81
+ end
82
+ render_statement << " %}"
83
+ render_statement.join
84
+ end
85
+
86
+ def _liquid_context
87
+ {
88
+ registers: {
89
+ site: site,
90
+ page: page,
91
+ cached_partials: Bridgetown::Renderer.cached_partials,
92
+ },
93
+ strict_filters: site.config["liquid"]["strict_filters"],
94
+ strict_variables: site.config["liquid"]["strict_variables"],
95
+ }
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+
5
+ module Bridgetown
6
+ module Tags
7
+ # A ClassMap class is meant to take a hash and append styles based on if the
8
+ # value is truthy or falsy
9
+ #
10
+ # @example
11
+ # center-var = true
12
+ # small-var = nil
13
+ #
14
+ # # input
15
+ # <div class="{% class_map has-centered-text: center-var, is-small: small-var %}">
16
+ # Text
17
+ # </div>
18
+ #
19
+ # # output
20
+ # <div class="has-centered-text">
21
+ # Text
22
+ # </div>
23
+ class ClassMap < Liquid::Tag
24
+ # @see https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
25
+ FALSE_VALUES = [
26
+ nil, "nil", "NIL", false, 0, "0", :"0", "f", :f, "F", :F, "false",
27
+ false, "FALSE", :FALSE,
28
+ ].to_set.freeze
29
+
30
+ # @param tag_name [String] The name to use for the tag
31
+ # @param input [String] The input to the tag
32
+ # @param tokens [Hash] A hash of config tokens for Liquid.
33
+ #
34
+ #
35
+ # @return [ClassMap] Returns a ClassMap object
36
+ def initialize(tag_name, input, tokens)
37
+ super
38
+ @input = input
39
+ end
40
+
41
+ def render(context)
42
+ class_map(@input, context)
43
+ end
44
+
45
+ private
46
+
47
+ def class_map(string, context)
48
+ ary = []
49
+
50
+ string.split(%r!,\s+!).each do |item|
51
+ kv_pair = item.split(%r!:\s+!)
52
+ klass = kv_pair[0]
53
+ variable = kv_pair[1]
54
+
55
+ # Check if a user wants the opposite of the variable
56
+ if variable[0] == "!"
57
+ check_opposite = true
58
+ variable.slice!(1..-1)
59
+ end
60
+
61
+ variable = find_variable(context, variable)
62
+
63
+ if check_opposite
64
+ ary.push(klass) if FALSE_VALUES.include?(variable)
65
+ else
66
+ ary.push(klass) unless FALSE_VALUES.include?(variable)
67
+ end
68
+ end
69
+
70
+ ary.join(" ")
71
+
72
+ # Gracefully handle if syntax is improper
73
+ rescue NoMethodError
74
+ "invalid-class-map"
75
+ end
76
+
77
+ def find_variable(context, variable)
78
+ lookup = context
79
+
80
+ variable.split(".").each do |value|
81
+ lookup = lookup[value.strip]
82
+ end
83
+
84
+ lookup || nil
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ Liquid::Template.register_tag("class_map", Bridgetown::Tags::ClassMap)
@@ -212,7 +212,9 @@ module Bridgetown
212
212
  else
213
213
  File.join(site.config["collections_dir"], page_payload["path"])
214
214
  end
215
+ # rubocop:disable Performance/DeleteSuffix
215
216
  resource_path.sub!(%r!/#excerpt\z!, "")
217
+ # rubocop:enable Performance/DeleteSuffix
216
218
  site.in_source_dir File.dirname(resource_path)
217
219
  end
218
220
  end
@@ -3,6 +3,7 @@
3
3
  module Bridgetown
4
4
  module Tags
5
5
  class BlockRenderTag < Liquid::Block
6
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
6
7
  def render(context)
7
8
  context.stack({}) do
8
9
  # unindent the incoming text
@@ -19,7 +20,15 @@ module Bridgetown
19
20
  unless regions.empty?
20
21
  regions.each do |region_name, region_content|
21
22
  region_name = region_name.sub("content_with_region_", "")
22
- context[region_name] = converter.convert(region_content.strip_heredoc)
23
+
24
+ if region_name.end_with? ":markdown"
25
+ region_name.sub!(%r!:markdown$!, "")
26
+ context[region_name] = converter.convert(
27
+ Bridgetown::Utils.reindent_for_markdown(region_content)
28
+ )
29
+ else
30
+ context[region_name] = region_content
31
+ end
23
32
  render_params.push "#{region_name}: #{region_name}"
24
33
  end
25
34
  end
@@ -28,6 +37,7 @@ module Bridgetown
28
37
  .render_tag(context, +"")
29
38
  end
30
39
  end
40
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
31
41
 
32
42
  private
33
43
 
@@ -2,38 +2,35 @@
2
2
 
3
3
  module Bridgetown
4
4
  module Tags
5
+ # A helper class to help find the path to webpack asset inside of a webpack
6
+ # manifest file.
5
7
  class WebpackPath < Liquid::Tag
6
- include Bridgetown::Filters::URLFilters
7
-
8
- def initialize(tag_name, asset_type, tokens)
8
+ # @param tag_name [String] Name of the tag
9
+ # @param asset_type [String] The type of asset to parse (js, css)
10
+ # @param options [Hash] An options hash
11
+ # @return [void]
12
+ # @see {https://www.rdoc.info/github/Shopify/liquid/Liquid/Tag#initialize-instance_method}
13
+ def initialize(tag_name, asset_type, options)
9
14
  super
10
15
 
11
16
  # js or css
12
17
  @asset_type = asset_type.strip
13
18
  end
14
19
 
20
+ # Render an asset path based on the Webpack manifest file
21
+ # @param context [Liquid::Context] Context passed to the tag
22
+ #
23
+ # @return [String] Returns "MISSING_WEBPACK_MANIFEST" if the manifest
24
+ # file isn't found
25
+ # @return [String] Returns a blank string if the asset isn't found
26
+ # @return [String] Returns the path to the asset if no issues parsing
27
+ #
28
+ # @raise [WebpackAssetError] if unable to find css or js in the manifest
29
+ # file
15
30
  def render(context)
16
31
  @context = context
17
32
  site = context.registers[:site]
18
-
19
- frontend_path = relative_url("_bridgetown/static")
20
-
21
- manifest_file = site.in_root_dir(".bridgetown-webpack", "manifest.json")
22
- if File.exist?(manifest_file)
23
- manifest = JSON.parse(File.read(manifest_file))
24
- if @asset_type == "js"
25
- js_path = manifest["main.js"].split("/").last
26
- [frontend_path, "js", js_path].join("/")
27
- elsif @asset_type == "css"
28
- css_path = manifest["main.css"].split("/").last
29
- [frontend_path, "css", css_path].join("/")
30
- else
31
- Bridgetown.logger.error("Unknown Webpack asset type", @asset_type)
32
- nil
33
- end
34
- else
35
- "MISSING_WEBPACK_MANIFEST"
36
- end
33
+ Bridgetown::Utils.parse_webpack_manifest_file(site, @asset_type) || ""
37
34
  end
38
35
  end
39
36
  end
@@ -331,6 +331,59 @@ module Bridgetown
331
331
  end
332
332
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
333
333
 
334
+ # Return an asset path based on the Webpack manifest file
335
+ # @param site [Bridgetown::Site] The current site object
336
+ # @param asset_type [String] js or css
337
+ #
338
+ # @return [String] Returns "MISSING_WEBPACK_MANIFEST" if the manifest
339
+ # file isnt found
340
+ # @return [nil] Returns nil if the asset isnt found
341
+ # @return [String] Returns the path to the asset if no issues parsing
342
+ #
343
+ # @raise [WebpackAssetError] if unable to find css or js in the manifest
344
+ # file
345
+ def parse_webpack_manifest_file(site, asset_type)
346
+ manifest_file = site.in_root_dir(".bridgetown-webpack", "manifest.json")
347
+ return "MISSING_WEBPACK_MANIFEST" unless File.exist?(manifest_file)
348
+
349
+ manifest = JSON.parse(File.read(manifest_file))
350
+
351
+ known_assets = %w(js css)
352
+ if known_assets.include?(asset_type)
353
+ asset_path = manifest["main.#{asset_type}"]
354
+
355
+ log_webpack_asset_error(asset_type) && return if asset_path.nil?
356
+
357
+ asset_path = asset_path.split("/").last
358
+ return [static_frontend_path(site), asset_type, asset_path].join("/")
359
+ end
360
+
361
+ Bridgetown.logger.error("Unknown Webpack asset type", asset_type)
362
+ nil
363
+ end
364
+
365
+ def static_frontend_path(site)
366
+ path_parts = [site.config["baseurl"].to_s.chomp("/"), "_bridgetown/static"]
367
+ path_parts[0] = "/#{path_parts[0]}" unless path_parts[0].empty?
368
+ Addressable::URI.parse(path_parts.join("/")).normalize.to_s
369
+ end
370
+
371
+ def log_webpack_asset_error(asset_type)
372
+ error_message = "There was an error parsing your #{asset_type} files. \
373
+ Please check your #{asset_type} for any errors."
374
+
375
+ Bridgetown.logger.warn(Errors::WebpackAssetError, error_message)
376
+ end
377
+
378
+ def default_github_branch_name(repo_url)
379
+ repo_match = Bridgetown::Commands::Actions::GITHUB_REPO_REGEX.match(repo_url)
380
+ api_endpoint = "https://api.github.com/repos/#{repo_match[1]}"
381
+ JSON.parse(Faraday.get(api_endpoint).body)["default_branch"] || "master"
382
+ rescue StandardError => e
383
+ Bridgetown.logger.warn("Unable to connect to GitHub API: #{e.message}")
384
+ "master"
385
+ end
386
+
334
387
  private
335
388
 
336
389
  def merge_values(target, overwrite)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bridgetown
4
- VERSION = "0.15.0.beta3"
5
- CODE_NAME = "Overlook"
4
+ VERSION = "0.16.0"
5
+ CODE_NAME = "Crystal Springs"
6
6
  end
@@ -10,12 +10,14 @@
10
10
  # For reloadable site metadata like title, SEO description, social media
11
11
  # handles, etc., take a look at src/_data/site_metadata.yml
12
12
  #
13
- # If you need help with YAML syntax, here are some quick references for you:
13
+ # If you need help with YAML syntax, here are some quick references for you:
14
14
  # https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml
15
15
  # https://learnxinyminutes.com/docs/yaml/
16
16
  #
17
17
 
18
18
  baseurl: "" # OPTIONAL: the subpath of your site, e.g. /blog
19
- url: "" # the base hostname & protocol for your site, e.g. http://example.com
19
+ url: "" # the base hostname & protocol for your site, e.g. https://example.com
20
20
 
21
- # Additional build settings go here
21
+ permalink: pretty
22
+
23
+ # timezone: America/Los_Angeles
@@ -4,7 +4,7 @@
4
4
  {% render "head", metadata: site.metadata, title: page.title %}
5
5
  </head>
6
6
  <body class="{{ page.layout }} {{ page.page_class }}">
7
- {% render "navbar" %}
7
+ {% render "navbar", metadata: site.metadata, page: page %}
8
8
 
9
9
  <main>
10
10
  {{ content }}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bridgetown-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0.beta3
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bridgetown Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-05 00:00:00.000000000 Z
11
+ date: 2020-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: awesome_print
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.8'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.8'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: colorator
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,20 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: erubi
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.9'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.9'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: faraday
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -248,6 +276,20 @@ dependencies:
248
276
  - - "~>"
249
277
  - !ruby/object:Gem::Version
250
278
  version: '1.0'
279
+ - !ruby/object:Gem::Dependency
280
+ name: tilt
281
+ requirement: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - "~>"
284
+ - !ruby/object:Gem::Version
285
+ version: '2.0'
286
+ type: :runtime
287
+ prerelease: false
288
+ version_requirements: !ruby/object:Gem::Requirement
289
+ requirements:
290
+ - - "~>"
291
+ - !ruby/object:Gem::Version
292
+ version: '2.0'
251
293
  description: Bridgetown is a Webpack-aware, Ruby-powered static site generator for
252
294
  the modern Jamstack era
253
295
  email: maintainers@bridgetownrb.com
@@ -278,15 +320,20 @@ files:
278
320
  - lib/bridgetown-core/commands/registrations.rb
279
321
  - lib/bridgetown-core/commands/serve.rb
280
322
  - lib/bridgetown-core/commands/serve/servlet.rb
281
- - lib/bridgetown-core/concerns/convertible.rb
323
+ - lib/bridgetown-core/concerns/data_accessible.rb
324
+ - lib/bridgetown-core/concerns/layout_placeable.rb
325
+ - lib/bridgetown-core/concerns/liquid_renderable.rb
326
+ - lib/bridgetown-core/concerns/publishable.rb
282
327
  - lib/bridgetown-core/concerns/site/configurable.rb
283
328
  - lib/bridgetown-core/concerns/site/content.rb
284
329
  - lib/bridgetown-core/concerns/site/extensible.rb
285
330
  - lib/bridgetown-core/concerns/site/processable.rb
286
331
  - lib/bridgetown-core/concerns/site/renderable.rb
287
332
  - lib/bridgetown-core/concerns/site/writable.rb
333
+ - lib/bridgetown-core/concerns/validatable.rb
288
334
  - lib/bridgetown-core/configuration.rb
289
335
  - lib/bridgetown-core/converter.rb
336
+ - lib/bridgetown-core/converters/erb_templates.rb
290
337
  - lib/bridgetown-core/converters/identity.rb
291
338
  - lib/bridgetown-core/converters/markdown.rb
292
339
  - lib/bridgetown-core/converters/markdown/kramdown_parser.rb
@@ -341,8 +388,10 @@ files:
341
388
  - lib/bridgetown-core/regenerator.rb
342
389
  - lib/bridgetown-core/related_posts.rb
343
390
  - lib/bridgetown-core/renderer.rb
391
+ - lib/bridgetown-core/ruby_template_view.rb
344
392
  - lib/bridgetown-core/site.rb
345
393
  - lib/bridgetown-core/static_file.rb
394
+ - lib/bridgetown-core/tags/class_map.rb
346
395
  - lib/bridgetown-core/tags/highlight.rb
347
396
  - lib/bridgetown-core/tags/include.rb
348
397
  - lib/bridgetown-core/tags/link.rb
@@ -370,14 +419,14 @@ files:
370
419
  - lib/site_template/plugins/builders/.keep
371
420
  - lib/site_template/plugins/site_builder.rb
372
421
  - lib/site_template/src/404.html
373
- - lib/site_template/src/_components/footer.html
374
- - lib/site_template/src/_components/head.html
375
- - lib/site_template/src/_components/navbar.html
422
+ - lib/site_template/src/_components/footer.liquid
423
+ - lib/site_template/src/_components/head.liquid
424
+ - lib/site_template/src/_components/navbar.liquid
376
425
  - lib/site_template/src/_data/site_metadata.yml
377
- - lib/site_template/src/_layouts/default.html
378
- - lib/site_template/src/_layouts/home.html
379
- - lib/site_template/src/_layouts/page.html
380
- - lib/site_template/src/_layouts/post.html
426
+ - lib/site_template/src/_layouts/default.liquid
427
+ - lib/site_template/src/_layouts/home.liquid
428
+ - lib/site_template/src/_layouts/page.liquid
429
+ - lib/site_template/src/_layouts/post.liquid
381
430
  - lib/site_template/src/_posts/0000-00-00-welcome-to-bridgetown.md.erb
382
431
  - lib/site_template/src/about.md
383
432
  - lib/site_template/src/favicon.ico