{"id":787,"date":"2025-09-23T17:39:24","date_gmt":"2025-09-23T09:39:24","guid":{"rendered":"https:\/\/rubasseroasters.com\/?page_id=787"},"modified":"2026-08-13T09:45:18","modified_gmt":"2026-08-13T01:45:18","slug":"course-rubasse-roasting-signup-page-zh","status":"publish","type":"page","link":"https:\/\/rubasseroasters.com\/zh\/course-rubasse-roasting-signup-page-zh\/","title":{"rendered":"\u5be6\u9ad4\u70d8\u8c46\u8ab2\u7a0b"},"content":{"rendered":"\n<!-- ================================================================\n     \u8ab2\u7a0b\u884c\u4e8b\u66c6 block\uff08zh\uff09\n     \u8cc7\u6599\u4f86\u6e90\uff1a\u7368\u7acb\u5b98\u7db2\u516c\u958b Google Sheet\uff1b\u767c\u5e03\u5f8c\u7db2\u7ad9\u91cd\u65b0\u8f09\u5165\u5373\u66f4\u65b0\n     \u26a0\ufe0f sheetId \/ gid \u4ecd\u662f PASTE_ \u958b\u982d\u6642\u4e0d\u53ef\u8cbc\u4e0a\u6b63\u5f0f\u7ad9\n     ================================================================ -->\n\n<!-- \u25bc\u25bc\u25bc\u25bc\u25bc\u25bc  \u7368\u7acb\u516c\u958b\u8868\u5efa\u7acb\u5f8c\uff0c\u53ea\u6539\u9019\u4e00\u6bb5  \u25bc\u25bc\u25bc\u25bc\u25bc\u25bc -->\n<script>\nwindow.RBSCAL_CONFIG = {\n\n  \/\/ \u3010\u7368\u7acb\u5b98\u7db2\u516c\u958b\u8868\u3011\u7db2\u5740\u5217 \/d\/ \u8207 \/edit \u4e2d\u9593\u90a3\u4e00\u9577\u4e32\n  sheetId: \"17uERN5prdDdHNwsy0ecaqfZ05M0GPmTWKFxk9sP3Jiw\",\n\n  \/\/ \u3010\u5b98\u7db2\u8ab2\u7a0b\u516c\u958b\u8cc7\u6599\u3011\u5206\u9801\u7684 gid\uff08\u7db2\u5740 #gid= \u5f8c\u9762\u7684\u6578\u5b57\uff09\n  gid: \"0\",\n\n  \/\/ \u820a\u7248\u76f8\u5bb9\u6b04\uff1b\u6b63\u5f0f\u67b6\u69cb\u4e0d\u90e8\u7f72\u516c\u958b Apps Script Web App\uff0c\u4fdd\u6301\u7a7a\u767d\n  apiUrl: \"\"\n\n};\n<\/script>\n<!-- \u25b2\u25b2\u25b2\u25b2\u25b2\u25b2  \u4ee5\u4e0a\u662f\u552f\u4e00\u9700\u8981\u6539\u7684\u5730\u65b9\uff0c\u4ee5\u4e0b\u8acb\u52ff\u624b\u6539  \u25b2\u25b2\u25b2\u25b2\u25b2\u25b2 -->\n\n<div class=\"rbscal\" id=\"rbscal-zh\">\n  <div class=\"rbscal-bar\">\n    <button type=\"button\" class=\"rbscal-nav rbscal-prev\">\u4e0a\u500b\u6708<\/button>\n    <div class=\"rbscal-title\">\u8ab2\u7a0b\u884c\u4e8b\u66c6<\/div>\n    <button type=\"button\" class=\"rbscal-nav rbscal-next\">\u4e0b\u500b\u6708<\/button>\n  <\/div>\n  <div class=\"rbscal-grid-wrap\"><\/div>\n  <div class=\"rbscal-list\"><\/div>\n  <div class=\"rbscal-msg\">\u8ab2\u7a0b\u8f09\u5165\u4e2d\u2026<\/div>\n<\/div>\n\n<style>\n.rbscal{--rbscal-main:#7a4f28;--rbscal-accent:#b8341f;--rbscal-bg:#f1e7da;\n  --rbscal-line:#b9a88f;--rbscal-ink:#241f1a;--rbscal-mute:#5f5850;\n  --rbscal-out:#e8e2d9;\n  font-family:\"Noto Sans TC\",system-ui,-apple-system,sans-serif;\n  color:var(--rbscal-ink);max-width:1100px;margin:0 auto}\n.rbscal *{box-sizing:border-box}\n.rbscal-bar{display:flex;align-items:center;justify-content:center;gap:16px;\n  margin-bottom:14px}\n.rbscal-title{font-size:20px;font-weight:700;min-width:180px;text-align:center;\n  letter-spacing:.5px}\n.rbscal-nav{border:1px solid var(--rbscal-line);background:#fff;cursor:pointer;\n  border-radius:6px;padding:7px 14px;font-size:14px;color:var(--rbscal-main);\n  font-family:inherit}\n.rbscal-nav:hover{background:var(--rbscal-main);color:#fff;\n  border-color:var(--rbscal-main)}\n.rbscal-msg{text-align:center;color:var(--rbscal-mute);padding:36px 12px;\n  font-size:15px}\n\n\/* \u683c\u7dda\u523b\u610f\u7528\u5be6\u8272\u6df1\u7dda\uff1a\u6dfa\u8272\u683c\u7dda\u5728 WP \u4f48\u666f\u7684\u6dfa\u5e95\u4e0a\u5e7e\u4e4e\u770b\u4e0d\u898b\uff082026-07-31 \u4f7f\u7528\u8005\u56de\u5831\uff09 *\/\n.rbscal-grid{width:100%;border-collapse:collapse;table-layout:fixed;\n  background:#fff;border:2px solid var(--rbscal-main)}\n.rbscal-grid th{background:var(--rbscal-main);color:#fff;\n  font-size:13px;font-weight:700;padding:10px 4px;letter-spacing:1px;\n  border:1px solid var(--rbscal-main)}\n.rbscal-grid td{border:1px solid var(--rbscal-line);vertical-align:top;\n  height:112px;padding:5px;width:14.28%}\n.rbscal-out{background:var(--rbscal-out)}\n.rbscal-daynum{font-size:13px;color:#4a4038;margin-bottom:4px;\n  font-weight:700}\n.rbscal-today .rbscal-daynum{background:var(--rbscal-main);color:#fff;\n  border-radius:50%;width:21px;height:21px;line-height:21px;text-align:center}\n\n.rbscal-ev{display:block;text-decoration:none;color:inherit;\n  border:1px solid var(--rbscal-line);border-left:4px solid var(--rbscal-main);\n  background:var(--rbscal-bg);\n  border-radius:3px;padding:4px 6px;margin-bottom:4px;font-size:12px;\n  line-height:1.35}\na.rbscal-ev:hover{background:var(--rbscal-main);color:#fff}\na.rbscal-ev:hover .rbscal-ev-meta{color:#fff}\n.rbscal-ev-name{font-weight:600;display:block}\n.rbscal-ev-meta{color:var(--rbscal-mute);display:block;font-size:11px;\n  margin-top:1px}\n.rbscal-ev-online{border-left-color:var(--rbscal-accent)}\n.rbscal-ev-past{opacity:.45}\n.rbscal-badge{display:inline-block;font-size:10px;padding:0 5px;\n  border-radius:8px;margin-left:4px;vertical-align:1px;line-height:15px}\n.rbscal-badge-full{background:#ddd;color:#666}\n.rbscal-badge-extra{background:var(--rbscal-accent);color:#fff}\n.rbscal-badge-past{background:#eee;color:#999}\n\n.rbscal-list{display:none}\n.rbscal-item{display:block;text-decoration:none;color:inherit;background:#fff;\n  border:1px solid var(--rbscal-line);border-left:4px solid var(--rbscal-main);\n  border-radius:6px;padding:11px 13px;margin-bottom:9px}\n.rbscal-item-date{font-size:12px;color:var(--rbscal-main);font-weight:700}\n\/* name\/meta \u662f <span>\uff0c\u4e0d\u7d66 display:block \u6703\u8ddf\u524d\u4e00\u6bb5\u64e0\u5728\u540c\u4e00\u884c *\/\n.rbscal-item-name{display:block;font-size:15px;font-weight:600;margin:3px 0 2px}\n.rbscal-item-meta{display:block;font-size:13px;color:var(--rbscal-mute)}\n.rbscal-item-online{border-left-color:var(--rbscal-accent)}\n.rbscal-item-past{opacity:.5}\n\n@media (max-width:767px){\n  .rbscal-grid-wrap{display:none}\n  .rbscal-list{display:block}\n  .rbscal-title{font-size:17px;min-width:130px}\n  .rbscal-nav{padding:6px 11px;font-size:13px}\n}\n<\/style>\n\n<script>\n(function(){\n  var CFG = {\"rootId\": \"rbscal-zh\", \"sheetId\": \"17uERN5prdDdHNwsy0ecaqfZ05M0GPmTWKFxk9sP3Jiw\", \"gid\": \"0\", \"lang\": \"\u4e2d\u6587\", \"locale\": \"zh\", \"i18n\": {\"prev\": \"\u4e0a\u500b\u6708\", \"next\": \"\u4e0b\u500b\u6708\", \"today\": \"\u672c\u6708\", \"empty\": \"\u672c\u6708\u5c1a\u7121\u8ab2\u7a0b\", \"loading\": \"\u8ab2\u7a0b\u8f09\u5165\u4e2d\u2026\", \"error\": \"\u8ab2\u7a0b\u8cc7\u6599\u8f09\u5165\u5931\u6557\uff0c\u8acb\u7a0d\u5f8c\u518d\u8a66\", \"full\": \"\u984d\u6eff\", \"extra\": \"\u52a0\u958b\u5834\", \"open\": \"\u53ef\u5831\u540d\", \"past\": \"\u5df2\u7d50\u675f\", \"venue\": \"\u5834\u5730\", \"days\": \"\u5929\", \"weekdays\": [\"\u65e5\", \"\u4e00\", \"\u4e8c\", \"\u4e09\", \"\u56db\", \"\u4e94\", \"\u516d\"]}};\n\n  var root = document.getElementById(CFG.rootId);\n  if(!root){ return; }\n  var msgEl   = root.querySelector('.rbscal-msg');\n  var titleEl = root.querySelector('.rbscal-title');\n  var gridWrap= root.querySelector('.rbscal-grid-wrap');\n  var listEl  = root.querySelector('.rbscal-list');\n\n  \/\/ \u6a94\u982d window.RBSCAL_CONFIG \u512a\u5148\uff1b\u6c92\u586b\u624d\u7528\u7522\u751f\u6642\u71d2\u9032\u4f86\u7684\u9810\u8a2d\u503c\n  var USER = window.RBSCAL_CONFIG;\n  if(!USER){ USER = {}; }\n  var sheetId = CFG.sheetId;\n  if(USER.sheetId){ sheetId = USER.sheetId; }\n  var gid = CFG.gid;\n  if(USER.gid){ gid = USER.gid; }\n  var apiUrl = '';\n  if(USER.apiUrl){ apiUrl = USER.apiUrl; }\n\n  \/\/ URL \u7684 ampersand \u5fc5\u9808\u7528 charCode \u4e32\uff0c\u4e0d\u80fd\u76f4\u63a5\u5beb\uff08\u898b\u624b\u518a\u7b2c\u4e00\u9435\u5f8b\uff09\n  var AMP = String.fromCharCode(38);\n  var CSV_URL = 'https:\/\/docs.google.com\/spreadsheets\/d\/' + sheetId +\n                '\/export?format=csv' + AMP + 'gid=' + gid;\n\n  var events = [];\n  var view = null;\n\n  function parseCsv(text){\n    var rows=[], row=[], cur='', inQ=false, i=0;\n    while(i < text.length){\n      var c = text.charAt(i);\n      if(inQ){\n        if(c === '\"'){\n          if(text.charAt(i+1) === '\"'){ cur += '\"'; i += 2; continue; }\n          inQ = false; i++; continue;\n        }\n        cur += c; i++; continue;\n      }\n      if(c === '\"'){ inQ = true; i++; continue; }\n      if(c === ','){ row.push(cur); cur=''; i++; continue; }\n      if(c === '\\r'){ i++; continue; }\n      if(c === '\\n'){ row.push(cur); rows.push(row); row=[]; cur=''; i++; continue; }\n      cur += c; i++;\n    }\n    if(row.length > 0){ row.push(cur); rows.push(row); }\n    else if(cur !== ''){ rows.push([cur]); }\n    return rows;\n  }\n\n  function toNum(iso){\n    var p = String(iso).split('-');\n    if(p.length !== 3){ return 0; }\n    return (+p[0]) * 10000 + (+p[1]) * 100 + (+p[2]);\n  }\n  function pad(n){ if(n < 10){ return '0' + n; } return '' + n; }\n\n  \/\/ CSV \u8207 Apps Script JSON \u5169\u7a2e\u4f86\u6e90\uff0c\u5148\u6b63\u898f\u5316\u6210\u540c\u4e00\u7a2e\u300c\u4e00\u5217\u4e00\u7269\u4ef6\u300d\n  function csvToObjects(rows){\n    if(rows.length < 2){ return []; }\n    var head = rows[0].map(function(h){ return h.replace(\/^\\ufeff\/,'').trim(); });\n    var out = [];\n    rows.slice(1).forEach(function(r){\n      var o = {};\n      head.forEach(function(h, i){\n        var v = '';\n        if(i < r.length){ v = r[i]; }\n        o[h] = String(v).trim();\n      });\n      out.push(o);\n    });\n    return out;\n  }\n\n  function buildEvents(recs){\n    if(recs.length === 0){ return []; }\n    var need = ['\u958b\u59cb\u65e5\u671f','\u7d50\u675f\u65e5\u671f','\u8ab2\u7a0b\u540d\u7a31','\u9023\u7d50','\u8a9e\u8a00'];\n    var missing = need.filter(function(k){ return recs[0][k] === undefined; });\n    if(missing.length > 0){ throw new Error('\u7f3a\u6b04\u4f4d: ' + missing.join(',')); }\n\n    var out = [];\n    recs.forEach(function(o){\n      function get(k){\n        var v = o[k];\n        if(v === undefined){ return ''; }\n        if(v === null){ return ''; }\n        return String(v).trim();\n      }\n      var s = get('\u958b\u59cb\u65e5\u671f');\n      if(s === ''){ return; }\n\n      \/\/ \u65b0\u7248\u8cc7\u6599\u6709 M \u6b04\u6642\u53ea\u986f\u793a\u52fe\u9078\u5217\uff1b\u820a\u8cc7\u6599\u6c92\u6709\u6b64\u6b04\u5247\u5168\u90e8\u986f\u793a\uff0c\u907f\u514d\u5347\u7d1a\u77ac\u9593\u6e05\u7a7a\u3002\n      if(o['\u662f\u5426\u52a0\u5165\u524d\u53f0\u884c\u4e8b\u66c6'] !== undefined){\n        var enabled = get('\u662f\u5426\u52a0\u5165\u524d\u53f0\u884c\u4e8b\u66c6').toLowerCase();\n        var checked = false;\n        if(enabled === 'true'){ checked = true; }\n        if(enabled === '1'){ checked = true; }\n        if(enabled === 'yes'){ checked = true; }\n        if(enabled === 'y'){ checked = true; }\n        if(enabled === '\u662f'){ checked = true; }\n        if(enabled === '\u52fe\u9078'){ checked = true; }\n        if(enabled === '\u5df2\u52fe\u9078'){ checked = true; }\n        if(!checked){ return; }\n      }\n\n      var lang = get('\u8a9e\u8a00');\n      if(CFG.lang !== ''){\n        if(lang !== CFG.lang){ return; }\n      }\n      var e = get('\u7d50\u675f\u65e5\u671f');\n      if(e === ''){ e = s; }\n      out.push({\n        start: s, end: e, sNum: toNum(s), eNum: toNum(e),\n        level: get('\u7b49\u7d1a'), name: get('\u8ab2\u7a0b\u540d\u7a31'), venue: get('\u5834\u5730'),\n        t1: get('\u958b\u59cb\u6642\u9593'), t2: get('\u7d50\u675f\u6642\u9593'), status: get('\u72c0\u614b'),\n        url: get('\u9023\u7d50'), type: get('\u985e\u578b'), note: get('\u5099\u8a3b')\n      });\n    });\n    out.sort(function(a,b){ return a.sNum - b.sNum; });\n    return out;\n  }\n\n  function todayNum(){\n    var d = new Date();\n    return d.getFullYear()*10000 + (d.getMonth()+1)*100 + d.getDate();\n  }\n\n  \/\/ YYYYMMDD -> YYYYMM\n  function monthNum(n){ return Math.floor(n \/ 100); }\n\n  \/**\n   * \u521d\u59cb\u986f\u793a\u54ea\u500b\u6708\uff1a\n   *   1. \u7576\u6708\u6709\u8ab2\uff08\u542b\u8de8\u6708\u8ab2\u7a0b\uff09\u5c31\u7559\u5728\u7576\u6708\n   *   2. \u5426\u5247\u8df3\u5230\u6700\u8fd1\u7684\u672a\u4f86\u8ab2\u7a0b\u6240\u5728\u6708\u4efd\n   *   3. \u5168\u90e8\u90fd\u662f\u904e\u53bb\u7684\u8ab2\u5c31\u505c\u5728\u6700\u5f8c\u4e00\u7b46\n   *   4. \u5b8c\u5168\u6c92\u6709\u8ab2\uff08\u4f8b\u5982\u82f1\u6587\u7248\u76ee\u524d\u7121\u8cc7\u6599\uff09\u5c31\u986f\u793a\u7576\u6708\n   * \u76ee\u7684\u662f\u907f\u514d\u8a2a\u5ba2\u4e00\u9032\u4f86\u770b\u5230\u7a7a\u6708\u66c6\uff0c\u9084\u5f97\u81ea\u5df1\u6309\u4e0a\/\u4e0b\u500b\u6708\u627e\u3002\n   *\/\n  function initialView(evs){\n    var d = new Date();\n    var curY = d.getFullYear();\n    var curM = d.getMonth() + 1;\n    var cur = curY * 100 + curM;\n    if(evs.length === 0){ return {y: curY, m: curM}; }\n    var inCur = evs.filter(function(ev){\n      if(monthNum(ev.sNum) > cur){ return false; }\n      if(monthNum(ev.eNum) < cur){ return false; }\n      return true;\n    });\n    if(inCur.length > 0){ return {y: curY, m: curM}; }\n    var pick = null;\n    for(var i = 0; i < evs.length; i++){\n      if(monthNum(evs[i].sNum) > cur){ pick = evs[i]; break; }\n    }\n    if(pick === null){ pick = evs[evs.length - 1]; }\n    var mn = monthNum(pick.sNum);\n    return {y: Math.floor(mn \/ 100), m: mn % 100};\n  }\n\n  function statusInfo(ev){\n    if(ev.eNum < todayNum()){ return {cls:'past', text:CFG.i18n.past}; }\n    if(ev.status.indexOf('\u984d\u6eff') >= 0){ return {cls:'full', text:CFG.i18n.full}; }\n    if(ev.status.indexOf('\u52a0\u958b') >= 0){ return {cls:'extra', text:CFG.i18n.extra}; }\n    return null;\n  }\n\n  function displayName(ev){\n    if(ev.level === ''){ return ev.name; }\n    return '\u3010' + ev.level + '\u3011' + ev.name;\n  }\n\n  function metaText(ev){\n    var bits = [];\n    if(ev.venue !== ''){ bits.push(ev.venue); }\n    if(ev.t1 !== ''){\n      if(ev.t2 !== ''){ bits.push(ev.t1 + '-' + ev.t2); }\n      else { bits.push(ev.t1); }\n    }\n    var span = (ev.eNum - ev.sNum);\n    if(span > 0){\n      var n = Math.round((new Date(ev.end) - new Date(ev.start)) \/ 86400000) + 1;\n      bits.push(n + CFG.i18n.days);\n    }\n    return bits.join(' \/ ');\n  }\n\n  \/\/ \u4e00\u5f8b createElement + textContent\uff1a\u8cc7\u6599\u542b ampersand \u4e5f\u4e0d\u6703\u58de\uff08\u8ab2\u540d\u300c\u70d8\u8c46X\u676f\u6e2c\u9ad4\u9a57\u300d\uff09\n  function makeNode(ev, kind){\n    var isLink = (ev.url !== '');\n    var el = document.createElement(isLink ? 'a' : 'div');\n    if(isLink){\n      el.setAttribute('href', ev.url);\n      el.setAttribute('rel', 'noopener');\n    }\n    var base = (kind === 'grid') ? 'rbscal-ev' : 'rbscal-item';\n    var cls = [base];\n    if(ev.type.indexOf('\u7dda\u4e0a') >= 0){ cls.push(base + '-online'); }\n    var st = statusInfo(ev);\n    if(st){ if(st.cls === 'past'){ cls.push(base + '-past'); } }\n    el.className = cls.join(' ');\n\n    if(kind === 'list'){\n      var d = document.createElement('div');\n      d.className = 'rbscal-item-date';\n      var txt = ev.start;\n      if(ev.end !== ev.start){ txt = ev.start + ' ~ ' + ev.end; }\n      d.textContent = txt;\n      el.appendChild(d);\n    }\n\n    var nameEl = document.createElement('span');\n    nameEl.className = (kind === 'grid') ? 'rbscal-ev-name' : 'rbscal-item-name';\n    nameEl.textContent = displayName(ev);\n    if(st){\n      var b = document.createElement('span');\n      b.className = 'rbscal-badge rbscal-badge-' + st.cls;\n      b.textContent = st.text;\n      nameEl.appendChild(b);\n    }\n    el.appendChild(nameEl);\n\n    var meta = metaText(ev);\n    if(meta !== ''){\n      var m = document.createElement('span');\n      m.className = (kind === 'grid') ? 'rbscal-ev-meta' : 'rbscal-item-meta';\n      m.textContent = meta;\n      el.appendChild(m);\n    }\n    return el;\n  }\n\n  function eventsOn(y, m, d){\n    var n = y*10000 + m*100 + d;\n    return events.filter(function(ev){\n      if(ev.sNum > n){ return false; }\n      if(ev.eNum < n){ return false; }\n      return true;\n    });\n  }\n\n  function renderGrid(y, m){\n    var tbl = document.createElement('table');\n    tbl.className = 'rbscal-grid';\n    var thead = document.createElement('thead');\n    var htr = document.createElement('tr');\n    CFG.i18n.weekdays.forEach(function(w){\n      var th = document.createElement('th');\n      th.textContent = w;\n      htr.appendChild(th);\n    });\n    thead.appendChild(htr);\n    tbl.appendChild(thead);\n\n    var first = new Date(y, m-1, 1).getDay();\n    var total = new Date(y, m, 0).getDate();\n    var tbody = document.createElement('tbody');\n    var tr = document.createElement('tr');\n    var col = 0;\n    var i;\n    for(i = 0; i < first; i++){\n      var pad0 = document.createElement('td');\n      pad0.className = 'rbscal-out';\n      tr.appendChild(pad0);\n      col++;\n    }\n    var tn = todayNum();\n    for(i = 1; i <= total; i++){\n      if(col === 7){ tbody.appendChild(tr); tr = document.createElement('tr'); col = 0; }\n      var td = document.createElement('td');\n      if(y*10000 + m*100 + i === tn){ td.className = 'rbscal-today'; }\n      var num = document.createElement('div');\n      num.className = 'rbscal-daynum';\n      num.textContent = '' + i;\n      td.appendChild(num);\n      eventsOn(y, m, i).forEach(function(ev){\n        td.appendChild(makeNode(ev, 'grid'));\n      });\n      tr.appendChild(td);\n      col++;\n    }\n    while(col < 7){\n      var pad1 = document.createElement('td');\n      pad1.className = 'rbscal-out';\n      tr.appendChild(pad1);\n      col++;\n    }\n    tbody.appendChild(tr);\n    tbl.appendChild(tbody);\n    return tbl;\n  }\n\n  function renderList(y, m){\n    var frag = document.createDocumentFragment();\n    var lo = y*10000 + m*100 + 1;\n    var hi = y*10000 + m*100 + 31;\n    var mine = events.filter(function(ev){\n      if(ev.eNum < lo){ return false; }\n      if(ev.sNum > hi){ return false; }\n      return true;\n    });\n    mine.forEach(function(ev){ frag.appendChild(makeNode(ev, 'list')); });\n    return frag;\n  }\n\n  function monthLabel(y, m){\n    if(CFG.locale === 'zh'){ return y + ' \u5e74 ' + m + ' \u6708'; }\n    var names = ['January','February','March','April','May','June','July',\n                 'August','September','October','November','December'];\n    return names[m-1] + ' ' + y;\n  }\n\n  function render(){\n    titleEl.textContent = monthLabel(view.y, view.m);\n    gridWrap.textContent = '';\n    listEl.textContent = '';\n    gridWrap.appendChild(renderGrid(view.y, view.m));\n    var frag = renderList(view.y, view.m);\n    if(frag.childNodes.length === 0){\n      var p = document.createElement('div');\n      p.className = 'rbscal-msg';\n      p.textContent = CFG.i18n.empty;\n      listEl.appendChild(p);\n    } else {\n      listEl.appendChild(frag);\n    }\n    msgEl.style.display = 'none';\n  }\n\n  function shift(delta){\n    var m = view.m + delta;\n    var y = view.y;\n    if(m < 1){ m = 12; y = y - 1; }\n    if(m > 12){ m = 1; y = y + 1; }\n    view = {y:y, m:m};\n    render();\n  }\n\n  root.querySelector('.rbscal-prev').addEventListener('click', function(){ shift(-1); });\n  root.querySelector('.rbscal-next').addEventListener('click', function(){ shift(1); });\n\n  function loadRecords(){\n    if(apiUrl !== ''){\n      \/\/ \u79c1\u6709\u8a66\u7b97\u8868\uff1a\u8d70 Apps Script Web App\uff08\u898b course-calendar-apps-script.gs\uff09\n      return fetch(apiUrl).then(function(r){\n        if(!r.ok){ throw new Error('HTTP ' + r.status); }\n        return r.json();\n      }).then(function(j){\n        if(j.rows){ return j.rows; }\n        return j;\n      });\n    }\n    return fetch(CSV_URL).then(function(r){\n      if(!r.ok){ throw new Error('HTTP ' + r.status); }\n      return r.text();\n    }).then(function(text){\n      return csvToObjects(parseCsv(text));\n    });\n  }\n\n  loadRecords().then(function(recs){\n    events = buildEvents(recs);\n    view = initialView(events);\n    render();\n  }).catch(function(err){\n    msgEl.textContent = CFG.i18n.error;\n    if(window.console){ console.error('[rbscal]', err); }\n  });\n})();\n<\/script>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<div class=\"gspb_button_wrapper gspb_button-id-gsbp-cd7abe9\" id=\"gspb_button-id-gsbp-cd7abe9\"><a class=\"wp-block-greenshift-blocks-buttonbox gspb-buttonbox wp-element-button\" href=\"https:\/\/rubasseroasters.com\/course-rubasse-roasting-signup-page-zh\/#offlineform\" rel=\"noopener\"><span class=\"gspb-buttonbox-textwrap\"><span class=\"gspb-buttonbox-text\"><span class=\"gspb-buttonbox-title\">\u9ede\u6211\u5831\u540d \u27a1\ufe0f \u7dda\u4e0b\u70d8\u8c46\u8ab2\u7a0b<\/span><\/span><\/span><\/a><\/div>\n\n\n\n<div class=\"wp-block-greenshift-blocks-video gs-video youtube gspb_video-id-gsbp-3e85ee2\" id=\"gs-video-gsbp-3e85ee2\"><div class=\"gs-video-wrapper\" itemscope><iframe class=\"gs-video-element\" data-src=\"https:\/\/www.youtube.com\/watch?v=tAJrmApaAUs\" data-provider=\"youtube\" data-autoplay=\"true\" data-playsinline=\"true\" data-controls=\"true\" data-loop=\"true\" data-mute=\"true\" data-overlay=\"false\" data-lightbox=\"false\" data-modestbranding=\"false\" data-suggested=\"false\" frameborder=\"0\" allowfullscreen><\/iframe><\/div><\/div>\n\n\n\n<div style=\"height:19px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div> <div id=\"offlineform\"><\/div>\n\n\n\n<div class=\"wp-block-greenshift-blocks-row gspb_row gspb_row-id-gsbp-9b09c98 gspb_row--gutter-60\" id=\"gspb_row-id-gsbp-9b09c98\"><div class=\"gspb_row__content\"> \n<div class=\"wp-block-greenshift-blocks-row-column gspb_row__col--4 gspb_col-id-gsbp-552765e\" id=\"gspb_col-id-gsbp-552765e\">\n<div class=\"wp-block-greenshift-blocks-image gspb_image gspb_image-id-gsbp-62e6f55\" id=\"gspb_image-id-gsbp-62e6f55\"><a href=\"https:\/\/rubasseroasters.com\/zh\/course-rubasse-basic-roasting-zh\/\" ><img decoding=\"async\" src=\"https:\/\/rubasseroasters.com\/wp-content\/uploads\/2025\/10\/scimggPCNjB.webp\" data-src=\"\" alt=\"Rbs Cupping Course Pic\" loading=\"lazy\" width=\"1440\" height=\"960\"\/><\/a><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">\u3010 2026\u5e7410\u6708 \u958b\u8ab2\u62db\u751f\u4e2d\u3011<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/rubasseroasters.com\/zh\/course-rubasse-basic-roasting-zh\/\">\u70d8\u8c46&amp;\u676f\u6e2c\u9ad4\u9a57\u8ab2\u7a0b(\u57fa\u790e)<\/a><\/h4>\n<\/div>\n\n\n\n<div class=\"wp-block-greenshift-blocks-row-column gspb_row__col--4 gspb_col-id-gsbp-aa806df\" id=\"gspb_col-id-gsbp-aa806df\">\n<div class=\"wp-block-greenshift-blocks-image gspb_image gspb_image-id-gsbp-0b8698f\" id=\"gspb_image-id-gsbp-0b8698f\"><a href=\"https:\/\/rubasseroasters.com\/zh\/course-rubasse-intermediate-roasting-zh\/\" ><img decoding=\"async\" src=\"https:\/\/rubasseroasters.com\/wp-content\/uploads\/2025\/10\/scimgiZy7L4.webp\" data-src=\"\" alt=\"Rbs Roast Course Pic\" loading=\"lazy\" width=\"1440\" height=\"960\"\/><\/a><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">\u3010 2026\u5e749\u6708\u958b\u8ab2\u62db\u751f\u4e2d\u3011<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/rubasseroasters.com\/zh\/course-rubasse-intermediate-roasting-zh\/\">\u70d8\u8c46\u5be6\u4f5c\u8ab2\u7a0b<\/a><\/h4>\n<\/div>\n\n\n\n<div class=\"wp-block-greenshift-blocks-row-column gspb_row__col--4 gspb_col-id-gsbp-7b95404\" id=\"gspb_col-id-gsbp-7b95404\">\n<div class=\"wp-block-greenshift-blocks-image gspb_image gspb_image-id-gsbp-a783ee9\" id=\"gspb_image-id-gsbp-a783ee9\"><a href=\"https:\/\/rubasseroasters.com\/zh\/course-rubasse-advanced-roasting-zh\/\" ><img decoding=\"async\" src=\"https:\/\/rubasseroasters.com\/wp-content\/uploads\/2025\/10\/scimgOThGVC.webp\" data-src=\"\" alt=\"Rbs Advanced Roast Course Pic\" loading=\"lazy\" width=\"1440\" height=\"960\"\/><\/a><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">\u3010 2026\u5e749\u6708\uff0c10\u6708 \u958b\u8ab2\u62db\u751f\u4e2d\u3011<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/rubasseroasters.com\/zh\/course-rubasse-advanced-roasting-zh\/\">\u9032\u968e\u70d8\u8c46\u5be6\u6230\u8ab2\u7a0b<\/a><\/h4>\n<\/div>\n <\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u4e0a\u500b\u6708 \u8ab2\u7a0b\u884c\u4e8b\u66c6 \u4e0b\u500b\u6708 \u8ab2\u7a0b\u8f09\u5165\u4e2d\u2026<\/p>","protected":false},"author":4,"featured_media":0,"parent":0,"menu_order":1,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"_gspb_post_css":"#gspb_button-id-gsbp-cd7abe9{display:flex;justify-content:flex-end}#gspb_button-id-gsbp-cd7abe9 .gspb-buttonbox-text{display:flex;flex-direction:column}#gspb_button-id-gsbp-cd7abe9>.gspb-buttonbox,div[id^=gspb_col-id]{box-sizing:border-box}.gs-video{position:relative}.gs-video-wrapper{position:relative;height:inherit;max-width:100%}.gs-video-header{text-align:center}.gs-video-header .gs-video-header-title{font-size:24px;line-height:1.3;font-weight:700;margin:0 0 15px}.gs-video-header .gs-video-header-description{font-size:16px;line-height:1.5;margin:0 0 25px}.gs-video video{display:block}.gs-video .gs-video-element,.gs-video .gs-video-wrapper iframe{width:100%;height:100%;object-fit:cover;border:0}.gs-video .gs-video-wrapper iframe{aspect-ratio:16\/9;display:block}.gs-video-overlay{position:absolute;left:0;top:0;width:100%;height:100%;z-index:3;background-color:rgba(0,0,0,.1);background-size:cover;background-position:center;background-repeat:no-repeat;cursor:pointer}.gs-video-overlay .gs-overlay-color{position:absolute;left:0;top:0;width:100%;height:100%;z-index:2}.gs-video-overlay:hover .gs-play-icon{opacity:1}.gs-video-popup .slbContentOuter{width:100%;max-width:1000px}.gs-video-popup .slbContentOuter .slbContent iframe,.gs-video-popup .slbContentOuter .slbContent video{width:100%;height:100%;object-fit:cover}.gs-video-popup .slbContentOuter .slbContent iframe{aspect-ratio:16\/9}.gs-video-popup .slbCloseBtn{font-size:30px;width:40px;height:40px;line-height:40px;right:0;top:-50px}#gspb_row-id-gsbp-9b09c98{justify-content:space-between;display:flex;flex-wrap:wrap;margin-top:50px;margin-bottom:75px}#gspb_row-id-gsbp-9b09c98>.gspb_row__content{display:flex;justify-content:space-between;margin:0 auto;width:100%;flex-wrap:wrap}.gspb_row{position:relative}div[id^=gspb_col-id]{position:relative}body.gspb-bodyfront #gspb_row-id-gsbp-9b09c98>.gspb_row__content{width:var(--theme-container-width, 1290px);max-width:var(--theme-normal-container-max-width, 1290px)}#gspb_col-id-gsbp-552765e.gspb_row__col--4{width:calc(33.333333333333336% - 30px)}@media (max-width:991.98px){#gspb_col-id-gsbp-552765e.gspb_row__col--4{width:calc(33.333333333333336% - 30px)}}@media (max-width:767.98px){#gspb_col-id-gsbp-552765e.gspb_row__col--4{width:calc(33.333333333333336% - 30px)}}@media (max-width:575.98px){#gspb_col-id-gsbp-552765e.gspb_row__col--4{width:100%}}#gspb_col-id-gsbp-aa806df.gspb_row__col--4{width:calc(33.333333333333336% - 30px)}@media (max-width:991.98px){#gspb_col-id-gsbp-aa806df.gspb_row__col--4{width:calc(33.333333333333336% - 30px)}}@media (max-width:767.98px){#gspb_col-id-gsbp-aa806df.gspb_row__col--4{width:calc(33.333333333333336% - 30px)}}@media (max-width:575.98px){#gspb_col-id-gsbp-aa806df.gspb_row__col--4{width:100%}}#gspb_col-id-gsbp-7b95404.gspb_row__col--4{width:calc(33.333333333333336% - 30px)}@media (max-width:991.98px){#gspb_col-id-gsbp-7b95404.gspb_row__col--4{width:calc(33.333333333333336% - 30px)}}@media (max-width:767.98px){#gspb_col-id-gsbp-7b95404.gspb_row__col--4{width:calc(33.333333333333336% - 30px)}}@media (max-width:575.98px){#gspb_col-id-gsbp-7b95404.gspb_row__col--4{width:100%}}#gspb_image-id-gsbp-0b8698f img,#gspb_image-id-gsbp-62e6f55 img,#gspb_image-id-gsbp-a783ee9 img{vertical-align:top;display:inline-block;box-sizing:border-box;max-width:100%;height:auto}","footnotes":""},"class_list":["post-787","page","type-page","status-publish","hentry"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":7}},"acf":[],"_links":{"self":[{"href":"https:\/\/rubasseroasters.com\/zh\/wp-json\/wp\/v2\/pages\/787","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rubasseroasters.com\/zh\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/rubasseroasters.com\/zh\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/rubasseroasters.com\/zh\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/rubasseroasters.com\/zh\/wp-json\/wp\/v2\/comments?post=787"}],"version-history":[{"count":2,"href":"https:\/\/rubasseroasters.com\/zh\/wp-json\/wp\/v2\/pages\/787\/revisions"}],"predecessor-version":[{"id":5321,"href":"https:\/\/rubasseroasters.com\/zh\/wp-json\/wp\/v2\/pages\/787\/revisions\/5321"}],"wp:attachment":[{"href":"https:\/\/rubasseroasters.com\/zh\/wp-json\/wp\/v2\/media?parent=787"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}