Recent Activities

This page shows what are we working on.

breezefront / module-breeze-ai

6 hours ago success
  • head
    • feat(skills): a query-scoped skill contract, so a search skill can exist (#189)

      SkillInterface::execute() takes an `object $entity`. A product-discovery
      skill has none: it is handed a phrase and the storefront scope, and the
      entities are its result. #190 and #192 both stop here.

      Adds, without touching anything that exists:

      * Api\QuerySkillInterface — getCode/getLabel/execute(string $query,
      array $history, array $options). Scope travels in $options, as it
      already does through GenerateService, AiRequest and every entity
      skill; a typed context object would have to be assembled by each of
      the planned callers for no consumer that exists yet.
      * Api\Data\QueryResultInterface + Model\Data\QueryResult — answer text
      plus the entities it refers to. A query skill returns structure, not
      a string: BuildPage shows the cost of the alternative, its caller
      json_decodes the result and finds a malformed answer three frames
      from where it was produced (BulkConsumer.php:348). Cost and latency
      stay out — the usage ledger (#171) already records both per request.
      * Model\QuerySkillPool — a second pool, not a widened SkillPool.
      Every consumer of SkillPool assumes entity semantics: SkillSupport
      and BulkAction\ViewData call getSupportedEntityTypes(), McpServer
      gives each pooled skill a tool whose schema requires entityType and
      entityId. One pool of a common parent type does not stay typed; it
      becomes a parent type plus an instanceof in four places, and a query
      skill nobody filtered out is published as a tool no client can call.

      QuerySkillInterface deliberately does not share a parent interface with
      SkillInterface. Declaring getCode() and getLabel() twice keeps this
      change strictly additive, so no implementor — ours or a merchant's —
      can break on upgrade; extracting the parent later is itself backwards
      compatible, so the option costs nothing to defer.

      The five existing skills, SkillPool, BulkConsumer and the MCP tool list
      are untouched. Unit tests cover resolution of both kinds and both
      cross-kind mistakes.

      Checked on 2.4.7 as well as 2.4.8 (#197): ConstructorIntegrity,
      TypeDuplication and ArgumentSequence against a standalone
      magento/framework 103.0.7.0-patch10 and 103.0.8.0-patch1 — clean on
      both, with the #197 widening re-introduced as a positive control to
      prove the gate was live.

      Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> 013f50

    • fix(content-builder): keep the failed payload and name the output limit (#188)

      Review of #199 found five things the structured-output move left behind.

      The providers carry no logger, so a payload that is not put on the
      exception is gone: StructuredResponseException now holds the raw reply
      and BuildPage logs it, which is what master's logUnreadableReply() was
      written to keep. Null on a truncation or a refusal, where the stop
      reason settles it before a body exists.

      A document cut off inside the "components" string is the one shape of
      #143 the stop reason cannot catch — the envelope closes normally and
      the provider reports an ordinary stop — so the sentence for an
      unreadable document names the output limit itself.

      Also: a negative "bands" is read as no count rather than as the number
      it says, because `minimum` is outside the subset Schema\Validator
      accepts and BandAudit would otherwise report "read as -2 band(s)"; and
      a reply that missed the schema no longer borrows the document's
      sentence, in the same words and punctuation on both skills.

      Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> 8568ec

    • chore(content-builder): move BuildPage and PlanPage to structured output (#188)

      Both skills asked for JSON in the prompt and dug the answer out of the reply
      text afterwards. That cost us the one fact that separates the failures: a
      document the provider cut off at the output limit and a document the model
      mangled both reached the merchant as json_decode's "Syntax error" (#143), and
      they want opposite answers — raise a number, or try again.

      Both now call AiRequest::sendStructured() with a response schema (#187), and a
      call that produced no usable answer arrives as StructuredResponseException with
      a reason. Each skill turns the three reasons into three named sentences,
      carrying the provider's own message — the one that names "Max Tokens" — whole.

      PlanPage is fully structured: PlanSchema describes {"sections": [...]} and the
      skill parses nothing at all. extractJson() and its json_decode are gone.

      BuildPage gets as far as the schema subset reaches. A Content Builder node has
      free-form "props" and recursive "children", and neither is expressible under
      OpenAI strict mode — nor, therefore, under the intersection Schema\Validator
      holds. So DocumentSchema schematises the envelope ("bands" an integer or null,
      "unsupported" a list of strings, both checked on the way out) and the document
      travels inside it as a JSON string, read by the new ContentBuilder\DocumentReader.
      DocumentSchema's class comment sets out why, and what finishing the job would
      take: a flat node list with parent references, which is a measurement to run
      rather than a refactor to slip in here.

      What that removes from Model/Skill: the fenced-block regex, the widest-bracket-run
      candidates, the lone-backslash repair pass, the hand-written bracket scanner that
      sliced a broken list element by element, and the envelope scraper. Around 630
      lines of BuildPage. The partial-page salvage goes with them — a truncation is now
      reported as a truncation before any document exists, instead of handing back a
      prefix nobody could verify.

      StopReason stays and is unchanged; it is read off the response field by
      Provider\StructuredResponse, which is where it already was.

      Checked: no json_decode or preg_match over a model reply is left in Model/Skill;
      the two schemas pass Schema\Validator and lower onto all three dialects
      (SkillSchemaTest); truncation, refusal and a reply that missed the shape each
      produce a different named error in both skills' tests. 2185 unit tests pass.

      Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> e506b3

  • 1.8.22
    • Version 1.8.22 9893b7

    • fix(providers): StructuredResponseException cause type breaks di:compile on 2.4.7 (#197) (#198)

      * fix(providers): StructuredResponseException cause type breaks di:compile on 2.4.7 (#197)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

      * style(providers): wrap the cause-type comment (#197)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

      ---------

      Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> 1d4842

    • style(providers): wrap the cause-type comment (#197)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 602747

    • fix(providers): StructuredResponseException cause type breaks di:compile on 2.4.7 (#197)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> a961ae

swissup / module-email

7 hours ago success
  • 0.7.15
    • Version 0.7.15 cd67bf

    • fix(smtp): reset STARTTLS state when the handshake fails (#44)

      A 220 reply to STARTTLS marked the connection as upgraded before the
      TLS handshake ran; if the handshake failed, the flag stayed set on a
      plain socket until the next start(). Clear it when start() fails and
      drop the redundant stop() override.

      Tests now also drive start() against a scripted SMTP server in a child
      process: a real STARTTLS handshake followed by AUTH, a server that
      does not offer STARTTLS, and a failed handshake.

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> 8b8e10

    • fix(smtp): allow mail after a STARTTLS upgrade (#44)

      SocketStream::isTLS() reports implicit TLS (port 465) only and stays
      false after STARTTLS, so RequireTlsSmtp refused AUTH on ports 587/2525
      even though the connection was encrypted. Track the accepted STARTTLS
      in the transport and reset it on reconnect.

      Fixes #44

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> 622063

    • fix(smtp): reset STARTTLS state when the handshake fails (#44)

      A 220 reply to STARTTLS marked the connection as upgraded before the
      TLS handshake ran; if the handshake failed, the flag stayed set on a
      plain socket until the next start(). Clear it when start() fails and
      drop the redundant stop() override.

      Tests now also drive start() against a scripted SMTP server in a child
      process: a real STARTTLS handshake followed by AUTH, a server that
      does not offer STARTTLS, and a failed handshake.

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> 4c4769

    • fix(smtp): allow mail after a STARTTLS upgrade (#44)

      SocketStream::isTLS() reports implicit TLS (port 465) only and stays
      false after STARTTLS, so RequireTlsSmtp refused AUTH on ports 587/2525
      even though the connection was encrypted. Track the accepted STARTTLS
      in the transport and reset it on reconnect.

      Fixes #44

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> f5e969

  • 0.7.14
    • Version 0.7.14 d58265

    • feat(log): delete logged emails after a configurable retention period (#42)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> e84db5

    • fix(acl): use matching ACL resources and ignore redirect and token fields in save (#42)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> e3a5f5

    • fix(service): stop exposing the stored password in the form and URL (#42)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> e1d05d

    • fix(smtp): enforce the SSL and TLS options of mail services (#42)

      SSL now uses implicit TLS (smtps). TLS now requires STARTTLS instead of silently continuing in clear text.

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 61be08

    • fix(grid): check ACL and stop returning bodies and passwords in grid data (#42)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> a0da7f

    • fix(acl): require ACL resources for inline edit and mass actions (#42)

      These actions fell back to Magento_Backend::admin, so any admin role could change or delete mail services.

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> f2baec

    • test: add PHPUnit setup (#42)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 4ee61c

    • feat(log): delete logged emails after a configurable retention period (#42)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 355c80

    • fix(acl): use matching ACL resources and ignore redirect and token fields in save (#42)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 72377f

    • fix(service): stop exposing the stored password in the form and URL (#42)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> f0a25a

    • fix(smtp): enforce the SSL and TLS options of mail services (#42)

      SSL now uses implicit TLS (smtps). TLS now requires STARTTLS instead of silently continuing in clear text.

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> b914b0

    • fix(acl): use matching ACL resources and ignore redirect and token fields in save (#42)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 5d4124

    • fix(service): stop exposing the stored password in the form and URL (#42)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 354f53

    • fix(smtp): enforce the SSL and TLS options of mail services (#42)

      SSL now uses implicit TLS (smtps). TLS now requires STARTTLS instead of silently continuing in clear text.

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 342801

    • fix(grid): check ACL and stop returning bodies and passwords in grid data (#42)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 8a3b83

    • fix(acl): require ACL resources for inline edit and mass actions (#42)

      These actions fell back to Magento_Backend::admin, so any admin role could change or delete mail services.

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 6d5242

    • test: add PHPUnit setup (#42)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> dec9a8

swissup / navigationpro

9 hours ago success

swissup / module-navigationpro

9 hours ago success
  • 1.19.5
  • 1.19.4
    • Version 1.19.4 f97cb2

    • Security: harden {{navpro}} directive, admin preview, admin actions (CSRF), GraphQL (#37)

      * Security: restrict {{navpro}} method calls, sanitize admin HTML preview

      - {{navpro data="..."}} called any get* method on any reachable object,
      bypassing Magento's template strict mode. An admin with only item_save
      could read DB credentials via
      remote_entity.getResource.getConnection.getConfig.password.
      Only allowlisted methods (getProductCount, getUrl, getName, getImageUrl)
      are now callable; other segments read DataObject data only.
      - Dropdown layout HTML preview parsed stored content with jQuery in the
      live admin document, so <img/src=x onerror> or <svg onload> executed
      for any admin opening the menu. Parse in an inert DOMParser document and
      strip all attributes except data-src/data-content-type.

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

      * Security: make state-changing admin actions POST-only (CSRF)

      None of the admin controllers implemented HttpPostActionInterface, so
      delete/duplicate/create/move/save worked over GET, protected only by the
      admin URL secret key. With "Add Secret Key to URLs" disabled, e.g.
      <img src=".../navigationpro/menu/delete/menu_id/1"> deleted a menu.
      POST requests always require a valid form_key.

      - Item: Delete, Import, MassSave, Move, Save
      - Menu: Create, Delete, Duplicate, MassDelete, Save

      Callers switched to POST: item Delete button (deleteConfirm postData),
      grid row delete ('post' => true), Duplicate button (mage/dataPost),
      item drag-and-drop move ajax (form_key added by backend ajaxSetup).

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

      * Security: stop GraphQL leaking exception messages and raw item html

      - getNavproMenu wrapped every exception into a client-aware
      GraphQlNoSuchEntityException with the original message, exposing
      internal errors (e.g. SQL) to anonymous clients. Only
      NoSuchEntityException is converted now; anything else goes through
      Magento's GraphQL error handler (logged, masked as "Internal server
      error" outside developer mode).
      - Node::getFlatArray() discarded the filtered result, so the GraphQL
      `html` field returned raw template source ({{block}}, {{widget}},
      {{navpro}}) instead of rendered html.

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> fe9760

    • Security: stop GraphQL leaking exception messages and raw item html

      - getNavproMenu wrapped every exception into a client-aware
      GraphQlNoSuchEntityException with the original message, exposing
      internal errors (e.g. SQL) to anonymous clients. Only
      NoSuchEntityException is converted now; anything else goes through
      Magento's GraphQL error handler (logged, masked as "Internal server
      error" outside developer mode).
      - Node::getFlatArray() discarded the filtered result, so the GraphQL
      `html` field returned raw template source ({{block}}, {{widget}},
      {{navpro}}) instead of rendered html.

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> 8387a0

    • Security: make state-changing admin actions POST-only (CSRF)

      None of the admin controllers implemented HttpPostActionInterface, so
      delete/duplicate/create/move/save worked over GET, protected only by the
      admin URL secret key. With "Add Secret Key to URLs" disabled, e.g.
      <img src=".../navigationpro/menu/delete/menu_id/1"> deleted a menu.
      POST requests always require a valid form_key.

      - Item: Delete, Import, MassSave, Move, Save
      - Menu: Create, Delete, Duplicate, MassDelete, Save

      Callers switched to POST: item Delete button (deleteConfirm postData),
      grid row delete ('post' => true), Duplicate button (mage/dataPost),
      item drag-and-drop move ajax (form_key added by backend ajaxSetup).

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> 88dd36

    • Security: restrict {{navpro}} method calls, sanitize admin HTML preview

      - {{navpro data="..."}} called any get* method on any reachable object,
      bypassing Magento's template strict mode. An admin with only item_save
      could read DB credentials via
      remote_entity.getResource.getConnection.getConfig.password.
      Only allowlisted methods (getProductCount, getUrl, getName, getImageUrl)
      are now callable; other segments read DataObject data only.
      - Dropdown layout HTML preview parsed stored content with jQuery in the
      live admin document, so <img/src=x onerror> or <svg onload> executed
      for any admin opening the menu. Parse in an inert DOMParser document and
      strip all attributes except data-src/data-content-type.

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> ad87a1

    • Move styles to non-critical. Remove search styles. Cleanup grid. e50a2b

    • Do not build the tree in prepareLayout 52e1ba

swissup / module-swissuplabs

11 hours ago success
  • head
    • Add icons to customer menu #44 cf113b

    • Subscription product page: add product-subscription body class ae2732

    • Redirect sales/order/reorder to the order page e19f99

    • Stores Using attribute: use wysiwyg/stores in field note example c49caf

    • Add product atribute stores_using 4f2b4a

    • Show subscription expired message on Activation and My Tickets pages e1d992

  • 1.0.0
    • Use category path in breadcrumbs #50 317f00

swissup / theme-frontend-swissuplabs

11 hours ago success
  • head
    • Add icons to customer menu #44 a6a11e

    • Subscription product page: show Buy button on mobile #43 ec0d18

    • Improve deployer page #48 d87605

    • Subscription archive: link Reorder to order page instead of sales/order/reorder #53 c42992

    • Stores using: add srcset with PageSpeed 0.5x/0.75x variants and sizes for store images #49 d8a112

    • Product Page: Add section Stores using ceed62

    • Fix Red Hat Display font preload 70dfce

    • Product page: keep product name from jumping when ProLabels label is inserted ed8eef

    • Fix listing grid columns for 1column layout: use current Breeze variable names #52 4c81d9

    • Blog: replace FontAwesome list icon with SVG, style wp-block-code like Prism 7febcd

    • Use category path in breadcrumbs #50 4b10c4

swissup / module-ignition

12 hours ago success
  • 1.3.4
    • Version 1.3.4 0c8f58

    • Integration tests fix: Restore error handlers and remove exit. #8 836796

  • 1.3.3
    • Version 1.3.3 0f8d9f

    • Security and robustness fixes (#9)

      - Restrict update-config to developer mode and validate values
      - Censor sensitive request data in Flare reports
      - Open the error modal only for Ignition error responses
      - Keep the store's error reporting level
      - Fix Magento coding standard errors in copy-buttons.js

      Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> d86e96

    • Security and robustness fixes

      - Restrict update-config to developer mode and validate values
      - Censor sensitive request data in Flare reports
      - Open the error modal only for Ignition error responses
      - Keep the store's error reporting level
      - Fix Magento coding standard errors in copy-buttons.js

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> e15a70

    • Strip query from Referer header in Flare reports

      The Referer header could contain tokens, e.g. a password reset link.
      Also use explode() instead of strtok(), which skips a leading "?".

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> 09d9c8

    • Fix Magento coding standard errors in copy-buttons.js

      Avoid self-closing tags with non-void elements in the SVG icons.

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> 20f4b7

    • Keep the store's error reporting level

      Ignition::register() without arguments forces error_reporting(-1), which
      overrode the level set in app/bootstrap.php or by the store. Stores that
      exclude deprecations (E_ALL & ~E_DEPRECATED) got 500 errors on every
      deprecation once the module was installed.

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> d98949

    • Open error modal only for responses marked by Plugin\App

      The modal opened for any failed ajax response containing the
      "window.ignite(window.data)" marker, including cross-origin responses
      and error responses that reflect user input, which allowed XSS.

      Plugin\App now sends an X-Ignition-Error-Page header with the error page
      and the modal requires it. Also fixes a JS error on Breeze network errors,
      where the fail callback receives no xhr.

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> d733c5

    • Censor cookies in Flare JS error reports

      The Flare JS client sent all cookies readable by JS (form_key and others)
      with every error report. Replace their values before submitting.

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> 22f466

    • Censor sensitive data in Flare reports

      Production reports sent to Flare included the full request: cookies,
      Authorization header, passwords and card data from the POST body, tokens
      in the URL, and stack frame arguments.

      - Add CensorSensitiveData middleware: censors cookies, sensitive headers,
      and sensitive keys in body and query string (nested keys included),
      and strips the query from the request URL.
      - Disable stack frame arguments in production.
      - Keep user provided context when copying the report, otherwise
      middleware changes were lost.

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> c5a9d0

    • Fix stored XSS via unauthenticated update-config endpoint

      The endpoint was available in all modes without authentication and saved
      arbitrary values, which the error page renders unescaped (theme). Now it
      works in developer mode only and accepts known values only.

      Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> abcc71

swissup / module-pro-labels-configurable-product

2 days ago success
  • head
    • Add AJAX controller for fetching product labels and update label handling logic 33072b

  • 1.0.10
    • Version 1.0.10 b8b88d

    • Fix child labels ignoring schedule, store and product status

      - Skip expired labels and pass active period to frontend
      - Filter index by store view, skip disabled and out-of-website children
      - Validate $mode before using it in SQL column names
      - Require swissup/module-pro-labels ^1.10.0 (active period columns) 3074b5

swissup / module-advanced-js-bundling

3 days ago success
  • 0.1.2
    • Version 0.1.2 10c36c

    • docs: mark Advanced JS Bundling as experimental

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 08c59d

  • 0.1.1
    • Version 0.1.1 cf896f

    • fix: skip the bundles block on Breeze themes, document the upgrade from pagespeed < 1.21

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> ec4301

swissup / module-pagespeed

3 days ago success
  • 1.21.0
    • Version 1.21.0 28f0bf

    • fix(installer): do not enable Advanced JS Bundling by default 19fc09

    • Merge pull request #134 from swissup/feat/extract-advanced-js-bundling

      refactor: move Advanced JS Bundling to swissup/module-advanced-js-bundling 343655

    • fix: keep deprecated config path constants, skip the order test without the new module

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 9d53ff

    • Merge master into feat/extract-advanced-js-bundling

      # Conflicts:
      # composer.json 1714b2

  • 1.20.1
    • Version 1.20.1 de757e

    • Merge pull request #136 from swissup/fix/security-audit-135

      fix(security): audit findings (#135) 8aa502

    • fix(critical-css): reject any markup in critical CSS and share the POST script (#135)

      - assertSafeCss rejects every markup start (<link>, <svg>, <img>, ...), not only
      style/script/comment; saveConfig() runs the same check
      - move the duplicated getPostScript() into PostScriptTrait
      - DebugModeDefaultTest asserts config.xml loaded

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 406f33

    • fix(csp): whitelist www.googleapis.com for the admin area only (#135)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> bab7ee

    • fix(critical-css): generate actions accept POST with form key only (#135)

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 46e02b

    • fix(critical-css): use https and reject markup in the API response (#135)

      The response is printed unescaped into a <style> tag, so a response that
      closes the tag or opens a script is refused.

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> aecc4f

    • fix(debug): disable debug mode by default (#135)

      The ?pagespeed= switch and the debug console output were open to every
      visitor on a fresh install. They stay available once debug mode is
      enabled on purpose.

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> 933453

    • test: run ProductionHeadOrderTest against the Bundles block of the new module

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> cb52e3

    • refactor: move Advanced JS Bundling to swissup/module-advanced-js-bundling

      Config keys and the bundle path are unchanged; the new package is required.

      Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> b964d6