Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,353 @@
;var _createClass=(function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if('value'in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor);}}return function(Constructor,protoProps,staticProps){if(protoProps)defineProperties(Constructor.prototype,protoProps);if(staticProps)defineProperties(Constructor,staticProps);return Constructor;};})();function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError('Cannot call a class as a function');}}
(function(){'use strict';function emit(listeners,...args){const type=args.shift();if(listeners['*']){listeners['*'].slice().forEach(listener=>listener.apply(this,args));}
if(listeners[type]){listeners[type].slice().forEach(listener=>listener.apply(this,args));}}
function addEventListener(listeners,type,listener){if(!(type in listeners)){listeners[type]=[];}
listeners[type].push(listener);}
function removeEventListener(listeners,type,listener){const typeListeners=listeners[type];const pos=typeListeners.indexOf(listener);if(pos===-1){return;}
typeListeners.splice(pos,1);}
let Client=(function(){function Client(remote){_classCallCheck(this,Client);this.id=this;this.remote=remote;const listeners={};this.on=(...args)=>addEventListener(listeners,...args);this.emit=(...args)=>emit(listeners,...args);}
_createClass(Client,[{key:'method',value:function method(name,...args){return this.remote[name](...args);}}]);return Client;})();function broadcast(type,data){Array.from(this.ctxs.keys()).forEach(client=>client.emit(type,data));}
function L10nError(message,id,lang){this.name='L10nError';this.message=message;this.id=id;this.lang=lang;}
L10nError.prototype=Object.create(Error.prototype);L10nError.prototype.constructor=L10nError;function load(type,url){return new Promise(function(resolve,reject){const xhr=new XMLHttpRequest();if(xhr.overrideMimeType){xhr.overrideMimeType(type);}
xhr.open('GET',url,true);if(type==='application/json'){xhr.responseType='json';}
xhr.addEventListener('load',function io_onload(e){if(e.target.status===200||e.target.status===0){resolve(e.target.response||e.target.responseText);}else{reject(new L10nError('Not found: '+url));}});xhr.addEventListener('error',reject);xhr.addEventListener('timeout',reject);try{xhr.send(null);}catch(e){if(e.name==='NS_ERROR_FILE_NOT_FOUND'){reject(new L10nError('Not found: '+url));}else{throw e;}}});}
const io={extra:function(code,ver,path,type){return navigator.mozApps.getLocalizationResource(code,ver,path,type);},app:function(code,ver,path,type){switch(type){case'text':return load('text/plain',path);case'json':return load('application/json',path);default:throw new L10nError('Unknown file type: '+type);}}};function fetchResource(res,{code,src,ver}){const url=res.replace('{locale}',code);const type=res.endsWith('.json')?'json':'text';return io[src](code,ver,url,type);}
const KNOWN_MACROS=['plural'];const MAX_PLACEABLE_LENGTH=2500;const FSI='⁨';const PDI='⁩';const resolutionChain=new WeakSet();function format(ctx,lang,args,entity){if(typeof entity==='string'){return[{},entity];}
if(resolutionChain.has(entity)){throw new L10nError('Cyclic reference detected');}
resolutionChain.add(entity);let rv;try{rv=resolveValue({},ctx,lang,args,entity.value,entity.index);}finally{resolutionChain.delete(entity);}
return rv;}
function resolveIdentifier(ctx,lang,args,id){if(KNOWN_MACROS.indexOf(id)>-1){return[{},ctx._getMacro(lang,id)];}
if(args&&args.hasOwnProperty(id)){if(typeof args[id]==='string'||typeof args[id]==='number'&&!isNaN(args[id])){return[{},args[id]];}else{throw new L10nError('Arg must be a string or a number: '+id);}}
if(id==='__proto__'){throw new L10nError('Illegal id: '+id);}
const entity=ctx._getEntity(lang,id);if(entity){return format(ctx,lang,args,entity);}
throw new L10nError('Unknown reference: '+id);}
function subPlaceable(locals,ctx,lang,args,id){let newLocals,value;try{[newLocals,value]=resolveIdentifier(ctx,lang,args,id);}catch(err){return[{error:err},FSI+'{{ '+id+' }}'+PDI];}
if(typeof value==='number'){const formatter=ctx._getNumberFormatter(lang);return[newLocals,formatter.format(value)];}
if(typeof value==='string'){if(value.length>=MAX_PLACEABLE_LENGTH){throw new L10nError('Too many characters in placeable ('+value.length+', max allowed is '+MAX_PLACEABLE_LENGTH+')');}
return[newLocals,FSI+value+PDI];}
return[{},FSI+'{{ '+id+' }}'+PDI];}
function interpolate(locals,ctx,lang,args,arr){return arr.reduce(function([localsSeq,valueSeq],cur){if(typeof cur==='string'){return[localsSeq,valueSeq+cur];}else{const[,value]=subPlaceable(locals,ctx,lang,args,cur.name);return[localsSeq,valueSeq+value];}},[locals,'']);}
function resolveSelector(ctx,lang,args,expr,index){let selectorName;if(index[0].type==='call'&&index[0].expr.type==='prop'&&index[0].expr.expr.name==='cldr'){selectorName='plural';}else{selectorName=index[0].name;}
const selector=resolveIdentifier(ctx,lang,args,selectorName)[1];if(typeof selector!=='function'){return selector;}
const argValue=index[0].args?resolveIdentifier(ctx,lang,args,index[0].args[0].name)[1]:undefined;if(selectorName==='plural'){if(argValue===0&&'zero'in expr){return'zero';}
if(argValue===1&&'one'in expr){return'one';}
if(argValue===2&&'two'in expr){return'two';}}
return selector(argValue);}
function resolveValue(locals,ctx,lang,args,expr,index){if(!expr){return[locals,expr];}
if(typeof expr==='string'||typeof expr==='boolean'||typeof expr==='number'){return[locals,expr];}
if(Array.isArray(expr)){return interpolate(locals,ctx,lang,args,expr);}
if(index){const selector=resolveSelector(ctx,lang,args,expr,index);if(selector in expr){return resolveValue(locals,ctx,lang,args,expr[selector]);}}
const defaultKey=expr.__default||'other';if(defaultKey in expr){return resolveValue(locals,ctx,lang,args,expr[defaultKey]);}
throw new L10nError('Unresolvable value');}
const locales2rules={'af':3,'ak':4,'am':4,'ar':1,'asa':3,'az':0,'be':11,'bem':3,'bez':3,'bg':3,'bh':4,'bm':0,'bn':3,'bo':0,'br':20,'brx':3,'bs':11,'ca':3,'cgg':3,'chr':3,'cs':12,'cy':17,'da':3,'de':3,'dv':3,'dz':0,'ee':3,'el':3,'en':3,'eo':3,'es':3,'et':3,'eu':3,'fa':0,'ff':5,'fi':3,'fil':4,'fo':3,'fr':5,'fur':3,'fy':3,'ga':8,'gd':24,'gl':3,'gsw':3,'gu':3,'guw':4,'gv':23,'ha':3,'haw':3,'he':2,'hi':4,'hr':11,'hu':0,'id':0,'ig':0,'ii':0,'is':3,'it':3,'iu':7,'ja':0,'jmc':3,'jv':0,'ka':0,'kab':5,'kaj':3,'kcg':3,'kde':0,'kea':0,'kk':3,'kl':3,'km':0,'kn':0,'ko':0,'ksb':3,'ksh':21,'ku':3,'kw':7,'lag':18,'lb':3,'lg':3,'ln':4,'lo':0,'lt':10,'lv':6,'mas':3,'mg':4,'mk':16,'ml':3,'mn':3,'mo':9,'mr':3,'ms':0,'mt':15,'my':0,'nah':3,'naq':7,'nb':3,'nd':3,'ne':3,'nl':3,'nn':3,'no':3,'nr':3,'nso':4,'ny':3,'nyn':3,'om':3,'or':3,'pa':3,'pap':3,'pl':13,'ps':3,'pt':3,'rm':3,'ro':9,'rof':3,'ru':11,'rwk':3,'sah':0,'saq':3,'se':7,'seh':3,'ses':0,'sg':0,'sh':11,'shi':19,'sk':12,'sl':14,'sma':7,'smi':7,'smj':7,'smn':7,'sms':7,'sn':3,'so':3,'sq':3,'sr':11,'ss':3,'ssy':3,'st':3,'sv':3,'sw':3,'syr':3,'ta':3,'te':3,'teo':3,'th':0,'ti':4,'tig':3,'tk':3,'tl':4,'tn':3,'to':0,'tr':0,'ts':3,'tzm':22,'uk':11,'ur':3,'ve':3,'vi':0,'vun':3,'wa':4,'wae':3,'wo':0,'xh':3,'xog':3,'yo':0,'zh':0,'zu':3};function isIn(n,list){return list.indexOf(n)!==-1;}
function isBetween(n,start,end){return typeof n===typeof start&&start<=n&&n<=end;}
const pluralRules={'0':function(){return'other';},'1':function(n){if(isBetween(n%100,3,10)){return'few';}
if(n===0){return'zero';}
if(isBetween(n%100,11,99)){return'many';}
if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'2':function(n){if(n!==0&&n%10===0){return'many';}
if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'3':function(n){if(n===1){return'one';}
return'other';},'4':function(n){if(isBetween(n,0,1)){return'one';}
return'other';},'5':function(n){if(isBetween(n,0,2)&&n!==2){return'one';}
return'other';},'6':function(n){if(n===0){return'zero';}
if(n%10===1&&n%100!==11){return'one';}
return'other';},'7':function(n){if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'8':function(n){if(isBetween(n,3,6)){return'few';}
if(isBetween(n,7,10)){return'many';}
if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'9':function(n){if(n===0||n!==1&&isBetween(n%100,1,19)){return'few';}
if(n===1){return'one';}
return'other';},'10':function(n){if(isBetween(n%10,2,9)&&!isBetween(n%100,11,19)){return'few';}
if(n%10===1&&!isBetween(n%100,11,19)){return'one';}
return'other';},'11':function(n){if(isBetween(n%10,2,4)&&!isBetween(n%100,12,14)){return'few';}
if(n%10===0||isBetween(n%10,5,9)||isBetween(n%100,11,14)){return'many';}
if(n%10===1&&n%100!==11){return'one';}
return'other';},'12':function(n){if(isBetween(n,2,4)){return'few';}
if(n===1){return'one';}
return'other';},'13':function(n){if(isBetween(n%10,2,4)&&!isBetween(n%100,12,14)){return'few';}
if(n!==1&&isBetween(n%10,0,1)||isBetween(n%10,5,9)||isBetween(n%100,12,14)){return'many';}
if(n===1){return'one';}
return'other';},'14':function(n){if(isBetween(n%100,3,4)){return'few';}
if(n%100===2){return'two';}
if(n%100===1){return'one';}
return'other';},'15':function(n){if(n===0||isBetween(n%100,2,10)){return'few';}
if(isBetween(n%100,11,19)){return'many';}
if(n===1){return'one';}
return'other';},'16':function(n){if(n%10===1&&n!==11){return'one';}
return'other';},'17':function(n){if(n===3){return'few';}
if(n===0){return'zero';}
if(n===6){return'many';}
if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'18':function(n){if(n===0){return'zero';}
if(isBetween(n,0,2)&&n!==0&&n!==2){return'one';}
return'other';},'19':function(n){if(isBetween(n,2,10)){return'few';}
if(isBetween(n,0,1)){return'one';}
return'other';},'20':function(n){if((isBetween(n%10,3,4)||n%10===9)&&!(isBetween(n%100,10,19)||isBetween(n%100,70,79)||isBetween(n%100,90,99))){return'few';}
if(n%1000000===0&&n!==0){return'many';}
if(n%10===2&&!isIn(n%100,[12,72,92])){return'two';}
if(n%10===1&&!isIn(n%100,[11,71,91])){return'one';}
return'other';},'21':function(n){if(n===0){return'zero';}
if(n===1){return'one';}
return'other';},'22':function(n){if(isBetween(n,0,1)||isBetween(n,11,99)){return'one';}
return'other';},'23':function(n){if(isBetween(n%10,1,2)||n%20===0){return'one';}
return'other';},'24':function(n){if(isBetween(n,3,10)||isBetween(n,13,19)){return'few';}
if(isIn(n,[2,12])){return'two';}
if(isIn(n,[1,11])){return'one';}
return'other';}};function getPluralRule(code){const index=locales2rules[code.replace(/-.*$/,'')];if(!(index in pluralRules)){return function(){return'other';};}
return pluralRules[index];}
const L20nIntl=typeof Intl!=='undefined'?Intl:{NumberFormat:function(){return{format:function(v){return v;}};}};let Context=(function(){function Context(env,langs,resIds){_classCallCheck(this,Context);this.langs=langs;this.resIds=resIds;this.env=env;this.emit=(type,evt)=>env.emit(type,evt,this);}
_createClass(Context,[{key:'_formatTuple',value:function _formatTuple(lang,args,entity,id,key){try{return format(this,lang,args,entity);}catch(err){err.id=key?id+'::'+key:id;err.lang=lang;this.emit('resolveerror',err);return[{error:err},err.id];}}},{key:'_formatEntity',value:function _formatEntity(lang,args,entity,id){const[,value]=this._formatTuple(lang,args,entity,id);const formatted={value,attrs:null};if(entity.attrs){formatted.attrs=Object.create(null);for(let key in entity.attrs){const[,attrValue]=this._formatTuple(lang,args,entity.attrs[key],id,key);formatted.attrs[key]=attrValue;}}
return formatted;}},{key:'_formatValue',value:function _formatValue(lang,args,entity,id){return this._formatTuple(lang,args,entity,id)[1];}},{key:'fetch',value:function fetch(langs=this.langs){if(langs.length===0){return Promise.resolve(langs);}
return Promise.all(this.resIds.map(resId=>this.env._getResource(langs[0],resId))).then(()=>langs);}},{key:'_resolve',value:function _resolve(langs,keys,formatter,prevResolved){const lang=langs[0];if(!lang){return reportMissing.call(this,keys,formatter,prevResolved);}
let hasUnresolved=false;const resolved=keys.map((key,i)=>{if(prevResolved&&prevResolved[i]!==undefined){return prevResolved[i];}
const[id,args]=Array.isArray(key)?key:[key,undefined];const entity=this._getEntity(lang,id);if(entity){return formatter.call(this,lang,args,entity,id);}
this.emit('notfounderror',new L10nError('"'+id+'"'+' not found in '+lang.code,id,lang));hasUnresolved=true;});if(!hasUnresolved){return resolved;}
return this.fetch(langs.slice(1)).then(nextLangs=>this._resolve(nextLangs,keys,formatter,resolved));}},{key:'formatEntities',value:function formatEntities(...keys){return this.fetch().then(langs=>this._resolve(langs,keys,this._formatEntity));}},{key:'formatValues',value:function formatValues(...keys){return this.fetch().then(langs=>this._resolve(langs,keys,this._formatValue));}},{key:'_getEntity',value:function _getEntity(lang,id){const cache=this.env.resCache;for(let i=0,resId;resId=this.resIds[i];i++){const resource=cache.get(resId+lang.code+lang.src);if(resource instanceof L10nError){continue;}
if(id in resource){return resource[id];}}
return undefined;}},{key:'_getNumberFormatter',value:function _getNumberFormatter(lang){if(!this.env.numberFormatters){this.env.numberFormatters=new Map();}
if(!this.env.numberFormatters.has(lang)){const formatter=L20nIntl.NumberFormat(lang);this.env.numberFormatters.set(lang,formatter);return formatter;}
return this.env.numberFormatters.get(lang);}},{key:'_getMacro',value:function _getMacro(lang,id){switch(id){case'plural':return getPluralRule(lang.code);default:return undefined;}}}]);return Context;})();function reportMissing(keys,formatter,resolved){const missingIds=new Set();keys.forEach((key,i)=>{if(resolved&&resolved[i]!==undefined){return;}
const id=Array.isArray(key)?key[0]:key;missingIds.add(id);resolved[i]=formatter===this._formatValue?id:{value:id,attrs:null};});this.emit('notfounderror',new L10nError('"'+Array.from(missingIds).join(', ')+'"'+' not found in any language',missingIds));return resolved;}
var MAX_PLACEABLES=100;var PropertiesParser={patterns:null,entryIds:null,emit:null,init:function(){this.patterns={comment:/^\s*#|^\s*$/,entity:/^([^=\s]+)\s*=\s*(.*)$/,multiline:/[^\\]\\$/,index:/\{\[\s*(\w+)(?:\(([^\)]*)\))?\s*\]\}/i,unicode:/\\u([0-9a-fA-F]{1,4})/g,entries:/[^\r\n]+/g,controlChars:/\\([\\\n\r\t\b\f\{\}\"\'])/g,placeables:/\{\{\s*([^\s]*?)\s*\}\}/};},parse:function(emit,source){if(!this.patterns){this.init();}
this.emit=emit;var entries={};var lines=source.match(this.patterns.entries);if(!lines){return entries;}
for(var i=0;i<lines.length;i++){var line=lines[i];if(this.patterns.comment.test(line)){continue;}
while(this.patterns.multiline.test(line)&&i<lines.length){line=line.slice(0,-1)+lines[++i].trim();}
var entityMatch=line.match(this.patterns.entity);if(entityMatch){try{this.parseEntity(entityMatch[1],entityMatch[2],entries);}catch(e){if(!this.emit){throw e;}}}}
return entries;},parseEntity:function(id,value,entries){var name,key;var pos=id.indexOf('[');if(pos!==-1){name=id.substr(0,pos);key=id.substring(pos+1,id.length-1);}else{name=id;key=null;}
var nameElements=name.split('.');if(nameElements.length>2){throw this.error('Error in ID: "'+name+'".'+' Nested attributes are not supported.');}
var attr;if(nameElements.length>1){name=nameElements[0];attr=nameElements[1];if(attr[0]==='$'){throw this.error('Attribute can\'t start with "$"');}}else{attr=null;}
this.setEntityValue(name,attr,key,this.unescapeString(value),entries);},setEntityValue:function(id,attr,key,rawValue,entries){var value=rawValue.indexOf('{{')>-1?this.parseString(rawValue):rawValue;var isSimpleValue=typeof value==='string';var root=entries;var isSimpleNode=typeof entries[id]==='string';if(!entries[id]&&(attr||key||!isSimpleValue)){entries[id]=Object.create(null);isSimpleNode=false;}
if(attr){if(isSimpleNode){const val=entries[id];entries[id]=Object.create(null);entries[id].value=val;}
if(!entries[id].attrs){entries[id].attrs=Object.create(null);}
if(!entries[id].attrs&&!isSimpleValue){entries[id].attrs[attr]=Object.create(null);}
root=entries[id].attrs;id=attr;}
if(key){isSimpleNode=false;if(typeof root[id]==='string'){const val=root[id];root[id]=Object.create(null);root[id].index=this.parseIndex(val);root[id].value=Object.create(null);}
root=root[id].value;id=key;isSimpleValue=true;}
if(isSimpleValue){if(id in root){throw this.error('Duplicated id: '+id);}
root[id]=value;}else{if(!root[id]){root[id]=Object.create(null);}
root[id].value=value;}},parseString:function(str){var chunks=str.split(this.patterns.placeables);var complexStr=[];var len=chunks.length;var placeablesCount=(len-1)/2;if(placeablesCount>=MAX_PLACEABLES){throw this.error('Too many placeables ('+placeablesCount+', max allowed is '+MAX_PLACEABLES+')');}
for(var i=0;i<chunks.length;i++){if(chunks[i].length===0){continue;}
if(i%2===1){complexStr.push({type:'idOrVar',name:chunks[i]});}else{complexStr.push(chunks[i]);}}
return complexStr;},unescapeString:function(str){if(str.lastIndexOf('\\')!==-1){str=str.replace(this.patterns.controlChars,'$1');}
return str.replace(this.patterns.unicode,function(match,token){return String.fromCodePoint(parseInt(token,16));});},parseIndex:function(str){var match=str.match(this.patterns.index);if(!match){throw new L10nError('Malformed index');}
if(match[2]){return[{type:'call',expr:{type:'prop',expr:{type:'glob',name:'cldr'},prop:'plural',cmpt:false},args:[{type:'idOrVar',name:match[2]}]}];}else{return[{type:'idOrVar',name:match[1]}];}},error:function(msg,type='parsererror'){const err=new L10nError(msg);if(this.emit){this.emit(type,err);}
return err;}};const MAX_PLACEABLES$1=100;var L20nParser={parse:function(emit,string){this._source=string;this._index=0;this._length=string.length;this.entries=Object.create(null);this.emit=emit;return this.getResource();},getResource:function(){this.getWS();while(this._index<this._length){try{this.getEntry();}catch(e){if(e instanceof L10nError){this.getJunkEntry();if(!this.emit){throw e;}}else{throw e;}}
if(this._index<this._length){this.getWS();}}
return this.entries;},getEntry:function(){if(this._source[this._index]==='<'){++this._index;const id=this.getIdentifier();if(this._source[this._index]==='['){++this._index;return this.getEntity(id,this.getItemList(this.getExpression,']'));}
return this.getEntity(id);}
if(this._source.startsWith('/*',this._index)){return this.getComment();}
throw this.error('Invalid entry');},getEntity:function(id,index){if(!this.getRequiredWS()){throw this.error('Expected white space');}
const ch=this._source[this._index];const hasIndex=index!==undefined;const value=this.getValue(ch,hasIndex,hasIndex);let attrs;if(value===undefined){if(ch==='>'){throw this.error('Expected ">"');}
attrs=this.getAttributes();}else{const ws1=this.getRequiredWS();if(this._source[this._index]!=='>'){if(!ws1){throw this.error('Expected ">"');}
attrs=this.getAttributes();}}
++this._index;if(id in this.entries){throw this.error('Duplicate entry ID "'+id,'duplicateerror');}
if(!attrs&&!index&&typeof value==='string'){this.entries[id]=value;}else{this.entries[id]={value,attrs,index};}},getValue:function(ch=this._source[this._index],index=false,required=true){switch(ch){case'\'':case'"':return this.getString(ch,1);case'{':return this.getHash(index);}
if(required){throw this.error('Unknown value type');}
return;},getWS:function(){let cc=this._source.charCodeAt(this._index);while(cc===32||cc===10||cc===9||cc===13){cc=this._source.charCodeAt(++this._index);}},getRequiredWS:function(){const pos=this._index;let cc=this._source.charCodeAt(pos);while(cc===32||cc===10||cc===9||cc===13){cc=this._source.charCodeAt(++this._index);}
return this._index!==pos;},getIdentifier:function(){const start=this._index;let cc=this._source.charCodeAt(this._index);if(cc>=97&&cc<=122||cc>=65&&cc<=90||cc===95){cc=this._source.charCodeAt(++this._index);}else{throw this.error('Identifier has to start with [a-zA-Z_]');}
while(cc>=97&&cc<=122||cc>=65&&cc<=90||cc>=48&&cc<=57||cc===95){cc=this._source.charCodeAt(++this._index);}
return this._source.slice(start,this._index);},getUnicodeChar:function(){for(let i=0;i<4;i++){let cc=this._source.charCodeAt(++this._index);if(cc>96&&cc<103||cc>64&&cc<71||cc>47&&cc<58){continue;}
throw this.error('Illegal unicode escape sequence');}
this._index++;return String.fromCharCode(parseInt(this._source.slice(this._index-4,this._index),16));},stringRe:/"|'|{{|\\/g,getString:function(opchar,opcharLen){const body=[];let placeables=0;this._index+=opcharLen;const start=this._index;let bufStart=start;let buf='';while(true){this.stringRe.lastIndex=this._index;const match=this.stringRe.exec(this._source);if(!match){throw this.error('Unclosed string literal');}
if(match[0]==='"'||match[0]==='\''){if(match[0]!==opchar){this._index+=opcharLen;continue;}
this._index=match.index+opcharLen;break;}
if(match[0]==='{{'){if(placeables>MAX_PLACEABLES$1-1){throw this.error('Too many placeables, maximum allowed is '+MAX_PLACEABLES$1);}
placeables++;if(match.index>bufStart||buf.length>0){body.push(buf+this._source.slice(bufStart,match.index));buf='';}
this._index=match.index+2;this.getWS();body.push(this.getExpression());this.getWS();this._index+=2;bufStart=this._index;continue;}
if(match[0]==='\\'){this._index=match.index+1;const ch2=this._source[this._index];if(ch2==='u'){buf+=this._source.slice(bufStart,match.index)+this.getUnicodeChar();}else if(ch2===opchar||ch2==='\\'){buf+=this._source.slice(bufStart,match.index)+ch2;this._index++;}else if(this._source.startsWith('{{',this._index)){buf+=this._source.slice(bufStart,match.index)+'{{';this._index+=2;}else{throw this.error('Illegal escape sequence');}
bufStart=this._index;}}
if(body.length===0){return buf+this._source.slice(bufStart,this._index-opcharLen);}
if(this._index-opcharLen>bufStart||buf.length>0){body.push(buf+this._source.slice(bufStart,this._index-opcharLen));}
return body;},getAttributes:function(){const attrs=Object.create(null);while(true){this.getAttribute(attrs);const ws1=this.getRequiredWS();const ch=this._source.charAt(this._index);if(ch==='>'){break;}else if(!ws1){throw this.error('Expected ">"');}}
return attrs;},getAttribute:function(attrs){const key=this.getIdentifier();let index;if(this._source[this._index]==='['){++this._index;this.getWS();index=this.getItemList(this.getExpression,']');}
this.getWS();if(this._source[this._index]!==':'){throw this.error('Expected ":"');}
++this._index;this.getWS();const hasIndex=index!==undefined;const value=this.getValue(undefined,hasIndex);if(key in attrs){throw this.error('Duplicate attribute "'+key,'duplicateerror');}
if(!index&&typeof value==='string'){attrs[key]=value;}else{attrs[key]={value,index};}},getHash:function(index){const items=Object.create(null);++this._index;this.getWS();let defKey;while(true){const[key,value,def]=this.getHashItem();items[key]=value;if(def){if(defKey){throw this.error('Default item redefinition forbidden');}
defKey=key;}
this.getWS();const comma=this._source[this._index]===',';if(comma){++this._index;this.getWS();}
if(this._source[this._index]==='}'){++this._index;break;}
if(!comma){throw this.error('Expected "}"');}}
if(defKey){items.__default=defKey;}else if(!index){throw this.error('Unresolvable Hash Value');}
return items;},getHashItem:function(){let defItem=false;if(this._source[this._index]==='*'){++this._index;defItem=true;}
const key=this.getIdentifier();this.getWS();if(this._source[this._index]!==':'){throw this.error('Expected ":"');}
++this._index;this.getWS();return[key,this.getValue(),defItem];},getComment:function(){this._index+=2;const start=this._index;const end=this._source.indexOf('*/',start);if(end===-1){throw this.error('Comment without a closing tag');}
this._index=end+2;},getExpression:function(){let exp=this.getPrimaryExpression();while(true){let ch=this._source[this._index];if(ch==='.'||ch==='['){++this._index;exp=this.getPropertyExpression(exp,ch==='[');}else if(ch==='('){++this._index;exp=this.getCallExpression(exp);}else{break;}}
return exp;},getPropertyExpression:function(idref,computed){let exp;if(computed){this.getWS();exp=this.getExpression();this.getWS();if(this._source[this._index]!==']'){throw this.error('Expected "]"');}
++this._index;}else{exp=this.getIdentifier();}
return{type:'prop',expr:idref,prop:exp,cmpt:computed};},getCallExpression:function(callee){this.getWS();return{type:'call',expr:callee,args:this.getItemList(this.getExpression,')')};},getPrimaryExpression:function(){const ch=this._source[this._index];switch(ch){case'$':++this._index;return{type:'var',name:this.getIdentifier()};case'@':++this._index;return{type:'glob',name:this.getIdentifier()};default:return{type:'id',name:this.getIdentifier()};}},getItemList:function(callback,closeChar){const items=[];let closed=false;this.getWS();if(this._source[this._index]===closeChar){++this._index;closed=true;}
while(!closed){items.push(callback.call(this));this.getWS();let ch=this._source.charAt(this._index);switch(ch){case',':++this._index;this.getWS();break;case closeChar:++this._index;closed=true;break;default:throw this.error('Expected "," or "'+closeChar+'"');}}
return items;},getJunkEntry:function(){const pos=this._index;let nextEntity=this._source.indexOf('<',pos);let nextComment=this._source.indexOf('/*',pos);if(nextEntity===-1){nextEntity=this._length;}
if(nextComment===-1){nextComment=this._length;}
let nextEntry=Math.min(nextEntity,nextComment);this._index=nextEntry;},error:function(message,type='parsererror'){const pos=this._index;let start=this._source.lastIndexOf('<',pos-1);const lastClose=this._source.lastIndexOf('>',pos-1);start=lastClose>start?lastClose+1:start;const context=this._source.slice(start,pos+10);const msg=message+' at pos '+pos+': `'+context+'`';const err=new L10nError(msg);if(this.emit){this.emit(type,err);}
return err;}};function walkEntry(entry,fn){if(typeof entry==='string'){return fn(entry);}
const newEntry=Object.create(null);if(entry.value){newEntry.value=walkValue(entry.value,fn);}
if(entry.index){newEntry.index=entry.index;}
if(entry.attrs){newEntry.attrs=Object.create(null);for(let key in entry.attrs){newEntry.attrs[key]=walkEntry(entry.attrs[key],fn);}}
return newEntry;}
function walkValue(value,fn){if(typeof value==='string'){return fn(value);}
if(value.type){return value;}
const newValue=Array.isArray(value)?[]:Object.create(null);const keys=Object.keys(value);for(let i=0,key;key=keys[i];i++){newValue[key]=walkValue(value[key],fn);}
return newValue;}
function createGetter(id,name){let _pseudo=null;return function getPseudo(){if(_pseudo){return _pseudo;}
const reAlphas=/[a-zA-Z]/g;const reVowels=/[aeiouAEIOU]/g;const reWords=/[^\W0-9_]+/g;const reExcluded=/(%[EO]?\w|\{\s*.+?\s*\}|&[#\w]+;|<\s*.+?\s*>)/;const charMaps={'fr-x-psaccent':'ȦƁƇḒḖƑƓĦĪĴĶĿḾȠǾƤɊŘŞŦŬṼẆẊẎẐ[\\]^_`ȧƀƈḓḗƒɠħīĵķŀḿƞǿƥɋřşŧŭṽẇẋẏẑ','ar-x-psbidi':'∀ԐↃpƎɟפHIſӼ˥WNOԀÒᴚS⊥∩ɅMXʎZ[\\]ᵥ_,ɐqɔpǝɟƃɥıɾʞʅɯuodbɹsʇnʌʍxʎz'};const mods={'fr-x-psaccent':val=>val.replace(reVowels,match=>match+match.toLowerCase()),'ar-x-psbidi':val=>val.replace(reWords,match=>'‮'+match+'‬')};const replaceChars=(map,val)=>val.replace(reAlphas,match=>map.charAt(match.charCodeAt(0)-65));const transform=val=>replaceChars(charMaps[id],mods[id](val));const apply=(fn,val)=>{if(!val){return val;}
const parts=val.split(reExcluded);const modified=parts.map(function(part){if(reExcluded.test(part)){return part;}
return fn(part);});return modified.join('');};return _pseudo={name:transform(name),process:str=>apply(transform,str)};};}
const pseudo=Object.defineProperties(Object.create(null),{'fr-x-psaccent':{enumerable:true,get:createGetter('fr-x-psaccent','Runtime Accented')},'ar-x-psbidi':{enumerable:true,get:createGetter('ar-x-psbidi','Runtime Bidi')}});let Env=(function(){function Env(fetchResource){_classCallCheck(this,Env);this.fetchResource=fetchResource;this.resCache=new Map();this.resRefs=new Map();this.numberFormatters=null;this.parsers={properties:PropertiesParser,l20n:L20nParser};const listeners={};this.emit=emit.bind(this,listeners);this.addEventListener=addEventListener.bind(this,listeners);this.removeEventListener=removeEventListener.bind(this,listeners);}
_createClass(Env,[{key:'createContext',value:function createContext(langs,resIds){const ctx=new Context(this,langs,resIds);resIds.forEach(resId=>{const usedBy=this.resRefs.get(resId)||0;this.resRefs.set(resId,usedBy+1);});return ctx;}},{key:'destroyContext',value:function destroyContext(ctx){ctx.resIds.forEach(resId=>{const usedBy=this.resRefs.get(resId)||0;if(usedBy>1){return this.resRefs.set(resId,usedBy-1);}
this.resRefs.delete(resId);this.resCache.forEach((val,key)=>key.startsWith(resId)?this.resCache.delete(key):null);});}},{key:'_parse',value:function _parse(syntax,lang,data){const parser=this.parsers[syntax];if(!parser){return data;}
const emit=(type,err)=>this.emit(type,amendError(lang,err));return parser.parse.call(parser,emit,data);}},{key:'_create',value:function _create(lang,entries){if(lang.src!=='pseudo'){return entries;}
const pseudoentries=Object.create(null);for(let key in entries){pseudoentries[key]=walkEntry(entries[key],pseudo[lang.code].process);}
return pseudoentries;}},{key:'_getResource',value:function _getResource(lang,res){const cache=this.resCache;const id=res+lang.code+lang.src;if(cache.has(id)){return cache.get(id);}
const syntax=res.substr(res.lastIndexOf('.')+1);const saveEntries=data=>{const entries=this._parse(syntax,lang,data);cache.set(id,this._create(lang,entries));};const recover=err=>{err.lang=lang;this.emit('fetcherror',err);cache.set(id,err);};const langToFetch=lang.src==='pseudo'?{code:'en-US',src:'app',ver:lang.ver}:lang;const resource=this.fetchResource(res,langToFetch).then(saveEntries,recover);cache.set(id,resource);return resource;}}]);return Env;})();function amendError(lang,err){err.lang=lang;return err;}
function prioritizeLocales(def,availableLangs,requested){let supportedLocale;for(let i=0;i<requested.length;i++){const locale=requested[i];if(availableLangs.indexOf(locale)!==-1){supportedLocale=locale;break;}}
if(!supportedLocale||supportedLocale===def){return[def];}
return[supportedLocale,def];}
function negotiateLanguages({appVersion,defaultLang,availableLangs},additionalLangs,prevLangs,requestedLangs){const allAvailableLangs=Object.keys(availableLangs).concat(Object.keys(additionalLangs)).concat(Object.keys(pseudo));const newLangs=prioritizeLocales(defaultLang,allAvailableLangs,requestedLangs);const langs=newLangs.map(code=>({code:code,src:getLangSource(appVersion,availableLangs,additionalLangs,code),ver:appVersion}));return{langs,haveChanged:!arrEqual(prevLangs,newLangs)};}
function arrEqual(arr1,arr2){return arr1.length===arr2.length&&arr1.every((elem,i)=>elem===arr2[i]);}
function getMatchingLangpack(appVersion,langpacks){for(let i=0,langpack;langpack=langpacks[i];i++){if(langpack.target===appVersion){return langpack;}}
return null;}
function getLangSource(appVersion,availableLangs,additionalLangs,code){if(additionalLangs&&additionalLangs[code]){const lp=getMatchingLangpack(appVersion,additionalLangs[code]);if(lp&&(!(code in availableLangs)||parseInt(lp.revision)>availableLangs[code])){return'extra';}}
if(code in pseudo&&!(code in availableLangs)){return'pseudo';}
return'app';}
let Remote=(function(){function Remote(fetchResource,broadcast){_classCallCheck(this,Remote);this.broadcast=broadcast;this.env=new Env(fetchResource);this.ctxs=new Map();}
_createClass(Remote,[{key:'registerView',value:function registerView(view,resources,meta,additionalLangs,requestedLangs){const{langs}=negotiateLanguages(meta,additionalLangs,[],requestedLangs);this.ctxs.set(view,this.env.createContext(langs,resources));return langs;}},{key:'unregisterView',value:function unregisterView(view){this.ctxs.delete(view);return true;}},{key:'formatEntities',value:function formatEntities(view,keys){return this.ctxs.get(view).formatEntities(...keys);}},{key:'formatValues',value:function formatValues(view,keys){return this.ctxs.get(view).formatValues(...keys);}},{key:'changeLanguages',value:function changeLanguages(view,meta,additionalLangs,requestedLangs){const oldCtx=this.ctxs.get(view);const prevLangs=oldCtx.langs;const newLangs=negotiateLanguages(meta,additionalLangs,prevLangs,requestedLangs);this.ctxs.set(view,this.env.createContext(newLangs.langs,oldCtx.resIds));return newLangs;}},{key:'requestLanguages',value:function requestLanguages(requestedLangs){this.broadcast('languageschangerequest',requestedLangs);}},{key:'getName',value:function getName(code){return pseudo[code].name;}},{key:'processString',value:function processString(code,str){return pseudo[code].process(str);}}]);return Remote;})();const observerConfig={attributes:true,characterData:false,childList:true,subtree:true,attributeFilter:['data-l10n-id','data-l10n-args']};const observers=new WeakMap();function initMutationObserver(view){observers.set(view,{roots:new Set(),observer:new MutationObserver(mutations=>translateMutations(view,mutations))});}
function translateRoots(view){return Promise.all([...observers.get(view).roots].map(root=>_translateFragment(view,root)));}
function observe(view,root){const obs=observers.get(view);if(obs){obs.roots.add(root);obs.observer.observe(root,observerConfig);}}
function disconnect(view,root,allRoots){const obs=observers.get(view);if(obs){obs.observer.disconnect();if(allRoots){return;}
obs.roots.delete(root);obs.roots.forEach(other=>obs.observer.observe(other,observerConfig));}}
function reconnect(view){const obs=observers.get(view);if(obs){obs.roots.forEach(root=>obs.observer.observe(root,observerConfig));}}
const reOverlay=/<|&#?\w+;/;const allowed={elements:['a','em','strong','small','s','cite','q','dfn','abbr','data','time','code','var','samp','kbd','sub','sup','i','b','u','mark','ruby','rt','rp','bdi','bdo','span','br','wbr'],attributes:{global:['title','aria-label','aria-valuetext','aria-moz-hint'],a:['download'],area:['download','alt'],input:['alt','placeholder'],menuitem:['label'],menu:['label'],optgroup:['label'],option:['label'],track:['label'],img:['alt'],textarea:['placeholder'],th:['abbr']}};function overlayElement(element,translation){const value=translation.value;if(typeof value==='string'){if(!reOverlay.test(value)){element.textContent=value;}else{const tmpl=element.ownerDocument.createElement('template');tmpl.innerHTML=value;overlay(element,tmpl.content);}}
for(let key in translation.attrs){const attrName=camelCaseToDashed(key);if(isAttrAllowed({name:attrName},element)){element.setAttribute(attrName,translation.attrs[key]);}}}
function overlay(sourceElement,translationElement){const result=translationElement.ownerDocument.createDocumentFragment();let k,attr;let childElement;while(childElement=translationElement.childNodes[0]){translationElement.removeChild(childElement);if(childElement.nodeType===childElement.TEXT_NODE){result.appendChild(childElement);continue;}
const index=getIndexOfType(childElement);const sourceChild=getNthElementOfType(sourceElement,childElement,index);if(sourceChild){overlay(sourceChild,childElement);result.appendChild(sourceChild);continue;}
if(isElementAllowed(childElement)){const sanitizedChild=childElement.ownerDocument.createElement(childElement.nodeName);overlay(sanitizedChild,childElement);result.appendChild(sanitizedChild);continue;}
result.appendChild(translationElement.ownerDocument.createTextNode(childElement.textContent));}
sourceElement.textContent='';sourceElement.appendChild(result);if(translationElement.attributes){for(k=0,attr;attr=translationElement.attributes[k];k++){if(isAttrAllowed(attr,sourceElement)){sourceElement.setAttribute(attr.name,attr.value);}}}}
function isElementAllowed(element){return allowed.elements.indexOf(element.tagName.toLowerCase())!==-1;}
function isAttrAllowed(attr,element){const attrName=attr.name.toLowerCase();const tagName=element.tagName.toLowerCase();if(allowed.attributes.global.indexOf(attrName)!==-1){return true;}
if(!allowed.attributes[tagName]){return false;}
if(allowed.attributes[tagName].indexOf(attrName)!==-1){return true;}
if(tagName==='input'&&attrName==='value'){const type=element.type.toLowerCase();if(type==='submit'||type==='button'||type==='reset'){return true;}}
return false;}
function getNthElementOfType(context,element,index){let nthOfType=0;for(let i=0,child;child=context.children[i];i++){if(child.nodeType===child.ELEMENT_NODE&&child.tagName===element.tagName){if(nthOfType===index){return child;}
nthOfType++;}}
return null;}
function getIndexOfType(element){let index=0;let child;while(child=element.previousElementSibling){if(child.tagName===element.tagName){index++;}}
return index;}
function camelCaseToDashed(string){if(string==='ariaValueText'){return'aria-valuetext';}
return string.replace(/[A-Z]/g,function(match){return'-'+match.toLowerCase();}).replace(/^-/,'');}
const reHtml=/[&<>]/g;const htmlEntities={'&':'&amp;','<':'&lt;','>':'&gt;'};function setAttributes(element,id,args){element.setAttribute('data-l10n-id',id);if(args){element.setAttribute('data-l10n-args',JSON.stringify(args));}}
function getAttributes(element){return{id:element.getAttribute('data-l10n-id'),args:JSON.parse(element.getAttribute('data-l10n-args'))};}
function getTranslatables(element){const nodes=Array.from(element.querySelectorAll('[data-l10n-id]'));if(typeof element.hasAttribute==='function'&&element.hasAttribute('data-l10n-id')){nodes.push(element);}
return nodes;}
function translateMutations(view,mutations){const targets=new Set();for(let mutation of mutations){switch(mutation.type){case'attributes':targets.add(mutation.target);break;case'childList':for(let addedNode of mutation.addedNodes){if(addedNode.nodeType===addedNode.ELEMENT_NODE){if(addedNode.childElementCount){getTranslatables(addedNode).forEach(targets.add.bind(targets));}else{if(addedNode.hasAttribute('data-l10n-id')){targets.add(addedNode);}}}}
break;}}
if(targets.size===0){return;}
translateElements(view,Array.from(targets));}
function _translateFragment(view,frag){return translateElements(view,getTranslatables(frag));}
function getElementsTranslation(view,elems){const keys=elems.map(elem=>{const id=elem.getAttribute('data-l10n-id');const args=elem.getAttribute('data-l10n-args');return args?[id,JSON.parse(args.replace(reHtml,match=>htmlEntities[match]))]:id;});return view.formatEntities(...keys);}
function translateElements(view,elements){return getElementsTranslation(view,elements).then(translations=>applyTranslations(view,elements,translations));}
function applyTranslations(view,elems,translations){disconnect(view,null,true);for(let i=0;i<elems.length;i++){overlayElement(elems[i],translations[i]);}
reconnect(view);}
if(typeof NodeList==='function'&&!NodeList.prototype[Symbol.iterator]){NodeList.prototype[Symbol.iterator]=Array.prototype[Symbol.iterator];}
function documentReady(){if(document.readyState!=='loading'){return Promise.resolve();}
return new Promise(resolve=>{document.addEventListener('readystatechange',function onrsc(){document.removeEventListener('readystatechange',onrsc);resolve();});});}
function getDirection(code){const tag=code.split('-')[0];return['ar','he','fa','ps','ur'].indexOf(tag)>=0?'rtl':'ltr';}
if(navigator.languages===undefined){navigator.languages=[navigator.language];}
function getResourceLinks(head){return Array.prototype.map.call(head.querySelectorAll('link[rel="localization"]'),el=>el.getAttribute('href'));}
function getMeta(head){let availableLangs=Object.create(null);let defaultLang=null;let appVersion=null;const metas=Array.from(head.querySelectorAll('meta[name="availableLanguages"],'+'meta[name="defaultLanguage"],'+'meta[name="appVersion"]'));for(let meta of metas){const name=meta.getAttribute('name');const content=meta.getAttribute('content').trim();switch(name){case'availableLanguages':availableLangs=getLangRevisionMap(availableLangs,content);break;case'defaultLanguage':const[lang,rev]=getLangRevisionTuple(content);defaultLang=lang;if(!(lang in availableLangs)){availableLangs[lang]=rev;}
break;case'appVersion':appVersion=content;}}
return{defaultLang,availableLangs,appVersion};}
function getLangRevisionMap(seq,str){return str.split(',').reduce((seq,cur)=>{const[lang,rev]=getLangRevisionTuple(cur);seq[lang]=rev;return seq;},seq);}
function getLangRevisionTuple(str){const[lang,rev]=str.trim().split(':');return[lang,parseInt(rev)];}
const viewProps=new WeakMap();let View=(function(){function View(client,doc){_classCallCheck(this,View);this.pseudo={'fr-x-psaccent':createPseudo(this,'fr-x-psaccent'),'ar-x-psbidi':createPseudo(this,'ar-x-psbidi')};const initialized=documentReady().then(()=>init(this,client));this._interactive=initialized.then(()=>client);this.ready=initialized.then(langs=>translateView(this,langs));initMutationObserver(this);viewProps.set(this,{doc:doc,ready:false});client.on('languageschangerequest',requestedLangs=>this.requestLanguages(requestedLangs));}
_createClass(View,[{key:'requestLanguages',value:function requestLanguages(requestedLangs,isGlobal){const method=isGlobal?client=>client.method('requestLanguages',requestedLangs):client=>changeLanguages(this,client,requestedLangs);return this._interactive.then(method);}},{key:'handleEvent',value:function handleEvent(){return this.requestLanguages(navigator.languages);}},{key:'formatEntities',value:function formatEntities(...keys){return this._interactive.then(client=>client.method('formatEntities',client.id,keys));}},{key:'formatValue',value:function formatValue(id,args){return this._interactive.then(client=>client.method('formatValues',client.id,[[id,args]])).then(values=>values[0]);}},{key:'formatValues',value:function formatValues(...keys){return this._interactive.then(client=>client.method('formatValues',client.id,keys));}},{key:'translateFragment',value:function translateFragment(frag){return _translateFragment(this,frag);}},{key:'observeRoot',value:function observeRoot(root){observe(this,root);}},{key:'disconnectRoot',value:function disconnectRoot(root){disconnect(this,root);}}]);return View;})();View.prototype.setAttributes=setAttributes;View.prototype.getAttributes=getAttributes;function createPseudo(view,code){return{getName:()=>view._interactive.then(client=>client.method('getName',code)),processString:str=>view._interactive.then(client=>client.method('processString',code,str))};}
function init(view,client){const doc=viewProps.get(view).doc;const resources=getResourceLinks(doc.head);const meta=getMeta(doc.head);view.observeRoot(doc.documentElement);return getAdditionalLanguages().then(additionalLangs=>client.method('registerView',client.id,resources,meta,additionalLangs,navigator.languages));}
function changeLanguages(view,client,requestedLangs){const doc=viewProps.get(view).doc;const meta=getMeta(doc.head);return getAdditionalLanguages().then(additionalLangs=>client.method('changeLanguages',client.id,meta,additionalLangs,requestedLangs)).then(({langs,haveChanged})=>haveChanged?translateView(view,langs):undefined);}
function getAdditionalLanguages(){if(navigator.mozApps&&navigator.mozApps.getAdditionalLanguages){return navigator.mozApps.getAdditionalLanguages().catch(()=>Object.create(null));}
return Promise.resolve(Object.create(null));}
function translateView(view,langs){const props=viewProps.get(view);const html=props.doc.documentElement;if(props.ready){return translateRoots(view).then(()=>setAllAndEmit(html,langs));}
const translated=langs[0].code===html.getAttribute('lang')?Promise.resolve():translateRoots(view).then(()=>setLangDir(html,langs));return translated.then(()=>{setLangs(html,langs);props.ready=true;});}
function setLangs(html,langs){const codes=langs.map(lang=>lang.code);html.setAttribute('langs',codes.join(' '));}
function setLangDir(html,langs){const code=langs[0].code;html.setAttribute('lang',code);html.setAttribute('dir',getDirection(code));}
function setAllAndEmit(html,langs){setLangDir(html,langs);setLangs(html,langs);html.parentNode.dispatchEvent(new CustomEvent('DOMRetranslated',{bubbles:false,cancelable:false}));}
const remote=new Remote(fetchResource,broadcast);const client=new Client(remote);document.l10n=new View(client,document);window.addEventListener('languagechange',document.l10n);document.addEventListener('additionallanguageschange',document.l10n);navigator.mozL10n={setAttributes:document.l10n.setAttributes,getAttributes:document.l10n.getAttributes,formatValue:(...args)=>document.l10n.formatValue(...args),translateFragment:(...args)=>document.l10n.translateFragment(...args),once:cb=>document.l10n.ready.then(cb),ready:cb=>document.l10n.ready.then(()=>{document.addEventListener('DOMRetranslated',cb);cb();})};})();;this.asyncStorage=(function(){'use strict';var DBNAME='asyncStorage';var DBVERSION=1;var STORENAME='keyvaluepairs';var db=null;function withDatabase(f){if(db){f();}else{var openreq=indexedDB.open(DBNAME,DBVERSION);openreq.onerror=function withStoreOnError(){console.error('asyncStorage: can\'t open database:',openreq.error.name);};openreq.onupgradeneeded=function withStoreOnUpgradeNeeded(){openreq.result.createObjectStore(STORENAME);};openreq.onsuccess=function withStoreOnSuccess(){db=openreq.result;f();};}}
function withStore(type,callback,oncomplete){withDatabase(function(){var transaction=db.transaction(STORENAME,type);if(oncomplete){transaction.oncomplete=oncomplete;}
callback(transaction.objectStore(STORENAME));});}
function getItem(key,callback){var req;withStore('readonly',function getItemBody(store){req=store.get(key);req.onerror=function getItemOnError(){console.error('Error in asyncStorage.getItem(): ',req.error.name);};},function onComplete(){var value=req.result;if(value===undefined){value=null;}
callback(value);});}
function setItem(key,value,callback){withStore('readwrite',function setItemBody(store){var req=store.put(value,key);req.onerror=function setItemOnError(){console.error('Error in asyncStorage.setItem(): ',req.error.name);};},callback);}
function removeItem(key,callback){withStore('readwrite',function removeItemBody(store){var req=store.delete(key);req.onerror=function removeItemOnError(){console.error('Error in asyncStorage.removeItem(): ',req.error.name);};},callback);}
function clear(callback){withStore('readwrite',function clearBody(store){var req=store.clear();req.onerror=function clearOnError(){console.error('Error in asyncStorage.clear(): ',req.error.name);};},callback);}
function length(callback){var req;withStore('readonly',function lengthBody(store){req=store.count();req.onerror=function lengthOnError(){console.error('Error in asyncStorage.length(): ',req.error.name);};},function onComplete(){callback(req.result);});}
function key(n,callback){if(n<0){callback(null);return;}
var req;withStore('readonly',function keyBody(store){var advanced=false;req=store.openCursor();req.onsuccess=function keyOnSuccess(){var cursor=req.result;if(!cursor){return;}
if(n===0||advanced){return;}
advanced=true;cursor.advance(n);};req.onerror=function keyOnError(){console.error('Error in asyncStorage.key(): ',req.error.name);};},function onComplete(){var cursor=req.result;callback(cursor?cursor.key:null);});}
return{getItem:getItem,setItem:setItem,removeItem:removeItem,clear:clear,length:length,key:key};}());;(function(exports){'use strict';const kEventName='statechange';const kCommunicationKey='airplaneMode.enabled';const kStatusKey='airplaneMode.status';var AirplaneModeHelper={_mozSettings:window.navigator.mozSettings,_callbacks:[],_cachedStatus:'',ready:function(cb){if(this._cachedStatus===''){var self=this;this.addEventListener(kEventName,function onChangeEvent(){if(self._cachedStatus!==''){self.removeEventListener(kEventName,onChangeEvent);cb();}});}else{cb();}},getStatus:function(){return this._cachedStatus;},addEventListener:function(eventName,callback){if(eventName===kEventName){this._callbacks.push(callback);}},removeEventListener:function(eventName,callback){if(eventName===kEventName){var index=this._callbacks.indexOf(callback);if(index>=0){this._callbacks.splice(index,1);}}},setEnabled:function(enabled){this.ready(function(){var status=this.getStatus();if(status==='enabling'||status==='disabling'){}else{if(enabled&&status==='enabled'||!enabled&&status==='disabled'){return;}
var setObj={};setObj[kCommunicationKey]=enabled;this._mozSettings.createLock().set(setObj);}}.bind(this));},init:function(){var self=this;var lock=window.navigator.mozSettings.createLock();var req=lock.get(kStatusKey);req.onsuccess=function(){self._cachedStatus=req.result[kStatusKey];self._callbacks.forEach(function(callback){callback(self._cachedStatus);});};this._mozSettings.addObserver(kStatusKey,function(evt){var currentStatus=evt.settingValue;self._cachedStatus=currentStatus;self._callbacks.forEach(function(callback){callback(currentStatus);});});}};exports.AirplaneModeHelper=AirplaneModeHelper;AirplaneModeHelper.init();})(this);;'use strict';function $(id){return document.getElementById(id);}
function $$(expr){return document.querySelectorAll(expr);}
var mozFMRadio=navigator.mozFM||navigator.mozFMRadio||{speakerEnabled:false,frequency:null,enabled:false,antennaAvailable:true,signalStrength:1,frequencyLowerBound:87.5,frequencyUpperBound:108,channelWidth:0.1,onsignalstrengthchange:function emptyFunction(){},onfrequencychange:function emptyFunction(){},onenabled:function emptyFunction(){},ondisabled:function emptyFunction(){},onantennaavailablechange:function emptyFunction(){},disable:function fm_disable(){if(!this.enabled){return;}
this.enabled=false;var self=this;window.setTimeout(function(){self.ondisabled();},500);return{};},enable:function fm_enable(frequency){if(this.enabled){return;}
this.enabled=true;var self=this;window.setTimeout(function(){self.onenabled();self.setFrequency(frequency);},500);return{};},setFrequency:function fm_setFrequency(freq){freq=parseFloat(freq.toFixed(1));var previousValue=this.frequency;this.frequency=freq;if(previousValue!=freq){this.onfrequencychange();}
return{};},seekUp:function fm_seekUp(){var self=this;if(this._seekRequest){return;}
this._seekRequest={};this._seekTimeout=window.setTimeout(function su_timeout(){self.setFrequency(self.frequency+0.5);if(self._seekRequest.onsuccess){self._seekRequest.onsuccess();}
self._clearSeekRequest();},1000);return this._seekRequest;},seekDown:function fm_seekDown(){var self=this;if(this._seekRequest){return;}
this._seekRequest={};this._seekTimeout=window.setTimeout(function sd_timeout(){self.setFrequency(self.frequency-0.5);if(self._seekRequest.onsuccess){self._seekRequest.onsuccess();}
self._clearSeekRequest();},1000);return this._seekRequest;},cancelSeek:function fm_cancelSeek(){this._clearSeekRequest();var request={};window.setTimeout(function(){if(request.onsuccess){request.onsuccess();}},0);return request;},_clearSeekRequest:function fm_clearSeek(){if(this._seekTimeout){window.clearTimeout(this._seekTimeout);this._seekTimeout=null;}
if(this._seekRequest&&this._seekRequest.onerror){this._seekRequest.onerror();this._seekRequest=null;}}};(function(aGlobal){aGlobal.SpeakerManager=aGlobal.SpeakerManager||aGlobal.MozSpeakerManager;if(aGlobal.SpeakerManager){return;}
function SpeakerManager(){this.speakerforced=false;}
SpeakerManager.prototype={set forcespeaker(enable){if(this.speakerforced!=enable){this.speakerforced=enable;if(this.onspeakerforcedchange){this.onspeakerforcedchange();}}}};aGlobal.SpeakerManager=SpeakerManager;})(window);var enabling=false;function updatePowerUI(){var enabled=mozFMRadio.enabled;var powerSwitch=$('power-switch');if(enabled){window.performance.mark('fmRadioEnabled');powerSwitch.setAttribute('data-l10n-id','power-switch-off');}else{powerSwitch.setAttribute('data-l10n-id','power-switch-on');}
console.log('Power status: '+(enabled?'on':'off'));powerSwitch.dataset.enabled=enabled;powerSwitch.dataset.enabling=enabling;}
var airplaneModeEnabled=false;function updateWarningModeUI(){$('airplane-mode-warning').hidden=!airplaneModeEnabled;$('antenna-warning').hidden=mozFMRadio.antennaAvailable||airplaneModeEnabled;$('container').classList.toggle('hidden-block',airplaneModeEnabled||!mozFMRadio.antennaAvailable);}
function updateFrequencyBarUI(){var frequencyBar=$('frequency-bar');if(enabling){frequencyBar.classList.add('dim');}else{frequencyBar.classList.remove('dim');}}
function updateEnablingState(enablingState){enabling=enablingState;updatePowerUI();updateFrequencyBarUI();}
function enableFMRadio(frequency){if(airplaneModeEnabled){return;}
var request=mozFMRadio.enable(frequency);request.onerror=function onerror_enableFMRadio(event){updateEnablingState(false);};updateEnablingState(true);}
function cancelSeekAndSetFreq(frequency){function setFreq(){mozFMRadio.setFrequency(frequency);}
var seeking=!!$('power-switch').getAttribute('data-seeking');if(!seeking){setFreq();}else{var request=mozFMRadio.cancelSeek();request.onsuccess=setFreq;request.onerror=setFreq;}}
var frequencyDialer={unit:2,_bandUpperBound:0,_bandLowerBound:0,_minFrequency:0,_maxFrequency:0,_currentFreqency:0,_translateX:0,init:function(){updateWarningModeUI();this._initUI();this.setFrequency(mozFMRadio.frequency);this._addEventListeners();},_addEventListeners:function(){function _removeEventListeners(){document.body.removeEventListener('touchend',fd_body_touchend,false);document.body.removeEventListener('touchmove',fd_body_touchmove,false);}
function cloneEvent(evt){if('touches'in evt){evt=evt.touches[0];}
return{x:evt.clientX,y:evt.clientX,timestamp:evt.timeStamp};}
var self=this;var SPEED_THRESHOLD=0.1;var currentEvent,startEvent,currentSpeed;var tunedFrequency=0;function toFixed(frequency){return parseFloat(frequency.toFixed(1));}
function _calcSpeed(){var movingSpace=startEvent.x-currentEvent.x;var deltaTime=currentEvent.timestamp-startEvent.timestamp;var speed=movingSpace/deltaTime;currentSpeed=parseFloat(speed.toFixed(2));}
function _calcTargetFrequency(){return tunedFrequency-getMovingSpace()/self._space;}
function getMovingSpace(){var movingSpace=currentEvent.x-startEvent.x;return movingSpace;}
function fd_body_touchmove(event){event.stopPropagation();currentEvent=cloneEvent(event);_calcSpeed();var dialer=$('frequency-dialer');var translateX=self._translateX+getMovingSpace();self._translateX=translateX;var count=dialer.childNodes.length;for(var i=0;i<count;i++){var child=dialer.childNodes[i];child.style.MozTransform='translateX('+translateX+'px)';}
tunedFrequency=_calcTargetFrequency();var roundedFrequency=Math.round(tunedFrequency*10)/10;if(roundedFrequency!=self._currentFreqency){self.setFrequency(toFixed(roundedFrequency),true);}
startEvent=currentEvent;}
function fd_body_touchend(event){event.stopPropagation();_removeEventListeners();$('frequency-dialer').classList.add('animation-on');if(Math.abs(currentSpeed)>SPEED_THRESHOLD){var direction=currentSpeed>0?1:-1;tunedFrequency+=Math.min(Math.abs(currentSpeed)*3,3)*direction;}
tunedFrequency=self.setFrequency(toFixed(tunedFrequency));cancelSeekAndSetFreq(tunedFrequency);currentEvent=null;startEvent=null;currentSpeed=0;}
function fd_touchstart(event){event.stopPropagation();$('frequency-dialer').classList.remove('animation-on');startEvent=currentEvent=cloneEvent(event);tunedFrequency=self._currentFreqency;_removeEventListeners();document.body.addEventListener('touchmove',fd_body_touchmove,false);document.body.addEventListener('touchend',fd_body_touchend,false);}
function fd_key(event){if(event.keyCode===event.DOM_VK_UP){tunedFrequency=self._currentFreqency+0.1;}else if(event.keyCode===event.DOM_VK_DOWN){tunedFrequency=self._currentFreqency-0.1;}else{return;}
tunedFrequency=self.setFrequency(toFixed(tunedFrequency));cancelSeekAndSetFreq(tunedFrequency);}
var dialerContainer=$('dialer-container');dialerContainer.addEventListener('touchstart',fd_touchstart,false);dialerContainer.addEventListener('keypress',fd_key,false);},_initUI:function(){$('frequency-dialer').innerHTML='';var lower=this._bandLowerBound=mozFMRadio.frequencyLowerBound;var upper=this._bandUpperBound=mozFMRadio.frequencyUpperBound;var unit=this.unit;this._minFrequency=lower-lower%unit;this._maxFrequency=upper+unit-upper%unit;var unitCount=(this._maxFrequency-this._minFrequency)/unit;for(var i=0;i<unitCount;++i){var start=this._minFrequency+i*unit;start=start<lower?lower:start;var end=this._maxFrequency+i*unit+unit;end=upper<end?upper:end;this._addDialerUnit(start,end);}
var _dialerUnits=$$('#frequency-dialer .dialer-unit');var _dialerUnitWidth=_dialerUnits[0].clientWidth;this._dialerWidth=_dialerUnitWidth*_dialerUnits.length;this._space=this._dialerWidth/(this._maxFrequency-this._minFrequency);for(i=0;i<_dialerUnits.length;i++){_dialerUnits[i].style.left=i*_dialerUnitWidth+'px';}},_addDialerUnit:function(start,end){var markStart=start-start%this.unit;var startMaskWidth=0;var endMaskWidth=0;var unitWidth=16;var total=this.unit*10;for(var i=0;i<total;i++){var dialValue=markStart+i*0.1;if(dialValue<start){startMaskWidth+=unitWidth;}else if(dialValue>end){endMaskWidth+=unitWidth;}}
var container=document.createElement('div');container.classList.add('dialer-unit-mark-box');if(startMaskWidth>0){var markEl=document.createElement('div');markEl.classList.add('dialer-unit-mark-mask-start');markEl.style.width=startMaskWidth+'px';container.appendChild(markEl);}
if(endMaskWidth>0){var markEnd=document.createElement('div');markEnd.classList.add('dialer-unit-mark-mask-end');markEnd.style.width=endMaskWidth+'px';container.appendChild(markEnd);}
var width=(100/this.unit)+'%';for(var j=0;j<this.unit;j++){var frequency=Math.floor(markStart)+j;var showFloor=frequency>=start&&frequency<=end;var unit=document.createElement('div');unit.classList.add('dialer-unit-floor');if(!showFloor){unit.classList.add('hidden-block');}
unit.style.width=width;unit.appendChild(document.createTextNode(frequency));container.appendChild(unit);}
var dialerUnit=document.createElement('div');dialerUnit.className='dialer-unit';dialerUnit.appendChild(container);$('frequency-dialer').appendChild(dialerUnit);},_updateUI:function(frequency,ignoreDialer){document.l10n.setAttributes($('frequency'),'frequency-MHz',{value:frequency.toFixed(1)});if(true!==ignoreDialer){this._translateX=(this._minFrequency-frequency)*this._space;var dialer=$('frequency-dialer');var count=dialer.childNodes.length;for(var i=0;i<count;i++){dialer.childNodes[i].style.MozTransform='translateX('+this._translateX+'px)';}
$('dialer-container').setAttribute('aria-valuenow',frequency);}},setFrequency:function(frequency,ignoreDialer){if(frequency<this._bandLowerBound){frequency=this._bandLowerBound;}
if(frequency>this._bandUpperBound){frequency=this._bandUpperBound;}
this._currentFreqency=frequency;this._updateUI(frequency,ignoreDialer);return frequency;},getFrequency:function(){return this._currentFreqency;}};var historyList={_historyList:[],KEYNAME:'historylist',SIZE:1,init:function hl_init(callback){var self=this;window.asyncStorage.getItem(this.KEYNAME,function storage_getItem(value){self._historyList=value||[];if(typeof callback=='function'){callback();}});},_save:function hl_save(){window.asyncStorage.setItem(this.KEYNAME,this._historyList);},add:function hl_add(freq){if(freq==null){return;}
var self=this;self._historyList.push({name:freq+'',frequency:freq});if(self._historyList.length>self.SIZE){self._historyList.shift();}
self._save();},last:function hl_last(){if(this._historyList.length===0){return null;}
else{return this._historyList[this._historyList.length-1];}}};var favoritesList={_favList:null,KEYNAME:'favlist',init:function(callback){var self=this;window.asyncStorage.getItem(this.KEYNAME,function storage_getItem(value){self._favList=value||{};self._showListUI();if(typeof callback=='function'){callback();}});var _container=$('fav-list-container');_container.addEventListener('click',function _onclick(event){var frequency=self._getElemFreq(event.target);if(!frequency){return;}
if(event.target.classList.contains('fav-list-remove-button')){self.remove(frequency);updateFreqUI();}else{if(mozFMRadio.enabled){cancelSeekAndSetFreq(frequency);}else{enableFMRadio(frequency);}}});},_save:function(){window.asyncStorage.setItem(this.KEYNAME,this._favList);},_showListUI:function(){var self=this;this.forEach(function(f){self._addItemToListUI(f);});},_addItemToListUI:function(item){var container=$('fav-list-container');var elem=document.createElement('div');elem.id=this._getUIElemId(item);elem.className='fav-list-item';elem.setAttribute('role','option');var subElem=document.createElement('div');subElem.className='fav-list-frequency';document.l10n.setAttributes(subElem,'fav-frequency-MHz',{value:item.frequency.toFixed(1)});elem.appendChild(subElem);subElem=document.createElement('div');subElem.className='fav-list-remove-button';elem.appendChild(subElem);if(container.childNodes.length===0){container.appendChild(elem);}else{var childNodes=container.childNodes;for(var i=0;i<childNodes.length;i++){var child=childNodes[i];var elemFreq=this._getElemFreq(child);if(item.frequency<elemFreq){container.insertBefore(elem,child);break;}else if(i==childNodes.length-1){container.appendChild(elem);break;}}}
return elem;},_removeItemFromListUI:function(freq){if(!this.contains(freq)){return;}
var itemElem=$(this._getUIElemId(this._favList[freq]));if(itemElem){itemElem.parentNode.removeChild(itemElem);}},_getUIElemId:function(item){return'frequency-'+item.frequency;},_getElemFreq:function(elem){elem=elem.closest('.fav-list-item');return parseFloat(elem.id.substring(elem.id.indexOf('-')+1));},forEach:function(callback){for(var freq in this._favList){callback(this._favList[freq]);}},contains:function(freq){if(!this._favList){return false;}
return typeof this._favList[freq]!='undefined';},add:function(freq){if(!this.contains(freq)){this._favList[freq]={name:freq+'',frequency:freq};this._save();var elem=this._addItemToListUI(this._favList[freq]);window.scrollTo(0,elem.offsetTop);}},remove:function(freq){var exists=this.contains(freq);this._removeItemFromListUI(freq);delete this._favList[freq];this._save();return exists;},select:function(freq){var items=$$('#fav-list-container div.fav-list-item');for(var i=0;i<items.length;i++){var item=items[i];if(this._getElemFreq(item)==freq){item.classList.add('selected');item.setAttribute('aria-selected',true);}else{item.classList.remove('selected');item.setAttribute('aria-selected',false);}}}};function updateFreqUI(){historyList.add(mozFMRadio.frequency);frequencyDialer.setFrequency(mozFMRadio.frequency);var frequency=frequencyDialer.getFrequency();favoritesList.select(frequency);var bookmarkButton=$('bookmark-button');bookmarkButton.dataset.bookmarked=favoritesList.contains(frequency);bookmarkButton.setAttribute('aria-pressed',favoritesList.contains(frequency));}
function init(){frequencyDialer.init();function onclick_seekbutton(event){var seekButton=this;var powerSwitch=$('power-switch');var seeking=!!powerSwitch.getAttribute('data-seeking');var up=seekButton.id=='frequency-op-seekup';function seek(){powerSwitch.dataset.seeking=true;var request=up?mozFMRadio.seekUp():mozFMRadio.seekDown();request.onsuccess=function seek_onsuccess(){powerSwitch.removeAttribute('data-seeking');};request.onerror=function seek_onerror(){powerSwitch.removeAttribute('data-seeking');};}
if(seeking){var request=mozFMRadio.cancelSeek();request.onsuccess=seek;request.onerror=seek;}else{seek();}}
$('frequency-op-seekdown').addEventListener('click',onclick_seekbutton,false);$('frequency-op-seekup').addEventListener('click',onclick_seekbutton,false);$('power-switch').addEventListener('click',function toggle_fm(){if(mozFMRadio.enabled){mozFMRadio.disable();}else{enableFMRadio(frequencyDialer.getFrequency());}},false);$('bookmark-button').addEventListener('click',function toggle_bookmark(){var frequency=frequencyDialer.getFrequency();if(favoritesList.contains(frequency)){favoritesList.remove(frequency);}else{favoritesList.add(frequency);}
updateFreqUI();},false);var speakerManager=new window.SpeakerManager();$('speaker-switch').addEventListener('click',function toggle_speaker(){speakerManager.forcespeaker=!speakerManager.speakerforced;},false);speakerManager.onspeakerforcedchange=function onspeakerforcedchange(){var speakerSwitch=$('speaker-switch');speakerSwitch.dataset.speakerOn=speakerManager.speakerforced;speakerSwitch.setAttribute('aria-pressed',speakerManager.speakerforced);};mozFMRadio.onfrequencychange=updateFreqUI;mozFMRadio.onenabled=function(){updateEnablingState(false);};mozFMRadio.ondisabled=function(){updateEnablingState(false);};mozFMRadio.onantennaavailablechange=function onAntennaChange(){updateWarningModeUI();if(mozFMRadio.antennaAvailable){if(!!window._previousFMRadioState||!!window._previousEnablingState){enableFMRadio(frequencyDialer.getFrequency());}}else{window._previousFMRadioState=mozFMRadio.enabled;window._previousEnablingState=enabling;mozFMRadio.disable();}};updateWarningModeUI();AirplaneModeHelper.addEventListener('statechange',function(status){airplaneModeEnabled=status==='enabled';updateWarningModeUI();});historyList.init(function hl_ready(){if(mozFMRadio.antennaAvailable){if(historyList.last()&&historyList.last().frequency){enableFMRadio(historyList.last().frequency);}else{enableFMRadio(mozFMRadio.frequencyLowerBound);}
favoritesList.init(updateFreqUI);}else{window._previousFMRadioState=true;updateWarningModeUI();favoritesList.init();}
updatePowerUI();window.performance.mark('fullyLoaded');});}
document.l10n.ready.then(function(){window.performance.mark('navigationLoaded');AirplaneModeHelper.ready(function(){airplaneModeEnabled=AirplaneModeHelper.getStatus()=='enabled';init();window.performance.mark('navigationInteractive');window.performance.mark('visuallyLoaded');window.performance.mark('contentInteractive');});});window.addEventListener('unload',function(e){mozFMRadio.disable();},false);

View file

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="en-US" dir="ltr">
<head>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
<meta charset="utf-8">
<meta name="theme-color" content="#242d33">
<title>FM Radio</title>
<link rel="stylesheet" href="app://theme.gaiamobile.org/shared/elements/gaia-theme/gaia-theme.css" type="text/css">
<link rel="stylesheet" href="style/fm.css" type="text/css">
<meta name="defaultLanguage" content="en-US">
<meta name="availableLanguages" content="ar:201601260729, bg:201601260729, bn-BD:201601260729, ca:201601260729, cs:201601260729, da:201601260729, de:201601260729, el:201601260729, en-US:201601260729, es:201601260729, eu:201601260729, fr:201601260729, gl:201601260729, hr:201601260729, hu:201601260729, it:201601260729, ja:201601260729, km:201601260729, ko:201601260729, lt:201601260729, mk:201601260729, ms:201601260729, ne-NP:201601260729, nl:201601260729, pa:201601260729, pl:201601260729, pt-BR:201601260729, ro:201601260729, ru:201601260729, sk:201601260729, sq:201601260729, sr-Cyrl:201601260729, sr-Latn:201601260729, sv-SE:201601260729, tr:201601260729, zh-CN:201601260729, zh-TW:201601260729">
<link rel="localization" href="/locales-obj/index.{locale}.json">
<!-- <script defer="" src="shared/js/intl/l20n.js"></script> -->
<!-- <script defer="" src="shared/js/async_storage.js"></script> -->
<!-- <script defer="" src="shared/js/airplane_mode_helper.js"></script> -->
<!-- <script defer="" src="js/fm.js"></script> --><script src="./gaia_build_defer_index.js" defer="" type="text/javascript"></script>
<meta content="2.5" name="appVersion"></head>
<body>
<div id="container" dir="ltr">
<div id="frequency-bar">
<div id="frequency-display">
<a aria-label="Speaker" id="speaker-switch" href="#speaker" data-speaker-on="false" data-l10n-id="speaker-switch" role="button" aria-pressed="false"></a>
<div id="frequency" role="status" data-l10n-id="frequency-MHz" data-l10n-args="{&quot;value&quot;: &quot;87.5&quot;}">⁨87.5⁩ <small>MHz</small></div>
<a aria-label="Favorite" id="bookmark-button" href="#bookmark" data-bookmarked="false" data-l10n-id="bookmark-button" role="button"></a>
</div>
</div>
<div id="dialer-bar">
<div aria-label="Frequency" id="dialer-container" data-l10n-id="dialer-container" role="slider" aria-valuemin="87.5" aria-valuemax="108" aria-controls="frequency">
<div id="frequency-indicator"></div>
<div id="frequency-dialer" class="animation-on"></div>
</div>
</div>
<div id="fav-list">
<div aria-label="Favorited stations" id="fav-list-container" role="listbox" data-l10n-id="fav-list-container"></div>
</div>
<div id="action-bar" role="toolbar">
<div>
<a aria-label="Seek Down" id="frequency-op-seekdown" href="#seekdown" data-l10n-id="frequency-op-seekdown" role="button"></a>
</div>
<div>
<a aria-label="Off" id="power-switch" href="#power-switch" data-enabled="false" data-enabling="false" data-l10n-id="power-switch-off" role="button"><span></span></a>
</div>
<div>
<a aria-label="Seek Up" id="frequency-op-seekup" href="#seekup" data-l10n-id="frequency-op-seekup" role="button"></a>
</div>
</div>
</div>
<div id="antenna-warning" class="warning" hidden="">
<div></div>
<div id="antenna-warning-header" class="warning-header" data-l10n-id="noAntenna">Plug in a headset</div>
<div id="antenna-warning-body" class="warning-body" data-l10n-id="noAntennaMsg">FM Radio requires a plugged in headset to receive radio signals.</div>
</div>
<div id="airplane-mode-warning" class="warning" hidden="">
<div class="warning-header" data-l10n-id="airplaneModeHeader">Airplane mode is on</div>
<div class="warning-body" data-l10n-id="airplaneModeMsg">Turn off Airplane mode to use FM Radio.</div>
</div>
</body>
</html>

View file

@ -0,0 +1,60 @@
;'use strict';function $(id){return document.getElementById(id);}
function $$(expr){return document.querySelectorAll(expr);}
var mozFMRadio=navigator.mozFM||navigator.mozFMRadio||{speakerEnabled:false,frequency:null,enabled:false,antennaAvailable:true,signalStrength:1,frequencyLowerBound:87.5,frequencyUpperBound:108,channelWidth:0.1,onsignalstrengthchange:function emptyFunction(){},onfrequencychange:function emptyFunction(){},onenabled:function emptyFunction(){},ondisabled:function emptyFunction(){},onantennaavailablechange:function emptyFunction(){},disable:function fm_disable(){if(!this.enabled){return;}
this.enabled=false;var self=this;window.setTimeout(function(){self.ondisabled();},500);return{};},enable:function fm_enable(frequency){if(this.enabled){return;}
this.enabled=true;var self=this;window.setTimeout(function(){self.onenabled();self.setFrequency(frequency);},500);return{};},setFrequency:function fm_setFrequency(freq){freq=parseFloat(freq.toFixed(1));var previousValue=this.frequency;this.frequency=freq;if(previousValue!=freq){this.onfrequencychange();}
return{};},seekUp:function fm_seekUp(){var self=this;if(this._seekRequest){return;}
this._seekRequest={};this._seekTimeout=window.setTimeout(function su_timeout(){self.setFrequency(self.frequency+0.5);if(self._seekRequest.onsuccess){self._seekRequest.onsuccess();}
self._clearSeekRequest();},1000);return this._seekRequest;},seekDown:function fm_seekDown(){var self=this;if(this._seekRequest){return;}
this._seekRequest={};this._seekTimeout=window.setTimeout(function sd_timeout(){self.setFrequency(self.frequency-0.5);if(self._seekRequest.onsuccess){self._seekRequest.onsuccess();}
self._clearSeekRequest();},1000);return this._seekRequest;},cancelSeek:function fm_cancelSeek(){this._clearSeekRequest();var request={};window.setTimeout(function(){if(request.onsuccess){request.onsuccess();}},0);return request;},_clearSeekRequest:function fm_clearSeek(){if(this._seekTimeout){window.clearTimeout(this._seekTimeout);this._seekTimeout=null;}
if(this._seekRequest&&this._seekRequest.onerror){this._seekRequest.onerror();this._seekRequest=null;}}};(function(aGlobal){aGlobal.SpeakerManager=aGlobal.SpeakerManager||aGlobal.MozSpeakerManager;if(aGlobal.SpeakerManager){return;}
function SpeakerManager(){this.speakerforced=false;}
SpeakerManager.prototype={set forcespeaker(enable){if(this.speakerforced!=enable){this.speakerforced=enable;if(this.onspeakerforcedchange){this.onspeakerforcedchange();}}}};aGlobal.SpeakerManager=SpeakerManager;})(window);var enabling=false;function updatePowerUI(){var enabled=mozFMRadio.enabled;var powerSwitch=$('power-switch');if(enabled){window.performance.mark('fmRadioEnabled');powerSwitch.setAttribute('data-l10n-id','power-switch-off');}else{powerSwitch.setAttribute('data-l10n-id','power-switch-on');}
console.log('Power status: '+(enabled?'on':'off'));powerSwitch.dataset.enabled=enabled;powerSwitch.dataset.enabling=enabling;}
var airplaneModeEnabled=false;function updateWarningModeUI(){$('airplane-mode-warning').hidden=!airplaneModeEnabled;$('antenna-warning').hidden=mozFMRadio.antennaAvailable||airplaneModeEnabled;$('container').classList.toggle('hidden-block',airplaneModeEnabled||!mozFMRadio.antennaAvailable);}
function updateFrequencyBarUI(){var frequencyBar=$('frequency-bar');if(enabling){frequencyBar.classList.add('dim');}else{frequencyBar.classList.remove('dim');}}
function updateEnablingState(enablingState){enabling=enablingState;updatePowerUI();updateFrequencyBarUI();}
function enableFMRadio(frequency){if(airplaneModeEnabled){return;}
var request=mozFMRadio.enable(frequency);request.onerror=function onerror_enableFMRadio(event){updateEnablingState(false);};updateEnablingState(true);}
function cancelSeekAndSetFreq(frequency){function setFreq(){mozFMRadio.setFrequency(frequency);}
var seeking=!!$('power-switch').getAttribute('data-seeking');if(!seeking){setFreq();}else{var request=mozFMRadio.cancelSeek();request.onsuccess=setFreq;request.onerror=setFreq;}}
var frequencyDialer={unit:2,_bandUpperBound:0,_bandLowerBound:0,_minFrequency:0,_maxFrequency:0,_currentFreqency:0,_translateX:0,init:function(){updateWarningModeUI();this._initUI();this.setFrequency(mozFMRadio.frequency);this._addEventListeners();},_addEventListeners:function(){function _removeEventListeners(){document.body.removeEventListener('touchend',fd_body_touchend,false);document.body.removeEventListener('touchmove',fd_body_touchmove,false);}
function cloneEvent(evt){if('touches'in evt){evt=evt.touches[0];}
return{x:evt.clientX,y:evt.clientX,timestamp:evt.timeStamp};}
var self=this;var SPEED_THRESHOLD=0.1;var currentEvent,startEvent,currentSpeed;var tunedFrequency=0;function toFixed(frequency){return parseFloat(frequency.toFixed(1));}
function _calcSpeed(){var movingSpace=startEvent.x-currentEvent.x;var deltaTime=currentEvent.timestamp-startEvent.timestamp;var speed=movingSpace/deltaTime;currentSpeed=parseFloat(speed.toFixed(2));}
function _calcTargetFrequency(){return tunedFrequency-getMovingSpace()/self._space;}
function getMovingSpace(){var movingSpace=currentEvent.x-startEvent.x;return movingSpace;}
function fd_body_touchmove(event){event.stopPropagation();currentEvent=cloneEvent(event);_calcSpeed();var dialer=$('frequency-dialer');var translateX=self._translateX+getMovingSpace();self._translateX=translateX;var count=dialer.childNodes.length;for(var i=0;i<count;i++){var child=dialer.childNodes[i];child.style.MozTransform='translateX('+translateX+'px)';}
tunedFrequency=_calcTargetFrequency();var roundedFrequency=Math.round(tunedFrequency*10)/10;if(roundedFrequency!=self._currentFreqency){self.setFrequency(toFixed(roundedFrequency),true);}
startEvent=currentEvent;}
function fd_body_touchend(event){event.stopPropagation();_removeEventListeners();$('frequency-dialer').classList.add('animation-on');if(Math.abs(currentSpeed)>SPEED_THRESHOLD){var direction=currentSpeed>0?1:-1;tunedFrequency+=Math.min(Math.abs(currentSpeed)*3,3)*direction;}
tunedFrequency=self.setFrequency(toFixed(tunedFrequency));cancelSeekAndSetFreq(tunedFrequency);currentEvent=null;startEvent=null;currentSpeed=0;}
function fd_touchstart(event){event.stopPropagation();$('frequency-dialer').classList.remove('animation-on');startEvent=currentEvent=cloneEvent(event);tunedFrequency=self._currentFreqency;_removeEventListeners();document.body.addEventListener('touchmove',fd_body_touchmove,false);document.body.addEventListener('touchend',fd_body_touchend,false);}
function fd_key(event){if(event.keyCode===event.DOM_VK_UP){tunedFrequency=self._currentFreqency+0.1;}else if(event.keyCode===event.DOM_VK_DOWN){tunedFrequency=self._currentFreqency-0.1;}else{return;}
tunedFrequency=self.setFrequency(toFixed(tunedFrequency));cancelSeekAndSetFreq(tunedFrequency);}
var dialerContainer=$('dialer-container');dialerContainer.addEventListener('touchstart',fd_touchstart,false);dialerContainer.addEventListener('keypress',fd_key,false);},_initUI:function(){$('frequency-dialer').innerHTML='';var lower=this._bandLowerBound=mozFMRadio.frequencyLowerBound;var upper=this._bandUpperBound=mozFMRadio.frequencyUpperBound;var unit=this.unit;this._minFrequency=lower-lower%unit;this._maxFrequency=upper+unit-upper%unit;var unitCount=(this._maxFrequency-this._minFrequency)/unit;for(var i=0;i<unitCount;++i){var start=this._minFrequency+i*unit;start=start<lower?lower:start;var end=this._maxFrequency+i*unit+unit;end=upper<end?upper:end;this._addDialerUnit(start,end);}
var _dialerUnits=$$('#frequency-dialer .dialer-unit');var _dialerUnitWidth=_dialerUnits[0].clientWidth;this._dialerWidth=_dialerUnitWidth*_dialerUnits.length;this._space=this._dialerWidth/(this._maxFrequency-this._minFrequency);for(i=0;i<_dialerUnits.length;i++){_dialerUnits[i].style.left=i*_dialerUnitWidth+'px';}},_addDialerUnit:function(start,end){var markStart=start-start%this.unit;var startMaskWidth=0;var endMaskWidth=0;var unitWidth=16;var total=this.unit*10;for(var i=0;i<total;i++){var dialValue=markStart+i*0.1;if(dialValue<start){startMaskWidth+=unitWidth;}else if(dialValue>end){endMaskWidth+=unitWidth;}}
var container=document.createElement('div');container.classList.add('dialer-unit-mark-box');if(startMaskWidth>0){var markEl=document.createElement('div');markEl.classList.add('dialer-unit-mark-mask-start');markEl.style.width=startMaskWidth+'px';container.appendChild(markEl);}
if(endMaskWidth>0){var markEnd=document.createElement('div');markEnd.classList.add('dialer-unit-mark-mask-end');markEnd.style.width=endMaskWidth+'px';container.appendChild(markEnd);}
var width=(100/this.unit)+'%';for(var j=0;j<this.unit;j++){var frequency=Math.floor(markStart)+j;var showFloor=frequency>=start&&frequency<=end;var unit=document.createElement('div');unit.classList.add('dialer-unit-floor');if(!showFloor){unit.classList.add('hidden-block');}
unit.style.width=width;unit.appendChild(document.createTextNode(frequency));container.appendChild(unit);}
var dialerUnit=document.createElement('div');dialerUnit.className='dialer-unit';dialerUnit.appendChild(container);$('frequency-dialer').appendChild(dialerUnit);},_updateUI:function(frequency,ignoreDialer){document.l10n.setAttributes($('frequency'),'frequency-MHz',{value:frequency.toFixed(1)});if(true!==ignoreDialer){this._translateX=(this._minFrequency-frequency)*this._space;var dialer=$('frequency-dialer');var count=dialer.childNodes.length;for(var i=0;i<count;i++){dialer.childNodes[i].style.MozTransform='translateX('+this._translateX+'px)';}
$('dialer-container').setAttribute('aria-valuenow',frequency);}},setFrequency:function(frequency,ignoreDialer){if(frequency<this._bandLowerBound){frequency=this._bandLowerBound;}
if(frequency>this._bandUpperBound){frequency=this._bandUpperBound;}
this._currentFreqency=frequency;this._updateUI(frequency,ignoreDialer);return frequency;},getFrequency:function(){return this._currentFreqency;}};var historyList={_historyList:[],KEYNAME:'historylist',SIZE:1,init:function hl_init(callback){var self=this;window.asyncStorage.getItem(this.KEYNAME,function storage_getItem(value){self._historyList=value||[];if(typeof callback=='function'){callback();}});},_save:function hl_save(){window.asyncStorage.setItem(this.KEYNAME,this._historyList);},add:function hl_add(freq){if(freq==null){return;}
var self=this;self._historyList.push({name:freq+'',frequency:freq});if(self._historyList.length>self.SIZE){self._historyList.shift();}
self._save();},last:function hl_last(){if(this._historyList.length===0){return null;}
else{return this._historyList[this._historyList.length-1];}}};var favoritesList={_favList:null,KEYNAME:'favlist',init:function(callback){var self=this;window.asyncStorage.getItem(this.KEYNAME,function storage_getItem(value){self._favList=value||{};self._showListUI();if(typeof callback=='function'){callback();}});var _container=$('fav-list-container');_container.addEventListener('click',function _onclick(event){var frequency=self._getElemFreq(event.target);if(!frequency){return;}
if(event.target.classList.contains('fav-list-remove-button')){self.remove(frequency);updateFreqUI();}else{if(mozFMRadio.enabled){cancelSeekAndSetFreq(frequency);}else{enableFMRadio(frequency);}}});},_save:function(){window.asyncStorage.setItem(this.KEYNAME,this._favList);},_showListUI:function(){var self=this;this.forEach(function(f){self._addItemToListUI(f);});},_addItemToListUI:function(item){var container=$('fav-list-container');var elem=document.createElement('div');elem.id=this._getUIElemId(item);elem.className='fav-list-item';elem.setAttribute('role','option');var subElem=document.createElement('div');subElem.className='fav-list-frequency';document.l10n.setAttributes(subElem,'fav-frequency-MHz',{value:item.frequency.toFixed(1)});elem.appendChild(subElem);subElem=document.createElement('div');subElem.className='fav-list-remove-button';elem.appendChild(subElem);if(container.childNodes.length===0){container.appendChild(elem);}else{var childNodes=container.childNodes;for(var i=0;i<childNodes.length;i++){var child=childNodes[i];var elemFreq=this._getElemFreq(child);if(item.frequency<elemFreq){container.insertBefore(elem,child);break;}else if(i==childNodes.length-1){container.appendChild(elem);break;}}}
return elem;},_removeItemFromListUI:function(freq){if(!this.contains(freq)){return;}
var itemElem=$(this._getUIElemId(this._favList[freq]));if(itemElem){itemElem.parentNode.removeChild(itemElem);}},_getUIElemId:function(item){return'frequency-'+item.frequency;},_getElemFreq:function(elem){elem=elem.closest('.fav-list-item');return parseFloat(elem.id.substring(elem.id.indexOf('-')+1));},forEach:function(callback){for(var freq in this._favList){callback(this._favList[freq]);}},contains:function(freq){if(!this._favList){return false;}
return typeof this._favList[freq]!='undefined';},add:function(freq){if(!this.contains(freq)){this._favList[freq]={name:freq+'',frequency:freq};this._save();var elem=this._addItemToListUI(this._favList[freq]);window.scrollTo(0,elem.offsetTop);}},remove:function(freq){var exists=this.contains(freq);this._removeItemFromListUI(freq);delete this._favList[freq];this._save();return exists;},select:function(freq){var items=$$('#fav-list-container div.fav-list-item');for(var i=0;i<items.length;i++){var item=items[i];if(this._getElemFreq(item)==freq){item.classList.add('selected');item.setAttribute('aria-selected',true);}else{item.classList.remove('selected');item.setAttribute('aria-selected',false);}}}};function updateFreqUI(){historyList.add(mozFMRadio.frequency);frequencyDialer.setFrequency(mozFMRadio.frequency);var frequency=frequencyDialer.getFrequency();favoritesList.select(frequency);var bookmarkButton=$('bookmark-button');bookmarkButton.dataset.bookmarked=favoritesList.contains(frequency);bookmarkButton.setAttribute('aria-pressed',favoritesList.contains(frequency));}
function init(){frequencyDialer.init();function onclick_seekbutton(event){var seekButton=this;var powerSwitch=$('power-switch');var seeking=!!powerSwitch.getAttribute('data-seeking');var up=seekButton.id=='frequency-op-seekup';function seek(){powerSwitch.dataset.seeking=true;var request=up?mozFMRadio.seekUp():mozFMRadio.seekDown();request.onsuccess=function seek_onsuccess(){powerSwitch.removeAttribute('data-seeking');};request.onerror=function seek_onerror(){powerSwitch.removeAttribute('data-seeking');};}
if(seeking){var request=mozFMRadio.cancelSeek();request.onsuccess=seek;request.onerror=seek;}else{seek();}}
$('frequency-op-seekdown').addEventListener('click',onclick_seekbutton,false);$('frequency-op-seekup').addEventListener('click',onclick_seekbutton,false);$('power-switch').addEventListener('click',function toggle_fm(){if(mozFMRadio.enabled){mozFMRadio.disable();}else{enableFMRadio(frequencyDialer.getFrequency());}},false);$('bookmark-button').addEventListener('click',function toggle_bookmark(){var frequency=frequencyDialer.getFrequency();if(favoritesList.contains(frequency)){favoritesList.remove(frequency);}else{favoritesList.add(frequency);}
updateFreqUI();},false);var speakerManager=new window.SpeakerManager();$('speaker-switch').addEventListener('click',function toggle_speaker(){speakerManager.forcespeaker=!speakerManager.speakerforced;},false);speakerManager.onspeakerforcedchange=function onspeakerforcedchange(){var speakerSwitch=$('speaker-switch');speakerSwitch.dataset.speakerOn=speakerManager.speakerforced;speakerSwitch.setAttribute('aria-pressed',speakerManager.speakerforced);};mozFMRadio.onfrequencychange=updateFreqUI;mozFMRadio.onenabled=function(){updateEnablingState(false);};mozFMRadio.ondisabled=function(){updateEnablingState(false);};mozFMRadio.onantennaavailablechange=function onAntennaChange(){updateWarningModeUI();if(mozFMRadio.antennaAvailable){if(!!window._previousFMRadioState||!!window._previousEnablingState){enableFMRadio(frequencyDialer.getFrequency());}}else{window._previousFMRadioState=mozFMRadio.enabled;window._previousEnablingState=enabling;mozFMRadio.disable();}};updateWarningModeUI();AirplaneModeHelper.addEventListener('statechange',function(status){airplaneModeEnabled=status==='enabled';updateWarningModeUI();});historyList.init(function hl_ready(){if(mozFMRadio.antennaAvailable){if(historyList.last()&&historyList.last().frequency){enableFMRadio(historyList.last().frequency);}else{enableFMRadio(mozFMRadio.frequencyLowerBound);}
favoritesList.init(updateFreqUI);}else{window._previousFMRadioState=true;updateWarningModeUI();favoritesList.init();}
updatePowerUI();window.performance.mark('fullyLoaded');});}
document.l10n.ready.then(function(){window.performance.mark('navigationLoaded');AirplaneModeHelper.ready(function(){airplaneModeEnabled=AirplaneModeHelper.getStatus()=='enabled';init();window.performance.mark('navigationInteractive');window.performance.mark('visuallyLoaded');window.performance.mark('contentInteractive');});});window.addEventListener('unload',function(e){mozFMRadio.disable();},false);

View file

@ -0,0 +1,18 @@
{
"name": "fm",
"tags": {
"dictionaries": ["jsdoc"]
},
"source": {
"include": ["apps/fm/js/**/*.js"]
},
"plugins": [
"plugins/markdown",
"plugins/summarize"
],
"opts": {
"private": true,
"recurse": true,
"destination": "docs/fm"
}
}

View file

@ -0,0 +1 @@
{"noAntenna":"صلِ سماعة الأذنين","noAntennaMsg":"يحتاج تشغيل مذياع إف‌إم إدخال سماعات الأذنين لاستقبال إشارات المذياع.","airplaneModeHeader":"وضع الطائرة مُفعَّل","airplaneModeMsg":"أطفئ وضع الطائرة لاستخدام مذياع إف‌إم.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"السماعة الخارجية"}},"bookmark-button":{"attrs":{"ariaLabel":"مفضل"}},"dialer-container":{"attrs":{"ariaLabel":"التردّد"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"التمرير للأسفل"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"التمرير للأعلى"}},"power-switch-on":{"attrs":{"ariaLabel":"فعال"}},"power-switch-off":{"attrs":{"ariaLabel":"معطل"}},"fav-list-container":{"attrs":{"ariaLabel":"المحطات المفضلة"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Включване на слушалки","noAntennaMsg":"FM Радио изисква включени слушалки, за да приема радио сигнал.","airplaneModeHeader":"Самолетен режим включен","airplaneModeMsg":"Изключете самолетния режим, за да използвате FM Радио.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>МХц</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>МХц</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Високоговорител"}},"bookmark-button":{"attrs":{"ariaLabel":"Добавяне към любимите"}},"dialer-container":{"attrs":{"ariaLabel":"Честота"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Търсене надолу по честотите"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Търсене нагоре по честотите"}},"power-switch-on":{"attrs":{"ariaLabel":"Включване"}},"power-switch-off":{"attrs":{"ariaLabel":"Изключване"}},"fav-list-container":{"attrs":{"ariaLabel":"Любими станции"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"হেডসেট সংযুক্ত করুন","noAntennaMsg":"রেডিও সংকেত পেতে এফএম রেডিওর হেডসেট সংযুক্ত করা প্রয়োজন।","airplaneModeHeader":"এরোপ্লেন মোড চালু আছে","airplaneModeMsg":"FM রেডিও ব্যবহার করতে এরোপ্লেন মোড বন্ধ করুন।","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"বক্তা"}},"bookmark-button":{"attrs":{"ariaLabel":"প্রিয়"}},"dialer-container":{"attrs":{"ariaLabel":"কম্পাঙ্ক"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"নিচে খোঁজ করুন"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"ওপরে খোঁজ করুন"}},"power-switch-on":{"attrs":{"ariaLabel":"খোলা"}},"power-switch-off":{"attrs":{"ariaLabel":"বন্ধ"}},"fav-list-container":{"attrs":{"ariaLabel":"প্রিয় স্টেশন"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Connecteu uns auriculars","noAntennaMsg":"Cal connectar uns auriculars per rebre els senyals de ràdio FM.","airplaneModeHeader":"El mode d'avió està activat","airplaneModeMsg":"Desactiveu el mode d'avió per utilitzar la ràdio FM.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Altaveu"}},"bookmark-button":{"attrs":{"ariaLabel":"Preferits"}},"dialer-container":{"attrs":{"ariaLabel":"Freqüència"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Cerca cap avall"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Cerca cap amunt"}},"power-switch-on":{"attrs":{"ariaLabel":"Activat"}},"power-switch-off":{"attrs":{"ariaLabel":"Desactivat"}},"fav-list-container":{"attrs":{"ariaLabel":"Emissores preferides"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Připojte sluchátka","noAntennaMsg":"FM rádio vyžaduje připojená sluchátka kvůli příjmu signálu rádia.","airplaneModeHeader":"Režim V letadle je zapnut","airplaneModeMsg":"Pro použití FM rádia vypněte režim V letadle ","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Reproduktor"}},"bookmark-button":{"attrs":{"ariaLabel":"Oblíbené"}},"dialer-container":{"attrs":{"ariaLabel":"Frekvence"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Hledat dolů"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Hledat nahoru"}},"power-switch-on":{"attrs":{"ariaLabel":"Zapnout"}},"power-switch-off":{"attrs":{"ariaLabel":"Vypnout"}},"fav-list-container":{"attrs":{"ariaLabel":"Oblíbené stanice"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Tilslut headset","noAntennaMsg":"Du skal tilslutte et headset for at kunne modtage radio (ledningen bruges som antenne).","airplaneModeHeader":"Flytilstand er aktiveret","airplaneModeMsg":"Du skal slå flytilstand fra, før du kan bruge FM-radio.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Højtaler"}},"bookmark-button":{"attrs":{"ariaLabel":"Foretrukne"}},"dialer-container":{"attrs":{"ariaLabel":"Frekvens"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Søg nedad"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Søg opad"}},"power-switch-on":{"attrs":{"ariaLabel":"Tændt"}},"power-switch-off":{"attrs":{"ariaLabel":"Slukket"}},"fav-list-container":{"attrs":{"ariaLabel":"Foretrukne stationer"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Bitte stecken Sie Kopfhörer an.","noAntennaMsg":"Das UKW-Radio benötigt Kopfhörer als Antenne.","airplaneModeHeader":"Flugmodus ist aktiv","airplaneModeMsg":"Bitte beachten Sie, dass zur Verwendung des UKW-Radios der Flugmodus deaktiviert sein muss.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Lautsprecher"}},"bookmark-button":{"attrs":{"ariaLabel":"Als Lieblingssender speichern"}},"dialer-container":{"attrs":{"ariaLabel":"Frequenz"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"In höheren Frequenzen suchen"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"In niedrigeren Frequenzen suchen"}},"power-switch-on":{"attrs":{"ariaLabel":"An"}},"power-switch-off":{"attrs":{"ariaLabel":"Aus"}},"fav-list-container":{"attrs":{"ariaLabel":"Lieblingssender"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Συνδέστε ακουστικά","noAntennaMsg":"Το ραδιόφωνο χρειάζεται ακουστικά για να λάβει σήμα.","airplaneModeHeader":"Η λειτουργία πτήσης είναι ενεργή","airplaneModeMsg":"Απενεργοποιήστε την λειτουργία πτήσης για να χρησιμοποιήσετε το ραδιόφωνο.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Ηχείο"}},"bookmark-button":{"attrs":{"ariaLabel":"Αγαπημένος"}},"dialer-container":{"attrs":{"ariaLabel":"Συχνότητα"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Αναζήτηση προηγούμενου"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Αναζήτηση επόμενου"}},"power-switch-on":{"attrs":{"ariaLabel":"Ενεργό"}},"power-switch-off":{"attrs":{"ariaLabel":"Ανενεργό"}},"fav-list-container":{"attrs":{"ariaLabel":"Αγαπημένοι σταθμοί"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Plug in a headset","noAntennaMsg":"FM Radio requires a plugged in headset to receive radio signals.","airplaneModeHeader":"Airplane mode is on","airplaneModeMsg":"Turn off Airplane mode to use FM Radio.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Speaker"}},"bookmark-button":{"attrs":{"ariaLabel":"Favorite"}},"dialer-container":{"attrs":{"ariaLabel":"Frequency"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Seek Down"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Seek Up"}},"power-switch-on":{"attrs":{"ariaLabel":"On"}},"power-switch-off":{"attrs":{"ariaLabel":"Off"}},"fav-list-container":{"attrs":{"ariaLabel":"Favorited stations"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Conecte unos auriculares","noAntennaMsg":"La aplicación Radio FM necesita que se conecten unos auriculares para recibir señal de radio.","airplaneModeHeader":"El modo avión está activado","airplaneModeMsg":"Desactive el modo avión para escuchar Radio FM.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Altavoz"}},"bookmark-button":{"attrs":{"ariaLabel":"Favorito"}},"dialer-container":{"attrs":{"ariaLabel":"Frecuencia"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Buscar abajo"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Buscar arriba"}},"power-switch-on":{"attrs":{"ariaLabel":"Sí"}},"power-switch-off":{"attrs":{"ariaLabel":"No"}},"fav-list-container":{"attrs":{"ariaLabel":"Emisoras favoritas"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Konektatu aurikularrak","noAntennaMsg":"FM irratiak aurikularrak konektatuta egotea eskatzen du irrati-seinaleak jasotzeko.","airplaneModeHeader":"Hegazkin modua piztuta dago","airplaneModeMsg":"Itzali hegazkin modua FM irratia erabiltzeko.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Bozgorailua"}},"bookmark-button":{"attrs":{"ariaLabel":"Gogokoa"}},"dialer-container":{"attrs":{"ariaLabel":"Maiztasuna"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Bilatu beherantz"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Bilatu gorantz"}},"power-switch-on":{"attrs":{"ariaLabel":"Aktibatuta"}},"power-switch-off":{"attrs":{"ariaLabel":"Desaktibatuta"}},"fav-list-container":{"attrs":{"ariaLabel":"Gogoko estazioak"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Casque débranché","noAntennaMsg":"La radio FM nécessite un casque branché pour servir d’antenne.","airplaneModeHeader":"Le mode avion est activé","airplaneModeMsg":"Pour utiliser l’application Radio FM, désactivez le mode avion.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Haut-parleur"}},"bookmark-button":{"attrs":{"ariaLabel":"Ajouter aux stations préférées"}},"dialer-container":{"attrs":{"ariaLabel":"Fréquence"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Recherche arrière"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Recherche avant"}},"power-switch-on":{"attrs":{"ariaLabel":"Allumer"}},"power-switch-off":{"attrs":{"ariaLabel":"Éteindre"}},"fav-list-container":{"attrs":{"ariaLabel":"Stations préférées"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Conecte uns auriculares","noAntennaMsg":"O aplicativo Radio FM require que se conecten uns auriculares para recibir sinais de radio.","airplaneModeHeader":"O modo avión está activo","airplaneModeMsg":"Desactive o modo avión para usar Radio FM.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Altofalante"}},"bookmark-button":{"attrs":{"ariaLabel":"Favorito"}},"dialer-container":{"attrs":{"ariaLabel":"Frecuencia"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Buscar abaixo"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Buscar arriba"}},"power-switch-on":{"attrs":{"ariaLabel":"Activada"}},"power-switch-off":{"attrs":{"ariaLabel":"Desactivada"}},"fav-list-container":{"attrs":{"ariaLabel":"Emisoras favoritas"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Priključite slušalice","noAntennaMsg":"Za primanje signala, FM radio zahtijeva priključene slušalice","airplaneModeHeader":"Zrakoplovni način rada je uključen","airplaneModeMsg":"Isključi zrakoplovni način rada za korištenje FM radia.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Speaker"}},"bookmark-button":{"attrs":{"ariaLabel":"Favorite"}},"dialer-container":{"attrs":{"ariaLabel":"Frequency"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Seek Down"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Seek Up"}},"power-switch-on":{"attrs":{"ariaLabel":"On"}},"power-switch-off":{"attrs":{"ariaLabel":"Off"}},"fav-list-container":{"attrs":{"ariaLabel":"Favorited stations"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Csatlakoztasson egy fejhallgatót","noAntennaMsg":"Az FM-rádiójelek vételéhez csatlakoztasson egy fejhallgatót.","airplaneModeHeader":"Repülő mód bekapcsolva","airplaneModeMsg":"Kapcsolja ki a repülő módot az FM rádió használatához.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Hangszóró"}},"bookmark-button":{"attrs":{"ariaLabel":"Kedvenc"}},"dialer-container":{"attrs":{"ariaLabel":"Frekvencia"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Keresés lefelé"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Keresés felfelé"}},"power-switch-on":{"attrs":{"ariaLabel":"Be"}},"power-switch-off":{"attrs":{"ariaLabel":"Ki"}},"fav-list-container":{"attrs":{"ariaLabel":"Kedvenc állomások"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Inserire le cuffie","noAntennaMsg":"È necessario collegare le cuffie per ricevere il segnale radio.","airplaneModeHeader":"Modalità aereo attiva","airplaneModeMsg":"Disattivare la modalità aereo per utilizzare la Radio FM.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Altoparlante"}},"bookmark-button":{"attrs":{"ariaLabel":"Preferita"}},"dialer-container":{"attrs":{"ariaLabel":"Frequenza"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Ricerca all’indietro"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Ricerca in avanti"}},"power-switch-on":{"attrs":{"ariaLabel":"Acceso"}},"power-switch-off":{"attrs":{"ariaLabel":"Spento"}},"fav-list-container":{"attrs":{"ariaLabel":"Stazioni preferite"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"ヘッドセットを接続してください","noAntennaMsg":"FM ラジオは信号を受信するためのヘッドセットを接続する必要があります。","airplaneModeHeader":"機内モードが ON です","airplaneModeMsg":"FM ラジオを使用するには機内モードを OFF にしてください。","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"},"<small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"},"<small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"スピーカー"}},"bookmark-button":{"attrs":{"ariaLabel":"お気に入り"}},"dialer-container":{"attrs":{"ariaLabel":"周波数"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"シークダウン"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"シークアップ"}},"power-switch-on":{"attrs":{"ariaLabel":"ON"}},"power-switch-off":{"attrs":{"ariaLabel":"OFF"}},"fav-list-container":{"attrs":{"ariaLabel":"お気に入りの放送局"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"ដោត​កាស​​ស្ដាប់​ចូល","noAntennaMsg":"វិទ្យុ FM ទាមទារ​ដោត​កាស​ស្ដាប់​ចូល​ដើម្បី​ទទួល​សញ្ញា​វិទ្យុ។","airplaneModeHeader":"បាន​បើក​របៀប​លើ​យន្តហោះ","airplaneModeMsg":"បិទ​របៀប​លើ​យន្ត​ហោះ​ដើម្បី​ប្រើវ​ិទ្យុ FM ។","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"ឧបករណ៍​​បំពង​សំឡេង"}},"bookmark-button":{"attrs":{"ariaLabel":"សំណព្វចិត្ត​"}},"dialer-container":{"attrs":{"ariaLabel":"ភាពញឹកញាប់​"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"រកមើល​ចុះក្រោម​"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"រកមើល​ឡើងលើ​"}},"power-switch-on":{"attrs":{"ariaLabel":"បើក"}},"power-switch-off":{"attrs":{"ariaLabel":"បិទ"}},"fav-list-container":{"attrs":{"ariaLabel":"ស្ថានីយ​សំណព្វ​"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"헤드셋 연결하기","noAntennaMsg":"헤드셋이 연결되어 있어야 FM 라디오가 라디오 신호를 수신할 수 있습니다.","airplaneModeHeader":"비행기 모드 켜져 있음","airplaneModeMsg":"FM 라디오를 들으시려면 비행기 모드를 꺼 주십시오.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"스피커"}},"bookmark-button":{"attrs":{"ariaLabel":"즐겨찾기"}},"dialer-container":{"attrs":{"ariaLabel":"주파수"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"아래로 찾기"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"위로 찾기"}},"power-switch-on":{"attrs":{"ariaLabel":"켜기"}},"power-switch-off":{"attrs":{"ariaLabel":"끄기"}},"fav-list-container":{"attrs":{"ariaLabel":"즐겨찾는 방송"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Prijunkite ausines","noAntennaMsg":"FM radijui veikti prie šio įrenginio būtina prijungti laidines ausines.","airplaneModeHeader":"Įgalinta skrydžio veiksena","airplaneModeMsg":"Jeigu norite klausytis radijo, išjunkite skrydžio veikseną.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Speaker"}},"bookmark-button":{"attrs":{"ariaLabel":"Favorite"}},"dialer-container":{"attrs":{"ariaLabel":"Frequency"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Seek Down"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Seek Up"}},"power-switch-on":{"attrs":{"ariaLabel":"On"}},"power-switch-off":{"attrs":{"ariaLabel":"Off"}},"fav-list-container":{"attrs":{"ariaLabel":"Favorited stations"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Поврзете слушалки","noAntennaMsg":"Потребни е да поврзете слушаки за ФМ-радиото да прима сигнали.","airplaneModeHeader":"Авионскиот режим е вклучен","airplaneModeMsg":"Исклучете го авионскиот режим за да слушате радио.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Speaker"}},"bookmark-button":{"attrs":{"ariaLabel":"Favorite"}},"dialer-container":{"attrs":{"ariaLabel":"Frequency"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Seek Down"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Seek Up"}},"power-switch-on":{"attrs":{"ariaLabel":"On"}},"power-switch-off":{"attrs":{"ariaLabel":"Off"}},"fav-list-container":{"attrs":{"ariaLabel":"Favorited stations"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Pasang set kepala","noAntennaMsg":"Radio FM memerlukan set kepala dipasang untuk menerima isyarat radio.","airplaneModeHeader":"Mod pesawat telah hidup","airplaneModeMsg":"Matikan mod pesawat untuk menggunakan Radio FM.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Speaker"}},"bookmark-button":{"attrs":{"ariaLabel":"Favorite"}},"dialer-container":{"attrs":{"ariaLabel":"Frequency"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Seek Down"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Seek Up"}},"power-switch-on":{"attrs":{"ariaLabel":"On"}},"power-switch-off":{"attrs":{"ariaLabel":"Off"}},"fav-list-container":{"attrs":{"ariaLabel":"Favorited stations"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"हेडसेट जोड्नुहोस्","noAntennaMsg":"FM रेडियोलाई रेडियो सिग्नल प्राप्त गर्नका लागि हेडसेट जोडिएको हुनुपर्दछ।","airplaneModeHeader":"उडान शैली चालू छ","airplaneModeMsg":"FM रेडियो प्रयोग गर्न उडान शैली बन्द गर्नुहोस्।","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Speaker"}},"bookmark-button":{"attrs":{"ariaLabel":"Favorite"}},"dialer-container":{"attrs":{"ariaLabel":"Frequency"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Seek Down"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Seek Up"}},"power-switch-on":{"attrs":{"ariaLabel":"On"}},"power-switch-off":{"attrs":{"ariaLabel":"Off"}},"fav-list-container":{"attrs":{"ariaLabel":"Favorited stations"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Sluit een headset aan","noAntennaMsg":"FM-radio vereist een aangesloten headset om radiosignalen te ontvangen.","airplaneModeHeader":"Vliegtuigmodus is ingeschakeld","airplaneModeMsg":"Schakel de vliegtuigmodus uit om FM-radio te gebruiken.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Luidspreker"}},"bookmark-button":{"attrs":{"ariaLabel":"Favoriet"}},"dialer-container":{"attrs":{"ariaLabel":"Frequentie"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Omlaag zoeken"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Omhoog zoeken"}},"power-switch-on":{"attrs":{"ariaLabel":"Aan"}},"power-switch-off":{"attrs":{"ariaLabel":"Uit"}},"fav-list-container":{"attrs":{"ariaLabel":"Favoriete stations"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"ਹੈੱਡਸੈੱਟ ਲਗਾਓ","noAntennaMsg":"FM ਰੇਡੀਓ ਲਈ ਰੇਡੀਓ ਸਿਗਨਲ ਵਾਸਤੇ ਹੈੱਡਸੈੱਟ ਲਗਾਉ।","airplaneModeHeader":"ਏਅਰਪਲੇਨ ਮੋਡ ਚਾਲੂ ਹੈ","airplaneModeMsg":"ਐਫਐਮ ਰੇਡੀਓ ਵਰਤਣ ਲਈ ਏਅਰਪਲੇਨ ਮੋਡ ਬੰਦ ਕਰੋ।","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Speaker"}},"bookmark-button":{"attrs":{"ariaLabel":"Favorite"}},"dialer-container":{"attrs":{"ariaLabel":"Frequency"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Seek Down"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Seek Up"}},"power-switch-on":{"attrs":{"ariaLabel":"On"}},"power-switch-off":{"attrs":{"ariaLabel":"Off"}},"fav-list-container":{"attrs":{"ariaLabel":"Favorited stations"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Podłącz słuchawki","noAntennaMsg":"Radio wymaga słuchawek, aby odbierać sygnał radiowy.","airplaneModeHeader":"Aktywny tryb lotu","airplaneModeMsg":"Wyłącz tryb lotu, aby korzystać z radia.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Głośnik"}},"bookmark-button":{"attrs":{"ariaLabel":"Dodaj do ulubionych"}},"dialer-container":{"attrs":{"ariaLabel":"Częstotliwość"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Szukaj wstecz"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Szukaj"}},"power-switch-on":{"attrs":{"ariaLabel":"Włącz"}},"power-switch-off":{"attrs":{"ariaLabel":"Wyłącz"}},"fav-list-container":{"attrs":{"ariaLabel":"Ulubione stacje"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Por favor, plugue o fone de ouvido.","noAntennaMsg":"O Rádio FM requer um fone de ouvido para ser usado como antena.","airplaneModeHeader":"Modo avião ativado","airplaneModeMsg":"Desative o modo avião para usar o rádio FM.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Alto-falante"}},"bookmark-button":{"attrs":{"ariaLabel":"Favorito"}},"dialer-container":{"attrs":{"ariaLabel":"Frequência"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Pesquisar abaixo"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Pesquisar acima"}},"power-switch-on":{"attrs":{"ariaLabel":"Ligado"}},"power-switch-off":{"attrs":{"ariaLabel":"Desligado"}},"fav-list-container":{"attrs":{"ariaLabel":"Estações favoritas"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Conectează căștile","noAntennaMsg":"Radioul FM solicită căștile conectate pentru a recepționa semnale radio.","airplaneModeHeader":"Modul avion este activat","airplaneModeMsg":"Oprește modul avion pentru a folosi radioul FM.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Difuzor"}},"bookmark-button":{"attrs":{"ariaLabel":"Favorit"}},"dialer-container":{"attrs":{"ariaLabel":"Frecvență"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Caută în jos"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Caută în sus"}},"power-switch-on":{"attrs":{"ariaLabel":"Activat"}},"power-switch-off":{"attrs":{"ariaLabel":"Dezactivat"}},"fav-list-container":{"attrs":{"ariaLabel":"Stații favorite"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Подключите проводную гарнитуру","noAntennaMsg":"Для работы FM радио нужно подключить проводную гарнитуру.","airplaneModeHeader":"Включён Режим Полёта","airplaneModeMsg":"Отключите режим полета, чтобы использовать FM радио.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>МГц</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>МГц</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Спикер"}},"bookmark-button":{"attrs":{"ariaLabel":"Избранное"}},"dialer-container":{"attrs":{"ariaLabel":"Частота"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Искать вниз"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Искать вверх"}},"power-switch-on":{"attrs":{"ariaLabel":"Включить"}},"power-switch-off":{"attrs":{"ariaLabel":"Отключить"}},"fav-list-container":{"attrs":{"ariaLabel":"Избранные станции"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Pripojte slúchadlá","noAntennaMsg":"Na príjem rozhlasových staníc je potrebné pripojiť slúchadlá, ktoré slúžia ako anténa.","airplaneModeHeader":"Je aktivovaný režim V lietadle","airplaneModeMsg":"Ak chcete používať FM Rádio, vypnite režim V lietadle.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Reproduktor"}},"bookmark-button":{"attrs":{"ariaLabel":"Obľúbené"}},"dialer-container":{"attrs":{"ariaLabel":"Frekvencia"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Hľadať nadol"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Hľadať nahor"}},"power-switch-on":{"attrs":{"ariaLabel":"Zapnuté"}},"power-switch-off":{"attrs":{"ariaLabel":"Vypnuté"}},"fav-list-container":{"attrs":{"ariaLabel":"Stanice uložené medzi obľúbené"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Futni një palë kufje","noAntennaMsg":"Që Radioja FM të marrë sinjal, lyp futjen e një palë kufjeve.","airplaneModeHeader":"Mënyra Aeroplan është aktive","airplaneModeMsg":"Që të përdorni Radion FM çaktivizoni mënyrën Aeroplan.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Altoparlant"}},"bookmark-button":{"attrs":{"ariaLabel":"I parapëlqyer"}},"dialer-container":{"attrs":{"ariaLabel":"Frekuencë"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Më poshtë"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Më sipër"}},"power-switch-on":{"attrs":{"ariaLabel":"On"}},"power-switch-off":{"attrs":{"ariaLabel":"Off"}},"fav-list-container":{"attrs":{"ariaLabel":"Stacione të parapëlqyer"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Прикључите слушалице","noAntennaMsg":"FM радио захтева прикључене слушалице да би примао радио сигнале.","airplaneModeHeader":"Режим рада у авиону је укључен","airplaneModeMsg":"Искључите режим рада у авиону да бисте користили FM радио.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Звучник"}},"bookmark-button":{"attrs":{"ariaLabel":"Омиљено"}},"dialer-container":{"attrs":{"ariaLabel":"Фреквенција"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Тражи доле"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Тражи горе"}},"power-switch-on":{"attrs":{"ariaLabel":"Укључено"}},"power-switch-off":{"attrs":{"ariaLabel":"Искључено"}},"fav-list-container":{"attrs":{"ariaLabel":"Омиљене станице"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Priključite slušalice","noAntennaMsg":"FM radio zahteva priključene slušalice da bi primao radio signale.","airplaneModeHeader":"Režim rada u avionu je uključen","airplaneModeMsg":"Isključite režim rada u avionu da biste koristili FM radio.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Zvučnik"}},"bookmark-button":{"attrs":{"ariaLabel":"Omiljeno"}},"dialer-container":{"attrs":{"ariaLabel":"Frekvencija"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Traži dole"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Traži gore"}},"power-switch-on":{"attrs":{"ariaLabel":"Uključeno"}},"power-switch-off":{"attrs":{"ariaLabel":"Isključeno"}},"fav-list-container":{"attrs":{"ariaLabel":"Omiljene stanice"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Koppla in ett headset","noAntennaMsg":"FM-radio kräver ett inkopplat headset för att ta emot radiosignaler.","airplaneModeHeader":"Flygplansläge är aktiverat","airplaneModeMsg":"Inaktivera flygplansläge för att använda FM-radio.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Högtalare"}},"bookmark-button":{"attrs":{"ariaLabel":"Favorit"}},"dialer-container":{"attrs":{"ariaLabel":"Frekvens"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Sök lägre"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Sök högre"}},"power-switch-on":{"attrs":{"ariaLabel":"På"}},"power-switch-off":{"attrs":{"ariaLabel":"Av"}},"fav-list-container":{"attrs":{"ariaLabel":"Favoritstationer"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"Bir kulaklık takın","noAntennaMsg":"FM Radyo, radyo sinyallerini almak için kulaklığa ihtiyaç duyar.","airplaneModeHeader":"Uçak modu açık","airplaneModeMsg":"FM Radyo'yu kullanmak için Uçak modunu kapatın.","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"Hoparlör"}},"bookmark-button":{"attrs":{"ariaLabel":"Favori"}},"dialer-container":{"attrs":{"ariaLabel":"Frekans"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"Aşağı git"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"Yukarı git"}},"power-switch-on":{"attrs":{"ariaLabel":"Açık"}},"power-switch-off":{"attrs":{"ariaLabel":"Kapalı"}},"fav-list-container":{"attrs":{"ariaLabel":"Favori istasyonlar"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"请插入耳机","noAntennaMsg":"FM 收音机需要插入耳机才能收到广播信号。","airplaneModeHeader":"飞行模式打开","airplaneModeMsg":"关闭飞行模式以使用调频收音机。","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"扬声器"}},"bookmark-button":{"attrs":{"ariaLabel":"收藏"}},"dialer-container":{"attrs":{"ariaLabel":"频率"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"向下调整"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"向上调整"}},"power-switch-on":{"attrs":{"ariaLabel":"开"}},"power-switch-off":{"attrs":{"ariaLabel":"关"}},"fav-list-container":{"attrs":{"ariaLabel":"收藏的频道"}}}

