require("luci.uvl")
require("luci.fs")
+--local event = require "luci.sys.event"
local uci = require("luci.model.uci")
local class = luci.util.class
local instanceof = luci.util.instanceof
FORM_NODATA = 0
+FORM_PROCEED = 0
FORM_VALID = 1
FORM_INVALID = -1
FORM_CHANGED = 2
local upldir = "/lib/uci/upload/"
local cbidir = luci.util.libpath() .. "/model/cbi/"
- local func, err = loadfile(cbimap) or loadfile(cbidir..cbimap..".lua")
+
+ assert(luci.fs.stat(cbimap) or luci.fs.stat(cbidir..cbimap..".lua"),
+ "Model not found!")
+
+ local func, err = loadfile(cbimap)
+ if not func then
+ func, err = loadfile(cbidir..cbimap..".lua")
+ end
assert(func, err)
luci.i18n.loadc("cbi")
self.parsechain = {self.config}
self.template = "cbi/map"
self.apply_on_parse = nil
+ self.readinput = true
+
self.uci = uci.cursor()
self.save = true
+
+ self.changed = false
+
if not self.uci:load(self.config) then
error("Unable to read UCI data: " .. self.config)
end
end
+function Map.formvalue(self, key)
+ return self.readinput and luci.http.formvalue(key)
+end
+
+function Map.formvaluetable(self, key)
+ return self.readinput and luci.http.formvaluetable(key)
+end
+
function Map.get_scheme(self, sectiontype, option)
if not option then
return self.scheme and self.scheme.sections[sectiontype]
end
function Map.submitstate(self)
- return luci.http.formvalue("cbi.submit")
+ return self:formvalue("cbi.submit")
end
-- Chain foreign config
table.insert(self.parsechain, config)
end
+function Map.state_handler(self, state)
+ return state
+end
+
-- Use optimized UCI writing
-function Map.parse(self)
- Node.parse(self)
+function Map.parse(self, readinput, ...)
+ self.readinput = (readinput ~= false)
+ Node.parse(self, ...)
if self.save then
for i, config in ipairs(self.parsechain) do
if self:submitstate() then
if self.save then
- return self.changed and FORM_CHANGED or FORM_VALID
+ self.state = self.changed and FORM_CHANGED or FORM_VALID
else
- return FORM_INVALID
+ self.state = FORM_INVALID
end
else
- return FORM_NODATA
+ self.state = FORM_NODATA
end
+
+ return self:state_handler(self.state)
end
function Map.render(self, ...)
end
end
+--[[
+Compound - Container
+]]--
+Compound = class(Node)
+
+function Compound.__init__(self, ...)
+ Node.__init__(self)
+ self.children = {...}
+end
+
+function Compound.parse(self, ...)
+ local cstate, state = 0, 0
+
+ for k, child in ipairs(self.children) do
+ cstate = child:parse(...)
+ state = (not state or cstate < state) and cstate or state
+ end
+
+ return state
+end
+
+
+--[[
+Delegator - Node controller
+]]--
+Delegator = class(Node)
+function Delegator.__init__(self, ...)
+ Node.__init__(self, ...)
+ self.nodes = {}
+ self.template = "cbi/delegator"
+end
+
+function Delegator.state(self, name, node, transitor)
+ transitor = transitor or self.transistor_linear
+ local state = {node=node, name=name, transitor=transitor}
+
+ assert(instanceof(node, Node), "Invalid node")
+ assert(not self.nodes[name], "Duplicate entry")
+
+ self.nodes[name] = state
+ self:append(state)
+
+ return state
+end
+
+function Delegator.get(self, name)
+ return self.nodes[name]
+end
+
+function Delegator.transistor_linear(self, state, cstate)
+ if cstate > 0 then
+ for i, child in ipairs(self.children) do
+ if state == child then
+ return self.children[i+1]
+ end
+ end
+ else
+ return state
+ end
+end
+
+function Delegator.parse(self, ...)
+ local active = self:getactive()
+ assert(active, "Invalid state")
+
+ local cstate = active.node:parse()
+ self.active = active.transistor(self, active.node, cstate)
+
+ if not self.active then
+ return FORM_DONE
+ else
+ self.active:parse(false)
+ return FROM_PROCEED
+ end
+end
+
+function Delegator.render(self, ...)
+ self.active.node:render(...)
+end
+
+function Delegator.getactive(self)
+ return self:get(Map.formvalue(self, "cbi.delegated")
+ or (self.children[1] and self.children[1].name))
+end
--[[
Page - A simple node
self.data = data or {}
self.template = "cbi/simpleform"
self.dorender = true
+ self.pageaction = false
+ self.readinput = true
end
-function SimpleForm.parse(self, ...)
- if luci.http.formvalue("cbi.submit") then
+SimpleForm.formvalue = Map.formvalue
+SimpleForm.formvaluetable = Map.formvaluetable
+
+function SimpleForm.parse(self, readinput, ...)
+ self.readinput = (readinput ~= false)
+ if self:submitstate() then
Node.parse(self, 1, ...)
end
valid = valid
and (not v.tag_missing or not v.tag_missing[1])
and (not v.tag_invalid or not v.tag_invalid[1])
+ and (not v.error)
end
end
end
function SimpleForm.submitstate(self)
- return luci.http.formvalue("cbi.submit")
+ return self:formvalue("cbi.submit")
end
function SimpleForm.section(self, class, ...)
self.tag_error = {}
self.tag_invalid = {}
self.tag_deperror = {}
+ self.changed = false
self.optional = true
self.addremove = false
self.optionals[section] = {}
- local field = luci.http.formvalue("cbi.opt."..self.config.."."..section)
+ local field = self.map:formvalue("cbi.opt."..self.config.."."..section)
for k,v in ipairs(self.children) do
if v.optional and not v:cfgvalue(section) then
if field == v.option then
end
local arr = luci.util.clone(self:cfgvalue(section))
- local form = luci.http.formvaluetable("cbid."..self.config.."."..section)
+ local form = self.map:formvaluetable("cbid."..self.config.."."..section)
for k, v in pairs(form) do
arr[k] = v
end
return self.map:get(section)
end
+-- Push events
+function AbstractSection.push_events(self)
+ --luci.util.append(self.map.events, self.events)
+ self.map.changed = true
+end
+
-- Removes the section
function AbstractSection.remove(self, section)
return self.map:del(section)
local datasource = {}
datasource.config = "table"
self.data = data
+
+ datasource.formvalue = Map.formvalue
+ datasource.formvaluetable = Map.formvaluetable
+ datasource.readinput = true
function datasource.get(self, section, option)
return data[section] and data[section][option]
end
function datasource.submitstate(self)
- return luci.http.formvalue("cbi.submit")
+ return Map.formvalue(self, "cbi.submit")
end
function datasource.del(...)
self.anonymous = true
end
-function Table.parse(self)
+function Table.parse(self, readinput)
+ self.map.readinput = (readinput ~= false)
for i, k in ipairs(self:cfgsections()) do
if self.map:submitstate() then
Node.parse(self, k)
if self.addremove then
local path = self.config.."."..s
if active then -- Remove the section
- if luci.http.formvalue("cbi.rns."..path) and self:remove(s) then
+ if self.map:formvalue("cbi.rns."..path) and self:remove(s) then
+ self:push_events()
return
end
else -- Create and apply default values
- if luci.http.formvalue("cbi.cns."..path) then
+ if self.map:formvalue("cbi.cns."..path) then
self:create(s)
return
end
end
end
AbstractSection.parse_optionals(self, s)
+
+ if self.changed then
+ self:push_events()
+ end
end
end
if self.addremove then
-- Remove
local crval = REMOVE_PREFIX .. self.config
- local name = luci.http.formvaluetable(crval)
+ local name = self.map:formvaluetable(crval)
for k,v in pairs(name) do
if k:sub(-2) == ".x" then
k = k:sub(1, #k - 2)
for i, k in ipairs(self:cfgsections()) do
AbstractSection.parse_dynamic(self, k)
if self.map:submitstate() then
- Node.parse(self, k)
+ Node.parse(self, k, novld)
if not novld and not self.override_scheme and self.map.scheme then
_uvl_validate_section(self, k)
-- Create
local created
local crval = CREATE_PREFIX .. self.config .. "." .. self.sectiontype
- local name = luci.http.formvalue(crval)
+ local name = self.map:formvalue(crval)
if self.anonymous then
if name then
created = self:create()
AbstractSection.parse_optionals(self, created)
end
end
+
+ if created or self.changed then
+ self:push_events()
+ end
end
-- Verifies scope of sections
-- Return whether this object should be created
function AbstractValue.formcreated(self, section)
local key = "cbi.opt."..self.config.."."..section
- return (luci.http.formvalue(key) == self.option)
+ return (self.map:formvalue(key) == self.option)
end
-- Returns the formvalue for this object
function AbstractValue.formvalue(self, section)
- return luci.http.formvalue(self:cbid(section))
+ return self.map:formvalue(self:cbid(section))
end
function AbstractValue.additional(self, value)
self.rmempty = not value
end
-function AbstractValue.parse(self, section)
+function AbstractValue.parse(self, section, novld)
local fvalue = self:formvalue(section)
local cvalue = self:cfgvalue(section)
if fvalue and #fvalue > 0 then -- If we have a form value, write it to UCI
fvalue = self:transform(self:validate(fvalue, section))
- if not fvalue then
- self.tag_invalid[section] = true
+ if not fvalue and not novld then
+ if self.error then
+ self.error[section] = "invalid"
+ else
+ self.error = { [section] = "invalid" }
+ end
+ self.map.save = false
end
if fvalue and not (fvalue == cvalue) then
- self:write(section, fvalue)
+ if self:write(section, fvalue) then
+ -- Push events
+ self.section.changed = true
+ --luci.util.append(self.map.events, self.events)
+ end
end
else -- Unset the UCI or error
if self.rmempty or self.optional then
- self:remove(section)
- elseif self.track_missing and (not fvalue or fvalue ~= cvalue) then
- self.tag_missing[section] = true
+ if self:remove(section) then
+ -- Push events
+ self.section.changed = true
+ --luci.util.append(self.map.events, self.events)
+ end
+ elseif cvalue ~= fvalue and not novld then
+ self:write(section, fvalue or "")
+ if self.error then
+ self.error[section] = "missing"
+ else
+ self.error = { [section] = "missing" }
+ end
+ self.map.save = false
end
end
end
local valid = {}
for i, v in ipairs(value) do
if v and #v > 0
- and not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i)
- and not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i..".x") then
+ and not self.map:formvalue("cbi.rle."..section.."."..self.option.."."..i)
+ and not self.map:formvalue("cbi.rle."..section.."."..self.option.."."..i..".x") then
table.insert(valid, v)
end
end
function FileUpload.formcreated(self, section)
return AbstractValue.formcreated(self, section) or
- luci.http.formvalue("cbi.rlf."..section.."."..self.option) or
- luci.http.formvalue("cbi.rlf."..section.."."..self.option..".x")
+ self.map:formvalue("cbi.rlf."..section.."."..self.option) or
+ self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
end
function FileUpload.cfgvalue(self, section)
function FileUpload.formvalue(self, section)
local val = AbstractValue.formvalue(self, section)
if val then
- if not luci.http.formvalue("cbi.rlf."..section.."."..self.option) and
- not luci.http.formvalue("cbi.rlf."..section.."."..self.option..".x")
+ if not self.map:formvalue("cbi.rlf."..section.."."..self.option) and
+ not self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
then
return val
end
--- /dev/null
+--[[
+LuCI - Autogenerated Zoneinfo Module
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+]]--
+
+module "luci.sys.zoneinfo"
+
+TZ = {
+ { 'Africa/Abidjan', 'GMT0' },
+ { 'Africa/Accra', 'GMT0' },
+ { 'Africa/Addis Ababa', 'EAT-3' },
+ { 'Africa/Algiers', 'CET-1' },
+ { 'Africa/Asmara', 'EAT-3' },
+ { 'Africa/Bamako', 'GMT0' },
+ { 'Africa/Bangui', 'WAT-1' },
+ { 'Africa/Banjul', 'GMT0' },
+ { 'Africa/Bissau', 'GMT0' },
+ { 'Africa/Blantyre', 'CAT-2' },
+ { 'Africa/Brazzaville', 'WAT-1' },
+ { 'Africa/Bujumbura', 'CAT-2' },
+ { 'Africa/Casablanca', 'WET0' },
+ { 'Africa/Ceuta', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Africa/Conakry', 'GMT0' },
+ { 'Africa/Dakar', 'GMT0' },
+ { 'Africa/Dar es Salaam', 'EAT-3' },
+ { 'Africa/Djibouti', 'EAT-3' },
+ { 'Africa/Douala', 'WAT-1' },
+ { 'Africa/El Aaiun', 'WET0' },
+ { 'Africa/Freetown', 'GMT0' },
+ { 'Africa/Gaborone', 'CAT-2' },
+ { 'Africa/Harare', 'CAT-2' },
+ { 'Africa/Johannesburg', 'SAST-2' },
+ { 'Africa/Kampala', 'EAT-3' },
+ { 'Africa/Khartoum', 'EAT-3' },
+ { 'Africa/Kigali', 'CAT-2' },
+ { 'Africa/Kinshasa', 'WAT-1' },
+ { 'Africa/Lagos', 'WAT-1' },
+ { 'Africa/Libreville', 'WAT-1' },
+ { 'Africa/Lome', 'GMT0' },
+ { 'Africa/Luanda', 'WAT-1' },
+ { 'Africa/Lubumbashi', 'CAT-2' },
+ { 'Africa/Lusaka', 'CAT-2' },
+ { 'Africa/Malabo', 'WAT-1' },
+ { 'Africa/Maputo', 'CAT-2' },
+ { 'Africa/Maseru', 'SAST-2' },
+ { 'Africa/Mbabane', 'SAST-2' },
+ { 'Africa/Mogadishu', 'EAT-3' },
+ { 'Africa/Monrovia', 'GMT0' },
+ { 'Africa/Nairobi', 'EAT-3' },
+ { 'Africa/Ndjamena', 'WAT-1' },
+ { 'Africa/Niamey', 'WAT-1' },
+ { 'Africa/Nouakchott', 'GMT0' },
+ { 'Africa/Ouagadougou', 'GMT0' },
+ { 'Africa/Porto-Novo', 'WAT-1' },
+ { 'Africa/Sao Tome', 'GMT0' },
+ { 'Africa/Tripoli', 'EET-2' },
+ { 'Africa/Tunis', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Africa/Windhoek', 'WAT-1WAST,M9.1.0,M4.1.0' },
+ { 'America/Adak', 'HAST10HADT,M3.2.0,M11.1.0' },
+ { 'America/Anchorage', 'AKST9AKDT,M3.2.0,M11.1.0' },
+ { 'America/Anguilla', 'AST4' },
+ { 'America/Antigua', 'AST4' },
+ { 'America/Araguaina', 'BRT3' },
+ { 'America/Argentina/Buenos Aires', 'ART3ARST,M10.1.0/0,M3.3.0/0' },
+ { 'America/Argentina/Catamarca', 'ART3ARST,M10.1.0/0,M3.3.0/0' },
+ { 'America/Argentina/Cordoba', 'ART3ARST,M10.1.0/0,M3.3.0/0' },
+ { 'America/Argentina/Jujuy', 'ART3ARST,M10.1.0/0,M3.3.0/0' },
+ { 'America/Argentina/La Rioja', 'ART3ARST,M10.1.0/0,M3.3.0/0' },
+ { 'America/Argentina/Mendoza', 'ART3ARST,M10.1.0/0,M3.3.0/0' },
+ { 'America/Argentina/Rio Gallegos', 'ART3ARST,M10.1.0/0,M3.3.0/0' },
+ { 'America/Argentina/San Juan', 'ART3ARST,M10.1.0/0,M3.3.0/0' },
+ { 'America/Argentina/San Luis', 'ART3' },
+ { 'America/Argentina/Tucuman', 'ART3ARST,M10.1.0/0,M3.3.0/0' },
+ { 'America/Argentina/Ushuaia', 'ART3ARST,M10.1.0/0,M3.3.0/0' },
+ { 'America/Aruba', 'AST4' },
+ { 'America/Asuncion', 'PYT4PYST,M10.3.0/0,M3.2.0/0' },
+ { 'America/Atikokan', 'EST5' },
+ { 'America/Bahia', 'BRT3' },
+ { 'America/Barbados', 'AST4' },
+ { 'America/Belem', 'BRT3' },
+ { 'America/Belize', 'CST6' },
+ { 'America/Blanc-Sablon', 'AST4' },
+ { 'America/Boa Vista', 'AMT4' },
+ { 'America/Bogota', 'COT5' },
+ { 'America/Boise', 'MST7MDT,M3.2.0,M11.1.0' },
+ { 'America/Cambridge Bay', 'MST7MDT,M3.2.0,M11.1.0' },
+ { 'America/Campo Grande', 'AMT4AMST,M10.2.0/0,M2.3.0/0' },
+ { 'America/Cancun', 'CST6CDT,M4.1.0,M10.5.0' },
+ { 'America/Caracas', 'VET4:30' },
+ { 'America/Cayenne', 'GFT3' },
+ { 'America/Cayman', 'EST5' },
+ { 'America/Chicago', 'CST6CDT,M3.2.0,M11.1.0' },
+ { 'America/Chihuahua', 'MST7MDT,M4.1.0,M10.5.0' },
+ { 'America/Costa Rica', 'CST6' },
+ { 'America/Cuiaba', 'AMT4AMST,M10.2.0/0,M2.3.0/0' },
+ { 'America/Curacao', 'AST4' },
+ { 'America/Danmarkshavn', 'GMT0' },
+ { 'America/Dawson', 'PST8PDT,M3.2.0,M11.1.0' },
+ { 'America/Dawson Creek', 'MST7' },
+ { 'America/Denver', 'MST7MDT,M3.2.0,M11.1.0' },
+ { 'America/Detroit', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Dominica', 'AST4' },
+ { 'America/Edmonton', 'MST7MDT,M3.2.0,M11.1.0' },
+ { 'America/Eirunepe', 'AMT4' },
+ { 'America/El Salvador', 'CST6' },
+ { 'America/Fortaleza', 'BRT3' },
+ { 'America/Glace Bay', 'AST4ADT,M3.2.0,M11.1.0' },
+ { 'America/Goose Bay', 'AST4ADT,M3.2.0/0:01,M11.1.0/0:01' },
+ { 'America/Grand Turk', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Grenada', 'AST4' },
+ { 'America/Guadeloupe', 'AST4' },
+ { 'America/Guatemala', 'CST6' },
+ { 'America/Guayaquil', 'ECT5' },
+ { 'America/Guyana', 'GYT4' },
+ { 'America/Halifax', 'AST4ADT,M3.2.0,M11.1.0' },
+ { 'America/Havana', 'CST5CDT,M3.3.0/0,M10.5.0/1' },
+ { 'America/Hermosillo', 'MST7' },
+ { 'America/Indiana/Indianapolis', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Indiana/Knox', 'CST6CDT,M3.2.0,M11.1.0' },
+ { 'America/Indiana/Marengo', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Indiana/Petersburg', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Indiana/Tell City', 'CST6CDT,M3.2.0,M11.1.0' },
+ { 'America/Indiana/Vevay', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Indiana/Vincennes', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Indiana/Winamac', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Inuvik', 'MST7MDT,M3.2.0,M11.1.0' },
+ { 'America/Iqaluit', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Jamaica', 'EST5' },
+ { 'America/Juneau', 'AKST9AKDT,M3.2.0,M11.1.0' },
+ { 'America/Kentucky/Louisville', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Kentucky/Monticello', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/La Paz', 'BOT4' },
+ { 'America/Lima', 'PET5' },
+ { 'America/Los Angeles', 'PST8PDT,M3.2.0,M11.1.0' },
+ { 'America/Maceio', 'BRT3' },
+ { 'America/Managua', 'CST6' },
+ { 'America/Manaus', 'AMT4' },
+ { 'America/Marigot', 'AST4' },
+ { 'America/Martinique', 'AST4' },
+ { 'America/Mazatlan', 'MST7MDT,M4.1.0,M10.5.0' },
+ { 'America/Menominee', 'CST6CDT,M3.2.0,M11.1.0' },
+ { 'America/Merida', 'CST6CDT,M4.1.0,M10.5.0' },
+ { 'America/Mexico City', 'CST6CDT,M4.1.0,M10.5.0' },
+ { 'America/Miquelon', 'PMST3PMDT,M3.2.0,M11.1.0' },
+ { 'America/Moncton', 'AST4ADT,M3.2.0,M11.1.0' },
+ { 'America/Monterrey', 'CST6CDT,M4.1.0,M10.5.0' },
+ { 'America/Montevideo', 'UYT3UYST,M10.1.0,M3.2.0' },
+ { 'America/Montreal', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Montserrat', 'AST4' },
+ { 'America/Nassau', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/New York', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Nipigon', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Nome', 'AKST9AKDT,M3.2.0,M11.1.0' },
+ { 'America/Noronha', 'FNT2' },
+ { 'America/North Dakota/Center', 'CST6CDT,M3.2.0,M11.1.0' },
+ { 'America/North Dakota/New Salem', 'CST6CDT,M3.2.0,M11.1.0' },
+ { 'America/Panama', 'EST5' },
+ { 'America/Pangnirtung', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Paramaribo', 'SRT3' },
+ { 'America/Phoenix', 'MST7' },
+ { 'America/Port of Spain', 'AST4' },
+ { 'America/Port-au-Prince', 'EST5' },
+ { 'America/Porto Velho', 'AMT4' },
+ { 'America/Puerto Rico', 'AST4' },
+ { 'America/Rainy River', 'CST6CDT,M3.2.0,M11.1.0' },
+ { 'America/Rankin Inlet', 'CST6CDT,M3.2.0,M11.1.0' },
+ { 'America/Recife', 'BRT3' },
+ { 'America/Regina', 'CST6' },
+ { 'America/Resolute', 'EST5' },
+ { 'America/Rio Branco', 'AMT4' },
+ { 'America/Santarem', 'BRT3' },
+ { 'America/Santo Domingo', 'AST4' },
+ { 'America/Sao Paulo', 'BRT3BRST,M10.2.0/0,M2.3.0/0' },
+ { 'America/Scoresbysund', 'EGT1EGST,M3.5.0/0,M10.5.0/1' },
+ { 'America/Shiprock', 'MST7MDT,M3.2.0,M11.1.0' },
+ { 'America/St Barthelemy', 'AST4' },
+ { 'America/St Johns', 'NST3:30NDT,M3.2.0/0:01,M11.1.0/0:01' },
+ { 'America/St Kitts', 'AST4' },
+ { 'America/St Lucia', 'AST4' },
+ { 'America/St Thomas', 'AST4' },
+ { 'America/St Vincent', 'AST4' },
+ { 'America/Swift Current', 'CST6' },
+ { 'America/Tegucigalpa', 'CST6' },
+ { 'America/Thule', 'AST4ADT,M3.2.0,M11.1.0' },
+ { 'America/Thunder Bay', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Tijuana', 'PST8PDT,M4.1.0,M10.5.0' },
+ { 'America/Toronto', 'EST5EDT,M3.2.0,M11.1.0' },
+ { 'America/Tortola', 'AST4' },
+ { 'America/Vancouver', 'PST8PDT,M3.2.0,M11.1.0' },
+ { 'America/Whitehorse', 'PST8PDT,M3.2.0,M11.1.0' },
+ { 'America/Winnipeg', 'CST6CDT,M3.2.0,M11.1.0' },
+ { 'America/Yakutat', 'AKST9AKDT,M3.2.0,M11.1.0' },
+ { 'America/Yellowknife', 'MST7MDT,M3.2.0,M11.1.0' },
+ { 'Antarctica/Casey', 'WST-8' },
+ { 'Antarctica/Davis', 'DAVT-7' },
+ { 'Antarctica/DumontDUrville', 'DDUT-10' },
+ { 'Antarctica/Mawson', 'MAWT-6' },
+ { 'Antarctica/McMurdo', 'NZST-12NZDT,M9.5.0,M4.1.0/3' },
+ { 'Antarctica/Rothera', 'ROTT3' },
+ { 'Antarctica/South Pole', 'NZST-12NZDT,M9.5.0,M4.1.0/3' },
+ { 'Antarctica/Syowa', 'SYOT-3' },
+ { 'Antarctica/Vostok', 'VOST-6' },
+ { 'Arctic/Longyearbyen', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Asia/Aden', 'AST-3' },
+ { 'Asia/Almaty', 'ALMT-6' },
+ { 'Asia/Amman', 'EET-2EEST,M3.5.4/0,M10.5.5/1' },
+ { 'Asia/Anadyr', 'ANAT-12ANAST,M3.5.0,M10.5.0/3' },
+ { 'Asia/Aqtau', 'AQTT-5' },
+ { 'Asia/Aqtobe', 'AQTT-5' },
+ { 'Asia/Ashgabat', 'TMT-5' },
+ { 'Asia/Baghdad', 'AST-3' },
+ { 'Asia/Bahrain', 'AST-3' },
+ { 'Asia/Baku', 'AZT-4AZST,M3.5.0/4,M10.5.0/5' },
+ { 'Asia/Bangkok', 'ICT-7' },
+ { 'Asia/Beirut', 'EET-2EEST,M3.5.0/0,M10.5.0/0' },
+ { 'Asia/Bishkek', 'KGT-6' },
+ { 'Asia/Brunei', 'BNT-8' },
+ { 'Asia/Choibalsan', 'CHOT-8' },
+ { 'Asia/Chongqing', 'CST-8' },
+ { 'Asia/Colombo', 'IST-5:30' },
+ { 'Asia/Damascus', 'EET-2EEST,M4.1.5/0,J274/0' },
+ { 'Asia/Dhaka', 'BDT-6' },
+ { 'Asia/Dili', 'TLT-9' },
+ { 'Asia/Dubai', 'GST-4' },
+ { 'Asia/Dushanbe', 'TJT-5' },
+ { 'Asia/Gaza', 'EET-2EEST,J91/0,M9.2.4' },
+ { 'Asia/Harbin', 'CST-8' },
+ { 'Asia/Ho Chi Minh', 'ICT-7' },
+ { 'Asia/Hong Kong', 'HKT-8' },
+ { 'Asia/Hovd', 'HOVT-7' },
+ { 'Asia/Irkutsk', 'IRKT-8IRKST,M3.5.0,M10.5.0/3' },
+ { 'Asia/Jakarta', 'WIT-7' },
+ { 'Asia/Jayapura', 'EIT-9' },
+ { 'Asia/Kabul', 'AFT-4:30' },
+ { 'Asia/Kamchatka', 'PETT-12PETST,M3.5.0,M10.5.0/3' },
+ { 'Asia/Karachi', 'PKT-5' },
+ { 'Asia/Kashgar', 'CST-8' },
+ { 'Asia/Katmandu', 'NPT-5:45' },
+ { 'Asia/Kolkata', 'IST-5:30' },
+ { 'Asia/Krasnoyarsk', 'KRAT-7KRAST,M3.5.0,M10.5.0/3' },
+ { 'Asia/Kuala Lumpur', 'MYT-8' },
+ { 'Asia/Kuching', 'MYT-8' },
+ { 'Asia/Kuwait', 'AST-3' },
+ { 'Asia/Macau', 'CST-8' },
+ { 'Asia/Magadan', 'MAGT-11MAGST,M3.5.0,M10.5.0/3' },
+ { 'Asia/Makassar', 'CIT-8' },
+ { 'Asia/Manila', 'PHT-8' },
+ { 'Asia/Muscat', 'GST-4' },
+ { 'Asia/Nicosia', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Asia/Novosibirsk', 'NOVT-6NOVST,M3.5.0,M10.5.0/3' },
+ { 'Asia/Omsk', 'OMST-6OMSST,M3.5.0,M10.5.0/3' },
+ { 'Asia/Oral', 'ORAT-5' },
+ { 'Asia/Phnom Penh', 'ICT-7' },
+ { 'Asia/Pontianak', 'WIT-7' },
+ { 'Asia/Pyongyang', 'KST-9' },
+ { 'Asia/Qatar', 'AST-3' },
+ { 'Asia/Qyzylorda', 'QYZT-6' },
+ { 'Asia/Rangoon', 'MMT-6:30' },
+ { 'Asia/Riyadh', 'AST-3' },
+ { 'Asia/Sakhalin', 'SAKT-10SAKST,M3.5.0,M10.5.0/3' },
+ { 'Asia/Samarkand', 'UZT-5' },
+ { 'Asia/Seoul', 'KST-9' },
+ { 'Asia/Shanghai', 'CST-8' },
+ { 'Asia/Singapore', 'SGT-8' },
+ { 'Asia/Taipei', 'CST-8' },
+ { 'Asia/Tashkent', 'UZT-5' },
+ { 'Asia/Tbilisi', 'GET-4' },
+ { 'Asia/Thimphu', 'BTT-6' },
+ { 'Asia/Tokyo', 'JST-9' },
+ { 'Asia/Ulaanbaatar', 'ULAT-8' },
+ { 'Asia/Urumqi', 'CST-8' },
+ { 'Asia/Vientiane', 'ICT-7' },
+ { 'Asia/Vladivostok', 'VLAT-10VLAST,M3.5.0,M10.5.0/3' },
+ { 'Asia/Yakutsk', 'YAKT-9YAKST,M3.5.0,M10.5.0/3' },
+ { 'Asia/Yekaterinburg', 'YEKT-5YEKST,M3.5.0,M10.5.0/3' },
+ { 'Asia/Yerevan', 'AMT-4AMST,M3.5.0,M10.5.0/3' },
+ { 'Atlantic/Azores', 'AZOT1AZOST,M3.5.0/0,M10.5.0/1' },
+ { 'Atlantic/Bermuda', 'AST4ADT,M3.2.0,M11.1.0' },
+ { 'Atlantic/Canary', 'WET0WEST,M3.5.0/1,M10.5.0' },
+ { 'Atlantic/Cape Verde', 'CVT1' },
+ { 'Atlantic/Faroe', 'WET0WEST,M3.5.0/1,M10.5.0' },
+ { 'Atlantic/Madeira', 'WET0WEST,M3.5.0/1,M10.5.0' },
+ { 'Atlantic/Reykjavik', 'GMT0' },
+ { 'Atlantic/South Georgia', 'GST2' },
+ { 'Atlantic/St Helena', 'GMT0' },
+ { 'Atlantic/Stanley', 'FKT4FKST,M9.1.0,M4.3.0' },
+ { 'Australia/Adelaide', 'CST-9:30CST,M10.1.0,M4.1.0/3' },
+ { 'Australia/Brisbane', 'EST-10' },
+ { 'Australia/Broken Hill', 'CST-9:30CST,M10.1.0,M4.1.0/3' },
+ { 'Australia/Currie', 'EST-10EST,M10.1.0,M4.1.0/3' },
+ { 'Australia/Darwin', 'CST-9:30' },
+ { 'Australia/Eucla', 'CWST-8:45' },
+ { 'Australia/Hobart', 'EST-10EST,M10.1.0,M4.1.0/3' },
+ { 'Australia/Lindeman', 'EST-10' },
+ { 'Australia/Lord Howe', 'LHST-10:30LHST-11,M10.1.0,M4.1.0' },
+ { 'Australia/Melbourne', 'EST-10EST,M10.1.0,M4.1.0/3' },
+ { 'Australia/Perth', 'WST-8' },
+ { 'Australia/Sydney', 'EST-10EST,M10.1.0,M4.1.0/3' },
+ { 'Europe/Amsterdam', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Andorra', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Athens', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Belgrade', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Berlin', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Bratislava', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Brussels', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Bucharest', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Budapest', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Chisinau', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Copenhagen', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Dublin', 'GMT0IST,M3.5.0/1,M10.5.0' },
+ { 'Europe/Gibraltar', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Guernsey', 'GMT0BST,M3.5.0/1,M10.5.0' },
+ { 'Europe/Helsinki', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Isle of Man', 'GMT0BST,M3.5.0/1,M10.5.0' },
+ { 'Europe/Istanbul', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Jersey', 'GMT0BST,M3.5.0/1,M10.5.0' },
+ { 'Europe/Kaliningrad', 'EET-2EEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Kiev', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Lisbon', 'WET0WEST,M3.5.0/1,M10.5.0' },
+ { 'Europe/Ljubljana', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/London', 'GMT0BST,M3.5.0/1,M10.5.0' },
+ { 'Europe/Luxembourg', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Madrid', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Malta', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Mariehamn', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Minsk', 'EET-2EEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Monaco', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Moscow', 'MSK-3MSD,M3.5.0,M10.5.0/3' },
+ { 'Europe/Oslo', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Paris', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Podgorica', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Prague', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Riga', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Rome', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Samara', 'SAMT-4SAMST,M3.5.0,M10.5.0/3' },
+ { 'Europe/San Marino', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Sarajevo', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Simferopol', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Skopje', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Sofia', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Stockholm', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Tallinn', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Tirane', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Uzhgorod', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Vaduz', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Vatican', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Vienna', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Vilnius', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Volgograd', 'VOLT-3VOLST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Warsaw', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Zagreb', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Europe/Zaporozhye', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
+ { 'Europe/Zurich', 'CET-1CEST,M3.5.0,M10.5.0/3' },
+ { 'Indian/Antananarivo', 'EAT-3' },
+ { 'Indian/Chagos', 'IOT-6' },
+ { 'Indian/Christmas', 'CXT-7' },
+ { 'Indian/Cocos', 'CCT-6:30' },
+ { 'Indian/Comoro', 'EAT-3' },
+ { 'Indian/Kerguelen', 'TFT-5' },
+ { 'Indian/Mahe', 'SCT-4' },
+ { 'Indian/Maldives', 'MVT-5' },
+ { 'Indian/Mauritius', 'MUT-4' },
+ { 'Indian/Mayotte', 'EAT-3' },
+ { 'Indian/Reunion', 'RET-4' },
+ { 'Pacific/Apia', 'WST11' },
+ { 'Pacific/Auckland', 'NZST-12NZDT,M9.5.0,M4.1.0/3' },
+ { 'Pacific/Chatham', 'CHAST-12:45CHADT,M9.5.0/2:45,M4.1.0/3:45' },
+ { 'Pacific/Efate', 'VUT-11' },
+ { 'Pacific/Enderbury', 'PHOT-13' },
+ { 'Pacific/Fakaofo', 'TKT10' },
+ { 'Pacific/Fiji', 'FJT-12' },
+ { 'Pacific/Funafuti', 'TVT-12' },
+ { 'Pacific/Galapagos', 'GALT6' },
+ { 'Pacific/Gambier', 'GAMT9' },
+ { 'Pacific/Guadalcanal', 'SBT-11' },
+ { 'Pacific/Guam', 'ChST-10' },
+ { 'Pacific/Honolulu', 'HST10' },
+ { 'Pacific/Johnston', 'HST10' },
+ { 'Pacific/Kiritimati', 'LINT-14' },
+ { 'Pacific/Kosrae', 'KOST-11' },
+ { 'Pacific/Kwajalein', 'MHT-12' },
+ { 'Pacific/Majuro', 'MHT-12' },
+ { 'Pacific/Marquesas', 'MART9:30' },
+ { 'Pacific/Midway', 'SST11' },
+ { 'Pacific/Nauru', 'NRT-12' },
+ { 'Pacific/Niue', 'NUT11' },
+ { 'Pacific/Norfolk', 'NFT-11:30' },
+ { 'Pacific/Noumea', 'NCT-11' },
+ { 'Pacific/Pago Pago', 'SST11' },
+ { 'Pacific/Palau', 'PWT-9' },
+ { 'Pacific/Pitcairn', 'PST8' },
+ { 'Pacific/Ponape', 'PONT-11' },
+ { 'Pacific/Port Moresby', 'PGT-10' },
+ { 'Pacific/Rarotonga', 'CKT10' },
+ { 'Pacific/Saipan', 'ChST-10' },
+ { 'Pacific/Tahiti', 'TAHT10' },
+ { 'Pacific/Tarawa', 'GILT-12' },
+ { 'Pacific/Tongatapu', 'TOT-13' },
+ { 'Pacific/Truk', 'TRUT-10' },
+ { 'Pacific/Wake', 'WAKT-12' },
+ { 'Pacific/Wallis', 'WFT-12' },
+}