tag
+ if (
+ (item.tagName === 'SECTION' || item.classList.contains('section')) &&
+ /^H[1-6]/.test(item.children[0].tagName)
+ ) {
+ name = item.children[0].textContent
+ item.classList.remove('panel-name')
+ item.removeChild(item.children[0])
+ return name
+ }
+
+ const nameDiv = item.querySelector('.panel-name')
+ if (!nameDiv) return name
+
+ // In remarkjs the .panel-name span might be in a paragraph tag
+ // and if the is empty, we'll remove it
+ if (
+ nameDiv.tagName === 'SPAN' &&
+ nameDiv.parentNode.tagName === 'P' &&
+ nameDiv.textContent === nameDiv.parentNode.textContent
+ ) {
+ name = nameDiv.textContent
+ item.removeChild(nameDiv.parentNode)
+ return name
+ }
+
+ // If none of the above, remove the nameDiv and return the name
+ name = nameDiv.textContent
+ nameDiv.parentNode.removeChild(nameDiv)
+ return name
+ }
+
+ function getElementAttributes (el) {
+ return {
+ classes: Array.from(el.classList)
+ .filter(c => !/^level\d$/.test(c))
+ .toString(),
+ style: el.style.cssText,
+ dataset: el.dataset
+ }
+ }
+
+ /**
+ * Processes an original section of content and prepare data for the content
+ * panel the item will become.
+ *
+ * @param {HTMLElement} item - The panel item to process.
+ * @returns {Object|null} - An object containing the panel's name, content,
+ * id, active status, and other attributes. Returns null if the panel name
+ * cannot be identified.
+ */
+ const processPanelItem = item => {
+ const name = identifyPanelName(item)
+ if (!name) {
+ return null
+ }
+ return {
+ name,
+ content: item.children,
+ id: uniquePanelId(name),
+ active:
+ item.dataset &&
+ ['', 'true'].includes(item.dataset.active?.toLowerCase()),
+ ...getElementAttributes(item)
+ }
+ }
+
+ /**
+ * Retrieves the current panel from the URL parameters.
+ * @param {string} panelsetId - The ID of the panelset.
+ * @returns {string|null} - The current panel ID or null if not in the URL.
+ */
+ const getCurrentPanelFromUrl = panelsetId => {
+ const params = new URLSearchParams(window.location.search)
+ return params.get(panelsetId)
+ }
+
+ /**
+ * Returns the initial selected panel ID based on the provided panels and
+ * the ID of the corresponding panelset. The active panel is chosen
+ * following:
+ *
+ * 1. If the panselset appears in the URL, use the panel ID from the URL.
+ * 2. If there is an active panel, use the ID of the first active panel.
+ * 3. Use the ID of the first panel in the array.
+ *
+ * Note that groups are not considered here. If the panelset is part of a
+ * group, the group state will be updated after the initial panelset is
+ * created.
+ *
+ * @param {Array} panels - The array of panel objects.
+ * @param {string} panelsetId - The ID of the panelset specified in the URL.
+ * @returns {string} - The ID of the initial selected panel.
+ */
+ function getInitSelectedPanel (panels, panelsetId) {
+ const panelIds = panels.map(p => p.id)
+
+ const panelSelectedUrl = getCurrentPanelFromUrl(panelsetId)
+ if (panelSelectedUrl && panelIds.includes(panelSelectedUrl)) {
+ return panelSelectedUrl
+ }
+
+ const panelsActive = panels.filter(p => p.active)
+ if (panelsActive.length) {
+ return panelsActive[0].id
+ }
+
+ return panels[0].id
+ }
+
+ /**
+ * Creates a panel set element with header tabs and corresponding content
+ * sections.
+ *
+ * @param {Array} panels - An array of panel objects.
+ * @param {Object} options - An object containing optional parameters for
+ * the panel set.
+ * @param {string} options.id - The ID of the panel set element.
+ * @param {string} options.classes - Additional CSS classes to be applied to
+ * the panel set element.
+ * @param {string} options.style - Inline CSS styles to be applied to the
+ * panel set element.
+ * @param {Object} options.dataset - Custom data attributes to be added to
+ * the panel set element.
+ * @returns {HTMLElement} - The created panel set element.
+ */
+ const reflowPanelSet = (panels, { id, classes, style, dataset }) => {
+ const res = document.createElement('div')
+ res.classList = 'panelset' + (classes ? ' ' + classes : '')
+ res.id = uniquePanelsetId(id)
+ res.style.cssText = style
+ if (dataset) {
+ Object.keys(dataset).forEach(key => {
+ res.dataset[key] = dataset[key]
+ })
+ }
+
+ const panelSelected = getInitSelectedPanel(panels, res.id)
+
+ // create header row
+ const headerRow = document.createElement('ul')
+ headerRow.className = 'panel-tabs'
+ headerRow.setAttribute('role', 'tablist')
+ panels
+ .map((p, idx) => {
+ const thisPanelIsActive = panelSelected === p.id
+
+ const panelHeaderItem = document.createElement('li')
+ panelHeaderItem.id = res.id + '_' + p.id // #panelsetid_panelid
+ panelHeaderItem.className = 'panel-tab'
+ panelHeaderItem.setAttribute('role', 'tab')
+ if (thisPanelIsActive) {
+ panelHeaderItem.tabIndex = 0
+ }
+ panelHeaderItem.classList.toggle(
+ 'panel-tab-active',
+ thisPanelIsActive
+ )
+ panelHeaderItem.setAttribute('aria-selected', thisPanelIsActive)
+
+ if (p.dataset) {
+ Object.keys(p.dataset).forEach(key => {
+ panelHeaderItem.dataset[key] = p.dataset[key]
+ })
+ }
+
+ const panelHeaderLink = document.createElement('a')
+ panelHeaderLink.href =
+ '?' + res.id + '=' + p.id + '#' + panelHeaderItem.id
+ panelHeaderLink.setAttribute('onclick', 'return false;')
+ panelHeaderLink.tabIndex = -1 // list item is tabable, not link
+ panelHeaderLink.innerHTML = p.name
+ panelHeaderLink.setAttribute('aria-controls', p.id)
+
+ panelHeaderItem.appendChild(panelHeaderLink)
+ return panelHeaderItem
+ })
+ .forEach(el => headerRow.appendChild(el))
+
+ res.appendChild(headerRow)
+
+ panels
+ .map((p, idx) => {
+ const thisPanelIsActive = panelSelected === p.id
+ const panelTag = inRevealjs() ? 'div' : 'section'
+ const panelContent = document.createElement(panelTag)
+ panelContent.classList = p.classes ? 'panel ' + p.classes : 'panel'
+ panelContent.style.cssText = p.style
+ panelContent.classList.toggle('panel-active', thisPanelIsActive)
+ panelContent.id = p.id
+ // https://www.w3.org/WAI/ARIA/apg/patterns/tabs/examples/tabs-automatic/
+ panelContent.setAttribute('role', 'tabpanel')
+ panelContent.setAttribute('aria-labelledby', p.id)
+ panelContent.tabIndex = 0
+ Array.from(p.content).forEach(el => panelContent.appendChild(el))
+ return panelContent
+ })
+ .forEach(el => res.appendChild(el))
+
+ return res
+ }
+
+ /*
+ * Update selected panel for panelset or delete panelset from query string
+ *
+ * @param panelset Panelset ID to update in the search params @param panel
+ * Panel ID of selected panel in panelset, or null to delete from search
+ * params @param params Current params object, or params from
+ * window.location.search
+ */
+
+ /**
+ * Updates the search parameters with the specified panelset and panel
+ * values. If a panel is provided, it sets the panelset and panel in the
+ * search parameters. If no panel is provided, it removes the panelset from
+ * the search parameters.
+ *
+ * @param {string} panelsetId - The ID of the panelset.
+ * @param {string} [panelId] - The ID of the panel (optional).
+ * @param {URLSearchParams} [params=new
+ * URLSearchParams(window.location.search)] - The search parameters object
+ * (optional).
+ * @returns {URLSearchParams} - The updated search parameters object.
+ */
+ function updateSearchParams (
+ panelsetId,
+ panelId,
+ params = new URLSearchParams(window.location.search)
+ ) {
+ if (panelId) {
+ params.set(panelsetId, panelId)
+ } else {
+ params.delete(panelsetId)
+ }
+ return params
+ }
+
+ /*
+ * Update the URL to match params
+ */
+ const updateUrl = params => {
+ if (typeof params === 'undefined') return
+ params = params.toString() ? '?' + params.toString() : ''
+ const { pathname, hash } = window.location
+ const uri = pathname + params + hash
+ window.history.replaceState(uri, '', uri)
+ }
+
+ /**
+ * Handles the click event on a panel tab within a panelset.
+ * @param {HTMLElement} clicked - The clicked element.
+ */
+ function handleClickedPanel (clicked) {
+ const panelset = clicked.closest('.panelset')
+ if (!panelset) return
+
+ clicked = clicked.closest('.panel-tab')
+ if (!clicked) return
+
+ togglePanel(panelset, clicked)
+ }
+
+ /**
+ * Handles keydown events for the `.panel-tabs` element within a panelset.
+ * This performs two actions: toggling the panel via space or enter and
+ * moving to the next or previous panel via arrow keys, depending on the
+ * panelset orientation.
+ *
+ * @see https://www.w3.org/WAI/ARIA/apg/patterns/tabs/examples/tabs-automatic/
+ *
+ * @param {HTMLElement} panelset - The panelset element.
+ * @param {KeyboardEvent} ev - The keydown event.
+ */
+ function handlePanelTabsKeydown (panelset, ev) {
+ const target = ev.currentTarget.querySelector('.panel-tab-active')
+
+ function stopEvent () {
+ ev.preventDefault()
+ if (inRemarkjs() || inRevealjs()) {
+ ev.stopPropagation()
+ }
+ }
+
+ if (ev.code === 'Space' || ev.code === 'Enter') {
+ togglePanel(panelset, ev.target)
+ stopEvent()
+ return
+ }
+
+ let direction
+
+ if (panelset.getAttribute('aria-orientation') === 'vertical') {
+ if (ev.code === 'ArrowUp') direction = 'prev'
+ if (ev.code === 'ArrowDown') direction = 'next'
+ }
+
+ if (
+ inRemarkSlide(panelset) ||
+ inRevealjs() ||
+ panelset.getAttribute('aria-orientation') === 'horizontal'
+ ) {
+ if (ev.code === 'ArrowLeft') direction = 'prev'
+ if (ev.code === 'ArrowRight') direction = 'next'
+ }
+
+ if (!direction) return
+
+ const newActive = toggleSibling(panelset, target, direction)
+ if (newActive) stopEvent()
+ return newActive
+ }
+
+ /**
+ * Finds a panel by name within a panelset. `name` is compared with the
+ * panel tab text content, case-insensitive and trimmed.
+ *
+ * @param {HTMLElement} panelset - The panelset element.
+ * @param {string} name - The name of the panel tab to find.
+ * @returns {HTMLElement|undefined} - The matching panel element, or
+ * undefined if not found.
+ */
+ function findPanelByName (panelset, name) {
+ const matches = Array.from(
+ panelset.querySelectorAll(':scope > .panel-tabs > .panel-tab')
+ ).filter(p => p.innerText.toLowerCase().trim() === name)
+
+ if (!matches) {
+ console.error(
+ `No panel with name "${name}" found in panelset ${panelset.id}`,
+ { panelset, name }
+ )
+ return
+ }
+
+ if (matches > 1) {
+ console.warn(
+ `Multiple panels with name "${name}" found in panelset ${panelset.id}`,
+ { panelset, name }
+ )
+ }
+ return matches[0]
+ }
+
+ /**
+ * Toggles the visibility of a panel in a panelset.
+ *
+ * @param {HTMLElement} panelset - The panelset element containing the
+ * panels.
+ * @param {HTMLElement|string} target - The target panel or panel name to
+ * toggle.
+ * @param {'string'} [update='all'] - The update mode for the
+ * panelset. Possible values are 'all', 'group', or 'url'.
+ */
+ function togglePanel (panelset, target, update = 'all', tabIndex = 0) {
+ // target is a .panel-tab element or a panel name
+ if (!(target instanceof window.HTMLElement)) {
+ target = findPanelByName(panelset, target)
+ if (!target) return
+ }
+
+ const tabs = panelset.querySelectorAll(
+ ':scope > .panel-tabs > .panel-tab'
+ )
+ const panels = panelset.querySelectorAll(':scope > .panel')
+
+ const targetPanelId = target.children[0].getAttribute('aria-controls')
+
+ // Set tab state
+ Array.from(tabs).forEach(t => {
+ t.classList.remove('panel-tab-active')
+ t.setAttribute('aria-selected', false)
+ t.removeAttribute('tabindex')
+ })
+
+ target.classList.add('panel-tab-active')
+ target.setAttribute('aria-selected', true)
+ target.tabIndex = tabIndex
+
+ Array.from(panels).forEach(p => {
+ const isActive = p.id === targetPanelId
+ p.classList.toggle('panel-active', isActive)
+ p.hidden = !isActive
+ })
+
+ // emit window resize event to trick html widgets into fitting to the panel width
+ window.dispatchEvent(new window.Event('resize'))
+
+ if (['all', 'group'].includes(update) && panelset.dataset.group) {
+ const group = panelset.dataset.group
+ const panel = target.innerText.toLowerCase().trim()
+
+ setStoredPanelGroupState(group, panel)
+
+ panelset.dispatchEvent(
+ new window.CustomEvent('panelset:group', {
+ bubbles: true,
+ detail: { group, panel }
+ })
+ )
+ }
+
+ // update query string
+ if (['all', 'url'].includes(update)) {
+ const params = updateSearchParams(panelset.id, targetPanelId)
+ updateUrl(params)
+ }
+ }
+
+ /**
+ * Toggles the sibling panel in the specified direction.
+ *
+ * @param {HTMLElement} panelset - The panelset element.
+ * @param {HTMLElement} target - The target panel element.
+ * @param {"next" | "prev"} [direction="next"] - The direction to toggle the
+ * sibling panel. Possible values are "next" and "prev".
+ */
+ function toggleSibling (panelset, target, direction = 'next') {
+ let sibling
+ switch (direction) {
+ case 'next':
+ sibling = target.nextSibling
+ break
+ case 'prev':
+ sibling = target.previousSibling
+ break
+ }
+
+ if (!sibling) return
+ const update = parseInt(target.tabIndex) < 0 ? 'url' : 'all'
+ togglePanel(panelset, sibling, update, target.tabIndex)
+ sibling.focus()
+ return sibling
+ }
+
+ /**
+ * Initializes a panel set from the original markup into a full panelset.
+ * This includes creating the panel tabs, rearranging content, adding event
+ * listeners, and synchronizing with a panel set group.
+ *
+ * @param {HTMLElement} panelset - The `.panelset` element to initialize.
+ * @returns {HTMLElement} - The new panelset element.
+ */
+ const initPanelSet = panelset => {
+ let panels = Array.from(panelset.querySelectorAll(':scope > .panel, :scope > .cell > .panel'))
+
+ const pandocSectionSelector = ':is(section, .section)[class*="level"]'
+ if (!panels.length) {
+ // we're in tabset-alike R Markdown or Quarto
+ const getSectionLevel = el => {
+ const levels = [...el.classList].filter(s => s.match(/^level/))
+ return levels.length ? levels[0].replace('level', '') : levels
+ }
+
+ // {.panelset} applied to a section heading
+ let panelsetLevel = getSectionLevel(panelset)
+
+ if (!panelsetLevel.length) {
+ // {.panelset} applied as a fenced div around subsections
+ const subSections = panelset.querySelectorAll(pandocSectionSelector)
+ if (!subSections.length) return
+
+ panelsetLevel = Array.from(subSections)
+ .map(getSectionLevel)
+ .map(x => parseInt(x))
+ .reduce((acc, x) => Math.min(acc, x), Infinity)
+
+ panelsetLevel = +panelsetLevel - 1
+ }
+
+ // move children that aren't inside a section up above the panelset
+ Array.from(panelset.children).forEach(function (el) {
+ if (el.matches(pandocSectionSelector)) return
+ panelset.parentElement.insertBefore(el, panelset)
+ })
+
+ // panels are all .sections with .level
+ const panelLevel = +panelsetLevel + 1
+ panels = Array.from(
+ panelset.querySelectorAll(`:is(section, .section).level${panelLevel}`)
+ )
+ }
+
+ if (!panels.length) return
+
+ // create content panels
+ const contents = panels.map(processPanelItem).filter(o => o !== null)
+
+ // create panelset
+ const panelsetAttrs = getElementAttributes(panelset)
+ const newPanelSet = reflowPanelSet(contents, {
+ id: panelset.id,
+ ...panelsetAttrs
+ })
+ newPanelSet.classList = panelset.classList
+
+ // set orientation
+ const isVertical = panelset.matches(
+ '.sideways, .vertical, [aria-orientation="vertical"]'
+ )
+ newPanelSet.setAttribute(
+ 'aria-orientation',
+ isVertical ? 'vertical' : 'horizontal'
+ )
+
+ panelset.parentNode.insertBefore(newPanelSet, panelset)
+ panelset.parentNode.removeChild(panelset)
+
+ // click and touch events
+ const panelTabs = newPanelSet.querySelector('.panel-tabs')
+ ;['click', 'touchend'].forEach(eventType => {
+ panelTabs.addEventListener(eventType, function (ev) {
+ handleClickedPanel(ev.target)
+ ev.stopPropagation()
+ })
+ })
+ panelTabs.addEventListener('touchmove', function (ev) {
+ ev.preventDefault()
+ })
+
+ // key events
+ newPanelSet
+ .querySelector('.panel-tabs')
+ .addEventListener('keydown', ev => {
+ handlePanelTabsKeydown(newPanelSet, ev)
+ })
+
+ // synchronize with the panelset group
+ if (newPanelSet.dataset.group) {
+ window.addEventListener('panelset:group', ev => {
+ if (ev.target === newPanelSet) return
+ if (ev.detail.group !== newPanelSet.dataset.group) return
+ togglePanel(newPanelSet, ev.detail.panel, 'url')
+ })
+
+ const groupData = getStoredPanelSettings()
+ const currentPanelFromUrl = getCurrentPanelFromUrl(newPanelSet.id)
+
+ if (!currentPanelFromUrl && groupData[newPanelSet.dataset.group]) {
+ togglePanel(newPanelSet, groupData[newPanelSet.dataset.group], null)
+ }
+ }
+
+ return newPanelSet
+ }
+
+ const localStorageKey = 'panelset-data'
+
+ /**
+ * Retrieves or creates the stored panel settings from local storage.
+ * @returns {{['string']: 'string'} | {}} The stored panel settings, as an
+ * empty object or an object with group names as keys and the currently
+ * activated panel names as values.
+ */
+ function getStoredPanelSettings () {
+ const data = window.localStorage.getItem(localStorageKey)
+ if (!data) {
+ window.localStorage.setItem(localStorageKey, '{}')
+ return {}
+ }
+ if (data) {
+ return JSON.parse(data)
+ }
+ }
+
+ function setStoredPanelSettings (data) {
+ window.localStorage.setItem(localStorageKey, JSON.stringify(data))
+ }
+
+ /**
+ * Sets the stored panel group state in local storage. The group `name` is
+ * used as a key and is globally checked across pages in the same domain.
+ *
+ * @param {string} name - The name of the panel group.
+ * @param {any} value - The value to set for the panel group.
+ */
+ function setStoredPanelGroupState (name, value) {
+ const data = getStoredPanelSettings()
+ data[name] = value
+ setStoredPanelSettings(data)
+ }
+
+ // initialize panels
+ document
+ .querySelectorAll('[data-panelset="true"]')
+ .forEach(el => {
+ const isCell = el.classList.contains('cell')
+ const hasParentPanelset = el.parentElement.classList.contains('panelset')
+ if (!isCell || !hasParentPanelset) {
+ // We let `data-panelset="true"` create a new panelset, unless it's on
+ // a code cell that's already inside a panelset, in which case the
+ // panels will be folded into the parent panelset.
+ el.classList.add('panelset')
+ }
+ })
+
+ const panelsets = { atomic: [], nested: [] }
+ Array.from(document.querySelectorAll('.panelset')).forEach(el => {
+ if (el.querySelector('.panelset')) {
+ // push nested panelsets to the start of the list (inner -> outer)
+ panelsets.nested.unshift(el)
+ } else {
+ // put panelsets without nested panelsets at the beginning
+ panelsets.atomic.push(el)
+ }
+ })
+
+ // initialize atomic panelsets first, then nested panelsets
+ panelsets.atomic.forEach(initPanelSet)
+ panelsets.nested.forEach(initPanelSet)
+
+ if (inRemarkjs()) {
+ const getVisibleActivePanelInfo = () => {
+ const slidePanels = document.querySelectorAll(
+ '.remark-visible .panel-tab-active'
+ )
+
+ if (!slidePanels.length) return null
+
+ return slidePanels.map(panel => {
+ return {
+ panel,
+ panelId: panel.children[0].getAttribute('aria-controls'),
+ panelSetId: panel.parentNode.parentNode.id
+ }
+ })
+ }
+
+ slideshow.on('hideSlide', slide => {
+ // clear focus if we had a panel-tab selected
+ document.activeElement.blur()
+
+ // clear search query for panelsets in current slide
+ const params = [
+ ...document.querySelectorAll('.remark-visible .panelset')
+ ].reduce(function (params, panelset) {
+ return updateSearchParams(panelset.id, null, params)
+ }, new URLSearchParams(window.location.search))
+
+ updateUrl(params)
+ })
+
+ slideshow.on('afterShowSlide', slide => {
+ const slidePanels = getVisibleActivePanelInfo()
+
+ if (slidePanels) {
+ // only first panel gets focus
+ slidePanels[0].panel.focus()
+ // but still update the url to reflect all active panels
+ const params = slidePanels.reduce(function (
+ params,
+ { panelId, panelSetId }
+ ) {
+ return updateSearchParams(panelSetId, panelId, params)
+ },
+ new URLSearchParams(window.location.search))
+ updateUrl(params)
+ }
+ })
+ }
+
+ if (inRevealjs()) {
+ window.Reveal.on('slidechanged', function ({ currentSlide, previousSlide, ...data }) {
+ // clear focus from any active panel-tab in the previous slide
+ const previousActive = previousSlide.querySelector('.panelset .panel-tab:focus')
+ if (previousActive) {
+ previousActive.blur()
+ previousActive.removeAttribute('tabindex')
+ }
+
+ const previousPanelsets = previousSlide.querySelectorAll('.panelset')
+ if (previousPanelsets.length) {
+ // clear search query for panelsets in previous slide
+ const params = [
+ ...previousSlide.querySelectorAll('.panelset')
+ ].reduce(function (params, panelset) {
+ return updateSearchParams(panelset.id, null, params)
+ }, new URLSearchParams(window.location.search))
+
+ updateUrl(params)
+ }
+
+ const firstPanelset = currentSlide.querySelector('.panelset')
+ if (!firstPanelset) return
+
+ const panelIdFromUrl = getCurrentPanelFromUrl(firstPanelset.id)
+ const panelFromUrl = !panelIdFromUrl
+ ? null
+ : firstPanelset
+ .querySelector(`[aria-controls="${panelIdFromUrl}"]`)
+ ?.parentElement
+
+ const firstPanel = panelIdFromUrl
+ ? panelFromUrl
+ : firstPanelset.querySelector('.panel-tab-active')
+
+ if (!firstPanel) return
+ firstPanel.setAttribute('tabindex', '-1')
+ firstPanel.focus()
+
+ // update url for all panels on this slide
+ const params = [
+ ...currentSlide.querySelectorAll('.panelset')
+ ].reduce(function (params, panelset) {
+ return updateSearchParams(
+ panelset.id,
+ panelset.querySelector('.panel-active').id,
+ params
+ )
+ }, new URLSearchParams(window.location.search))
+
+ updateUrl(params)
+ })
+ }
+ })
+})()
diff --git a/Presentations-Brazil-SEFAZ/Feb 2025/libs/remark-css/custom.css b/Presentations-Brazil-SEFAZ/Feb 2025/libs/remark-css/custom.css
new file mode 100644
index 0000000..00aa63e
--- /dev/null
+++ b/Presentations-Brazil-SEFAZ/Feb 2025/libs/remark-css/custom.css
@@ -0,0 +1,251 @@
+.vlarge {
+ font-size: 200%
+}
+
+.large {
+ font-size: 150%
+}
+
+.medium {
+ font-size: 120%
+}
+
+.small {
+ font-size: 70%
+}
+
+.red {
+ color: #ac142a
+}
+
+.green{
+ color: #046307
+}
+
+.cell-center {
+ text-align: center;
+}
+
+div.command {
+ padding: 5px 20px;
+ margin: 20px;
+ background-position: 15px center;
+ color: #58595B;
+ background-color: #fdeccf;
+ border-radius: 10px;
+ }
+
+div.exercise {
+ padding: 2px 20px;
+ margin: 20px;
+ background-position: 15px center;
+ color: #58595B;
+ background-color: #e3f5fb;
+ border-radius: 20px;
+ }
+
+div.solution {
+ padding: 2px 20px;
+ margin: 20px;
+ background-position: 15px center;
+ color: #58595B;
+ background-color: #f7fbe3;
+ border-radius: 20px;
+ }
+
+div.notes {
+ padding: 2px 20px;
+ margin: 20px;
+ background-position: 15px center;
+ color: #58595B;
+ background-color: #e8e8e8;
+ border-radius: 20px;
+ }
+
+div.extra_container {
+ padding: 2px 20px;
+ margin: 20px;
+ background-position: 15px center;
+ color: #58595B;
+ background-color: #e8fbe8;
+ border-radius: 20px;
+ }
+
+.sp-after {
+ margin-bottom: 1em !important;
+}
+
+.sp-after-half {
+ margin-bottom: 0.7em !important;
+}
+
+/*
+Coloring and inverse coloring in title bars and content boxes
+*/
+.box-1,
+.section-title-1 {
+ background-color: #0D0887;
+}
+
+.box-2,
+.section-title-2 {
+ background-color: #5601A4;
+}
+
+.box-3,
+.section-title-3 {
+ background-color: #900DA4;
+}
+
+.box-4,
+.section-title-4 {
+ background-color: #BF3984;
+}
+
+.box-5,
+.section-title-5 {
+ background-color: #E16462;
+}
+
+.box-6,
+.section-title-6 {
+ background-color: #F89441;
+}
+
+.box-7,
+.section-title-7 {
+ background-color: #FCCE25;
+}
+
+.box-inv-1,
+.section-title-inv-1 {
+ background-color: #B2B1F9;
+}
+
+.box-inv-2,
+.section-title-inv-2 {
+ background-color: #CBB5FF;
+}
+
+.box-inv-3,
+.section-title-inv-3 {
+ background-color: #EFB3FF;
+}
+
+.box-inv-4,
+.section-title-inv-4 {
+ background-color: #FFC0DC;
+}
+
+.box-inv-5,
+.section-title-inv-5 {
+ background-color: #FFD0CF;
+}
+
+.box-inv-6,
+.section-title-inv-6 {
+ background-color: #FFDFD1;
+}
+
+.box-inv-7,
+.section-title-inv-7 {
+ background-color: #FFF0D4;
+}
+
+.box-inv-1,
+.title-inv-1 h1,
+.section-title-inv-1 h1 {
+ color: #0D0887;
+}
+
+.box-inv-2,
+.title-inv-2 h1,
+.section-title-inv-2 h1 {
+ color: #5601A4;
+}
+
+.box-inv-3,
+.title-inv-3 h1,
+.section-title-inv-3 h1 {
+ color: #900DA4;
+}
+
+.box-inv-4,
+.title-inv-4 h1,
+.section-title-inv-4 h1 {
+ color: #BF3984;
+}
+
+.box-inv-5,
+.title-inv-5 h1,
+.section-title-inv-5 h1 {
+ color: #E16462;
+}
+
+.box-inv-6,
+.title-inv-6 h1,
+.section-title-inv-6 h1 {
+ color: #F89441;
+}
+
+.box-inv-7,
+.title-inv-7 h1,
+.section-title-inv-7 h1 {
+ color: #FCCE25;
+}
+
+.box-7, .box-6, .box-5, .box-4, .box-3, .box-2, .box-1, .title-7 h1, .title-6 h1, .title-5 h1, .title-4 h1, .title-3 h1, .title-2 h1, .title-1 h1, .section-title h1 {
+ color: #FFFFFF;
+}
+
+.box-7, .box-inv-7, .box-6, .box-inv-6, .box-5, .box-inv-5, .box-4, .box-inv-4, .box-3, .box-inv-3, .box-2, .box-inv-2, .box-1, .box-inv-1 {
+ margin: 0em auto;
+ overflow: hidden;
+ padding: 0.1em 0.4em;
+ font-weight: 600;
+ display: table;
+ text-align: center;
+}
+
+.float-left {
+ text-align: left;
+}
+
+.float-right {
+ text-align: right;
+}
+
+.float-left .box-1, .float-left .box-inv-1,
+.float-right .box-1, .float-right .box-inv-1 {
+ display: inline;
+}
+
+.float-left .box-2, .float-left .box-inv-2,
+.float-right .box-2, .float-right .box-inv-2 {
+ display: inline;
+}
+
+.float-left .box-3, .float-left .box-inv-3,
+.float-right .box-3, .float-right .box-inv-3 {
+ display: inline;
+}
+
+.float-left .box-4, .float-left .box-inv-4,
+.float-right .box-4, .float-right .box-inv-4 {
+ display: inline;
+}
+
+.float-left .box-5, .float-left .box-inv-5,
+.float-right .box-5, .float-right .box-inv-5 {
+ display: inline;
+}
+
+.float-left .box-6, .float-left .box-inv-6,
+.float-right .box-6, .float-right .box-inv-6 {
+ display: inline;
+}
+
+.float-left .box-7, .float-left .box-inv-7,
+.float-right .box-7, .float-right .box-inv-7 {
+ display: inline;
+}
diff --git a/Presentations-Brazil-SEFAZ/Feb 2025/libs/remark-css/default.css b/Presentations-Brazil-SEFAZ/Feb 2025/libs/remark-css/default.css
new file mode 100644
index 0000000..93bd1ff
--- /dev/null
+++ b/Presentations-Brazil-SEFAZ/Feb 2025/libs/remark-css/default.css
@@ -0,0 +1,72 @@
+a, a > code {
+ color: #D38C28;
+ text-decoration: none;
+}
+.footnote {
+ position: absolute;
+ bottom: 3em;
+ padding-right: 4em;
+ font-size: 90%;
+}
+.remark-code-line-highlighted { background-color: #ffff88; }
+
+.inverse {
+ background-color: #272822;
+ color: #d6d6d6;
+ text-shadow: 0 0 20px #333;
+}
+.inverse h1, .inverse h2, .inverse h3 {
+ color: #f3f3f3;
+}
+/* Two-column layout */
+.left-column {
+ color: #777;
+ width: 20%;
+ height: 92%;
+ float: left;
+}
+.left-column h2:last-of-type, .left-column h3:last-child {
+ color: #000;
+}
+.right-column {
+ width: 75%;
+ float: right;
+ padding-top: 1em;
+}
+.pull-left {
+ float: left;
+ width: 47%;
+}
+.pull-right {
+ float: right;
+ width: 47%;
+}
+.pull-right + * {
+ clear: both;
+}
+img, video, iframe {
+ max-width: 100%;
+}
+blockquote {
+ border-left: solid 5px lightgray;
+ padding-left: 1em;
+}
+.remark-slide table {
+ margin: auto;
+ border-top: 1px solid #666;
+ border-bottom: 1px solid #666;
+}
+.remark-slide table thead th { border-bottom: 1px solid #ddd; }
+th, td { padding: 5px; }
+.remark-slide thead, .remark-slide tfoot, .remark-slide tr:nth-child(even) { background: #eee }
+
+@page { margin: 0; }
+@media print {
+ .remark-slide-scaler {
+ width: 100% !important;
+ height: 100% !important;
+ transform: scale(1) !important;
+ top: 0 !important;
+ left: 0 !important;
+ }
+}
diff --git a/Presentations-Brazil-SEFAZ/Feb 2025/libs/remark-css/metropolis-fonts.css b/Presentations-Brazil-SEFAZ/Feb 2025/libs/remark-css/metropolis-fonts.css
new file mode 100644
index 0000000..70312d9
--- /dev/null
+++ b/Presentations-Brazil-SEFAZ/Feb 2025/libs/remark-css/metropolis-fonts.css
@@ -0,0 +1,12 @@
+@import url(https://fonts.googleapis.com/css?family=Fira+Sans:300,300i,400,400i,500,500i,700,700i);
+@import url(https://cdn.rawgit.com/tonsky/FiraCode/1.204/distr/fira_code.css);
+@import url('https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap');
+
+body {
+ font-family: 'Fira Sans','Droid Serif', 'Palatino Linotype', 'Book Antiqua', Palatino, 'Microsoft YaHei', 'Songti SC', serif;
+}
+
+.remark-code, .remark-inline-code {
+ font-family: 'Share Tech Mono', monospace;
+ font-size: 90%;
+}
diff --git a/Presentations-Brazil-SEFAZ/Feb 2025/libs/remark-css/metropolis.css b/Presentations-Brazil-SEFAZ/Feb 2025/libs/remark-css/metropolis.css
new file mode 100644
index 0000000..2773be2
--- /dev/null
+++ b/Presentations-Brazil-SEFAZ/Feb 2025/libs/remark-css/metropolis.css
@@ -0,0 +1,257 @@
+.remark-slide-content {
+ background-color: #FFFFFF;
+ border-top: 80px solid #1f7ba6;
+ font-size: 20px;
+ font-weight: 300;
+ line-height: 1.5;
+ padding: 1em 2em 1em 2em
+}
+
+.title-slide {
+ background-color: #FFFFFF;
+ background-image: url(https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQm-BqPfNF1xgT-HzzKkeetCZP72hbFBiz4BQ&usqp=CAU);
+ background-position:4.5% 90%;
+ background-size: 100px;
+}
+
+.inverse {
+ background-color: #1f7ba6;
+ text-shadow: none;
+}
+
+/* Removes colored bar from top of the slide resulting in a clear slide */
+.clear{
+ border-top: 0px solid #FFFFFF;
+}
+
+h1 {
+ font-weight: normal;
+ margin-top: -95px;
+ margin-left: -00px;
+ color: #FFFFFF;
+}
+
+h2, h3, h4 {
+ padding-top: -15px;
+ padding-bottom: 00px;
+ color: #1A292C;
+ text-shadow: none;
+ font-weight: 400;
+ text-align: left;
+ margin-left: 00px;
+ margin-bottom: -10px;
+}
+
+.remark-slide-content h1 {
+ font-size: 45px;
+}
+
+.remark-slide-content h2 {
+ font-size: 35px;
+}
+
+.remark-slide-content h3 {
+ font-size: 30px;
+}
+
+.left-column h2, .left-column h3, .left-column h4 {
+ color: #777;
+}
+
+.left-column h2:last-of-type, .left-column h3:last-child {
+ color: #1A292C;
+}
+
+.title-slide {
+ background-color: #FFFFFF;
+ border-top: 80px solid #FFFFFF;
+}
+
+.title-slide h1 {
+ color: #1A292C;
+ font-size: 40px;
+ text-shadow: none;
+ font-weight: 400;
+ text-align: left;
+ margin-left: 15px;
+ padding-top: 80px;
+}
+.title-slide h2 {
+ margin-top: -25px;
+ padding-bottom: -20px;
+ color: #1A292C;
+ text-shadow: none;
+ font-weight: 300;
+ font-size: 35px;
+ text-align: left;
+ margin-left: 15px;
+}
+.title-slide h3 {
+ color: #1A292C;
+ text-shadow: none;
+ font-weight: 300;
+ font-size: 25px;
+ text-align: left;
+ margin-left: 15px;
+ margin-bottom: -30px;
+}
+
+hr, .title-slide h2::after, .mline h1::after {
+ content: '';
+ display: block;
+ border: none;
+ background-color: #D38C28;
+ color: #D38C28;
+ height: 1px;
+}
+
+hr, .mline h1::after {
+ margin: 1em 15px 0 15px;
+}
+
+.title-slide h2::after {
+ margin: 10px 15px 35px 0;
+}
+
+.mline h1::after {
+ margin: 10px 15px 0 15px;
+}
+
+.remark-slide-number {
+ font-size: 13pt;
+ color: #272822;
+ opacity: 1;
+}
+.inverse .remark-slide-number {
+ font-size: 13pt;
+ color: #FFFFFF;
+ opacity: 1;
+}
+
+/* turns off slide numbers for title page: https://github.com/gnab/remark/issues/298 */
+.title-slide .remark-slide-number {
+ display: none;
+}
+
+.remark-inline-code {
+ /* background: #F5F5F5; /* lighter */
+ background: #e7e8e2; /* darker */
+ border-radius: 3px;
+ padding: 4px;
+}
+
+.code10 .remark-code {
+ font-size: 10%;
+}
+
+.code20 .remark-code {
+ font-size: 20%;
+}
+
+.code30 .remark-code {
+ font-size: 30%;
+}
+
+.code40 .remark-code {
+ font-size: 40%;
+}
+
+.code50 .remark-code {
+ font-size: 50%;
+}
+
+.code60 .remark-code {
+ font-size: 60%;
+}
+
+.code70 .remark-code {
+ font-size: 70%;
+}
+
+.code80 .remark-code {
+ font-size: 80%;
+}
+
+.code90 .remark-code {
+ font-size: 90%;
+}
+
+.code100 .remark-code {
+ font-size: 100%;
+}
+
+.font10 {
+ font-size: 10%;
+}
+
+.font20 {
+ font-size: 20%;
+}
+
+.font30 {
+ font-size: 30%;
+}
+
+.font40 {
+ font-size: 40%;
+}
+
+.font50 {
+ font-size: 50%;
+}
+
+.font60 {
+ font-size: 60%;
+}
+
+.font70 {
+ font-size: 70%;
+}
+
+.font80 {
+ font-size: 80%;
+}
+
+.font90 {
+ font-size: 90%;
+}
+
+.font100 {
+ font-size: 100%;
+}
+
+.font110 {
+ font-size: 110%;
+}
+
+.font120 {
+ font-size: 120%;
+}
+
+.font130 {
+ font-size: 130%;
+}
+
+.font140 {
+ font-size: 140%;
+}
+
+.font150 {
+ font-size: 150%;
+}
+
+.font160 {
+ font-size: 160%;
+}
+.font170 {
+ font-size: 170%;
+}
+.font180 {
+ font-size: 180%;
+}
+.font190 {
+ font-size: 190%;
+}
+.font200 {
+ font-size: 200%;
+}
diff --git a/Presentations-Brazil-SEFAZ/Feb 2025/libs/xaringanExtra-clipboard/xaringanExtra-clipboard.css b/Presentations-Brazil-SEFAZ/Feb 2025/libs/xaringanExtra-clipboard/xaringanExtra-clipboard.css
new file mode 100644
index 0000000..2a38a37
--- /dev/null
+++ b/Presentations-Brazil-SEFAZ/Feb 2025/libs/xaringanExtra-clipboard/xaringanExtra-clipboard.css
@@ -0,0 +1,23 @@
+.xaringanextra-clipboard-button {
+ position: absolute;
+ top: 0;
+ right: 0;
+ font-size: 0.8em;
+ padding: 0.5em;
+ display: none;
+ background-color: transparent;
+ border: none;
+ opacity: 0.5;
+ border-radius: 0;
+}
+
+.xaringanextra-clipboard-button:hover {
+ background-color: rgba(0, 0, 0, 0.1);
+ border: none;
+ opacity: 1;
+}
+
+:hover > .xaringanextra-clipboard-button {
+ display: block;
+ transform: translateY(0);
+}
diff --git a/Presentations-Brazil-SEFAZ/Feb 2025/libs/xaringanExtra-clipboard/xaringanExtra-clipboard.js b/Presentations-Brazil-SEFAZ/Feb 2025/libs/xaringanExtra-clipboard/xaringanExtra-clipboard.js
new file mode 100644
index 0000000..0532818
--- /dev/null
+++ b/Presentations-Brazil-SEFAZ/Feb 2025/libs/xaringanExtra-clipboard/xaringanExtra-clipboard.js
@@ -0,0 +1,98 @@
+/* global slideshow,window,document */
+window.xaringanExtraClipboard = function (selector, text) {
+ if (!window.ClipboardJS.isSupported()) return
+ if (!window.xaringanExtraClipboards) window.xaringanExtraClipboards = {}
+
+ const ready = function (fn) {
+ /* MIT License Copyright (c) 2016 Nuclei */
+ /* https://github.com/nuclei/readyjs */
+ const completed = () => {
+ document.removeEventListener('DOMContentLoaded', completed)
+ window.removeEventListener('load', completed)
+ fn()
+ }
+ if (document.readyState !== 'loading') {
+ setTimeout(fn)
+ } else {
+ document.addEventListener('DOMContentLoaded', completed)
+ window.addEventListener('load', completed)
+ }
+ }
+
+ ready(function () {
+ const {
+ button: buttonText = 'Copy Code',
+ success: successText = 'Copied!',
+ error: errorText = 'Press Ctrl+C to Copy'
+ } = text
+
+ const template = '`
+
+ const isRemarkSlideshow = typeof slideshow !== 'undefined' &&
+ Object.prototype.hasOwnProperty.call(slideshow, 'getSlides')
+
+ let siblingSelector = selector || 'pre'
+ if (!selector && isRemarkSlideshow) {
+ siblingSelector = '.remark-slides-area ' + siblingSelector
+ }
+
+ // insert