PageSourceSearch

https://the-aroma.site/assets/js/cms.js

js the-aroma.site collected 2026-10-09 17:49:44 UTC 21,670 bytes, 611 lines download raw bytes

1const timeEndDay = 6;
2
3function getTodaySchedule(flg) {
4  const formattedToday = getTodayFormatDate();
5  // 予約満了ではないセラピスト
6  const ary1 = shopData.schedules.filter(function (schedule) {
7    return schedule.workDate.length < 1 || (schedule.workDate === formattedToday && schedule.scheduleType !== '予約満了');
8  });
9
10  // 予約満了のセラピスト
11  const ary2 = shopData.schedules.filter(function (schedule) {
12    return schedule.workDate.length < 1 || (schedule.workDate === formattedToday && schedule.scheduleType === '予約満了');
13  });
14
15  return handleSchedulesData(arySort(ary1, flg).concat(arySort(ary2, flg)));
16}
17
18// 時間ソート - 時間変換
19function timeToInt(time) {
20    const [hours, minutes] = time.split(':');
21    return parseInt(hours) < 10 ? parseInt(hours) + 24 : parseInt(hours);
22}
23
24// 時間ソート - 時間順に並べ替える
25function arySort(ary, flg){
26  switch(flg){
27    case "time1": // 時間順(昇順)
28    default:
29      ary.sort((a, b) => timeToInt(a.startTime) - timeToInt(b.startTime));
30      break;
31    case "time2": // 時間順(降順)
32      ary.sort((a, b) => timeToInt(b.startTime) - timeToInt(a.startTime));
33      break;
34    case "none": // 変換なし(ID順)
35      break;
36  }
37  return ary;
38}
39
40function getTodayFormatDate() {
41  // 今日の日付を取得してフォーマットを合わせる
42  const now = new Date();
43  const today = new Date(now.getTime() - (timeEndDay * 3600000));
44  const year = today.getFullYear();
45  const month = ("0" + (today.getMonth() + 1)).slice(-2);
46  const day = ("0" + today.getDate()).slice(-2);
47  return year + "/" + month + "/" + day;
48}
49
50function getThisPageSchedule(flg) {
51  const searchDate = getPageTargetDate();
52  // 予約満了ではないセラピスト
53  const ary1 = shopData.schedules.filter(function (schedule) {
54    return schedule.workDate === searchDate && schedule.scheduleType !== '予約満了';
55  });
56
57  // 予約満了のセラピスト
58  const ary2 = shopData.schedules.filter(function (schedule) {
59    return schedule.workDate === searchDate && schedule.scheduleType === '予約満了';
60  });
61  return handleSchedulesData(arySort(ary1, flg).concat(arySort(ary2, flg)));
62}
63
64function getPageTargetDate() {
65  const url = new URL(window.location.href);
66  const date = url.searchParams.get("date");
67  let searchDate = "";
68  if (date) {
69    searchDate = date.split("-").join("/");
70  } else {
71    searchDate = getTodayFormatDate();
72  }
73  return searchDate;
74}
75
76function getThisWeekDaysObj() {
77  const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
78  const today = new Date(getTodayFormatDate());
79  const next7Days = [];
80  const searchDate = getPageTargetDate();
81  for (let i = 0; i < 7; i++) {
82    const nextDay = new Date(today);
83    nextDay.setDate(today.getDate() + i);
84    const year = nextDay.getFullYear();
85    const month = nextDay.getMonth() + 1; // 月は0から始まるので1を足す
86    let fullMonth = month;
87    if (fullMonth < 10) {
88      fullMonth = "0" + fullMonth;
89    }
90    const date = nextDay.getDate();
91    let fullDate = date;
92    if (fullDate < 10) {
93      fullDate = "0" + fullDate;
94    }
95    const dayOfWeek = daysOfWeek[nextDay.getDay()];
96    const formattedDate = month + "/" + date + "(" + dayOfWeek + ")";
97    const fullFormattedDate = year + "/" + fullMonth + "/" + fullDate;
98    const isTargetDate = searchDate === fullFormattedDate;
99    const dateObj = {
100      date: formattedDate,
101      cls: getDayClass(formattedDate, isTargetDate),
102      url: "/schedule?date=" + year + "-" + fullMonth + "-" + fullDate,
103    };
104    next7Days.push(dateObj);
105  }
106  return next7Days;
107}
108
109function getThisWeekDaysYYYYMMDD() {
110  const now = new Date();
111  const today = new Date(now.getTime() - (timeEndDay * 3600000));
112  const next7Days = [];
113  for (let i = 0; i < 7; i++) {
114    const nextDay = new Date(today);
115    nextDay.setDate(today.getDate() + i);
116    const year = nextDay.getFullYear();
117    const month = ("0" + (nextDay.getMonth() + 1)).slice(-2);
118    const date = ("0" + nextDay.getDate()).slice(-2);
119    const formattedDate = year + "/" + month + "/" + date;
120    next7Days.push(formattedDate);
121  }
122  return next7Days;
123}
124
125function getDayClass(date, isTargetDate) {
126  let targetCls = "";
127  if (isTargetDate) {
128    targetCls = "todays ";
129  }
130  if (date.indexOf("Sat") > 1) {
131    return targetCls + "week6";
132  }
133  if (date.indexOf("Sun") > 1) {
134    return targetCls + "week0";
135  }
136  return targetCls + "week1";
137}
138
139function getScheduleThisPageGirl() {
140  const url = new URL(window.location.href);
141  const id = url.searchParams.get("id");
142  const schedules = [];
143  const weekDays = getThisWeekDaysYYYYMMDD();
144
145  for (const date of weekDays) {
146    let val = " ";
147    for (const schedule of shopData.schedules) {
148      if (schedule.workDate == date && schedule.therapistId == id) {
149        val = schedule.startTime + "~" + schedule.endTime;
150        break;
151      }
152    }
153    schedules.push(val);
154  }
155
156  return schedules;
157}
158
159function getThisPageGirl() {
160  const url = new URL(window.location.href);
161  const id = url.searchParams.get("id");
162  for (const therapist of shopData.therapists) {
163    if (therapist.id == id) {
164      return therapist;
165    }
166  }
167  return {
168    id: "0",
169    therapistName: "--",
170    url: "--",
171    img1: "",
172    img2: "",
173    img3: "",
174    img4: "",
175    img5: "",
176    img6: "",
177    age: "--",
178    height: "--",
179    threeSize: "--",
180    bloodType: "--",
181    goodAt: "--",
182    xUrl: "--",
183    pickup: "0",
184    comment: "--",
185    tags: [],
186  };
187}
188
189function getThisPageArea() {
190  const url = new URL(window.location.href);
191  const pathParts = url.pathname.split('/').filter(p => p !== '');
192  const rawId = pathParts.slice(1).join('/');
193  const id = rawId ? decodeURIComponent(rawId) : rawId;
194
195  const fallback = {
196    id: "0",
197    categoryId: "0",
198    categoryName: "--",
199    name: "--",
200    content: "--",
201    tags: [],
202  };
203
204  if (!id || typeof shopData === "undefined" || !shopData.areas) {
205    return fallback;
206  }
207
208  for (const area of shopData.areas) {
209    if (area.name == id || getEnglishAreaSlug(area.name) == id) {
210      const translatedArea = { ...area };
211      translatedArea.slug = getEnglishAreaSlug(area.name);
212      
213      // Fix bold text for CMS data
214      if (translatedArea.content) {
215        const tempDiv = document.createElement('div');
216        tempDiv.innerHTML = translatedArea.content;
217        
218        // Find leaf block elements
219        const blocks = tempDiv.querySelectorAll('h2, h3, p, div');
220        blocks.forEach(block => {
221          if (!block.querySelector('h2, h3, p, div')) {
222            const text = block.textContent.trim();
223            if (text.length === 0) return;
224
225            // Make paragraphs inside headings normal weight.
226            // A reliable way to detect a paragraph vs a title in Japanese is the presence of a full stop '。'.
227            if ((block.tagName === 'H2' || block.tagName === 'H3') && text.includes('。')) {
228              block.style.fontWeight = 'normal';
229            }
230
231            // Ensure titles starting with '・' or '【' are bold (even if they are inside <p>)
232            if (text.startsWith('・') || text.startsWith('【')) {
233              block.style.fontWeight = 'bold';
234            }
235          }
236        });
237        
238        translatedArea.content = tempDiv.innerHTML;
239      }
240
241      return translatedArea;
242    }
243  }
244  return fallback;
245}
246
247function redirectByAreaId() {
248  const url = new URL(window.location.href);
249  const qid = url.searchParams.get('id');
250  if (!qid) return false;
251
252  if (typeof shopData === "undefined" || !shopData.areas) {
253    window.location.replace('/areas');
254    return true;
255  }
256
257  const found = shopData.areas.find(a => a.id == qid);
258  if (found) {
259    window.location.replace('/area/' + getEnglishAreaSlug(found.name));
260  } else {
261    window.location.replace('/areas');
262  }
263  return true;
264}
265
266function getThisPageNotice() {
267  const url = new URL(window.location.href);
268  const id = url.searchParams.get("id");
269  const notices = shopData.notices;
270  for (let i = 0; i < notices.length; i++) {
271    const notice = notices[i];
272    const prevId = notices[i-1] ? notices[i-1].id : null;
273    const nextId = notices[i+1] ? notices[i+1].id : null;
274    if (notice.id == id) {
275      return {
276        id: notice.id,
277        title: notice.title,
278        detail: notice.detail,
279        noticeAt: notice.noticeAt,
280        hasBefore: i > 0,
281        hasAfter: i < notices.length - 1,
282        prevId: prevId,
283        nextId: nextId,
284      };
285    }
286  }
287  return {
288    id: "0",
289    title: "",
290    detail: "",
291    noticeAt: "",
292    hasBefore: false,
293    hasAfter: false,
294    prevId: 0,
295    nextId: 0,
296  };
297}
298
299function recruitFormHandler() {
300  return {
301    name: "",
302    email: "",
303    phone_number: "",
304    inquiry: "",
305
306    saveDataAndRedirect() {
307      localStorage.setItem("recruit_inquiry_name", this.name);
308      localStorage.setItem("recruit_inquiry_email", this.email);
309      localStorage.setItem("recruit_inquiry_phone_number", this.phone_number);
310      localStorage.setItem("recruit_inquiry_inquiry", this.inquiry);
311
312      window.location.href = "/recruit-confirm";
313    },
314
315    loadData() {
316      this.name = localStorage.getItem("recruit_inquiry_name") || "";
317      this.email = localStorage.getItem("recruit_inquiry_email") || "";
318      this.phone_number =
319        localStorage.getItem("recruit_inquiry_phone_number") || "";
320      this.inquiry = localStorage.getItem("recruit_inquiry_inquiry") || "";
321    },
322
323    async submitForm() {
324      const payload = {
325        name: this.name,
326        email: this.email,
327        phone_number: this.phone_number,
328        inquiry: this.inquiry,
329      };
330
331      try {
332        const response = await fetch(shopData.recruit.postUrl, {
333          method: "POST",
334          headers: {
335            "Content-Type": "application/json",
336            "api-key": "qSPgj8LOXCNx05MrLawoBhbKQ6GHrUhm",
337          },
338          body: JSON.stringify(payload),
339        });
340
341        if (response.ok) {
342          alert("Form submitted successfully!");
343
344          localStorage.clear();
345          window.location.href = "/recruit-thanks";
346        } else {
347          alert("Failed to submit the form. Please try again.");
348        }
349      } catch (error) {
350        console.error("Error:", error);
351        alert("An error occurred. Please try again.");
352      }
353    },
354  };
355}
356
357function reservationFormHandler() {
358  return {
359    name: "",
360    email: "",
361    phone_number: "",
362    visit_count: "",
363    coming_at: "",
364    course_name: "",
365    option_name: "",
366    course_menu_name: "",
367    option_menu_name: "",
368    therapist_name: "",
369    inquiry: "",
370
371    selectedCourseMenus: [],
372    selectedOptionMenus: [],
373    therapists: [],
374
375    updateCourseMenu() {
376      const selectedCourse = shopData.courses.find(
377        (course) => course.title === this.course_name
378      );
379      this.selectedCourseMenus = selectedCourse ? selectedCourse.menu : [];
380      this.course_menu_name = "";
381    },
382
383    updateOptionMenu() {
384      const selectedOption = shopData.options.find(
385        (option) => option.title === this.option_name
386      );
387      this.selectedOptionMenus = selectedOption ? selectedOption.menu : [];
388      this.option_menu_name = "";
389    },
390
391    isWithinWorkingHours(selectedTime, startTime, endTime) {
392      const [startHour, startMinute] = startTime.split(":").map(Number);
393      const [endHour, endMinute] = endTime.split(":").map(Number);
394      const [selectedHour, selectedMinute] = selectedTime
395        .split(":")
396        .map(Number);
397
398      const start = startHour * 60 + startMinute;
399      const end =
400        (endHour < startHour ? endHour + 24 : endHour) * 60 + endMinute;
401      const selected = selectedHour * 60 + selectedMinute;
402
403      return selected >= start && selected <= end;
404    },
405
406    searchTherapists() {
407      if (!this.coming_at) {
408        alert("ご来店日時を指定してください");
409        return;
410      }
411
412      const [selectedDate, selectedTime] = this.coming_at.split("T");
413
414      this.therapists = shopData.schedules.filter((schedule) => {
415        const scheduleDate = schedule.workDate.replace(/\//g, "-");
416
417        return (
418          scheduleDate === selectedDate &&
419          this.isWithinWorkingHours(
420            selectedTime,
421            schedule.startTime,
422            schedule.endTime
423          )
424        );
425      });
426
427      this.therapists.unshift({
428        therapistName: "Free (フリー)",
429      });
430    },
431
432    selectTherapist(therapist) {
433      this.therapist_name = therapist.therapistName;
434    },
435
436    saveDataAndRedirect() {
437      localStorage.setItem("reservation_inquiry_name", this.name);
438      localStorage.setItem("reservation_inquiry_email", this.email);
439      localStorage.setItem(
440        "reservation_inquiry_phone_number",
441        this.phone_number
442      );
443      localStorage.setItem("reservation_inquiry_visit_count", this.visit_count);
444      localStorage.setItem(
445        "reservation_inquiry_coming_at_date",
446        this.coming_at
447      );
448      localStorage.setItem("reservation_inquiry_course_name", this.course_name);
449      localStorage.setItem(
450        "reservation_inquiry_course_menu_name",
451        this.course_menu_name
452      );
453      localStorage.setItem("reservation_inquiry_option_name", this.option_name);
454      localStorage.setItem(
455        "reservation_inquiry_option_menu_name",
456        this.option_menu_name
457      );
458      localStorage.setItem(
459        "reservation_inquiry_therapist_name",
460        this.therapist_name
461      );
462      localStorage.setItem("reservation_inquiry_inquiry", this.inquiry);
463
464      window.location.href = "/reservation-confirm";
465    },
466
467    loadData() {
468      this.name = localStorage.getItem("reservation_inquiry_name") || "";
469      this.email = localStorage.getItem("reservation_inquiry_email") || "";
470      this.phone_number =
471        localStorage.getItem("reservation_inquiry_phone_number") || "";
472      this.visit_count =
473        localStorage.getItem("reservation_inquiry_visit_count") || "";
474      this.coming_at =
475        localStorage.getItem("reservation_inquiry_coming_at_date") || "";
476      this.course_name =
477        localStorage.getItem("reservation_inquiry_course_name") || "";
478      this.course_menu_name =
479        localStorage.getItem("reservation_inquiry_course_menu_name") || "";
480      this.option_name =
481        localStorage.getItem("reservation_inquiry_option_name") || "";
482      this.option_menu_name =
483        localStorage.getItem("reservation_inquiry_option_menu_name") || "";
484      this.therapist_name =
485        localStorage.getItem("reservation_inquiry_therapist_name") || "";
486      this.inquiry = localStorage.getItem("reservation_inquiry_inquiry") || "";
487    },
488
489    async submitForm() {
490      const payload = {
491        name: this.name,
492        email: this.email,
493        phone_number: this.phone_number,
494        visit_count: this.visit_count,
495        coming_at: this.coming_at,
496        course_name: this.course_name,
497        course_menu_name: this.course_menu_name,
498        option_name: this.option_name,
499        option_menu_name: this.option_menu_name,
500        therapist_name: this.therapist_name,
501        inquiry: this.inquiry,
502      };
503
504      try {
505        const response = await fetch(shopData.reservation.postUrl, {
506          method: "POST",
507          headers: {
508            "Content-Type": "application/json",
509            "api-key": "qSPgj8LOXCNx05MrLawoBhbKQ6GHrUhm",
510          },
511          body: JSON.stringify(payload),
512        });
513
514        if (response.ok) {
515          alert("Form submitted successfully!");
516
517          localStorage.clear();
518          window.location.href = "/reservation-thanks";
519        } else {
520          alert("Failed to submit the form. Please try again.");
521        }
522      } catch (error) {
523        console.error("Error:", error);
524        alert("An error occurred. Please try again.");
525      }
526    },
527  };
528}
529
530function getPickupTherapists() {
531  return shopData.therapists.filter((therapist) => therapist.pickup === "True");
532}
533
534// remove duplicate schedule
535function handleSchedulesData(data) {
536  return data.filter((value, index, self) => 
537    index === self.findIndex((t) => (
538        t.therapistId === value.therapistId && t.workDate === value.workDate
539    ))
540  );
541}
542
543const AREA_MAPPING = {
544  "銀座": "Ginza", "東銀座": "Higashiginza", "日本橋": "Nihonbashi", "新日本橋": "Shinnihonbashi",
545  "馬喰町": "Bakurotyo", "宝町": "Takaratyo", "京橋": "Kyoubashi", "八丁堀": "Hattyoubori",
546  "築地": "Tsukiji", "月島・晴海": "Tukisima/Harumi", "勝どき": "Katidoki", "茅場町": "Kayabatyo",
547  "人形町": "Ningyoutyo", "小伝馬町": "Kodenmatyo", "浜町": "Hamatyo", "水天宮前": "Suitenguumae",
548  "三越前": "Mitsukoshimae", "新橋": "Shinbashi", "虎ノ門": "Toranomono", "大門": "Daimon",
549  "お台場": "Odaiba", "汐留": "Shiodome", "赤坂": "Akasaka", "表参道": "Omotesandou",
550  "青山一丁目": "Aoyamaittyoume", "青山": "Aoyamaittyoume", "六本木": "Ropponngi", "赤坂見附": "Akasakamitsuke",
551  "神谷町": "Kamiyatyo", "麻布十番": "Azabujyuban", "品川": "Shinagawa", "浜松町": "Hamamatutyo",
552  "田町・三田": "Tamati/Mita", "竹芝・芝浦": "Takeshiba/Sibaura", "泉岳寺": "Sengakuji",
553  "芝公園": "Shibakouen", "東京駅": "Tokyoeki", "大手町": "Otemachi", "有楽町・日比谷": "Yurakutyo/Hibiya",
554  "内幸町": "Utisaiwaityo", "竹橋": "Takebashi", "神田・お茶の水": "Kanda/Otyanomizu",
555  "神田・御茶ノ水": "Kanda/Otyanomizu",
556  "水道橋・飯田橋": "Suidoubasi/Idabasi", "秋葉原": "Akihabara", "神保町": "Jinbotyo",
557  "市ヶ谷・四ツ谷": "Ichigaya/Yotsuya", "麹町": "Koujimachi", "永田町": "Nagatatyo",
558  "半蔵門・九段下": "Hanzoumon/Kudanshita", "溜池山王": "Tameikesannou", "小川町": "Ogawatyo",
559  "目黒": "Meguro", "五反田": "Gotanda", "大井町": "Oimachi", "大崎": "Osaki",
560  "天王洲アイル": "Tennouzuairu", "品川シーサイド": "Shinagawashisaido", "新宿": "Shinjyuku",
561  "新宿三丁目": "Shinjyukusantyome", "都庁前": "Totyoumae", "新宿西口": "Shinjyukunishiguchi",
562  "高田馬場": "Takadanobaba", "大久保": "Okubo", "神楽坂": "Kagurazaka", "曙橋": "Akebonobashi",
563  "渋谷": "Shibuya", "代官山": "Daikanyama", "恵比寿": "Ebisu", "原宿": "Harajyuku",
564  "代々木": "Yoyogi", "笹塚": "Sasaduka", "幡ヶ谷": "Hatagaya", "幡谷": "Hatagaya", "初台": "Hatudai",
565  "門前仲町": "Monzennakatyo", "東陽町": "Touyoutyo", "豊洲": "Toyosu", "新木場": "Shinkiba",
566  "亀戸": "Kameido", "大島": "Ooshima", "森下・菊川": "Morishita/Kikukawa", "森下/菊川": "Morishita/Kikukawa", "青海": "Aomi",
567  "国際展示場・有明": "Kokusaitenjijyo/Ariake", "東京テレポート": "Tokyoterepoto",
568  "錦糸町": "Kinshityo", "両国": "Ryogoku", "押上": "Oshiage", "曳舟": "Hikihune",
569  "とうきょうスカイツリー": "Tokyoskytree", "上野": "Ueno", "浅草": "Asakusa",
570  "御徒町": "Okachimachi", "浅草橋": "Asakusabashi", "鶯谷": "Uguisudani", "三ノ輪": "Minowa",
571  "中目黒": "Nakameguro", "自由が丘": "Jiyugaoka", "後楽園": "Kourakuen", "春日": "Kazuga",
572  "千駄木": "Sendagi", "池袋": "Ikebukuro", "大塚": "Ootsuka", "巣鴨": "Sugamo",
573  "駒込": "Komagome", "目白": "Mejiro", "葛西": "Kasai", "西葛西": "Nishikasai",
574  "浦安": "Urayasu", "中野": "Nakano", "光が丘": "Hikarigaoka", "板橋": "Itabashi",
575  "北千住": "Kitasenjyu", "綾瀬": "Ayase", "竹ノ塚": "Takenotsuka", "新小岩": "Shinkoiwa",
576  "大森": "Omori", "大森海岸": "Omorikaigan", "羽田空港": "Hanedakukou",
577  "蒲田": "Kamata", "穴守稲荷": "Anamorinari", "高円寺": "Kouenji", "阿佐ヶ谷": "Asagaya",
578  "荻窪": "Ogikubo", "赤羽": "Akabane", "二子玉川": "Hutakotamagawa", "三軒茶屋": "Sangentyaya",
579  "下北沢": "Simokitazawa", "経堂": "Kyodo", "日暮里": "Nippori", "西日暮里": "Nishinippori",
580  "南千住": "Minamisenjyu",
581  "東池袋": "Higashiikebukuro", "北池袋": "Kitaikebukuro", "要町": "Kanamecho",
582  "千川": "Sengawa", "椎名町": "Shiinachou", "雑司ヶ谷": "Zoshigaya",
583  "本郷三丁目": "Hongosanchome", "茗荷谷": "Myougadani", "護国寺": "Gokokuji",
584  "白山": "Hakusan", "本駒込": "Honkomagome", "根津": "Nezu",
585  "湯島": "Yushima", "東大前": "Todaimae", "江戸川橋": "Edogawabashi",
586  "中野坂上": "Nakanosakauye", "東中野": "Higashinakano", "新中野": "Shinnakano",
587  "中野新橋": "Nakanoshinbashi", "中野富士見町": "Nakanofujimicho",
588  "祐天寺": "Yutenji", "学芸大学": "Gakugeidaigaku", "都立大学": "Toritsudaigaku",
589  "東雲": "Shinonome",
590  "西荻窪": "Nishiogikubo", "方南町": "Honancho", "永福町": "Eifukucho",
591  "町屋": "Machiya", "三河島": "Mikawashima",
592  "王子": "Oji", "田端": "Tabata", "東十条": "Higashijujo", "十条": "Jujo",
593  "練馬": "Nerima", "石神井公園": "Shakujiikoen", "大泉学園": "Oizumigakuen",
594  "江古田": "Ekoda", "豊島園": "Toshimaen",
595  "大山": "Oyama", "成増": "Narimasu", "板橋本町": "Itabashihoncho",
596  "ときわ台": "Tokiwadai", "高島平": "Takashimadaira",
597  "千歳烏山": "Chitosekarasuyama", "成城学園前": "Seijogakuenmae", "用賀": "Yoga",
598  "平和島": "Heiwajima",
599  "金町": "Kanamachi", "青砥": "Aoto", "亀有": "Kameari",
600  "西新井": "Nishiarai",
601  "小岩": "Koiwa", "船堀": "Funabori"
602};
603
604function getEnglishAreaName(jpName) {
605  return AREA_MAPPING[jpName] || jpName;
606}
607
608function getEnglishAreaSlug(jpName) {
609  const enName = getEnglishAreaName(jpName);
610  return enName.toLowerCase().replace(/[・\s\.]+/g, '-');
611}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.