View file

@ -0,0 +1 @@
{"noAntenna":"插入耳機","noAntennaMsg":"需要插入耳機才能接收廣播訊號。","airplaneModeHeader":"已開啟飛航模式","airplaneModeMsg":"關閉飛航模式以使用 FM 收音機。","frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"fav-frequency-MHz":{"value":[{"type":"idOrVar","name":"value"}," <small>MHz</small>"]},"speaker-switch":{"attrs":{"ariaLabel":"擴音"}},"bookmark-button":{"attrs":{"ariaLabel":"最愛"}},"dialer-container":{"attrs":{"ariaLabel":"頻道"}},"frequency-op-seekdown":{"attrs":{"ariaLabel":"向下尋找"}},"frequency-op-seekup":{"attrs":{"ariaLabel":"向上尋找"}},"power-switch-on":{"attrs":{"ariaLabel":"開啟"}},"power-switch-off":{"attrs":{"ariaLabel":"關閉"}},"fav-list-container":{"attrs":{"ariaLabel":"最愛電台"}}}

View file

@ -0,0 +1 @@
{"name":"FM Radio","description":"Gaia FM Radio","type":"certified","launch_path":"/index.html","developer":{"name":"The Gaia Team","url":"https://github.com/mozilla-b2g/gaia"},"permissions":{"themeable":{},"fmradio":{},"settings":{"access":"readonly"},"speaker-control":{},"audio-channel-content":{},"moz-extremely-unstable-and-will-change-webcomponents":{}},"locales":{"ar":{"name":"اف ام راديو","description":"الراديو"},"bg":{"name":"FM Радио","description":"Gaia FM Радио"},"bn-BD":{"name":"এফএম রেডিও","description":"গায়া এফএম রেডিও"},"ca":{"name":"Ràdio FM","description":"Radio FM del Gaia"},"cs":{"name":"FM rádio","description":"FM rádio systému Gaia"},"da":{"name":"FM-radio","description":"Gaia FM-radio"},"de":{"name":"UKW-Radio","description":"UKW-Radio für Gaia"},"el":{"name":"Ραδιόφωνο","description":"Ραδιόφωνο του Gaia"},"en-US":{"name":"FM Radio","description":"Gaia FM Radio"},"es":{"name":"Radio FM","description":"Radio FM de Gaia"},"eu":{"name":"FM irratia","description":"Gaia FM irratia"},"fr":{"name":"Radio FM","description":"Radio FM de Gaia"},"gl":{"name":"Radio FM","description":"Radio FM de Gaia"},"hr":{"name":"FM radio","description":"Gaia FM radio"},"hu":{"name":"FM rádió","description":"Gaia FM rádió"},"it":{"name":"Radio FM","description":"Radio FM Gaia"},"ja":{"name":"FM ラジオ","description":"Gaia FM ラジオ"},"km":{"name":"វិទ្យុ FM","description":"វិទ្យុ FM Gaia"},"ko":{"name":"FM 라디오","description":"Gaia FM 라디오"},"lt":{"name":"FM radijas","description":"„Gaia“ FM radijas"},"mk":{"name":"ФМ-радио","description":"ФМ-радио на Гаја"},"ms":{"name":"Radio FM","description":"Radio FM Gaia"},"ne-NP":{"name":"FM रेडियो","description":"गाइया FM रेडियो"},"nl":{"name":"FM-radio","description":"Gaia-FM-radio"},"pa":{"name":"FM ਰੇਡੀਓ","description":"ਗੀਗਾ FM ਰੇਡੀਓ"},"pl":{"name":"Radio","description":"Radio Gaia"},"pt-BR":{"name":"Rádio FM","description":"Rádio FM do Gaia"},"ro":{"name":"Radio FM","description":"Radio FM Gaia"},"ru":{"name":"FM-радио","description":"FM-радио Gaia"},"sk":{"name":"FM Rádio","description":"FM Rádio Gaia"},"sq":{"name":"Radio FM","description":"Radio FM Gaia"},"sr-Cyrl":{"name":"FM радио","description":"Gaia FM радио"},"sr-Latn":{"name":"FM radio","description":"Gaia FM radio"},"sv-SE":{"name":"FM-radio","description":"Gaia FM-radio"},"tr":{"name":"FM Radyo","description":"Gaia FM Radyo"},"zh-CN":{"name":"收音机","description":"Gaia 收音机"},"zh-TW":{"name":"FM 收音機","description":"Gaia FM 收音機"}},"default_locale":"en-US","icons":{"84":"/style/icons/fm_84.png","126":"/style/icons/fm_126.png","142":"/style/icons/fm_142.png","189":"/style/icons/fm_189.png","284":"/style/icons/fm_284.png"},"orientation":"default","origin":"app://fm.gaiamobile.org","version":"2.5"}

View file

@ -0,0 +1,2 @@
;(function(exports){'use strict';const kEventName='statechange';const kCommunicationKey='airplaneMode.enabled';const kStatusKey='airplaneMode.status';var AirplaneModeHelper={_mozSettings:window.navigator.mozSettings,_callbacks:[],_cachedStatus:'',ready:function(cb){if(this._cachedStatus===''){var self=this;this.addEventListener(kEventName,function onChangeEvent(){if(self._cachedStatus!==''){self.removeEventListener(kEventName,onChangeEvent);cb();}});}else{cb();}},getStatus:function(){return this._cachedStatus;},addEventListener:function(eventName,callback){if(eventName===kEventName){this._callbacks.push(callback);}},removeEventListener:function(eventName,callback){if(eventName===kEventName){var index=this._callbacks.indexOf(callback);if(index>=0){this._callbacks.splice(index,1);}}},setEnabled:function(enabled){this.ready(function(){var status=this.getStatus();if(status==='enabling'||status==='disabling'){}else{if(enabled&&status==='enabled'||!enabled&&status==='disabled'){return;}
var setObj={};setObj[kCommunicationKey]=enabled;this._mozSettings.createLock().set(setObj);}}.bind(this));},init:function(){var self=this;var lock=window.navigator.mozSettings.createLock();var req=lock.get(kStatusKey);req.onsuccess=function(){self._cachedStatus=req.result[kStatusKey];self._callbacks.forEach(function(callback){callback(self._cachedStatus);});};this._mozSettings.addObserver(kStatusKey,function(evt){var currentStatus=evt.settingValue;self._cachedStatus=currentStatus;self._callbacks.forEach(function(callback){callback(currentStatus);});});}};exports.AirplaneModeHelper=AirplaneModeHelper;AirplaneModeHelper.init();})(this);

View file

@ -0,0 +1,14 @@
;this.asyncStorage=(function(){'use strict';var DBNAME='asyncStorage';var DBVERSION=1;var STORENAME='keyvaluepairs';var db=null;function withDatabase(f){if(db){f();}else{var openreq=indexedDB.open(DBNAME,DBVERSION);openreq.onerror=function withStoreOnError(){console.error('asyncStorage: can\'t open database:',openreq.error.name);};openreq.onupgradeneeded=function withStoreOnUpgradeNeeded(){openreq.result.createObjectStore(STORENAME);};openreq.onsuccess=function withStoreOnSuccess(){db=openreq.result;f();};}}
function withStore(type,callback,oncomplete){withDatabase(function(){var transaction=db.transaction(STORENAME,type);if(oncomplete){transaction.oncomplete=oncomplete;}
callback(transaction.objectStore(STORENAME));});}
function getItem(key,callback){var req;withStore('readonly',function getItemBody(store){req=store.get(key);req.onerror=function getItemOnError(){console.error('Error in asyncStorage.getItem(): ',req.error.name);};},function onComplete(){var value=req.result;if(value===undefined){value=null;}
callback(value);});}
function setItem(key,value,callback){withStore('readwrite',function setItemBody(store){var req=store.put(value,key);req.onerror=function setItemOnError(){console.error('Error in asyncStorage.setItem(): ',req.error.name);};},callback);}
function removeItem(key,callback){withStore('readwrite',function removeItemBody(store){var req=store.delete(key);req.onerror=function removeItemOnError(){console.error('Error in asyncStorage.removeItem(): ',req.error.name);};},callback);}
function clear(callback){withStore('readwrite',function clearBody(store){var req=store.clear();req.onerror=function clearOnError(){console.error('Error in asyncStorage.clear(): ',req.error.name);};},callback);}
function length(callback){var req;withStore('readonly',function lengthBody(store){req=store.count();req.onerror=function lengthOnError(){console.error('Error in asyncStorage.length(): ',req.error.name);};},function onComplete(){callback(req.result);});}
function key(n,callback){if(n<0){callback(null);return;}
var req;withStore('readonly',function keyBody(store){var advanced=false;req=store.openCursor();req.onsuccess=function keyOnSuccess(){var cursor=req.result;if(!cursor){return;}
if(n===0||advanced){return;}
advanced=true;cursor.advance(n);};req.onerror=function keyOnError(){console.error('Error in asyncStorage.key(): ',req.error.name);};},function onComplete(){var cursor=req.result;callback(cursor?cursor.key:null);});}
return{getItem:getItem,setItem:setItem,removeItem:removeItem,clear:clear,length:length,key:key};}());

View file

@ -0,0 +1,280 @@
;var _createClass=(function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if('value'in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor);}}return function(Constructor,protoProps,staticProps){if(protoProps)defineProperties(Constructor.prototype,protoProps);if(staticProps)defineProperties(Constructor,staticProps);return Constructor;};})();function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError('Cannot call a class as a function');}}
(function(){'use strict';function emit(listeners,...args){const type=args.shift();if(listeners['*']){listeners['*'].slice().forEach(listener=>listener.apply(this,args));}
if(listeners[type]){listeners[type].slice().forEach(listener=>listener.apply(this,args));}}
function addEventListener(listeners,type,listener){if(!(type in listeners)){listeners[type]=[];}
listeners[type].push(listener);}
function removeEventListener(listeners,type,listener){const typeListeners=listeners[type];const pos=typeListeners.indexOf(listener);if(pos===-1){return;}
typeListeners.splice(pos,1);}
let Client=(function(){function Client(remote){_classCallCheck(this,Client);this.id=this;this.remote=remote;const listeners={};this.on=(...args)=>addEventListener(listeners,...args);this.emit=(...args)=>emit(listeners,...args);}
_createClass(Client,[{key:'method',value:function method(name,...args){return this.remote[name](...args);}}]);return Client;})();function broadcast(type,data){Array.from(this.ctxs.keys()).forEach(client=>client.emit(type,data));}
function L10nError(message,id,lang){this.name='L10nError';this.message=message;this.id=id;this.lang=lang;}
L10nError.prototype=Object.create(Error.prototype);L10nError.prototype.constructor=L10nError;function load(type,url){return new Promise(function(resolve,reject){const xhr=new XMLHttpRequest();if(xhr.overrideMimeType){xhr.overrideMimeType(type);}
xhr.open('GET',url,true);if(type==='application/json'){xhr.responseType='json';}
xhr.addEventListener('load',function io_onload(e){if(e.target.status===200||e.target.status===0){resolve(e.target.response||e.target.responseText);}else{reject(new L10nError('Not found: '+url));}});xhr.addEventListener('error',reject);xhr.addEventListener('timeout',reject);try{xhr.send(null);}catch(e){if(e.name==='NS_ERROR_FILE_NOT_FOUND'){reject(new L10nError('Not found: '+url));}else{throw e;}}});}
const io={extra:function(code,ver,path,type){return navigator.mozApps.getLocalizationResource(code,ver,path,type);},app:function(code,ver,path,type){switch(type){case'text':return load('text/plain',path);case'json':return load('application/json',path);default:throw new L10nError('Unknown file type: '+type);}}};function fetchResource(res,{code,src,ver}){const url=res.replace('{locale}',code);const type=res.endsWith('.json')?'json':'text';return io[src](code,ver,url,type);}
const KNOWN_MACROS=['plural'];const MAX_PLACEABLE_LENGTH=2500;const FSI='⁨';const PDI='⁩';const resolutionChain=new WeakSet();function format(ctx,lang,args,entity){if(typeof entity==='string'){return[{},entity];}
if(resolutionChain.has(entity)){throw new L10nError('Cyclic reference detected');}
resolutionChain.add(entity);let rv;try{rv=resolveValue({},ctx,lang,args,entity.value,entity.index);}finally{resolutionChain.delete(entity);}
return rv;}
function resolveIdentifier(ctx,lang,args,id){if(KNOWN_MACROS.indexOf(id)>-1){return[{},ctx._getMacro(lang,id)];}
if(args&&args.hasOwnProperty(id)){if(typeof args[id]==='string'||typeof args[id]==='number'&&!isNaN(args[id])){return[{},args[id]];}else{throw new L10nError('Arg must be a string or a number: '+id);}}
if(id==='__proto__'){throw new L10nError('Illegal id: '+id);}
const entity=ctx._getEntity(lang,id);if(entity){return format(ctx,lang,args,entity);}
throw new L10nError('Unknown reference: '+id);}
function subPlaceable(locals,ctx,lang,args,id){let newLocals,value;try{[newLocals,value]=resolveIdentifier(ctx,lang,args,id);}catch(err){return[{error:err},FSI+'{{ '+id+' }}'+PDI];}
if(typeof value==='number'){const formatter=ctx._getNumberFormatter(lang);return[newLocals,formatter.format(value)];}
if(typeof value==='string'){if(value.length>=MAX_PLACEABLE_LENGTH){throw new L10nError('Too many characters in placeable ('+value.length+', max allowed is '+MAX_PLACEABLE_LENGTH+')');}
return[newLocals,FSI+value+PDI];}
return[{},FSI+'{{ '+id+' }}'+PDI];}
function interpolate(locals,ctx,lang,args,arr){return arr.reduce(function([localsSeq,valueSeq],cur){if(typeof cur==='string'){return[localsSeq,valueSeq+cur];}else{const[,value]=subPlaceable(locals,ctx,lang,args,cur.name);return[localsSeq,valueSeq+value];}},[locals,'']);}
function resolveSelector(ctx,lang,args,expr,index){let selectorName;if(index[0].type==='call'&&index[0].expr.type==='prop'&&index[0].expr.expr.name==='cldr'){selectorName='plural';}else{selectorName=index[0].name;}
const selector=resolveIdentifier(ctx,lang,args,selectorName)[1];if(typeof selector!=='function'){return selector;}
const argValue=index[0].args?resolveIdentifier(ctx,lang,args,index[0].args[0].name)[1]:undefined;if(selectorName==='plural'){if(argValue===0&&'zero'in expr){return'zero';}
if(argValue===1&&'one'in expr){return'one';}
if(argValue===2&&'two'in expr){return'two';}}
return selector(argValue);}
function resolveValue(locals,ctx,lang,args,expr,index){if(!expr){return[locals,expr];}
if(typeof expr==='string'||typeof expr==='boolean'||typeof expr==='number'){return[locals,expr];}
if(Array.isArray(expr)){return interpolate(locals,ctx,lang,args,expr);}
if(index){const selector=resolveSelector(ctx,lang,args,expr,index);if(selector in expr){return resolveValue(locals,ctx,lang,args,expr[selector]);}}
const defaultKey=expr.__default||'other';if(defaultKey in expr){return resolveValue(locals,ctx,lang,args,expr[defaultKey]);}
throw new L10nError('Unresolvable value');}
const locales2rules={'af':3,'ak':4,'am':4,'ar':1,'asa':3,'az':0,'be':11,'bem':3,'bez':3,'bg':3,'bh':4,'bm':0,'bn':3,'bo':0,'br':20,'brx':3,'bs':11,'ca':3,'cgg':3,'chr':3,'cs':12,'cy':17,'da':3,'de':3,'dv':3,'dz':0,'ee':3,'el':3,'en':3,'eo':3,'es':3,'et':3,'eu':3,'fa':0,'ff':5,'fi':3,'fil':4,'fo':3,'fr':5,'fur':3,'fy':3,'ga':8,'gd':24,'gl':3,'gsw':3,'gu':3,'guw':4,'gv':23,'ha':3,'haw':3,'he':2,'hi':4,'hr':11,'hu':0,'id':0,'ig':0,'ii':0,'is':3,'it':3,'iu':7,'ja':0,'jmc':3,'jv':0,'ka':0,'kab':5,'kaj':3,'kcg':3,'kde':0,'kea':0,'kk':3,'kl':3,'km':0,'kn':0,'ko':0,'ksb':3,'ksh':21,'ku':3,'kw':7,'lag':18,'lb':3,'lg':3,'ln':4,'lo':0,'lt':10,'lv':6,'mas':3,'mg':4,'mk':16,'ml':3,'mn':3,'mo':9,'mr':3,'ms':0,'mt':15,'my':0,'nah':3,'naq':7,'nb':3,'nd':3,'ne':3,'nl':3,'nn':3,'no':3,'nr':3,'nso':4,'ny':3,'nyn':3,'om':3,'or':3,'pa':3,'pap':3,'pl':13,'ps':3,'pt':3,'rm':3,'ro':9,'rof':3,'ru':11,'rwk':3,'sah':0,'saq':3,'se':7,'seh':3,'ses':0,'sg':0,'sh':11,'shi':19,'sk':12,'sl':14,'sma':7,'smi':7,'smj':7,'smn':7,'sms':7,'sn':3,'so':3,'sq':3,'sr':11,'ss':3,'ssy':3,'st':3,'sv':3,'sw':3,'syr':3,'ta':3,'te':3,'teo':3,'th':0,'ti':4,'tig':3,'tk':3,'tl':4,'tn':3,'to':0,'tr':0,'ts':3,'tzm':22,'uk':11,'ur':3,'ve':3,'vi':0,'vun':3,'wa':4,'wae':3,'wo':0,'xh':3,'xog':3,'yo':0,'zh':0,'zu':3};function isIn(n,list){return list.indexOf(n)!==-1;}
function isBetween(n,start,end){return typeof n===typeof start&&start<=n&&n<=end;}
const pluralRules={'0':function(){return'other';},'1':function(n){if(isBetween(n%100,3,10)){return'few';}
if(n===0){return'zero';}
if(isBetween(n%100,11,99)){return'many';}
if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'2':function(n){if(n!==0&&n%10===0){return'many';}
if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'3':function(n){if(n===1){return'one';}
return'other';},'4':function(n){if(isBetween(n,0,1)){return'one';}
return'other';},'5':function(n){if(isBetween(n,0,2)&&n!==2){return'one';}
return'other';},'6':function(n){if(n===0){return'zero';}
if(n%10===1&&n%100!==11){return'one';}
return'other';},'7':function(n){if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'8':function(n){if(isBetween(n,3,6)){return'few';}
if(isBetween(n,7,10)){return'many';}
if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'9':function(n){if(n===0||n!==1&&isBetween(n%100,1,19)){return'few';}
if(n===1){return'one';}
return'other';},'10':function(n){if(isBetween(n%10,2,9)&&!isBetween(n%100,11,19)){return'few';}
if(n%10===1&&!isBetween(n%100,11,19)){return'one';}
return'other';},'11':function(n){if(isBetween(n%10,2,4)&&!isBetween(n%100,12,14)){return'few';}
if(n%10===0||isBetween(n%10,5,9)||isBetween(n%100,11,14)){return'many';}
if(n%10===1&&n%100!==11){return'one';}
return'other';},'12':function(n){if(isBetween(n,2,4)){return'few';}
if(n===1){return'one';}
return'other';},'13':function(n){if(isBetween(n%10,2,4)&&!isBetween(n%100,12,14)){return'few';}
if(n!==1&&isBetween(n%10,0,1)||isBetween(n%10,5,9)||isBetween(n%100,12,14)){return'many';}
if(n===1){return'one';}
return'other';},'14':function(n){if(isBetween(n%100,3,4)){return'few';}
if(n%100===2){return'two';}
if(n%100===1){return'one';}
return'other';},'15':function(n){if(n===0||isBetween(n%100,2,10)){return'few';}
if(isBetween(n%100,11,19)){return'many';}
if(n===1){return'one';}
return'other';},'16':function(n){if(n%10===1&&n!==11){return'one';}
return'other';},'17':function(n){if(n===3){return'few';}
if(n===0){return'zero';}
if(n===6){return'many';}
if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'18':function(n){if(n===0){return'zero';}
if(isBetween(n,0,2)&&n!==0&&n!==2){return'one';}
return'other';},'19':function(n){if(isBetween(n,2,10)){return'few';}
if(isBetween(n,0,1)){return'one';}
return'other';},'20':function(n){if((isBetween(n%10,3,4)||n%10===9)&&!(isBetween(n%100,10,19)||isBetween(n%100,70,79)||isBetween(n%100,90,99))){return'few';}
if(n%1000000===0&&n!==0){return'many';}
if(n%10===2&&!isIn(n%100,[12,72,92])){return'two';}
if(n%10===1&&!isIn(n%100,[11,71,91])){return'one';}
return'other';},'21':function(n){if(n===0){return'zero';}
if(n===1){return'one';}
return'other';},'22':function(n){if(isBetween(n,0,1)||isBetween(n,11,99)){return'one';}
return'other';},'23':function(n){if(isBetween(n%10,1,2)||n%20===0){return'one';}
return'other';},'24':function(n){if(isBetween(n,3,10)||isBetween(n,13,19)){return'few';}
if(isIn(n,[2,12])){return'two';}
if(isIn(n,[1,11])){return'one';}
return'other';}};function getPluralRule(code){const index=locales2rules[code.replace(/-.*$/,'')];if(!(index in pluralRules)){return function(){return'other';};}
return pluralRules[index];}
const L20nIntl=typeof Intl!=='undefined'?Intl:{NumberFormat:function(){return{format:function(v){return v;}};}};let Context=(function(){function Context(env,langs,resIds){_classCallCheck(this,Context);this.langs=langs;this.resIds=resIds;this.env=env;this.emit=(type,evt)=>env.emit(type,evt,this);}
_createClass(Context,[{key:'_formatTuple',value:function _formatTuple(lang,args,entity,id,key){try{return format(this,lang,args,entity);}catch(err){err.id=key?id+'::'+key:id;err.lang=lang;this.emit('resolveerror',err);return[{error:err},err.id];}}},{key:'_formatEntity',value:function _formatEntity(lang,args,entity,id){const[,value]=this._formatTuple(lang,args,entity,id);const formatted={value,attrs:null};if(entity.attrs){formatted.attrs=Object.create(null);for(let key in entity.attrs){const[,attrValue]=this._formatTuple(lang,args,entity.attrs[key],id,key);formatted.attrs[key]=attrValue;}}
return formatted;}},{key:'_formatValue',value:function _formatValue(lang,args,entity,id){return this._formatTuple(lang,args,entity,id)[1];}},{key:'fetch',value:function fetch(langs=this.langs){if(langs.length===0){return Promise.resolve(langs);}
return Promise.all(this.resIds.map(resId=>this.env._getResource(langs[0],resId))).then(()=>langs);}},{key:'_resolve',value:function _resolve(langs,keys,formatter,prevResolved){const lang=langs[0];if(!lang){return reportMissing.call(this,keys,formatter,prevResolved);}
let hasUnresolved=false;const resolved=keys.map((key,i)=>{if(prevResolved&&prevResolved[i]!==undefined){return prevResolved[i];}
const[id,args]=Array.isArray(key)?key:[key,undefined];const entity=this._getEntity(lang,id);if(entity){return formatter.call(this,lang,args,entity,id);}
this.emit('notfounderror',new L10nError('"'+id+'"'+' not found in '+lang.code,id,lang));hasUnresolved=true;});if(!hasUnresolved){return resolved;}
return this.fetch(langs.slice(1)).then(nextLangs=>this._resolve(nextLangs,keys,formatter,resolved));}},{key:'formatEntities',value:function formatEntities(...keys){return this.fetch().then(langs=>this._resolve(langs,keys,this._formatEntity));}},{key:'formatValues',value:function formatValues(...keys){return this.fetch().then(langs=>this._resolve(langs,keys,this._formatValue));}},{key:'_getEntity',value:function _getEntity(lang,id){const cache=this.env.resCache;for(let i=0,resId;resId=this.resIds[i];i++){const resource=cache.get(resId+lang.code+lang.src);if(resource instanceof L10nError){continue;}
if(id in resource){return resource[id];}}
return undefined;}},{key:'_getNumberFormatter',value:function _getNumberFormatter(lang){if(!this.env.numberFormatters){this.env.numberFormatters=new Map();}
if(!this.env.numberFormatters.has(lang)){const formatter=L20nIntl.NumberFormat(lang);this.env.numberFormatters.set(lang,formatter);return formatter;}
return this.env.numberFormatters.get(lang);}},{key:'_getMacro',value:function _getMacro(lang,id){switch(id){case'plural':return getPluralRule(lang.code);default:return undefined;}}}]);return Context;})();function reportMissing(keys,formatter,resolved){const missingIds=new Set();keys.forEach((key,i)=>{if(resolved&&resolved[i]!==undefined){return;}
const id=Array.isArray(key)?key[0]:key;missingIds.add(id);resolved[i]=formatter===this._formatValue?id:{value:id,attrs:null};});this.emit('notfounderror',new L10nError('"'+Array.from(missingIds).join(', ')+'"'+' not found in any language',missingIds));return resolved;}
var MAX_PLACEABLES=100;var PropertiesParser={patterns:null,entryIds:null,emit:null,init:function(){this.patterns={comment:/^\s*#|^\s*$/,entity:/^([^=\s]+)\s*=\s*(.*)$/,multiline:/[^\\]\\$/,index:/\{\[\s*(\w+)(?:\(([^\)]*)\))?\s*\]\}/i,unicode:/\\u([0-9a-fA-F]{1,4})/g,entries:/[^\r\n]+/g,controlChars:/\\([\\\n\r\t\b\f\{\}\"\'])/g,placeables:/\{\{\s*([^\s]*?)\s*\}\}/};},parse:function(emit,source){if(!this.patterns){this.init();}
this.emit=emit;var entries={};var lines=source.match(this.patterns.entries);if(!lines){return entries;}
for(var i=0;i<lines.length;i++){var line=lines[i];if(this.patterns.comment.test(line)){continue;}
while(this.patterns.multiline.test(line)&&i<lines.length){line=line.slice(0,-1)+lines[++i].trim();}
var entityMatch=line.match(this.patterns.entity);if(entityMatch){try{this.parseEntity(entityMatch[1],entityMatch[2],entries);}catch(e){if(!this.emit){throw e;}}}}
return entries;},parseEntity:function(id,value,entries){var name,key;var pos=id.indexOf('[');if(pos!==-1){name=id.substr(0,pos);key=id.substring(pos+1,id.length-1);}else{name=id;key=null;}
var nameElements=name.split('.');if(nameElements.length>2){throw this.error('Error in ID: "'+name+'".'+' Nested attributes are not supported.');}
var attr;if(nameElements.length>1){name=nameElements[0];attr=nameElements[1];if(attr[0]==='$'){throw this.error('Attribute can\'t start with "$"');}}else{attr=null;}
this.setEntityValue(name,attr,key,this.unescapeString(value),entries);},setEntityValue:function(id,attr,key,rawValue,entries){var value=rawValue.indexOf('{{')>-1?this.parseString(rawValue):rawValue;var isSimpleValue=typeof value==='string';var root=entries;var isSimpleNode=typeof entries[id]==='string';if(!entries[id]&&(attr||key||!isSimpleValue)){entries[id]=Object.create(null);isSimpleNode=false;}
if(attr){if(isSimpleNode){const val=entries[id];entries[id]=Object.create(null);entries[id].value=val;}
if(!entries[id].attrs){entries[id].attrs=Object.create(null);}
if(!entries[id].attrs&&!isSimpleValue){entries[id].attrs[attr]=Object.create(null);}
root=entries[id].attrs;id=attr;}
if(key){isSimpleNode=false;if(typeof root[id]==='string'){const val=root[id];root[id]=Object.create(null);root[id].index=this.parseIndex(val);root[id].value=Object.create(null);}
root=root[id].value;id=key;isSimpleValue=true;}
if(isSimpleValue){if(id in root){throw this.error('Duplicated id: '+id);}
root[id]=value;}else{if(!root[id]){root[id]=Object.create(null);}
root[id].value=value;}},parseString:function(str){var chunks=str.split(this.patterns.placeables);var complexStr=[];var len=chunks.length;var placeablesCount=(len-1)/2;if(placeablesCount>=MAX_PLACEABLES){throw this.error('Too many placeables ('+placeablesCount+', max allowed is '+MAX_PLACEABLES+')');}
for(var i=0;i<chunks.length;i++){if(chunks[i].length===0){continue;}
if(i%2===1){complexStr.push({type:'idOrVar',name:chunks[i]});}else{complexStr.push(chunks[i]);}}
return complexStr;},unescapeString:function(str){if(str.lastIndexOf('\\')!==-1){str=str.replace(this.patterns.controlChars,'$1');}
return str.replace(this.patterns.unicode,function(match,token){return String.fromCodePoint(parseInt(token,16));});},parseIndex:function(str){var match=str.match(this.patterns.index);if(!match){throw new L10nError('Malformed index');}
if(match[2]){return[{type:'call',expr:{type:'prop',expr:{type:'glob',name:'cldr'},prop:'plural',cmpt:false},args:[{type:'idOrVar',name:match[2]}]}];}else{return[{type:'idOrVar',name:match[1]}];}},error:function(msg,type='parsererror'){const err=new L10nError(msg);if(this.emit){this.emit(type,err);}
return err;}};const MAX_PLACEABLES$1=100;var L20nParser={parse:function(emit,string){this._source=string;this._index=0;this._length=string.length;this.entries=Object.create(null);this.emit=emit;return this.getResource();},getResource:function(){this.getWS();while(this._index<this._length){try{this.getEntry();}catch(e){if(e instanceof L10nError){this.getJunkEntry();if(!this.emit){throw e;}}else{throw e;}}
if(this._index<this._length){this.getWS();}}
return this.entries;},getEntry:function(){if(this._source[this._index]==='<'){++this._index;const id=this.getIdentifier();if(this._source[this._index]==='['){++this._index;return this.getEntity(id,this.getItemList(this.getExpression,']'));}
return this.getEntity(id);}
if(this._source.startsWith('/*',this._index)){return this.getComment();}
throw this.error('Invalid entry');},getEntity:function(id,index){if(!this.getRequiredWS()){throw this.error('Expected white space');}
const ch=this._source[this._index];const hasIndex=index!==undefined;const value=this.getValue(ch,hasIndex,hasIndex);let attrs;if(value===undefined){if(ch==='>'){throw this.error('Expected ">"');}
attrs=this.getAttributes();}else{const ws1=this.getRequiredWS();if(this._source[this._index]!=='>'){if(!ws1){throw this.error('Expected ">"');}
attrs=this.getAttributes();}}
++this._index;if(id in this.entries){throw this.error('Duplicate entry ID "'+id,'duplicateerror');}
if(!attrs&&!index&&typeof value==='string'){this.entries[id]=value;}else{this.entries[id]={value,attrs,index};}},getValue:function(ch=this._source[this._index],index=false,required=true){switch(ch){case'\'':case'"':return this.getString(ch,1);case'{':return this.getHash(index);}
if(required){throw this.error('Unknown value type');}
return;},getWS:function(){let cc=this._source.charCodeAt(this._index);while(cc===32||cc===10||cc===9||cc===13){cc=this._source.charCodeAt(++this._index);}},getRequiredWS:function(){const pos=this._index;let cc=this._source.charCodeAt(pos);while(cc===32||cc===10||cc===9||cc===13){cc=this._source.charCodeAt(++this._index);}
return this._index!==pos;},getIdentifier:function(){const start=this._index;let cc=this._source.charCodeAt(this._index);if(cc>=97&&cc<=122||cc>=65&&cc<=90||cc===95){cc=this._source.charCodeAt(++this._index);}else{throw this.error('Identifier has to start with [a-zA-Z_]');}
while(cc>=97&&cc<=122||cc>=65&&cc<=90||cc>=48&&cc<=57||cc===95){cc=this._source.charCodeAt(++this._index);}
return this._source.slice(start,this._index);},getUnicodeChar:function(){for(let i=0;i<4;i++){let cc=this._source.charCodeAt(++this._index);if(cc>96&&cc<103||cc>64&&cc<71||cc>47&&cc<58){continue;}
throw this.error('Illegal unicode escape sequence');}
this._index++;return String.fromCharCode(parseInt(this._source.slice(this._index-4,this._index),16));},stringRe:/"|'|{{|\\/g,getString:function(opchar,opcharLen){const body=[];let placeables=0;this._index+=opcharLen;const start=this._index;let bufStart=start;let buf='';while(true){this.stringRe.lastIndex=this._index;const match=this.stringRe.exec(this._source);if(!match){throw this.error('Unclosed string literal');}
if(match[0]==='"'||match[0]==='\''){if(match[0]!==opchar){this._index+=opcharLen;continue;}
this._index=match.index+opcharLen;break;}
if(match[0]==='{{'){if(placeables>MAX_PLACEABLES$1-1){throw this.error('Too many placeables, maximum allowed is '+MAX_PLACEABLES$1);}
placeables++;if(match.index>bufStart||buf.length>0){body.push(buf+this._source.slice(bufStart,match.index));buf='';}
this._index=match.index+2;this.getWS();body.push(this.getExpression());this.getWS();this._index+=2;bufStart=this._index;continue;}
if(match[0]==='\\'){this._index=match.index+1;const ch2=this._source[this._index];if(ch2==='u'){buf+=this._source.slice(bufStart,match.index)+this.getUnicodeChar();}else if(ch2===opchar||ch2==='\\'){buf+=this._source.slice(bufStart,match.index)+ch2;this._index++;}else if(this._source.startsWith('{{',this._index)){buf+=this._source.slice(bufStart,match.index)+'{{';this._index+=2;}else{throw this.error('Illegal escape sequence');}
bufStart=this._index;}}
if(body.length===0){return buf+this._source.slice(bufStart,this._index-opcharLen);}
if(this._index-opcharLen>bufStart||buf.length>0){body.push(buf+this._source.slice(bufStart,this._index-opcharLen));}
return body;},getAttributes:function(){const attrs=Object.create(null);while(true){this.getAttribute(attrs);const ws1=this.getRequiredWS();const ch=this._source.charAt(this._index);if(ch==='>'){break;}else if(!ws1){throw this.error('Expected ">"');}}
return attrs;},getAttribute:function(attrs){const key=this.getIdentifier();let index;if(this._source[this._index]==='['){++this._index;this.getWS();index=this.getItemList(this.getExpression,']');}
this.getWS();if(this._source[this._index]!==':'){throw this.error('Expected ":"');}
++this._index;this.getWS();const hasIndex=index!==undefined;const value=this.getValue(undefined,hasIndex);if(key in attrs){throw this.error('Duplicate attribute "'+key,'duplicateerror');}
if(!index&&typeof value==='string'){attrs[key]=value;}else{attrs[key]={value,index};}},getHash:function(index){const items=Object.create(null);++this._index;this.getWS();let defKey;while(true){const[key,value,def]=this.getHashItem();items[key]=value;if(def){if(defKey){throw this.error('Default item redefinition forbidden');}
defKey=key;}
this.getWS();const comma=this._source[this._index]===',';if(comma){++this._index;this.getWS();}
if(this._source[this._index]==='}'){++this._index;break;}
if(!comma){throw this.error('Expected "}"');}}
if(defKey){items.__default=defKey;}else if(!index){throw this.error('Unresolvable Hash Value');}
return items;},getHashItem:function(){let defItem=false;if(this._source[this._index]==='*'){++this._index;defItem=true;}
const key=this.getIdentifier();this.getWS();if(this._source[this._index]!==':'){throw this.error('Expected ":"');}
++this._index;this.getWS();return[key,this.getValue(),defItem];},getComment:function(){this._index+=2;const start=this._index;const end=this._source.indexOf('*/',start);if(end===-1){throw this.error('Comment without a closing tag');}
this._index=end+2;},getExpression:function(){let exp=this.getPrimaryExpression();while(true){let ch=this._source[this._index];if(ch==='.'||ch==='['){++this._index;exp=this.getPropertyExpression(exp,ch==='[');}else if(ch==='('){++this._index;exp=this.getCallExpression(exp);}else{break;}}
return exp;},getPropertyExpression:function(idref,computed){let exp;if(computed){this.getWS();exp=this.getExpression();this.getWS();if(this._source[this._index]!==']'){throw this.error('Expected "]"');}
++this._index;}else{exp=this.getIdentifier();}
return{type:'prop',expr:idref,prop:exp,cmpt:computed};},getCallExpression:function(callee){this.getWS();return{type:'call',expr:callee,args:this.getItemList(this.getExpression,')')};},getPrimaryExpression:function(){const ch=this._source[this._index];switch(ch){case'$':++this._index;return{type:'var',name:this.getIdentifier()};case'@':++this._index;return{type:'glob',name:this.getIdentifier()};default:return{type:'id',name:this.getIdentifier()};}},getItemList:function(callback,closeChar){const items=[];let closed=false;this.getWS();if(this._source[this._index]===closeChar){++this._index;closed=true;}
while(!closed){items.push(callback.call(this));this.getWS();let ch=this._source.charAt(this._index);switch(ch){case',':++this._index;this.getWS();break;case closeChar:++this._index;closed=true;break;default:throw this.error('Expected "," or "'+closeChar+'"');}}
return items;},getJunkEntry:function(){const pos=this._index;let nextEntity=this._source.indexOf('<',pos);let nextComment=this._source.indexOf('/*',pos);if(nextEntity===-1){nextEntity=this._length;}
if(nextComment===-1){nextComment=this._length;}
let nextEntry=Math.min(nextEntity,nextComment);this._index=nextEntry;},error:function(message,type='parsererror'){const pos=this._index;let start=this._source.lastIndexOf('<',pos-1);const lastClose=this._source.lastIndexOf('>',pos-1);start=lastClose>start?lastClose+1:start;const context=this._source.slice(start,pos+10);const msg=message+' at pos '+pos+': `'+context+'`';const err=new L10nError(msg);if(this.emit){this.emit(type,err);}
return err;}};function walkEntry(entry,fn){if(typeof entry==='string'){return fn(entry);}
const newEntry=Object.create(null);if(entry.value){newEntry.value=walkValue(entry.value,fn);}
if(entry.index){newEntry.index=entry.index;}
if(entry.attrs){newEntry.attrs=Object.create(null);for(let key in entry.attrs){newEntry.attrs[key]=walkEntry(entry.attrs[key],fn);}}
return newEntry;}
function walkValue(value,fn){if(typeof value==='string'){return fn(value);}
if(value.type){return value;}
const newValue=Array.isArray(value)?[]:Object.create(null);const keys=Object.keys(value);for(let i=0,key;key=keys[i];i++){newValue[key]=walkValue(value[key],fn);}
return newValue;}
function createGetter(id,name){let _pseudo=null;return function getPseudo(){if(_pseudo){return _pseudo;}
const reAlphas=/[a-zA-Z]/g;const reVowels=/[aeiouAEIOU]/g;const reWords=/[^\W0-9_]+/g;const reExcluded=/(%[EO]?\w|\{\s*.+?\s*\}|&[#\w]+;|<\s*.+?\s*>)/;const charMaps={'fr-x-psaccent':'ȦƁƇḒḖƑƓĦĪĴĶĿḾȠǾƤɊŘŞŦŬṼẆẊẎẐ[\\]^_`ȧƀƈḓḗƒɠħīĵķŀḿƞǿƥɋřşŧŭṽẇẋẏẑ','ar-x-psbidi':'∀ԐↃpƎɟפHIſӼ˥WNOԀÒᴚS⊥∩ɅMXʎZ[\\]ᵥ_,ɐqɔpǝɟƃɥıɾʞʅɯuodbɹsʇnʌʍxʎz'};const mods={'fr-x-psaccent':val=>val.replace(reVowels,match=>match+match.toLowerCase()),'ar-x-psbidi':val=>val.replace(reWords,match=>'‮'+match+'‬')};const replaceChars=(map,val)=>val.replace(reAlphas,match=>map.charAt(match.charCodeAt(0)-65));const transform=val=>replaceChars(charMaps[id],mods[id](val));const apply=(fn,val)=>{if(!val){return val;}
const parts=val.split(reExcluded);const modified=parts.map(function(part){if(reExcluded.test(part)){return part;}
return fn(part);});return modified.join('');};return _pseudo={name:transform(name),process:str=>apply(transform,str)};};}
const pseudo=Object.defineProperties(Object.create(null),{'fr-x-psaccent':{enumerable:true,get:createGetter('fr-x-psaccent','Runtime Accented')},'ar-x-psbidi':{enumerable:true,get:createGetter('ar-x-psbidi','Runtime Bidi')}});let Env=(function(){function Env(fetchResource){_classCallCheck(this,Env);this.fetchResource=fetchResource;this.resCache=new Map();this.resRefs=new Map();this.numberFormatters=null;this.parsers={properties:PropertiesParser,l20n:L20nParser};const listeners={};this.emit=emit.bind(this,listeners);this.addEventListener=addEventListener.bind(this,listeners);this.removeEventListener=removeEventListener.bind(this,listeners);}
_createClass(Env,[{key:'createContext',value:function createContext(langs,resIds){const ctx=new Context(this,langs,resIds);resIds.forEach(resId=>{const usedBy=this.resRefs.get(resId)||0;this.resRefs.set(resId,usedBy+1);});return ctx;}},{key:'destroyContext',value:function destroyContext(ctx){ctx.resIds.forEach(resId=>{const usedBy=this.resRefs.get(resId)||0;if(usedBy>1){return this.resRefs.set(resId,usedBy-1);}
this.resRefs.delete(resId);this.resCache.forEach((val,key)=>key.startsWith(resId)?this.resCache.delete(key):null);});}},{key:'_parse',value:function _parse(syntax,lang,data){const parser=this.parsers[syntax];if(!parser){return data;}
const emit=(type,err)=>this.emit(type,amendError(lang,err));return parser.parse.call(parser,emit,data);}},{key:'_create',value:function _create(lang,entries){if(lang.src!=='pseudo'){return entries;}
const pseudoentries=Object.create(null);for(let key in entries){pseudoentries[key]=walkEntry(entries[key],pseudo[lang.code].process);}
return pseudoentries;}},{key:'_getResource',value:function _getResource(lang,res){const cache=this.resCache;const id=res+lang.code+lang.src;if(cache.has(id)){return cache.get(id);}
const syntax=res.substr(res.lastIndexOf('.')+1);const saveEntries=data=>{const entries=this._parse(syntax,lang,data);cache.set(id,this._create(lang,entries));};const recover=err=>{err.lang=lang;this.emit('fetcherror',err);cache.set(id,err);};const langToFetch=lang.src==='pseudo'?{code:'en-US',src:'app',ver:lang.ver}:lang;const resource=this.fetchResource(res,langToFetch).then(saveEntries,recover);cache.set(id,resource);return resource;}}]);return Env;})();function amendError(lang,err){err.lang=lang;return err;}
function prioritizeLocales(def,availableLangs,requested){let supportedLocale;for(let i=0;i<requested.length;i++){const locale=requested[i];if(availableLangs.indexOf(locale)!==-1){supportedLocale=locale;break;}}
if(!supportedLocale||supportedLocale===def){return[def];}
return[supportedLocale,def];}
function negotiateLanguages({appVersion,defaultLang,availableLangs},additionalLangs,prevLangs,requestedLangs){const allAvailableLangs=Object.keys(availableLangs).concat(Object.keys(additionalLangs)).concat(Object.keys(pseudo));const newLangs=prioritizeLocales(defaultLang,allAvailableLangs,requestedLangs);const langs=newLangs.map(code=>({code:code,src:getLangSource(appVersion,availableLangs,additionalLangs,code),ver:appVersion}));return{langs,haveChanged:!arrEqual(prevLangs,newLangs)};}
function arrEqual(arr1,arr2){return arr1.length===arr2.length&&arr1.every((elem,i)=>elem===arr2[i]);}
function getMatchingLangpack(appVersion,langpacks){for(let i=0,langpack;langpack=langpacks[i];i++){if(langpack.target===appVersion){return langpack;}}
return null;}
function getLangSource(appVersion,availableLangs,additionalLangs,code){if(additionalLangs&&additionalLangs[code]){const lp=getMatchingLangpack(appVersion,additionalLangs[code]);if(lp&&(!(code in availableLangs)||parseInt(lp.revision)>availableLangs[code])){return'extra';}}
if(code in pseudo&&!(code in availableLangs)){return'pseudo';}
return'app';}
let Remote=(function(){function Remote(fetchResource,broadcast){_classCallCheck(this,Remote);this.broadcast=broadcast;this.env=new Env(fetchResource);this.ctxs=new Map();}
_createClass(Remote,[{key:'registerView',value:function registerView(view,resources,meta,additionalLangs,requestedLangs){const{langs}=negotiateLanguages(meta,additionalLangs,[],requestedLangs);this.ctxs.set(view,this.env.createContext(langs,resources));return langs;}},{key:'unregisterView',value:function unregisterView(view){this.ctxs.delete(view);return true;}},{key:'formatEntities',value:function formatEntities(view,keys){return this.ctxs.get(view).formatEntities(...keys);}},{key:'formatValues',value:function formatValues(view,keys){return this.ctxs.get(view).formatValues(...keys);}},{key:'changeLanguages',value:function changeLanguages(view,meta,additionalLangs,requestedLangs){const oldCtx=this.ctxs.get(view);const prevLangs=oldCtx.langs;const newLangs=negotiateLanguages(meta,additionalLangs,prevLangs,requestedLangs);this.ctxs.set(view,this.env.createContext(newLangs.langs,oldCtx.resIds));return newLangs;}},{key:'requestLanguages',value:function requestLanguages(requestedLangs){this.broadcast('languageschangerequest',requestedLangs);}},{key:'getName',value:function getName(code){return pseudo[code].name;}},{key:'processString',value:function processString(code,str){return pseudo[code].process(str);}}]);return Remote;})();const observerConfig={attributes:true,characterData:false,childList:true,subtree:true,attributeFilter:['data-l10n-id','data-l10n-args']};const observers=new WeakMap();function initMutationObserver(view){observers.set(view,{roots:new Set(),observer:new MutationObserver(mutations=>translateMutations(view,mutations))});}
function translateRoots(view){return Promise.all([...observers.get(view).roots].map(root=>_translateFragment(view,root)));}
function observe(view,root){const obs=observers.get(view);if(obs){obs.roots.add(root);obs.observer.observe(root,observerConfig);}}
function disconnect(view,root,allRoots){const obs=observers.get(view);if(obs){obs.observer.disconnect();if(allRoots){return;}
obs.roots.delete(root);obs.roots.forEach(other=>obs.observer.observe(other,observerConfig));}}
function reconnect(view){const obs=observers.get(view);if(obs){obs.roots.forEach(root=>obs.observer.observe(root,observerConfig));}}
const reOverlay=/<|&#?\w+;/;const allowed={elements:['a','em','strong','small','s','cite','q','dfn','abbr','data','time','code','var','samp','kbd','sub','sup','i','b','u','mark','ruby','rt','rp','bdi','bdo','span','br','wbr'],attributes:{global:['title','aria-label','aria-valuetext','aria-moz-hint'],a:['download'],area:['download','alt'],input:['alt','placeholder'],menuitem:['label'],menu:['label'],optgroup:['label'],option:['label'],track:['label'],img:['alt'],textarea:['placeholder'],th:['abbr']}};function overlayElement(element,translation){const value=translation.value;if(typeof value==='string'){if(!reOverlay.test(value)){element.textContent=value;}else{const tmpl=element.ownerDocument.createElement('template');tmpl.innerHTML=value;overlay(element,tmpl.content);}}
for(let key in translation.attrs){const attrName=camelCaseToDashed(key);if(isAttrAllowed({name:attrName},element)){element.setAttribute(attrName,translation.attrs[key]);}}}
function overlay(sourceElement,translationElement){const result=translationElement.ownerDocument.createDocumentFragment();let k,attr;let childElement;while(childElement=translationElement.childNodes[0]){translationElement.removeChild(childElement);if(childElement.nodeType===childElement.TEXT_NODE){result.appendChild(childElement);continue;}
const index=getIndexOfType(childElement);const sourceChild=getNthElementOfType(sourceElement,childElement,index);if(sourceChild){overlay(sourceChild,childElement);result.appendChild(sourceChild);continue;}
if(isElementAllowed(childElement)){const sanitizedChild=childElement.ownerDocument.createElement(childElement.nodeName);overlay(sanitizedChild,childElement);result.appendChild(sanitizedChild);continue;}
result.appendChild(translationElement.ownerDocument.createTextNode(childElement.textContent));}
sourceElement.textContent='';sourceElement.appendChild(result);if(translationElement.attributes){for(k=0,attr;attr=translationElement.attributes[k];k++){if(isAttrAllowed(attr,sourceElement)){sourceElement.setAttribute(attr.name,attr.value);}}}}
function isElementAllowed(element){return allowed.elements.indexOf(element.tagName.toLowerCase())!==-1;}
function isAttrAllowed(attr,element){const attrName=attr.name.toLowerCase();const tagName=element.tagName.toLowerCase();if(allowed.attributes.global.indexOf(attrName)!==-1){return true;}
if(!allowed.attributes[tagName]){return false;}
if(allowed.attributes[tagName].indexOf(attrName)!==-1){return true;}
if(tagName==='input'&&attrName==='value'){const type=element.type.toLowerCase();if(type==='submit'||type==='button'||type==='reset'){return true;}}
return false;}
function getNthElementOfType(context,element,index){let nthOfType=0;for(let i=0,child;child=context.children[i];i++){if(child.nodeType===child.ELEMENT_NODE&&child.tagName===element.tagName){if(nthOfType===index){return child;}
nthOfType++;}}
return null;}
function getIndexOfType(element){let index=0;let child;while(child=element.previousElementSibling){if(child.tagName===element.tagName){index++;}}
return index;}
function camelCaseToDashed(string){if(string==='ariaValueText'){return'aria-valuetext';}
return string.replace(/[A-Z]/g,function(match){return'-'+match.toLowerCase();}).replace(/^-/,'');}
const reHtml=/[&<>]/g;const htmlEntities={'&':'&amp;','<':'&lt;','>':'&gt;'};function setAttributes(element,id,args){element.setAttribute('data-l10n-id',id);if(args){element.setAttribute('data-l10n-args',JSON.stringify(args));}}
function getAttributes(element){return{id:element.getAttribute('data-l10n-id'),args:JSON.parse(element.getAttribute('data-l10n-args'))};}
function getTranslatables(element){const nodes=Array.from(element.querySelectorAll('[data-l10n-id]'));if(typeof element.hasAttribute==='function'&&element.hasAttribute('data-l10n-id')){nodes.push(element);}
return nodes;}
function translateMutations(view,mutations){const targets=new Set();for(let mutation of mutations){switch(mutation.type){case'attributes':targets.add(mutation.target);break;case'childList':for(let addedNode of mutation.addedNodes){if(addedNode.nodeType===addedNode.ELEMENT_NODE){if(addedNode.childElementCount){getTranslatables(addedNode).forEach(targets.add.bind(targets));}else{if(addedNode.hasAttribute('data-l10n-id')){targets.add(addedNode);}}}}
break;}}
if(targets.size===0){return;}
translateElements(view,Array.from(targets));}
function _translateFragment(view,frag){return translateElements(view,getTranslatables(frag));}
function getElementsTranslation(view,elems){const keys=elems.map(elem=>{const id=elem.getAttribute('data-l10n-id');const args=elem.getAttribute('data-l10n-args');return args?[id,JSON.parse(args.replace(reHtml,match=>htmlEntities[match]))]:id;});return view.formatEntities(...keys);}
function translateElements(view,elements){return getElementsTranslation(view,elements).then(translations=>applyTranslations(view,elements,translations));}
function applyTranslations(view,elems,translations){disconnect(view,null,true);for(let i=0;i<elems.length;i++){overlayElement(elems[i],translations[i]);}
reconnect(view);}
if(typeof NodeList==='function'&&!NodeList.prototype[Symbol.iterator]){NodeList.prototype[Symbol.iterator]=Array.prototype[Symbol.iterator];}
function documentReady(){if(document.readyState!=='loading'){return Promise.resolve();}
return new Promise(resolve=>{document.addEventListener('readystatechange',function onrsc(){document.removeEventListener('readystatechange',onrsc);resolve();});});}
function getDirection(code){const tag=code.split('-')[0];return['ar','he','fa','ps','ur'].indexOf(tag)>=0?'rtl':'ltr';}
if(navigator.languages===undefined){navigator.languages=[navigator.language];}
function getResourceLinks(head){return Array.prototype.map.call(head.querySelectorAll('link[rel="localization"]'),el=>el.getAttribute('href'));}
function getMeta(head){let availableLangs=Object.create(null);let defaultLang=null;let appVersion=null;const metas=Array.from(head.querySelectorAll('meta[name="availableLanguages"],'+'meta[name="defaultLanguage"],'+'meta[name="appVersion"]'));for(let meta of metas){const name=meta.getAttribute('name');const content=meta.getAttribute('content').trim();switch(name){case'availableLanguages':availableLangs=getLangRevisionMap(availableLangs,content);break;case'defaultLanguage':const[lang,rev]=getLangRevisionTuple(content);defaultLang=lang;if(!(lang in availableLangs)){availableLangs[lang]=rev;}
break;case'appVersion':appVersion=content;}}
return{defaultLang,availableLangs,appVersion};}
function getLangRevisionMap(seq,str){return str.split(',').reduce((seq,cur)=>{const[lang,rev]=getLangRevisionTuple(cur);seq[lang]=rev;return seq;},seq);}
function getLangRevisionTuple(str){const[lang,rev]=str.trim().split(':');return[lang,parseInt(rev)];}
const viewProps=new WeakMap();let View=(function(){function View(client,doc){_classCallCheck(this,View);this.pseudo={'fr-x-psaccent':createPseudo(this,'fr-x-psaccent'),'ar-x-psbidi':createPseudo(this,'ar-x-psbidi')};const initialized=documentReady().then(()=>init(this,client));this._interactive=initialized.then(()=>client);this.ready=initialized.then(langs=>translateView(this,langs));initMutationObserver(this);viewProps.set(this,{doc:doc,ready:false});client.on('languageschangerequest',requestedLangs=>this.requestLanguages(requestedLangs));}
_createClass(View,[{key:'requestLanguages',value:function requestLanguages(requestedLangs,isGlobal){const method=isGlobal?client=>client.method('requestLanguages',requestedLangs):client=>changeLanguages(this,client,requestedLangs);return this._interactive.then(method);}},{key:'handleEvent',value:function handleEvent(){return this.requestLanguages(navigator.languages);}},{key:'formatEntities',value:function formatEntities(...keys){return this._interactive.then(client=>client.method('formatEntities',client.id,keys));}},{key:'formatValue',value:function formatValue(id,args){return this._interactive.then(client=>client.method('formatValues',client.id,[[id,args]])).then(values=>values[0]);}},{key:'formatValues',value:function formatValues(...keys){return this._interactive.then(client=>client.method('formatValues',client.id,keys));}},{key:'translateFragment',value:function translateFragment(frag){return _translateFragment(this,frag);}},{key:'observeRoot',value:function observeRoot(root){observe(this,root);}},{key:'disconnectRoot',value:function disconnectRoot(root){disconnect(this,root);}}]);return View;})();View.prototype.setAttributes=setAttributes;View.prototype.getAttributes=getAttributes;function createPseudo(view,code){return{getName:()=>view._interactive.then(client=>client.method('getName',code)),processString:str=>view._interactive.then(client=>client.method('processString',code,str))};}
function init(view,client){const doc=viewProps.get(view).doc;const resources=getResourceLinks(doc.head);const meta=getMeta(doc.head);view.observeRoot(doc.documentElement);return getAdditionalLanguages().then(additionalLangs=>client.method('registerView',client.id,resources,meta,additionalLangs,navigator.languages));}
function changeLanguages(view,client,requestedLangs){const doc=viewProps.get(view).doc;const meta=getMeta(doc.head);return getAdditionalLanguages().then(additionalLangs=>client.method('changeLanguages',client.id,meta,additionalLangs,requestedLangs)).then(({langs,haveChanged})=>haveChanged?translateView(view,langs):undefined);}
function getAdditionalLanguages(){if(navigator.mozApps&&navigator.mozApps.getAdditionalLanguages){return navigator.mozApps.getAdditionalLanguages().catch(()=>Object.create(null));}
return Promise.resolve(Object.create(null));}
function translateView(view,langs){const props=viewProps.get(view);const html=props.doc.documentElement;if(props.ready){return translateRoots(view).then(()=>setAllAndEmit(html,langs));}
const translated=langs[0].code===html.getAttribute('lang')?Promise.resolve():translateRoots(view).then(()=>setLangDir(html,langs));return translated.then(()=>{setLangs(html,langs);props.ready=true;});}
function setLangs(html,langs){const codes=langs.map(lang=>lang.code);html.setAttribute('langs',codes.join(' '));}
function setLangDir(html,langs){const code=langs[0].code;html.setAttribute('lang',code);html.setAttribute('dir',getDirection(code));}
function setAllAndEmit(html,langs){setLangDir(html,langs);setLangs(html,langs);html.parentNode.dispatchEvent(new CustomEvent('DOMRetranslated',{bubbles:false,cancelable:false}));}
const remote=new Remote(fetchResource,broadcast);const client=new Client(remote);document.l10n=new View(client,document);window.addEventListener('languagechange',document.l10n);document.addEventListener('additionallanguageschange',document.l10n);navigator.mozL10n={setAttributes:document.l10n.setAttributes,getAttributes:document.l10n.getAttributes,formatValue:(...args)=>document.l10n.formatValue(...args),translateFragment:(...args)=>document.l10n.translateFragment(...args),once:cb=>document.l10n.ready.then(cb),ready:cb=>document.l10n.ready.then(()=>{document.addEventListener('DOMRetranslated',cb);cb();})};})();

View file

@ -0,0 +1,522 @@
html, body {
padding: 0;
border: 0;
margin: 0;
height: 100%;
overflow: hidden;
color: #FFF;
font-size: 10px;
}
/**
* 1. No content inside the app
* should be user-selectable.
*/
* {
-moz-user-select: none; /* 1 */
}
a {
outline: 0 none;
text-decoration: none;
color: #FFF;
}
a:active {
color: #000;
background-color: #00ABCD;
}
.hidden-block {
visibility: hidden;
}
#container {
height: 100%;
width: 100%;
background-color: #2F3337;
}
#container > div {
position: absolute;
left: 0;
width: 100%;
}
/****** styles for frequency view *******/
#frequency-bar {
border-bottom: 1px solid #24292E;
box-sizing: border-box;
top: 0;
height: 10rem;
width: 100%;
text-align: center;
background-color: #353A41;
overflow: hidden;
transition: background-color 680ms ease;
}
#frequency-bar.dim {
background-color: #232323;
}
#frequency-bar > div {
text-align: center;
}
#frequency-bar a {
position: absolute;
z-index: 1;
line-height: 4rem;
width: 3.8rem;
height: 3.8rem;
font-size: 1.4rem;
border-radius: 50%;
display: inline-block;
margin-top: 3rem;
box-shadow: 0 -.1rem .1rem #111;
}
#frequency-display {
position: relative;
transition: opacity 680ms ease;
}
.dim #frequency-display {
opacity: 0.1;
}
#bookmark-button {
top: 0;
right: 2rem;
}
#frequency {
font-size: 6rem;
font-weight: 300;
color: #fff;
padding-top: 1.5rem;
position: absolute;
width: 100%;
height: 10rem;
display: block;
top: 0;
left: 0;
}
#frequency small {
font-size: 1.5rem;
padding-left: 0.3rem;
}
#bookmark-button {
background: url("images/toggle-fav-star-off.png") no-repeat center center / 4rem;
}
#bookmark-button:focus {
border-color: #888;
}
#bookmark-button:active,
#bookmark-button[data-bookmarked="true"]:active {
background: #00ABCD url("images/toggle-fav-star-pressed.png") no-repeat center center / 4rem;
}
#bookmark-button[data-bookmarked="true"] {
background: url("images/toggle-fav-star-on.png") no-repeat center center / 4rem;
}
#speaker-switch {
top: 0;
left: 2rem;
background: url("images/speaker-off.png") no-repeat center center / 4rem;
}
#speaker-switch:focus {
border-color: #888;
}
#speaker-switch:active,
#speaker-switch[data-speaker-on="true"]:active {
background: #00ABCD url("images/speaker-pressed.png") no-repeat center center / 4rem;
}
#speaker-switch[data-speaker-on="true"] {
background: url("images/speaker-on.png") no-repeat center center / 4rem;
}
/***** end *****/
/**** styles for frequency dialer *****/
#dialer-bar {
top: 10rem;
font-size: 1.4rem;
font-weight: 400;
height: 9rem;
overflow: hidden;
background: #2F3337;
color: #FFF;
box-shadow: 0 0.2rem 0.4rem rgba(0, 0, 0, 0.3);
}
#dialer-container {
box-shadow: inset 0 0.05rem 0 #3A3F44;
position: relative;
padding-left: 50%;
margin: 0 2rem;
height: 100%;
}
#dialer-container:before,
#dialer-container:after {
content: "";
background-color: #474E57;
box-shadow: inset 0 0.05rem 0 #585E65;
position: absolute;
width: 2rem;
height: 100%;
z-index: 1;
pointer-events: none;
}
#dialer-container:before {
border-right: 0.1rem solid #24292E;
left: -2rem;
}
#dialer-container:after {
border-left: 0.1rem solid #24292E;
right: -2rem;
}
#frequency-indicator {
border-radius: 50%/0.1rem;
height: 8.6rem;
width: 1.6rem;
margin: 0.6rem 0 0 -0.8rem;
position: absolute;
z-index: 1;
background: url(images/selector.png) no-repeat center center / 1.6rem;
top: 0;
left: 50%;
}
div.animation-on > div {
transition: -moz-transform var(--transition-duration) ease 0s;
}
#frequency-dialer {
display: inline-block;
display: -moz-inline-box;
-moz-user-select: none;
width: 100%;
margin-left: -2.2rem;
position: absolute;
top: 0;
}
#frequency-dialer .dialer-unit-mark-box {
background: url(images/dial-notches.png) no-repeat 0 3.4rem / 32rem;
overflow: hidden;
height: 5.5rem;
}
#frequency-dialer .dialer-unit {
text-align: left;
height: 7.5rem;
position: absolute;
width: 32rem;
}
/* The beginning and end of the dial are masked to hide notches that
are out of range. */
.dialer-unit-mark-mask-start,
.dialer-unit-mark-mask-end {
background-color: #2F3337;
display: block;
height: 5.5rem;
position: absolute;
}
/* The mask at the end should be jogged left by 0.3rem, since the
mask is intended to cover everything except the first notch. */
.dialer-unit-mark-mask-end {
margin-left: .3rem;
}
#frequency-dialer .dialer-unit-floor {
color: #AAA;
float: left;
}
/**** end *******/
/***** styles for favorites list ******/
div#fav-list {
overflow: auto;
top: 19rem;
bottom: 9rem;
}
div#fav-list-container {
max-height: 100%;
position: absolute;
bottom: 0;
width: 100%;
}
div#fav-list-container > div:before {
content: "";
position: absolute;
top: 0;
left: 2rem;
right: 2rem;
width: calc(100% - 4rem);
height: .1rem;
background-color: #3D4045;
}
div#fav-list-container > div {
position: relative;
font-size: 2.3rem;
font-weight: 300;
height: 4.4rem;
padding-bottom: 0.2rem;
clear: both;
}
div#fav-list-container > div:active {
background-color: rgba(52,140,158, .6);
}
div#fav-list-container > div:active:before,
div#fav-list-container > div:active + div:before {
background-color: transparent;
}
div#fav-list-container div.fav-list-remove-button {
height: 100%;
width: 4rem;
margin-left: 2rem;
float: right;
cursor: pointer;
background: url("images/fav-star.png") no-repeat center center / 1.4rem;
}
div#fav-list-container div.selected div.fav-list-remove-button {
background: url("images/fav-star-selected.png") no-repeat center center / 1.4rem;
}
div#fav-list-container div.fav-list-frequency {
float: right;
padding: 0.8rem -moz-calc(50% - 2.4rem) 0 0;
text-align: right;
width: 6rem;
}
div#fav-list-container div.fav-list-frequency small {
font-size: 1.5rem;
position: absolute;
padding: .6rem .2rem 0 1rem;
}
/***** end *****/
/***** styles for status bars *****/
#action-bar {
bottom: 0;
border-top: .1rem solid #3A3E46;
box-shadow: 0 0 .2rem #111;
height: 9rem;
overflow: hidden;
}
/* Styles for action bar */
/* FIX: it doesn't hide itself */
#action-bar[hidden] {
display: none;
}
#action-bar > div {
text-align: center;
padding: 1rem 0 0;
width: 33.333%;
float: left;
}
#action-bar > div:first-child {
text-align: right;
}
#action-bar > div:last-child {
text-align: left;
}
#action-bar a {
display: inline-block;
border: none;
font-size: 2.5rem;
width: 7rem;
height: 7rem;
border-radius: 50%;
text-align: center;
box-shadow: 0 .1rem .1rem #A8A8A8 inset, 0 .2rem 0 #1e2226;
}
#action-bar a:active {
color: #FFF;
background-color: #00ABCD;
box-shadow: 0 .1rem .1rem #3F6978 inset, 0 .2rem 0 #1e2226;
}
#power-switch, #power-switch span {
background-image: url(images/play.png), url(images/reflection-72.png);
background-repeat: no-repeat, no-repeat;
background-color: transparent;
background-position: center center, 0 0;
background-size: 7.2rem;
overflow: hidden;
position: relative;
}
#power-switch:active {
background-image: url(images/play.png);
}
#power-switch[data-enabled="true"] {
background-image: url(images/stop.png), url(images/reflection-72.png);
}
#power-switch[data-enabled="true"]:active {
background-image: url(images/stop.png);
}
#power-switch span {
background-image: url(images/spinner-FMRadio.png);
background-size: 6.6rem;
display: none;
height: 6.6rem;
left: 0.2rem;
position: absolute;
top: 0.2rem;
width: 6.6rem;
}
#power-switch[data-enabling="true"] span,
#power-switch[data-seeking="true"] span {
animation: 0.9s spinner-animation infinite steps(30);
display: block;
}
@keyframes spinner-animation {
from {
transform: rotate(1deg);
}
to {
transform: rotate(360deg);
}
}
a#frequency-op-seekdown {
width: 5rem;
height: 5rem;
margin: 1rem 0;
background-image: url(images/seekdown.png), url(images/reflection-56.png);
background-repeat: no-repeat, no-repeat;
background-color: transparent;
background-position: center center;
background-size: 5.6rem;
}
a#frequency-op-seekdown:active {
background-image: url(images/seekdown.png);
}
a#frequency-op-seekup {
width: 5rem;
height: 5rem;
margin: 1rem 0;
background-image: url(images/seekup.png), url(images/reflection-56.png);
background-repeat: no-repeat, no-repeat;
background-color: transparent;
background-position: center center;
background-size: 5.6rem;
}
a#frequency-op-seekup:active {
background-image: url(images/seekup.png);
}
/**** end ****/
/*** styles for warning box ****/
.warning {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
color: #FFF;
background-color: #2d2d2d;
}
.warning .warning-header {
padding: 1rem 3rem 1rem 3rem;
font-weight: normal;
font-size: 1.9rem;
color: #fff;
}
.warning .warning-body {
font-weight: 300;
font-size: 2.5rem;
padding: .5rem;
border-top: .1rem solid #686868;
margin: 0 2.5rem;
}
/* Press (default & recommend) */
.warning .menu button:active {
border-color: #008aaa;
color: #333;
}
/**** end ****/
/*** styles for antenna warning box ****/
#antenna-warning {
z-index: 2;
}
#antenna-warning:not([hidden]) {
display: flex;
flex-direction: column;
}
#antenna-warning > div:first-child {
height: 60%;
background: url(images/headset.png) no-repeat center center / 18.4rem;
}
#antenna-warning .warning-header {
margin-top: -2.5rem;
}
/******* end *******/
/*** styles for airplane mode warning box ****/
#airplane-mode-warning {
z-index: 3;
}
#airplane-mode-warning .warning-header {
margin-top: 50%;
}
/******* end *******/
/*** styles for RTL languages ****/
/* The scrollbar should be on the left.
* But direction is explicitly set to LTR on #container
So we force #fav-list to be RTL, while keeping the children LTR
*/
html[dir=rtl] #fav-list {
direction: rtl;
}
html[dir=rtl] #fav-list > * {
direction: ltr;
}
/******* end *******/

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B