diff --git a/lib/plankton/plankton.d.ts b/lib/plankton/plankton.d.ts index ff7db18..22fc7d6 100644 --- a/lib/plankton/plankton.d.ts +++ b/lib/plankton/plankton.d.ts @@ -2405,3 +2405,677 @@ declare namespace lib_plankton.xml { compile(depth?: int): string; } } +declare module lib_et { + /** + * @desc type of extended timestamp + * @author fenris + */ + type type_et = { + era: int; + stamp: int; + }; + /** + * @desc type of UNIX timestamp + * @author fenris + */ + type type_timestamp = int; + /** + * @desc type of Javascript Date object + * @author fenris + */ + type type_jsdate = Date; + /** + * @author fenris + */ + type type_components = { + year: int; + month: int; + day: int; + hour: int; + minute: int; + second: int; + }; + /** + * @author fenris + */ + type type_ywd = { + year: int; + week: int; + day: int; + }; + /** + * @author fenris + */ + function part(et1: type_et, et2: type_et): type_et; + /** + * @desc less + * @author fenris + */ + function before(reference: type_et, et: type_et): boolean; + /** + * @desc greater + * @author fenris + */ + function after(reference: type_et, et: type_et): boolean; + /** + * @author fenris + */ + function between(begin: type_et, end: type_et, et: type_et): boolean; + /** + * @author fenris + */ + function intersect(begin1: type_et, end1: type_et, begin2: type_et, end2: type_et): boolean; + /** + * @author fenris + */ + function move(base: type_et, span: type_et): type_et; + /** + * @desc currified version of "move" + * @author fenris + */ + function move_(span: type_et): (base: type_et) => type_et; + /** + * @author fenris + */ + function from_timestamp(timestamp: type_timestamp): type_et; + /** + * @author fenris + */ + function to_timestamp(et: type_et): type_timestamp; + /** + * @author fenris + */ + function from_jsdate(jsdate: type_jsdate): type_et; + /** + * @author fenris + */ + function to_jsdate(et: type_et): type_jsdate; + /** + * @author fenris + */ + function from_components(components: type_components): type_et; + /** + * @author fenris + */ + function to_components(et: type_et): type_components; + /** + * @author fenris + */ + function now(): type_et; + /** + * @author fenris + */ + function to_string(et: type_et): string; + /** + * @author fenris + */ + function to_string_ywd(et: type_et): string; + /** + * @desc retrieve week of year + * @author fenris + */ + function get_woy(et: type_et): int; + /** + * @desc retrieve day of week + * @author fenris + */ + function get_dow(et: type_et): int; + /** + * @author fenris + */ + function trunc_minute(et?: type_et): type_et; + /** + * @author fenris + */ + function trunc_hour(et?: type_et): type_et; + /** + * @author fenris + */ + function trunc_day(et?: type_et): type_et; + /** + * @author fenris + */ + function trunc_month(et?: type_et): type_et; + /** + * @author fenris + */ + function trunc_year(et?: type_et): type_et; + /** + * @author fenris + */ + function trunc_week(et?: type_et): type_et; + /** + * @author fenris + */ + function span_second(seconds?: int): type_et; + /** + * @author fenris + */ + function span_minute(minutes?: int): type_et; + /** + * @author fenris + */ + function span_hour(hours?: int): type_et; + /** + * @author fenris + */ + function span_day(days?: int): type_et; + /** + * @author fenris + */ + function span_week(weeks?: int): type_et; + /** + * @author fenris + */ + function span_year(years?: int): type_et; +} +declare module lib_et { + /** + * @author fenris + */ + class class_et { + /** + * @author fenris + */ + protected subject: type_et; + /** + * @author fenris + */ + constructor(subject: type_et); + /** + * @author fenris + */ + move(et: class_et): class_et; + /** + * @author fenris + */ + before(et: class_et): boolean; + /** + * @author fenris + */ + after(et: class_et): boolean; + /** + * @author fenris + */ + between(et1: class_et, et2: class_et): boolean; + /** + * @author fenris + */ + trunc_minute(): class_et; + /** + * @author fenris + */ + trunc_hour(): class_et; + /** + * @author fenris + */ + trunc_day(): class_et; + /** + * @author fenris + */ + trunc_month(): class_et; + /** + * @author fenris + */ + trunc_year(): class_et; + /** + * @author fenris + */ + trunc_week(): class_et; + /** + * @author fenris + */ + static now(): class_et; + /** + * @author fenris + */ + static span_second(count?: int): class_et; + /** + * @author fenris + */ + static span_minute(count?: int): class_et; + /** + * @author fenris + */ + static span_hour(count?: int): class_et; + /** + * @author fenris + */ + static span_day(count?: int): class_et; + /** + * @author fenris + */ + static span_week(count?: int): class_et; + /** + * @author fenris + */ + static span_year(count?: int): class_et; + /** + * @author fenris + */ + static from_timestamp(timestamp: type_timestamp): class_et; + /** + * @author fenris + */ + to_timestamp(): type_timestamp; + /** + * @author fenris + */ + static from_jsdate(jsdate: type_jsdate): class_et; + /** + * @author fenris + */ + to_jsdate(): type_jsdate; + /** + * @author fenris + */ + static from_components(components: type_components): class_et; + /** + * @author fenris + */ + to_components(): type_components; + /** + * @author fenris + */ + get_woy(): int; + /** + * @author fenris + */ + get_dow(): int; + /** + * @author fenris + */ + to_string(): string; + } +} +declare var global_config: any; +/** + * @author neuc + */ +declare namespace lib_plankton.date { + /** + * @author neu3no, fenris + */ + function set_days(day_names: Array): void; + /** + * @author neu3no, fenris + */ + function set_months(month_names: Array): void; + /** + * @desc week of year + * @param {Date} date + * @return {int} + * @author fenris + */ + function get_week(date: Date): int; + /** + * @author neu3no, fenris + */ + function set_currentDate(date: Date): void; + /** + * @author neu3no, fenris + */ + function parse(format: string, date?: Date): string; + /** + * @author neu3no, fenris + */ + function locale_date(date?: Date, ignore_error?: boolean): string; + /** + */ + type type_unixtimestamp = int; + /** + */ + type type_components = { + timezone_offset: int; + year: int; + month: int; + day: int; + hour: int; + minute: int; + second: int; + }; + /** + */ + function now(): type_unixtimestamp; + /** + */ + function from_components(components: type_components): type_unixtimestamp; + /** + */ + function to_components(unixtimestamp: type_unixtimestamp): type_components; + /** + */ + function get_timestamp_from_year_and_week_and_day(year: int, week: int, day: int): type_unixtimestamp; +} +declare var strftime: typeof lib_plankton.date; +declare namespace lib_plankton.ical { + /** + */ + type type_rrule = { + freq?: string; + byday?: string; + bymonth?: string; + }; + /** + */ + type type_offset = string; + /** + */ + /** + */ + export enum enum_class { + public = "public", + private = "private", + confidential = "confidential" + } + /** + */ + export enum enum_event_status { + tentative = "tentative", + confirmed = "confirmed", + cancelled = "cancelled" + } + /** + */ + export enum enum_transp { + opaque = "opaque", + transparent = "transparent" + } + /** + */ + type type_tzid = string; + /** + */ + export type type_date = { + year: int; + month: int; + day: int; + }; + /** + */ + export type type_time = { + hour: int; + minute: int; + second: int; + utc: boolean; + }; + /** + */ + export type type_datetime = { + date: type_date; + time: (null | type_time); + }; + /** + */ + export type type_dt = { + tzid: type_tzid; + value: type_datetime; + }; + /** + */ + type type_duration = { + negative: boolean; + weeks?: int; + days?: int; + hours?: int; + minutes?: int; + seconds?: int; + }; + /** + */ + type type_vtimezone = { + tzid?: type_tzid; + standard?: { + dtstart: type_datetime; + rrule: type_rrule; + tzoffsetfrom?: type_offset; + tzoffsetto?: type_offset; + }; + daylight?: { + dtstart: type_datetime; + rrule: type_rrule; + tzoffsetfrom?: type_offset; + tzoffsetto?: type_offset; + }; + }; + /** + * @see https://www.rfc-editor.org/rfc/rfc5545#section-3.6.1 + */ + export type type_vevent = { + uid: string; + dtstamp: type_datetime; + dtstart?: type_dt; + class?: enum_class; + created?: type_datetime; + description?: string; + geo?: { + latitude: float; + longitude: float; + }; + last_modified?: type_datetime; + location?: string; + organizer?: { + cn?: string; + value?: string; + }; + priority?: int; + sequence?: int; + status?: enum_event_status; + summary?: string; + transp?: enum_transp; + url?: string; + recurid?: any; + rrule?: type_rrule; + dtend?: type_dt; + duration?: type_duration; + attach?: any; + attendee?: string; + categories?: Array; + comment?: any; + contact?: any; + exdate?: any; + rstatus?: any; + related?: any; + resources?: any; + rdate?: any; + x_props?: Record; + iana_props?: Record; + }; + /** + * @see https://www.rfc-editor.org/rfc/rfc5545#section-3.4 + */ + export type type_vcalendar = { + version: string; + prodid: string; + vevents: Array; + calscale?: string; + method?: string; + vtimezone?: type_vtimezone; + x_props?: Record; + iana_props?: Record; + }; + export {}; +} +declare namespace lib_plankton.ical { + /** + */ + function datetime_to_unixtimestamp(datetime: type_datetime): lib_plankton.date.type_unixtimestamp; + /** + * @see https://www.rfc-editor.org/rfc/rfc5545 + * @see https://icalendar.org/iCalendar-RFC-5545/ + * @todo implement edge cases + */ + function ics_decode(ics: string, options?: { + debug?: boolean; + }): type_vcalendar; + /** + * @todo method + * @todo add missing fields + */ + function ics_encode(vcalendar: type_vcalendar): string; +} +declare namespace lib_plankton.http { + /** + * @author fenris + */ + enum enum_method { + options = "options", + head = "head", + get = "get", + delete = "delete", + post = "post", + put = "put", + patch = "patch" + } + /** + * @author fenris + */ + type type_request = { + scheme: ("http" | "https"); + host: (null | string); + path: string; + version: string; + method: enum_method; + query: (null | string); + headers: Record; + body: (null | Buffer); + }; + /** + * @author fenris + */ + type type_response = { + version: (null | string); + status_code: int; + headers: Record; + body: Buffer; + }; +} +declare namespace lib_plankton.http { + /** + * @author fenris + */ + function encode_method(method: enum_method): string; + /** + * @author fenris + */ + function encode_request(request: type_request): string; + /** + * @author fenris + */ + function decode_request(request_raw: string): type_request; + /** + * @author fenris + */ + function encode_response(response: type_response): string; + /** + * @author fenris + */ + function decode_response(response_raw: string): type_response; + /** + * executes an HTTP request + * + * @todo define type_signal + */ + function call(request: type_request, options?: { + timeout?: (null | float); + follow_redirects?: boolean; + implementation?: ("fetch" | "http_module"); + }): Promise; +} +declare namespace lib_plankton.http { + /** + * @author fenris + */ + class class_http_request implements lib_plankton.code.interface_code { + /** + * @author fenris + */ + constructor(); + /** + * @implementation + * @author fenris + */ + encode(x: type_request): string; + /** + * @implementation + * @author fenris + */ + decode(x: string): type_request; + } + /** + * @author fenris + */ + class class_http_response implements lib_plankton.code.interface_code { + /** + * @author fenris + */ + constructor(); + /** + * @implementation + * @author fenris + */ + encode(x: type_response): string; + /** + * @implementation + * @author fenris + */ + decode(x: string): type_response; + } +} +declare namespace lib_plankton.url { + /** + * @author fenris + */ + type type_url = { + scheme: (null | string); + host: (null | string); + username: (null | string); + password: (null | string); + port: (null | int); + path: (null | string); + query: (null | string); + hash: (null | string); + }; +} +declare namespace lib_plankton.url { + /** + */ + function query_args_encode(query_args: Record): string; + /** + */ + function query_args_decode(query: string): Record; + /** + * @author fenris + */ + function encode(url: type_url): string; + /** + * @author fenris + * @todo arguments + */ + function decode(url_raw: string): type_url; + /** + * @author fenris + */ + function implementation_code(): lib_plankton.code.type_code; +} +declare namespace lib_plankton.url { + /** + * @author fenris + */ + class class_url implements lib_plankton.code.interface_code { + /** + * @author fenris + */ + constructor(); + /** + * @implementation + * @author fenris + */ + encode(x: any): string; + /** + * @implementation + * @author fenris + */ + decode(x: string): any; + } +} diff --git a/lib/plankton/plankton.js b/lib/plankton/plankton.js index 214a149..bb63f46 100644 --- a/lib/plankton/plankton.js +++ b/lib/plankton/plankton.js @@ -6452,3 +6452,2392 @@ var lib_plankton; xml.class_node_complex = class_node_complex; })(xml = lib_plankton.xml || (lib_plankton.xml = {})); })(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:date«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:date« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:date« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:date«. If not, see . + */ +var lib_et; +(function (lib_et) { + /** + * @author fenris + */ + function div(x, y) { + return Math.floor(x / y); + } + /** + * @author fenris + */ + function mod(x, y) { + return (x - (y * div(x, y))); + } + /** + * @author fenris + */ + function json_encode(obj) { + return JSON.stringify(obj); + } + /** + * @desc the maximum of a regular UNIX-timestamp: 2^31-1; one second is cut + * @author fenris + */ + const _modulus = 0x7FFFFFFF; + /** + * @desc add (e1,s1) (e2,s2) = (e1+e2+((s1+s2) div m),(s1+s2) mod m) + * @author fenris + */ + function add(et1, et2) { + let era = (et1.era + et2.era + div(et1.stamp + et2.stamp, _modulus)); + let stamp = mod(et1.stamp + et2.stamp, _modulus); + return { "era": era, "stamp": stamp }; + } + /** + * @desc neutral = (0,0) + */ + function neutral() { + return { "era": 0, "stamp": 0 }; + } + /** + * @desc invert (e,s) = (-1-e,m-s) + */ + function invert(et) { + let era = (-1 - et.era); + let stamp = (_modulus - et.stamp); + return { "era": era, "stamp": stamp }; + } + /** + * @author fenris + */ + function part(et1, et2) { + return add(et1, invert(et2)); + } + lib_et.part = part; + /** + * @desc less + * @author fenris + */ + function before(reference, et) { + let et_ = part(et, reference); + return ((et_.era >= 0) && (et_.stamp > 0)); + } + lib_et.before = before; + /** + * @desc greater + * @author fenris + */ + function after(reference, et) { + let et_ = part(reference, et); + return ((et_.era >= 0) && (et_.stamp > 0)); + } + lib_et.after = after; + /** + * @author fenris + */ + function between(begin, end, et) { + return (before(begin, et) + && + after(end, et)); + } + lib_et.between = between; + /** + * @author fenris + */ + function intersect(begin1, end1, begin2, end2) { + return ((between(begin1, end1, begin2) + || + between(begin1, end1, end2)) + || + (between(begin2, end2, begin1) + || + between(begin2, end2, end1))); + } + lib_et.intersect = intersect; + /** + * @author fenris + */ + function move(base, span) { + return add(base, span); + } + lib_et.move = move; + /** + * @desc currified version of "move" + * @author fenris + */ + function move_(span) { + return (base => move(base, span)); + } + lib_et.move_ = move_; + /** + * @author fenris + */ + function from_timestamp(timestamp) { + let era = div(timestamp, _modulus); + let stamp = mod(timestamp, _modulus); + let et = { "era": era, "stamp": stamp }; + return et; + } + lib_et.from_timestamp = from_timestamp; + /** + * @author fenris + */ + function to_timestamp(et) { + if (et.era != 0) { + const message = "case (era <> 0) not properly implemented"; + console.warn(message + "; well ... i'll do my very best ..."); + // throw (new Error(message)); + } + let timestamp = ((et.era * _modulus) + et.stamp); + return timestamp; + } + lib_et.to_timestamp = to_timestamp; + /** + * @author fenris + */ + function from_jsdate(jsdate) { + const timestamp = Math.floor(jsdate.getTime() / 1000); + const et = from_timestamp(timestamp); + return et; + } + lib_et.from_jsdate = from_jsdate; + /** + * @author fenris + */ + function to_jsdate(et) { + const timestamp = to_timestamp(et); + const jsdate = (new Date(timestamp * 1000)); + return jsdate; + } + lib_et.to_jsdate = to_jsdate; + /** + * @author fenris + */ + function from_components(components) { + const timestamp = Math.floor(Date.UTC((components.year), (components.month - 1), (components.day), (components.hour || 0), (components.minute || 0), (components.second || 0)) + / + 1000); + const et = from_timestamp(timestamp); + return et; + } + lib_et.from_components = from_components; + /** + * @author fenris + */ + function to_components(et) { + const jsdate = to_jsdate(et); + const components = { + "year": jsdate.getUTCFullYear(), + "month": jsdate.getUTCMonth() + 1, + "day": jsdate.getUTCDate(), + "hour": jsdate.getUTCHours(), + "minute": jsdate.getUTCMinutes(), + "second": jsdate.getUTCSeconds(), + }; + return components; + } + lib_et.to_components = to_components; + /** + * @author fenris + */ + function now() { + let timestamp = Math.floor(Date.now() / 1000); + let et = from_timestamp(timestamp); + return et; + } + lib_et.now = now; + /** + * @author fenris + */ + function to_string(et) { + // return (json_encode(et) + " ~ " + json_encode(to_components(et))); + return to_jsdate(et).toUTCString(); + } + lib_et.to_string = to_string; + /** + * @author fenris + */ + function to_string_ywd(et) { + // return (json_encode(et) + " ~ " + json_encode(to_components(et))); + return to_jsdate(et).toUTCString(); + } + lib_et.to_string_ywd = to_string_ywd; + /** + * @desc retrieve week of year + * @author fenris + */ + function get_woy(et) { + let jsdate = to_jsdate(et); + let begin_of_year = new Date(jsdate.getFullYear(), 0, 1, 12, 0, 0); + let day_of_week = begin_of_year.getDay(); + let overhang = (day_of_week >= 4); + let factor = (1000 * 60 * 60 * 24); + let days = ((jsdate.getTime() - begin_of_year.getTime()) / factor); + let week = (Math.ceil((days + day_of_week) / 7) - (overhang ? 1 : 0)); + return week; + } + lib_et.get_woy = get_woy; + /** + * @desc retrieve day of week + * @author fenris + */ + function get_dow(et) { + let jsdate = to_jsdate(et); + let dow = (mod(jsdate.getDay() - 1, 7) + 1); + return dow; + } + lib_et.get_dow = get_dow; + /** + * @author fenris + */ + function trunc_minute(et = now()) { + let components = to_components(et); + let components_ = { + "year": components.year, + "month": components.month, + "day": components.day, + "hour": components.hour, + "minute": components.minute, + "second": 0 + }; + let et_ = from_components(components_); + return et_; + } + lib_et.trunc_minute = trunc_minute; + /** + * @author fenris + */ + function trunc_hour(et = now()) { + let components = to_components(et); + let components_ = { + "year": components.year, + "month": components.month, + "day": components.day, + "hour": components.hour, + "minute": 0, + "second": 0 + }; + let et_ = from_components(components_); + return et_; + } + lib_et.trunc_hour = trunc_hour; + /** + * @author fenris + */ + function trunc_day(et = now()) { + let components = to_components(et); + let components_ = { + "year": components.year, + "month": components.month, + "day": components.day, + "hour": 0, + "minute": 0, + "second": 0 + }; + let et_ = from_components(components_); + return et_; + } + lib_et.trunc_day = trunc_day; + /** + * @author fenris + */ + function trunc_month(et = now()) { + let components = to_components(et); + let components_ = { + "year": components.year, + "month": components.month, + "day": 0, + "hour": 0, + "minute": 0, + "second": 0 + }; + let et_ = from_components(components_); + return et_; + } + lib_et.trunc_month = trunc_month; + /** + * @author fenris + */ + function trunc_year(et = now()) { + let components = to_components(et); + let components_ = { + "year": components.year, + "month": 0, + "day": 0, + "hour": 0, + "minute": 0, + "second": 0 + }; + let et_ = from_components(components_); + return et_; + } + lib_et.trunc_year = trunc_year; + /** + * @author fenris + */ + function trunc_week(et = now()) { + let et_ = trunc_day(et); + while (to_jsdate(et_).getDay() > 1) { + et_ = add(et_, span_day(-1)); + } + return et_; + } + lib_et.trunc_week = trunc_week; + /** + * @author fenris + */ + function span_second(seconds = 1) { + return from_timestamp(seconds); + } + lib_et.span_second = span_second; + /** + * @author fenris + */ + function span_minute(minutes = 1) { + return span_second(minutes * 60); + } + lib_et.span_minute = span_minute; + /** + * @author fenris + */ + function span_hour(hours = 1) { + return span_minute(hours * 60); + } + lib_et.span_hour = span_hour; + /** + * @author fenris + */ + function span_day(days = 1) { + return span_hour(days * 24); + } + lib_et.span_day = span_day; + /** + * @author fenris + */ + function span_week(weeks = 1) { + return span_day(weeks * 7); + } + lib_et.span_week = span_week; + /** + * @author fenris + */ + function span_year(years = 1) { + return span_second(Math.floor(years * 365.25 * 24 * 60 * 60)); + } + lib_et.span_year = span_year; +})(lib_et || (lib_et = {})); +/* +This file is part of »bacterio-plankton:date«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:date« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:date« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:date«. If not, see . + */ +var lib_et; +(function (lib_et) { + /** + * @author fenris + */ + class class_et { + /** + * @author fenris + */ + constructor(subject) { + this.subject = subject; + } + /** + * @author fenris + */ + move(et) { + return (new class_et(lib_et.move(this.subject, et.subject))); + } + /** + * @author fenris + */ + before(et) { + return lib_et.before(et.subject, this.subject); + } + /** + * @author fenris + */ + after(et) { + return lib_et.after(et.subject, this.subject); + } + /** + * @author fenris + */ + between(et1, et2) { + return lib_et.between(et1.subject, et2.subject, this.subject); + } + /** + * @author fenris + */ + trunc_minute() { + return (new class_et(lib_et.trunc_minute(this.subject))); + } + /** + * @author fenris + */ + trunc_hour() { + return (new class_et(lib_et.trunc_hour(this.subject))); + } + /** + * @author fenris + */ + trunc_day() { + return (new class_et(lib_et.trunc_day(this.subject))); + } + /** + * @author fenris + */ + trunc_month() { + return (new class_et(lib_et.trunc_month(this.subject))); + } + /** + * @author fenris + */ + trunc_year() { + return (new class_et(lib_et.trunc_year(this.subject))); + } + /** + * @author fenris + */ + trunc_week() { + return (new class_et(lib_et.trunc_week(this.subject))); + } + /** + * @author fenris + */ + static now() { + return (new class_et(lib_et.now())); + } + /** + * @author fenris + */ + static span_second(count = 1) { + return (new class_et(lib_et.span_second(count))); + } + /** + * @author fenris + */ + static span_minute(count = 1) { + return (new class_et(lib_et.span_minute(count))); + } + /** + * @author fenris + */ + static span_hour(count = 1) { + return (new class_et(lib_et.span_hour(count))); + } + /** + * @author fenris + */ + static span_day(count = 1) { + return (new class_et(lib_et.span_day(count))); + } + /** + * @author fenris + */ + static span_week(count = 1) { + return (new class_et(lib_et.span_week(count))); + } + /** + * @author fenris + */ + static span_year(count = 1) { + return (new class_et(lib_et.span_year(count))); + } + /** + * @author fenris + */ + static from_timestamp(timestamp) { + return (new class_et(lib_et.from_timestamp(timestamp))); + } + /** + * @author fenris + */ + to_timestamp() { + return lib_et.to_timestamp(this.subject); + } + /** + * @author fenris + */ + static from_jsdate(jsdate) { + return (new class_et(lib_et.from_jsdate(jsdate))); + } + /** + * @author fenris + */ + to_jsdate() { + return lib_et.to_jsdate(this.subject); + } + /** + * @author fenris + */ + static from_components(components) { + return (new class_et(lib_et.from_components(components))); + } + /** + * @author fenris + */ + to_components() { + return lib_et.to_components(this.subject); + } + /** + * @author fenris + */ + get_woy() { + return lib_et.get_woy(this.subject); + } + /** + * @author fenris + */ + get_dow() { + return lib_et.get_dow(this.subject); + } + /** + * @author fenris + */ + to_string() { + return lib_et.to_string(this.subject); + } + } + lib_et.class_et = class_et; +})(lib_et || (lib_et = {})); +/* +This file is part of »bacterio-plankton:date«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:date« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:date« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:date«. If not, see . + */ +/** + * @author neuc + */ +var lib_plankton; +(function (lib_plankton) { + var date; + (function (date_1) { + /** + * @author neu3no, fenris + */ + var _days = [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" + ]; + /** + * @author neu3no, fenris + */ + var _months = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December" + ]; + /** + * @author neu3no, fenris + */ + var _segments = { + "%a": (date => _days[date.getDay()].slice(0, 3)), + "%A": (date => _days[date.getDay()]), + "%b": (date => _days[date.getMonth()].slice(0, 3)), + "%B": (date => _days[date.getMonth()]), + "%c": (date => date.toLocaleString()), + "%C": (date => Math.floor((date.getFullYear()) / 100).toString()), + "%d": (date => lib_plankton.string.sprintf("%02d", [date.getDate()])), + "%D": (date => parse("%m/%d/%y", date)), + "%e": (date => lib_plankton.string.sprintf("%2d", [date.getDate()])), + "%F": (date => parse("%Y-%m-%d", date)), + "%g": (date => lib_plankton.string.sprintf("%02d", [date.getFullYear() % 1000])), + "%G": (date => date.getFullYear().toString()), + "%h": (date => parse("%b", date)), + "%H": (date => lib_plankton.string.sprintf("%02d", [date.getHours()])), + "%I": (date => lib_plankton.string.sprintf("%02d", [((date.getHours() > 12) ? (date.getHours() - 12) : date.getHours())])), + "%j": (date => lib_plankton.string.sprintf("%03d", [helper_dayOfYear(date)])), + "%m": (date => lib_plankton.string.sprintf("%02d", [date.getMonth() + 1])), + "%M": (date => lib_plankton.string.sprintf("%02d", [date.getMinutes()])), + "%n": (date => "\n"), + "%p": (date => ((date.getHours() > 12) ? "PM" : "AM")), + "%r": (date => parse("%I:%M:%S %p", date)), + "%R": (date => parse("%H:%M", date)), + "%S": (date => date.getSeconds().toString()), + "%t": (date => "\t"), + "%T": (date => parse("%H:%M:%S", date)), + "%u": (date => lib_plankton.string.sprintf("%02d", [((date.getDay() === 0) ? 7 : date.getDay())])), + "%U": (date => lib_plankton.string.sprintf("%02d", [helper_englishWeekOfYear(date)])), + "%V": (date => lib_plankton.string.sprintf("%02d", [helper_weekOfYear(date)])), + "%w": (date => lib_plankton.string.sprintf("%02d", [date.getDay().toString()])), + "%W": (date => parse("%w", date)), + "%x": (date => parse("%m/%d/%G", date)), + "%X": (date => parse("%T", date)), + "%y": (date => parse("%g", date)), + "%Y": (date => parse("%G", date)), + "%z": (date => date.getTimezoneOffset().toString()), + "%Z": (date => date.toUTCString().split(' ').pop()), + "%%": (date => "%"), + }; + /** + * @author neu3no, fenris + */ + var _currentDate = (new Date(Date.now())); + /** + * @author neu3no, fenris + */ + function set_days(day_names) { + _days = day_names; + } + date_1.set_days = set_days; + /** + * @author neu3no, fenris + */ + function set_months(month_names) { + _months = month_names; + } + date_1.set_months = set_months; + /** + * @desc source: https://stackoverflow.com/questions/8619879/javascript-calculate-the-day-of-the-year-1-366 + * @author neu3no, fenris + */ + function helper_dayOfYear(date) { + let start = new Date(date.getFullYear(), 0, 0); + let diff = (date.getTime() - start.getTime()); + let oneDay = (1000 * 60 * 60 * 24); + return Math.floor(diff / oneDay); + } + /** + * @desc source: http://weeknumber.net/how-to/javascript + * @author neu3no, fenris + */ + function helper_weekOfYear(date_) { + let date = new Date(date_.getTime()); + date.setHours(0, 0, 0, 0); + // Thursday in current week decides the year. + date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); + // January 4 is always in week 1. + let week1 = new Date(date.getFullYear(), 0, 4); + // Adjust to Thursday in week 1 and count number of weeks from date to week1. + return (1 + + + Math.round((((date.getTime() - week1.getTime()) / 86400000) + - + 3 + + + (week1.getDay() + 6) % 7) + / + 7)); + } + /** + * @author neu3no, fenris + */ + function helper_englishWeekOfYear(date) { + let nr = helper_weekOfYear(date); + if (date.getDay() === 0) { + nr = nr - 1; + } + return nr; + } + /** + * @desc week of year + * @param {Date} date + * @return {int} + * @author fenris + */ + function get_week(date) { + let begin_of_year = new Date(date.getFullYear(), 0, 1, 12, 0, 0); + let day_of_week = begin_of_year.getDay(); + let overhang = (day_of_week >= 4); + let factor = (1000 * 60 * 60 * 24); + let days = ((date.getTime() - begin_of_year.getTime()) / factor); + let week = (Math.ceil((days + day_of_week) / 7) - (overhang ? 1 : 0)); + return week; + } + date_1.get_week = get_week; + /** + * @author neu3no, fenris + */ + function set_currentDate(date) { + _currentDate = date; + } + date_1.set_currentDate = set_currentDate; + /** + * @author neu3no, fenris + */ + function parse(format, date = _currentDate) { + let ret = format; + let re = new RegExp("%[a-z]", "gi"); + let match; + while (match = re.exec(format)) { + ret = ret.replace(match[0], parse_segment(match[0], date)); + } + return ret; + } + date_1.parse = parse; + /** + * @author neu3no, fenris + */ + function parse_segment(segment, date = _currentDate) { + if (!(segment in _segments)) { + let message = ("unknown format argument '" + segment + "'"); + throw (new Error(message)); + } + else { + return _segments[segment](date); + } + } + /** + * @author neu3no, fenris + */ + function locale_date(date = new Date(), ignore_error = false) { + if (!(date instanceof Date)) { + if (!ignore_error) { + throw new SyntaxError("date must be instance of Date"); + } + else { + console.warn("'" + date + "' seems not to be instance of Date; try to force convert."); + let tmp = date; + date = new Date(tmp); + if ((date.toString() === "Invalid Date") + || + (!(date < new Date(0)) && !(date > new Date(0)))) { + console.warn("conversion didn't work, returning default value"); + return "Ø"; + } + } + } + let conf = ( + /* + global_config.get_value("date") + || + */ + { + "use_locale_date": true, + "format_string": "%d.%m.%Y" + }); + if (conf.use_locale_date) { + return date.toLocaleDateString(); + } + else { + return strftime.parse(conf.format_string, date); + } + } + date_1.locale_date = locale_date; + /** + */ + function now() { + return Math.floor(Date.now() / 1000); + } + date_1.now = now; + /** + */ + function from_components(components) { + return Math.floor(new Date(Date.parse(lib_string.coin("{{year}}-{{month}}-{{day}}T{{hour}}:{{minute}}:{{second}}.{{milliseconds}}{{timezone_offset}}", { + "year": components.year.toFixed(0).padStart(4, "0"), + "month": components.month.toFixed(0).padStart(2, "0"), + "day": components.day.toFixed(0).padStart(2, "0"), + "hour": components.hour.toFixed(0).padStart(2, "0"), + "minute": components.minute.toFixed(0).padStart(2, "0"), + "second": components.second.toFixed(0).padStart(2, "0"), + "milliseconds": (0).toFixed(0).padStart(3, "0"), + "timezone_offset": lib_string.coin("{{sign}}{{amount}}:00", { + "sign": ((components.timezone_offset < 0) ? "-" : "+"), + "amount": Math.abs(components.timezone_offset).toFixed(0).padStart(2, "0"), + }), + }))).getTime() + / + 1000); + } + date_1.from_components = from_components; + /** + */ + function to_components(unixtimestamp) { + const date_object = new Date(unixtimestamp * 1000); + const date_string = date_object.toISOString(); + return { + "timezone_offset": 0, + "year": parseInt(date_string.slice(0, 4)), + "month": parseInt(date_string.slice(5, 7)), + "day": parseInt(date_string.slice(8, 10)), + "hour": parseInt(date_string.slice(11, 13)), + "minute": parseInt(date_string.slice(14, 16)), + "second": parseInt(date_string.slice(17, 19)), + }; + } + date_1.to_components = to_components; + /** + */ + function get_timestamp_from_year_and_week_and_day(year, week, day) { + const d = (1 + ((week - 1) * 7)); + const date_raw = new Date(year, 0, d); + return (Math.round(date_raw.getTime() / 1000) + + + (60 * 60 * 24 * (day - date_raw.getDay() + 1))); + } + date_1.get_timestamp_from_year_and_week_and_day = get_timestamp_from_year_and_week_and_day; + })(date = lib_plankton.date || (lib_plankton.date = {})); +})(lib_plankton || (lib_plankton = {})); +var strftime = lib_plankton.date; +/* +This file is part of »bacterio-plankton:ical«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:ical« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:ical« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:ical«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var ical; + (function (ical) { + /** + */ + // type type_timestamp = string; + /** + */ + let enum_class; + (function (enum_class) { + enum_class["public"] = "public"; + enum_class["private"] = "private"; + enum_class["confidential"] = "confidential"; + })(enum_class = ical.enum_class || (ical.enum_class = {})); + ; + /** + */ + let enum_event_status; + (function (enum_event_status) { + enum_event_status["tentative"] = "tentative"; + enum_event_status["confirmed"] = "confirmed"; + enum_event_status["cancelled"] = "cancelled"; + })(enum_event_status = ical.enum_event_status || (ical.enum_event_status = {})); + ; + /** + */ + let enum_transp; + (function (enum_transp) { + enum_transp["opaque"] = "opaque"; + enum_transp["transparent"] = "transparent"; + })(enum_transp = ical.enum_transp || (ical.enum_transp = {})); + ; + })(ical = lib_plankton.ical || (lib_plankton.ical = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:ical«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:ical« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:ical« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:ical«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var ical; + (function (ical) { + /** + */ + function date_decode(date_encoded) { + return { + "year": parseInt(date_encoded.slice(0, 4)), + "month": parseInt(date_encoded.slice(4, 6)), + "day": parseInt(date_encoded.slice(6, 8)), + }; + } + /** + */ + function time_decode(time_encoded) { + return { + "hour": parseInt(time_encoded.slice(0, 2)), + "minute": parseInt(time_encoded.slice(2, 4)), + "second": parseInt(time_encoded.slice(4, 6)), + "utc": ((time_encoded.length >= 7) && (time_encoded[6] === "Z")) + }; + } + /** + */ + function datetime_decode(datetime_encoded) { + const parts = datetime_encoded.split("T", 2); + return { + "date": date_decode(parts[0]), + "time": ((parts.length >= 2) ? time_decode(parts[1]) : null), + }; + } + /** + */ + let enum_decode_state_label; + (function (enum_decode_state_label) { + enum_decode_state_label["expect_vcalendar_begin"] = "expect_vcalendar_begin"; + enum_decode_state_label["expect_vcalendar_property"] = "expect_vcalendar_property"; + enum_decode_state_label["expect_vevent_property"] = "expect_vevent_property"; + enum_decode_state_label["done"] = "done"; + })(enum_decode_state_label || (enum_decode_state_label = {})); + ; + /** + */ + function class_encode(class_) { + switch (class_) { + case ical.enum_class.private: { + return "PRIVATE"; + break; + } + case ical.enum_class.public: { + return "PUBLIC"; + break; + } + case ical.enum_class.confidential: { + return "CONFIDENTIAL"; + break; + } + } + } + /** + */ + function class_decode(class_encoded) { + return { + "PRIVATE": ical.enum_class.private, + "PUBLIC": ical.enum_class.public, + "CONFIDENTIAL": ical.enum_class.confidential, + }[class_encoded]; + } + /** + */ + function event_status_encode(event_status) { + switch (event_status) { + case ical.enum_event_status.tentative: { + return "TENTATIVE"; + break; + } + case ical.enum_event_status.confirmed: { + return "CONFIRMED"; + break; + } + case ical.enum_event_status.cancelled: { + return "CANCELLED"; + break; + } + } + } + /** + */ + function event_status_decode(event_status_encoded) { + return { + "TENTATIVE": ical.enum_event_status.tentative, + "CONFIRMED": ical.enum_event_status.confirmed, + "CANCELLED": ical.enum_event_status.cancelled, + }[event_status_encoded]; + } + /** + */ + function transp_encode(transp) { + switch (transp) { + case ical.enum_transp.opaque: { + return "OPAQUE"; + break; + } + case ical.enum_transp.transparent: { + return "TRANSPARENT"; + break; + } + } + } + /** + */ + function transp_decode(transp_encoded) { + return { + "OPAQUE": ical.enum_transp.opaque, + "TRANSPARENT": ical.enum_transp.transparent, + }[transp_encoded]; + } + /** + */ + function datetime_to_unixtimestamp(datetime) { + if ((datetime.time !== null) && (!datetime.time.utc)) { + throw (new Error("can not convert not utc time values")); + } + else { + return lib_plankton.date.from_components({ + "timezone_offset": 0, + "year": datetime.date.year, + "month": datetime.date.month, + "day": datetime.date.day, + "hour": ((datetime.time === null) ? 0 : datetime.time.hour), + "minute": ((datetime.time === null) ? 0 : datetime.time.minute), + "second": ((datetime.time === null) ? 0 : datetime.time.second), + }); + } + } + ical.datetime_to_unixtimestamp = datetime_to_unixtimestamp; + /** + * @see https://www.rfc-editor.org/rfc/rfc5545 + * @see https://icalendar.org/iCalendar-RFC-5545/ + * @todo implement edge cases + */ + function ics_decode(ics, options = {}) { + options = Object.assign({ + "debug": false, + }, options); + // preprocessing + const lines = ics.split("\r\n"); + let content_lines = []; + let content_line_buffer = null; + lines.forEach(line => { + if (line.trim() === "") { + // do nothing + } + else { + const is_folding = ((line.length >= 2) + && + ((line[0] === " ") + || + (line[0] === "\t")) + /* + && + ! ( + (line[1] === " ") + || + (line[1] === "\t") + ) + */ + ); + if (is_folding) { + content_line_buffer += line.slice(1); + } + else { + if (content_line_buffer === null) { + // do nothing + } + else { + content_lines.push(content_line_buffer); + } + content_line_buffer = line; + } + } + }); + const instructions = content_lines.map((content_line) => { + const parts = content_line.split(":"); + const parts_left = parts[0].split(";"); + return { + "command": parts_left[0], + "parameters": Object.fromEntries(parts_left.slice(1).map(x => x.split("=", 2))), + "value": (parts.slice(1).join(":") + .split(";") + .map(x => x.replace(new RegExp("\\\\,", "g"), ","))), + }; + }); + // core + let state = { + "label": enum_decode_state_label.expect_vcalendar_begin, + "vcalendar": null, + "vevent": null, + }; + instructions.forEach((instruction) => { + if (options.debug) { + console.info(JSON.stringify({ "instruction": instruction, "state": state }, undefined, "\t")); + } + switch (state.label) { + default: { + throw (new Error("unhandled state label: " + state.label)); + break; + } + case enum_decode_state_label.expect_vcalendar_begin: { + switch (instruction.command) { + default: { + throw (new Error("unexpected instruction key: " + instruction.command)); + break; + } + case "BEGIN": { + switch (instruction.value[0]) { + default: { + throw (new Error("unexpected instruction value: " + instruction.value[0])); + break; + } + case "VCALENDAR": { + state = { + "label": enum_decode_state_label.expect_vcalendar_property, + "vcalendar": { + "version": "", + "prodid": "", + "vevents": [], + }, + "vevent": null, + }; + break; + } + } + break; + } + } + break; + } + case enum_decode_state_label.expect_vcalendar_property: { + switch (instruction.command) { + case "VERSION": { + state = { + "label": enum_decode_state_label.expect_vcalendar_property, + "vcalendar": Object.assign(state.vcalendar, Object.fromEntries([["version", instruction.value[0]]])), + "vevent": state.vevent, + }; + break; + } + case "PRODID": { + state = { + "label": enum_decode_state_label.expect_vcalendar_property, + "vcalendar": Object.assign(state.vcalendar, Object.fromEntries([["prodid", instruction.value[0]]])), + "vevent": state.vevent, + }; + break; + } + case "METHOD": { + state = { + "label": enum_decode_state_label.expect_vcalendar_property, + "vcalendar": Object.assign(state.vcalendar, Object.fromEntries([["method", instruction.value[0]]])), + "vevent": state.vevent, + }; + break; + } + case "BEGIN": { + const object = instruction.value[0]; + switch (object) { + default: { + throw (new Error("unhandled object: " + object)); + break; + } + case "VCALENDAR": { + throw (new Error("unexpected object: " + object)); + break; + } + case "VEVENT": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": { + "uid": "", + "dtstamp": { + "date": { "year": 2000, "month": 0, "day": 0 }, + "time": { "hour": 0, "minute": 0, "second": 0, "utc": true }, + }, + }, + }; + break; + } + } + break; + } + case "END": { + const object = instruction.value[0]; + switch (object) { + default: { + throw (new Error("unhandled object: " + object)); + break; + } + case "VCALENDAR": { + state = { + "label": enum_decode_state_label.done, + "vcalendar": state.vcalendar, + "vevent": state.vevent, + }; + break; + } + } + break; + } + default: { + if (instruction.command.startsWith("X-")) { + const key = instruction.command.slice(2).toLowerCase(); + const value = instruction.value.join(";"); + state = { + "label": enum_decode_state_label.expect_vcalendar_property, + "vcalendar": Object.assign(state.vcalendar, { + "x_props": Object.assign((state.vcalendar.x_props ?? {}), Object.fromEntries([[key, value]])) + }), + "vevent": state.vevent, + }; + } + else { + console.info({ "instruction": instruction, "state": state }); + throw (new Error("unhandled instruction key: " + instruction.command)); + } + break; + } + } + break; + } + case enum_decode_state_label.expect_vevent_property: { + switch (instruction.command) { + case "UID": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([["uid", instruction.value[0]]])), + }; + break; + } + case "DTSTART": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([ + [ + "dtstart", + { + "tzid": instruction.parameters["tzid"], + "value": datetime_decode(instruction.value[0]), + } + ] + ])), + }; + break; + } + case "DTEND": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([ + [ + "dtend", + { + "tzid": instruction.parameters["tzid"], + "value": datetime_decode(instruction.value[0]), + } + ] + ])), + }; + break; + } + case "DTSTAMP": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([ + [ + "dtstamp", + datetime_decode(instruction.value[0]) + ] + ])), + }; + break; + } + case "SEQUENCE": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([["sequence", parseInt(instruction.value[0])]])), + }; + break; + } + case "TRANSP": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([["transp", transp_decode(instruction.value[0])]])), + }; + break; + } + case "SUMMARY": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([["summary", instruction.value[0]]])), + }; + break; + } + case "CLASS": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([["class", class_decode(instruction.value[0])]])), + }; + break; + } + case "STATUS": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([["status", event_status_decode(instruction.value[0])]])), + }; + break; + } + case "DESCRIPTION": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([["description", instruction.value[0]]])), + }; + break; + } + case "CATEGORIES": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([["categories", instruction.value[0].split(",")]])), + }; + break; + } + case "CREATED": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([ + [ + "created", + { + "value": datetime_decode(instruction.value[0]), + } + ] + ])), + }; + break; + } + case "LOCATION": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([["location", instruction.value[0]]])), + }; + break; + } + case "URL": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([["url", instruction.value[0]]])), + }; + break; + } + case "LAST-MODIFIED": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([ + [ + "last_modified", + { + "value": datetime_decode(instruction.value[0]), + } + ] + ])), + }; + break; + } + case "ATTENDEE": { + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, Object.fromEntries([["attendee", instruction.value[0]]])), + }; + break; + } + case "BEGIN": { + const object = instruction.value[0]; + switch (object) { + default: { + throw (new Error("unhandled object: " + object)); + break; + } + case "VCALENDAR": { + throw (new Error("unexpected object: " + object)); + break; + } + case "VEVENT": { + throw (new Error("unexpected object: " + object)); + break; + } + } + break; + } + case "END": { + const object = instruction.value[0]; + switch (object) { + default: { + throw (new Error("unhandled value: " + object)); + break; + } + case "VEVENT": { + state = { + "label": enum_decode_state_label.expect_vcalendar_property, + "vcalendar": Object.assign(state.vcalendar, { + "vevents": state.vcalendar.vevents.concat([state.vevent]), + }), + "vevent": null, + }; + break; + } + } + break; + } + default: { + if (instruction.command.startsWith("X-")) { + const key = instruction.command.slice(2).toLowerCase(); + const value = instruction.value.join(";"); + state = { + "label": enum_decode_state_label.expect_vevent_property, + "vcalendar": state.vcalendar, + "vevent": Object.assign(state.vevent, { + "x_props": Object.assign((state.vevent.x_props ?? {}), Object.fromEntries([[key, value]])) + }), + }; + } + else { + console.info({ "instruction": instruction, "state": state }); + throw (new Error("unhandled instruction key: " + instruction.command)); + } + break; + } + } + break; + } + case enum_decode_state_label.done: { + console.info({ "instruction": instruction, "state": state }); + throw (new Error("end expected")); + break; + } + } + }); + return state.vcalendar; + } + ical.ics_decode = ics_decode; + /** + * @see https://www.rfc-editor.org/rfc/rfc5545 + * @see https://icalendar.org/iCalendar-RFC-5545/ + */ + function date_encode(date) { + return lib_plankton.string.coin("{{year}}{{month}}{{day}}", { + "year": date.year.toFixed(0).padStart(4, "0"), + "month": date.month.toFixed(0).padStart(2, "0"), + "day": date.day.toFixed(0).padStart(2, "0"), + }); + } + /** + */ + function time_encode(time) { + return lib_plankton.string.coin("{{hour}}{{minute}}{{second}}{{utc}}", { + "hour": time.hour.toFixed(0).padStart(2, "0"), + "minute": time.minute.toFixed(0).padStart(2, "0"), + "second": time.second.toFixed(0).padStart(2, "0"), + "utc": (time.utc ? "Z" : ""), + }); + } + /** + */ + function datetime_encode(datetime) { + return lib_plankton.string.coin("{{date}}T{{time}}", { + "date": date_encode(datetime.date), + "time": time_encode(datetime.time), + }); + } + /** + * @todo method + * @todo add missing fields + */ + function ics_encode(vcalendar) { + let content_lines = []; + content_lines.push("BEGIN:VCALENDAR"); + content_lines.push(lib_plankton.string.coin("VERSION:{{version}}", { "version": vcalendar.version })); + content_lines.push(lib_plankton.string.coin("PRODID:{{prodid}}", { "prodid": vcalendar.prodid })); + content_lines.push(lib_plankton.string.coin("METHOD:{{method}}", { "method": vcalendar.method })); + vcalendar.vevents.forEach((vevent) => { + content_lines.push("BEGIN:VEVENT"); + { + // uid + content_lines.push(lib_plankton.string.coin("UID:{{uid}}", { + "uid": vevent.uid, + })); + // dtstart + content_lines.push(lib_plankton.string.coin( + // "DTSTART;TZID={{tzid}}:{{value}}", + "DTSTART:{{value}}", { + "tzid": vevent.dtstart.tzid, + "value": datetime_encode(vevent.dtstart.value), + })); + // dtend + if (vevent.dtend !== undefined) { + content_lines.push(lib_plankton.string.coin( + // "DTEND;TZID={{tzid}}:{{value}}", + "DTEND:{{value}}", { + "tzid": vevent.dtend.tzid, + "value": datetime_encode(vevent.dtend.value), + })); + } + // dtstamp + content_lines.push(lib_plankton.string.coin("DTSTAMP:{{value}}", { + "value": datetime_encode(vevent.dtstamp), + })); + // class + if (vevent.class !== undefined) { + content_lines.push(lib_plankton.string.coin("CLASS:{{class}}", { + "class": vevent.class, + })); + } + // summary + content_lines.push(lib_plankton.string.coin("SUMMARY:{{summary}}", { + "summary": vevent.summary, + })); + // description + if (vevent.description !== undefined) { + content_lines.push(lib_plankton.string.coin("DESCRIPTION:{{description}}", { + "description": vevent.description, + })); + } + // location + if (vevent.location !== undefined) { + content_lines.push(lib_plankton.string.coin("LOCATION:{{location}}", { + "location": vevent.location, + })); + } + // geo + if (vevent.geo !== undefined) { + content_lines.push(lib_plankton.string.coin("GEO:{{geo_latitude}};{{geo_longitude}}", { + "geo_latitude": vevent.geo.latitude.toFixed(4), + "geo_longitude": vevent.geo.longitude.toFixed(4), + })); + } + // url + if (vevent.url !== undefined) { + content_lines.push(lib_plankton.string.coin("URL:{{url}}", { + "url": vevent.url, + })); + } + } + content_lines.push("END:VEVENT"); + }); + content_lines.push("END:VCALENDAR"); + let lines = []; + content_lines.forEach((content_line) => { + const slices = lib_plankton.string.slice(content_line, 75 - 1); + lines.push(slices[0]); + slices.slice(1).forEach((slice) => { lines.push(" " + slice); }); + }); + return lines.join("\r\n"); + } + ical.ics_encode = ics_encode; + })(ical = lib_plankton.ical || (lib_plankton.ical = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:http«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:http« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:http« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:http«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var http; + (function (http) { + /** + * @author fenris + */ + let enum_method; + (function (enum_method) { + enum_method["options"] = "options"; + enum_method["head"] = "head"; + enum_method["get"] = "get"; + enum_method["delete"] = "delete"; + enum_method["post"] = "post"; + enum_method["put"] = "put"; + enum_method["patch"] = "patch"; + })(enum_method = http.enum_method || (http.enum_method = {})); + })(http = lib_plankton.http || (lib_plankton.http = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:http«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:http« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:http« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:http«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var http; + (function (http) { + /** + * @author fenris + */ + const linebreak = "\r\n"; + /** + * @todo outsource to string module + */ + function capitalize(str) { + return (str[0].toUpperCase() + str.slice(1)); + } + /** + * @todo outsource to string module + */ + function capitalize_all(str) { + return str.split("-").map(x => capitalize(x)).join("-"); + } + /** + * @author fenris + */ + function encode_method(method) { + switch (method) { + case http.enum_method.get: return "GET"; + case http.enum_method.post: return "POST"; + case http.enum_method.patch: return "PATCH"; + case http.enum_method.put: return "PUT"; + case http.enum_method.delete: return "DELETE"; + case http.enum_method.options: return "OPTIONS"; + case http.enum_method.head: return "HEAD"; + default: throw (new Error("impossible")); + } + } + http.encode_method = encode_method; + /** + * @author fenris + */ + function decode_method(method_raw) { + switch (method_raw) { + case "GET": return http.enum_method.get; + case "POST": return http.enum_method.post; + case "PATCH": return http.enum_method.patch; + case "PUT": return http.enum_method.put; + case "DELETE": return http.enum_method.delete; + case "OPTIONS": return http.enum_method.options; + case "HEAD": return http.enum_method.head; + default: throw (new Error("unhandled method: " + method_raw)); + } + } + /** + * @author fenris + */ + function get_statustext(statuscode) { + switch (statuscode) { + case 100: return "Continue"; + case 101: return "Switching Protocols"; + case 103: return "Early Hints"; + case 200: return "OK"; + case 201: return "Created"; + case 202: return "Accepted"; + case 203: return "Non-Authoritative Information"; + case 204: return "No Content"; + case 205: return "Reset Content"; + case 206: return "Partial Content"; + case 300: return "Multiple Choices"; + case 301: return "Moved Permanently"; + case 302: return "Found"; + case 303: return "See Other"; + case 304: return "Not Modified"; + case 307: return "Temporary Redirect"; + case 308: return "Permanent Redirect"; + case 400: return "Bad Request"; + case 401: return "Unauthorized"; + case 402: return "Payment Required"; + case 403: return "Forbidden"; + case 404: return "Not Found"; + case 405: return "Method Not Allowed"; + case 406: return "Not Acceptable"; + case 407: return "Proxy Authentication Required"; + case 408: return "Request Timeout"; + case 409: return "Conflict"; + case 410: return "Gone"; + case 411: return "Length Required"; + case 412: return "Precondition Failed"; + case 413: return "Payload Too Large"; + case 414: return "URI Too Long"; + case 415: return "Unsupported Media Type"; + case 416: return "Range Not Satisfiable"; + case 417: return "Expectation Failed"; + case 418: return "I'm a teapot"; + case 422: return "Unprocessable Entity"; + case 425: return "Too Early"; + case 426: return "Upgrade Required"; + case 428: return "Precondition Required"; + case 429: return "Too Many Requests"; + case 431: return "Request Header Fields Too Large"; + case 451: return "Unavailable For Legal Reasons"; + case 500: return "Internal Server Error"; + case 501: return "Not Implemented"; + case 502: return "Bad Gateway"; + case 503: return "Service Unavailable"; + case 504: return "Gateway Timeout"; + case 505: return "HTTP Version Not Supported"; + case 506: return "Variant Also Negotiates"; + case 507: return "Insufficient Storage"; + case 508: return "Loop Detected"; + case 510: return "Not Extended"; + case 511: return "Network Authentication"; + default: throw (new Error("unhandled statuscode: " + statuscode.toFixed(0))); + } + } + /** + * @author fenris + */ + function encode_request(request) { + let request_raw = ""; + request_raw += (encode_method(request.method) + + + " " + + + request.path + + + ((request.query === null) ? "" : request.query) + + + " " + + + request.version + + + linebreak); + if (request.host === null) { + // do nothing + } + else { + request_raw += ("Host: " + request.host + linebreak); + } + for (const [key, value] of Object.entries(request.headers)) { + request_raw += (capitalize_all(key) + ": " + value + linebreak); + } + request_raw += linebreak; + if (request.body === null) { + // do nothing + } + else { + request_raw += request.body.toString(); + } + return request_raw; + } + http.encode_request = encode_request; + /** + * @author fenris + */ + function decode_request(request_raw) { + const lines = request_raw.split(linebreak); + const first = lines.shift(); + const parts = first.split(" "); + const method = decode_method(parts[0]); + const path_and_query = parts[1]; + const parts_ = path_and_query.split("?"); + const path = parts_[0]; + const query = ((parts_.length <= 1) ? null : ("?" + parts_.slice(1).join("?"))); + const version = parts[2]; + let headers = {}; + while (true) { + const line = lines.shift(); + if (line === "") { + break; + } + else { + const [key, value] = line.split(": ", 2); + headers[key.toLowerCase()] = value; + } + } + const body = ([http.enum_method.post, http.enum_method.put, http.enum_method.patch].includes(method) + // @ts-ignore + ? Buffer.from(lines.join(linebreak)) + : null); + const request = { + // TODO + "scheme": "http", + "host": (headers["host"] ?? null), + "path": path, + "version": version, + "method": method, + "query": query, + "headers": headers, + "body": body, + }; + return request; + } + http.decode_request = decode_request; + /** + * @author fenris + */ + function encode_response(response) { + let response_raw = ""; + response_raw += (response.version + + + " " + + + response.status_code.toFixed(0) + + + " " + + + get_statustext(response.status_code) + + + linebreak); + for (const [key, value] of Object.entries(response.headers)) { + response_raw += (capitalize_all(key) + ": " + value + linebreak); + } + response_raw += linebreak; + response_raw += response.body; + return response_raw; + } + http.encode_response = encode_response; + /** + * @author fenris + */ + function decode_response(response_raw) { + const lines = response_raw.split(linebreak); + const first = lines.shift(); + const first_parts = first.split(" "); + const version = first_parts[0]; + const status_code = parseInt(first_parts[1]); + // first_parts.slice(2) ? probably irrelevant + let headers = {}; + while (true) { + const line = lines.shift(); + if (line === "") { + break; + } + else { + const [key, value] = line.split(": ", 2); + headers[key.toLowerCase()] = value; + } + } + // @ts-ignore + const body = Buffer.from(lines.join(linebreak)); + const response = { + // TODO + "version": version, + "status_code": status_code, + "headers": headers, + "body": body, + }; + return response; + } + http.decode_response = decode_response; + /** + * executes an HTTP request + * + * @todo define type_signal + */ + async function call(request, options = {}) { + options = Object.assign({ + "timeout": 5.0, + "follow_redirects": false, + "implementation": "fetch", + }, options); + const target = (request.scheme + + + "://" + + + request.host + + + request.path + + + ((request.query === null) + ? "" + : request.query)); + switch (options.implementation) { + default: { + return Promise.reject("invalid implementation: " + options.implementation); + break; + } + case "fetch": { + function core(signal) { + return (fetch(target, Object.assign({ + "method": ((method => { + switch (method) { + case http.enum_method.head: return "HEAD"; + case http.enum_method.options: return "OPTIONS"; + case http.enum_method.get: return "GET"; + case http.enum_method.delete: return "DELETE"; + case http.enum_method.post: return "POST"; + case http.enum_method.put: return "PUT"; + case http.enum_method.patch: return "PATCH"; + } + })(request.method)), + "headers": request.headers, + /* + "redirect": ( + options.follow_redirects + ? + "follow" + : + "manual" + ), + */ + "signal": (signal + ?? + undefined), + // "keepalive": false, + }, ((((method => { + switch (method) { + case http.enum_method.head: return false; + case http.enum_method.options: return false; + case http.enum_method.get: return false; + case http.enum_method.delete: return false; + case http.enum_method.post: return true; + case http.enum_method.put: return true; + case http.enum_method.patch: return true; + } + })(request.method)) + && + (request.body !== null)) + ? { + "body": request.body.toString(), + } + : {}))) + .catch((reason) => { + // console.info(reason); + return Promise.reject(reason); + }) + .then((response_raw) => (response_raw.text() + .then((body) => Promise.resolve({ + // TODO + "version": null, + "status_code": response_raw.status, + "headers": ((headers_raw => { + let headers = {}; + headers_raw.forEach((value, key) => { + headers[key] = value; + }); + return headers; + })(response_raw.headers)), + "body": body, + }))))); + } + function timeout(controller) { + return (new Promise((resolve, reject) => { + if (options.timeout === null) { + // do nothing (neither resolve nor reject ever) + } + else { + setTimeout(() => { + controller.abort(); + resolve(null); + }, (options.timeout * 1000)); + } + })); + } + const controller = new AbortController(); + const signal = controller.signal; + const response = await Promise.race([ + timeout(controller), + core(signal), + ]); + if (response === null) { + throw (new Error("http_request_timeout")); + } + else { + return response; + } + break; + } + case "http_module": { + // @ts-ignore + const nm_http = require("http"); + // @ts-ignore + const nm_https = require("https"); + return (new Promise((resolve, reject) => { + const req = ((request.scheme === "https") + ? nm_https + : nm_http) + .request(target, { + "method": request.method, + "headers": request.headers, + }, (res) => { + try { + let response_body = ""; + res.setEncoding("utf8"); + res.on("data", (chunk) => { + response_body += chunk; + }); + res.on("end", () => { + resolve({ + // TODO + "version": null, + "status_code": res.statusCode, + "headers": res.headers, + "body": response_body, + }); + }); + } + catch (error) { + reject(error); + } + }); + req.on("error", (error) => { + reject(error); + }); + req.write(request.body); + req.end(); + })); + break; + } + } + } + http.call = call; + })(http = lib_plankton.http || (lib_plankton.http = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:http«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:http« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:http« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:http«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var http; + (function (http) { + /** + * @author fenris + */ + class class_http_request { + /** + * @author fenris + */ + constructor() { + } + /** + * @implementation + * @author fenris + */ + encode(x) { + return http.encode_request(x); + } + /** + * @implementation + * @author fenris + */ + decode(x) { + return http.decode_request(x); + } + } + http.class_http_request = class_http_request; + /** + * @author fenris + */ + class class_http_response { + /** + * @author fenris + */ + constructor() { + } + /** + * @implementation + * @author fenris + */ + encode(x) { + return http.encode_response(x); + } + /** + * @implementation + * @author fenris + */ + decode(x) { + return http.decode_response(x); + } + } + http.class_http_response = class_http_response; + })(http = lib_plankton.http || (lib_plankton.http = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:url«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:url« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:url« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:url«. If not, see . + */ +/* +This file is part of »bacterio-plankton:url«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:url« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:url« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:url«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var url; + (function (url_1) { + /** + */ + function query_args_encode(query_args) { + return (Object.entries(query_args) + .map(([key, value]) => (key + "=" + value)) + .join("&")); + } + url_1.query_args_encode = query_args_encode; + /** + */ + function query_args_decode(query) { + return (Object.fromEntries(query.split("&") + .map((part) => { + const components = part.split("="); + const key = components[0]; + const value = components.slice(1).join("="); + return [key, value]; + }))); + } + url_1.query_args_decode = query_args_decode; + /** + * @author fenris + */ + function encode(url) { + let result = ""; + // scheme + { + if (url.scheme !== null) { + result += (url.scheme + ":"); + } + } + // host + { + if (url.host !== null) { + result += "//"; + // username + { + if (url.username !== null) { + result += url.username; + // password + { + if (url.password !== null) { + result += (":" + url.password); + } + } + result += "@"; + } + } + result += url.host; + } + } + // port + { + if (url.port !== null) { + result += (":" + url.port.toString()); + } + } + // path + { + if (url.path !== null) { + result += (url.path); + } + } + // query + { + if (url.query !== null) { + result += ("?" + encodeURI(url.query)); + } + } + // hash + { + if (url.hash !== null) { + result += ("#" + url.hash); + } + } + return result; + } + url_1.encode = encode; + /** + * @author fenris + * @todo arguments + */ + function decode(url_raw) { + const builtin_url = new URL(url_raw); + return { + "scheme": builtin_url.protocol.slice(0, -1), + "host": builtin_url.hostname, + "username": ((builtin_url.username !== "") + ? + builtin_url.username + : + null), + "password": ((builtin_url.password !== "") + ? + builtin_url.password + : + null), + "port": ((builtin_url.port !== "") + ? + parseInt(builtin_url.port) + : + null), + "path": builtin_url.pathname, + "query": builtin_url.search.slice(1), + "hash": ((builtin_url.hash !== "") + ? + builtin_url.hash.slice(1) + : + null), + }; + } + url_1.decode = decode; + /** + * @author fenris + */ + function implementation_code() { + return { + "encode": encode, + "decode": decode, + }; + } + url_1.implementation_code = implementation_code; + })(url = lib_plankton.url || (lib_plankton.url = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:url«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:url« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:url« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:url«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var url; + (function (url) { + /** + * @author fenris + */ + class class_url { + /** + * @author fenris + */ + constructor() { + } + /** + * @implementation + * @author fenris + */ + encode(x) { + return url.encode(x); + } + /** + * @implementation + * @author fenris + */ + decode(x) { + return url.decode(x); + } + } + url.class_url = class_url; + })(url = lib_plankton.url || (lib_plankton.url = {})); +})(lib_plankton || (lib_plankton = {})); diff --git a/tools/update-plankton b/tools/update-plankton index b8878f3..41270c0 100755 --- a/tools/update-plankton +++ b/tools/update-plankton @@ -13,6 +13,10 @@ modules="${modules} args" modules="${modules} string" modules="${modules} color" modules="${modules} xml" +modules="${modules} ical" +modules="${modules} http" +modules="${modules} log" +modules="${modules} url" ## exec