WiFi QR 🛜

textSize = 0 hides text

wi-fi.org/system/fil…n%20v3.2.pdf#page=25

Log in to post a comment.

// Forked from "Rounded QR 🔲" by Jurgen
// https://turtletoy.net/turtle/f9fc3f2348

//const url = 'https://turtletoy.net'; // type=string 
const ssid = 'myNetworkName'; // type=string
const security = 1; //min=0 max=2 step=1 (WEP, WPA, nopass)
const password = 'theSecretWifiPassword'; // type=string
const hidden_ssid = 0; //min=0 max=1 step=1 (No, Yes)
const wifi_certified = 2; //min=0 max=2 step=1 (No, Yes; the way you want it, Yes; the way you should have it)
const outlinesLogo = 0; //min=0 max=1 step=1 (No, Yes)
const outlineQr = 0; //min=0 max=1 step=1 (No, Yes)
const penThickness = .15; //min=.01 max=2 step=.01, Set to max for no hatching
const textSize = 1; //min=0 max=2 step=.01
const margin = 5;

// You can find the Turtle API reference here: https://turtletoy.net/syntax
Canvas.setpenopacity(1);

const url = `WIFI:S:${ssid};T:${['WEP','WPA','nopass'][security]}${password == '' || security == 2? '': `;P:${password}`}${hidden_ssid == 0? '': `;H:true`};;`;

// Global code will be evaluated once.
const turtle = new Turtle();
const polygons = new Polygons();
const text = new Text({"name":"HersheySans1","unitsPerEm":1000,"ascent":800,"descent":-200,"capHeight":500,"xHeight":300,"glyphs":"IADEDgDAIQBODE4MJOZODGj3AEBODIr9GAvF\/k4MAACEDcX+TgyK\/QBAAMAiALATmAgk5pgIxu4AQHASJOZwEsbuAEAAwCMA3Bk6ETjhmAiYCABAnBg44QQQmAgAQJgIPPHcGTzxAEBiB574nBie+ABAAMAkAJwYhA044YQN7AQAQHASOOFwEuwEAECcGNrpJhZk53ASJOaEDSTm2Alk52IH2uliB1DsmAjG7tgJ\/O9ODDzxsBOy8yYW6PRcFyj2nBie+JwYT\/wmFsX+cBIAAIQNAADYCcX+YgdP\/ABAAMAlAIgdiB0k5mIHAAAAQIQNJOYEEKToBBAQ68QOkO1ODMbu2AnG7mIHUOxiB9rpmAhk5xgLJOaEDSTmBBBk57ATpOhcF6ToEhtk54gdJOYAQJwYaPcmFp748BQU+\/AUiv1cFwAA3BkAAEgcxf6IHU\/8iB3U+RIbaPecGGj3AEAAwCYA\/h\/+Hzzx\/h\/878gexu6IHcbuSBz87xIbfPKcGJ74JhZP\/LATxf46EQAATgwAANgJxf6YCIr9YgcU+2IHnviYCCj22Ano9HAS\/O+wE8bu8BRQ7PAU2umwE2TnOhEk5sQOZOeEDdrphA1Q7MQO\/O86EbLzXBdP\/NwZxf5IHAAAyB4AAP4fxf7+H4r9AEAAwCcATgzYCaTomAhk59gJJOYYC2TnGAva6dgJUOyYCJDtAEAAwCgAOhE6ETjhxA64404MZOfYCVDsmAh88pgIaPfYCYr9Tgx2AsQOLAY6EZgIAEAAwCkAOhFiBzjh2Am4404MZOfEDlDsBBB88gQQaPfEDor9Tgx2AtgJLAZiB5gIAEAAwCoAsBOEDZDthA1P\/ABAYgc88bATnvgAQLATPPFiB574AEAAwCsA\/h+wE9rpsBMAAABAmAjo9Mge6PQAQADALADYCdgJFPuYCE\/8YgcU+5gI1PnYCRT72AmK\/WIHAAAAQADALQD+H5gI6PTIHuj0AEAAwC4A2AmYCNT5YgcU+5gIT\/zYCRT7mAjU+QBAAMAvABIbSBw44SwGmAgAQADAMACcGMQOJOYYC2TnmAgQ62IHPPFiB+j0mAgU+xgLxf7EDgAAOhEAAPAUxf5cFxT7nBjo9JwYPPFcFxDr8BRk5zoRJObEDiTmAEAAwDEAnBgYCxDrhA3a6ToRJOY6EQAAAEAAwDIAnBiYCFDsmAgQ69gJpOgYC2TnhA0k5nASJObwFGTnJhak6FwXEOtcF5DtJhb877ATsvNiBwAAnBgAAABAAMAzAJwY2Akk5lwXJOYEEPzvsBP87yYWPPFcF3zynBgo9pwYnvhcF0\/88BTF\/joRAACEDQAA2AnF\/pgIiv1iBxT7AEAAwDQAnBiwEyTmYgdo99wZaPcAQLATJOawEwAAAEAAwDUAnBgmFiTm2Akk5pgIPPHYCfzvhA3G7joRxu7wFPzvXBd88pwYKPacGJ74XBdP\/PAUxf46EQAAhA0AANgJxf6YCIr9YgcU+wBAAMA2AJwYXBfa6SYWZOdwEiTmBBAk5k4MZOfYCRDrmAg88ZgIaPfYCU\/8TgzF\/gQQAAA6EQAA8BTF\/lwXT\/ycGJ74nBho91wXsvPwFDzxOhH87wQQ\/O9ODDzx2Amy85gIaPcAQADANwCcGJwYJOZODAAAAEBiByTmnBgk5gBAAMA4AJwYhA0k5tgJZOeYCNrpmAhQ7NgJxu5ODPzvOhE88fAUfPJcF+j0nBho95wYFPtcF4r9JhbF\/nASAACEDQAA2AnF\/pgIiv1iBxT7Ygdo95gI6PQYC3zyxA488bAT\/O8mFsbuXBdQ7FwX2ukmFmTncBIk5oQNJOYAQADAOQCcGFwXxu4mFnzysBPo9AQQKPbEDij2GAvo9JgIfPJiB8buYgeQ7ZgI2ukYC2TnxA4k5gQQJOawE2TnJhba6VwXxu5cF+j0JhYU+7ATxf4EEAAAhA0AANgJxf6YCE\/8AEAAwDoA2AmYCDzxYgd88pgIsvPYCXzymAg88QBAmAjU+WIHFPuYCE\/82AkU+5gI1PkAQADAOwDYCZgIPPFiB3zymAiy89gJfPKYCDzxAEDYCRT7mAhP\/GIHFPuYCNT52AkU+9gJiv1iBwAAAEAAwDwAiB1IHNrpmAjo9EgcAAAAQADAPQD+H5gIPPHIHjzxAECYCJ74yB6e+ABAAMA+AIgdmAja6Ugc6PSYCAAAAEAAwD8AJhZiB1DsYgcQ65gIpOjYCWTnTgwk5joRJOawE2Tn8BSk6CYWEOsmFpDt8BT877ATPPHEDrLzxA5o9wBAxA6K\/YQNxf7EDgAABBDF\/sQOiv0AQADAQAA0IdwZ\/O+cGJDtJhZQ7HASUOwEEJDtxA7G7oQNfPKEDSj2xA6e+DoR1PnwFNT5XBee+JwYKPYAQHASUOwEEMbuxA588sQOKPYEEJ74OhHU+QBA3BlQ7JwYKPacGJ74EhvU+Ygd1Pn+H2j3NCGy8zQhPPH+H5DtyB4Q60gcpOjcGWTnJhYk5nASJObEDmTnTgyk6NgJEOuYCJDtYgc88WIH6PSYCJ742AkU+04Miv3EDsX+cBIAACYWAADcGcX+SByK\/YgdT\/wAQBIbUOzcGSj23Bme+BIb1PkAQADAQQAmFsQOJObsBAAAAEDEDiTmnBgAAABAmAho9\/AUaPcAQADAQgDcGZgIJOaYCAAAAECYCCTmsBMk5lwXZOecGKTo3BkQ69wZkO2cGPzvXBc88bATfPIAQJgIfPKwE3zyXBey85wY6PTcGWj33BkU+5wYiv1cF8X+sBMAAJgIAAAAQADAQwDcGdwZUOycGNrpJhZk57ATJObEDiTmTgxk59gJ2umYCFDsYgf872IHKPaYCNT52AlP\/E4Mxf7EDgAAsBMAACYWxf6cGE\/83BnU+QBAAMBEANwZmAgk5pgIAAAAQJgIJOY6ESTm8BRk51wX2umcGFDs3Bn879wZKPacGNT5XBdP\/PAUxf46EQAAmAgAAABAAMBFAFwXmAgk5pgIAAAAQJgIJOacGCTmAECYCHzycBJ88gBAmAgAAJwYAAAAQADARgAmFpgIJOaYCAAAAECYCCTmnBgk5gBAmAh88nASfPIAQADARwDcGdwZUOycGNrpJhZk57ATJObEDiTmTgxk59gJ2umYCFDsYgf872IHKPaYCNT52AlP\/E4Mxf7EDgAAsBMAACYWxf6cGE\/83BnU+dwZKPYAQLATKPbcGSj2AEAAwEgAEhuYCCTmmAgAAABA3Bkk5twZAAAAQJgIfPLcGXzyAEAAwEkA2AmYCCTmmAgAAABAAMBKALATcBIk5nAS1Pk6EYr9BBDF\/oQNAAAYCwAAmAjF\/mIHiv0sBtT5LAZo9wBAAMBLANwZmAgk5pgIAAAAQNwZJOaYCGj3AEDEDjzx3BkAAABAAMBMAPAUmAgk5pgIAAAAQJgIAABcFwAAAEAAwE0AiB2YCCTmmAgAAABAmAgk5nASAAAAQEgcJOZwEgAAAEBIHCTmSBwAAABAAMBOABIbmAgk5pgIAAAAQJgIJObcGQAAAEDcGSTm3BkAAABAAMBPABIbxA4k5k4MZOfYCdrpmAhQ7GIH\/O9iByj2mAjU+dgJT\/xODMX+xA4AALATAAAmFsX+nBhP\/NwZ1PkSGyj2Ehv879wZUOycGNrpJhZk57ATJObEDiTmAEAAwFAA3BmYCCTmmAgAAABAmAgk5rATJOZcF2TnnBik6NwZEOvcGcbunBg88VwXfPKwE7LzmAiy8wBAAMBRABIbxA4k5k4MZOfYCdrpmAhQ7GIH\/O9iByj2mAjU+dgJT\/xODMX+xA4AALATAAAmFsX+nBhP\/NwZ1PkSGyj2Ehv879wZUOycGNrpJhZk57ATJObEDiTmAEBwEhT73Bl2AgBAAMBSANwZmAgk5pgIAAAAQJgIJOawEyTmXBdk55wYpOjcGRDr3BmQ7ZwY\/O9cFzzxsBN88pgIfPIAQDoRfPLcGQAAAEAAwFMAnBicGNrpJhZk53ASJOaEDSTm2Alk52IH2uliB1DsmAjG7tgJ\/O9ODDzxsBOy8yYW6PRcFyj2nBie+JwYT\/wmFsX+cBIAAIQNAADYCcX+YgdP\/ABAAMBUALAThA0k5oQNAAAAQOwEJOYmFiTmAEAAwFUAEhuYCCTmmAie+NgJT\/xODMX+BBAAAHASAAAmFsX+nBhP\/NwZnvjcGSTmAEAAwFYAJhbsBCTmxA4AAABAnBgk5sQOAAAAQADAVwCIHSwGJOZODAAAAEBwEiTmTgwAAABAcBIk5pwYAAAAQMgeJOacGAAAAEAAwFgAnBhiByTmnBgAAABAnBgk5mIHAAAAQADAWQAmFuwEJObEDnzyxA4AAABAnBgk5sQOfPIAQADAWgCcGJwYJOZiBwAAAEBiByTmnBgk5gBAYgcAAJwYAAAAQADAWwA6EZgIOOGYCJgIAEDYCTjh2AmYCABAmAg44ToROOEAQJgImAg6EZgIAEAAwFwAOhGxAyTm8BSxAwBAAMBdADoRxA444cQOmAgAQAQQOOEEEJgIAEBiBzjhBBA44QBAYgeYCAQQmAgAQADAXgCwE4QNuOOxA+j0AECEDbjjXBfo9ABAAMBfACYWsQOYCNwZmAgAQADAYADYCdgJUOxiB8buYgc88ZgIfPLYCTzxmAj872IHPPEAQADAYQBcFyYWxu4mFgAAAEAmFnzysBP87zoRxu6EDcbuGAv875gIfPJiByj2Ygee+JgIT\/wYC8X+hA0AADoRAACwE8X+JhZP\/ABAAMBiAFwXmAgk5pgIAAAAQJgIfPIYC\/zvhA3G7joRxu6wE\/zvJhZ88lwXKPZcF574JhZP\/LATxf46EQAAhA0AABgLxf6YCE\/8AEAAwGMAJhYmFnzysBP87zoRxu6EDcbuGAv875gIfPJiByj2Ygee+JgIT\/wYC8X+hA0AADoRAACwE8X+JhZP\/ABAAMBkAFwXJhYk5iYWAAAAQCYWfPKwE\/zvOhHG7oQNxu4YC\/zvmAh88mIHKPZiB574mAhP\/BgLxf6EDQAAOhEAALATxf4mFk\/8AEAAwGUAJhZiByj2JhYo9iYWsvPwFDzxsBP87zoRxu6EDcbuGAv875gIfPJiByj2Ygee+JgIT\/wYC8X+hA0AADoRAACwE8X+JhZP\/ABAAMBmAMQOBBAk5oQNJOYYC2Tn2AkQ69gJAAAAQCwGxu7EDsbuAEAAwGcAXBcmFsbuJhZ2AvAULAawE2IHOhGYCIQNmAgYC2IHAEAmFnzysBP87zoRxu6EDcbuGAv875gIfPJiByj2Ygee+JgIT\/wYC8X+hA0AADoRAACwE8X+JhZP\/ABAAMBoAFwXmAgk5pgIAAAAQJgIsvNODPzvxA7G7nASxu7wFPzvJhay8yYWAAAAQADAaQDYCWIHJOaYCGTn2Akk5pgI7uRiByTmAECYCMbumAgAAABAAMBqAE4M2Akk5hgLZOdODCTmGAvu5NgJJOYAQBgLxu4YC7ED2AliB2IHmAjsBJgIAEAAwGsA8BSYCCTmmAgAAABA8BTG7pgIFPsAQIQNKPYmFgAAAEAAwGwA2AmYCCTmmAgAAABAAMBtAOokmAjG7pgIAAAAQJgIsvNODPzvxA7G7nASxu7wFPzvJhay8yYWAAAAQCYWsvPcGfzvSBzG7v4fxu50IvzvtCOy87QjAAAAQADAbgBcF5gIxu6YCAAAAECYCLLzTgz878QOxu5wEsbu8BT87yYWsvMmFgAAAEAAwG8AXBeEDcbuGAv875gIfPJiByj2Ygee+JgIT\/wYC8X+hA0AADoRAACwE8X+JhZP\/FwXnvhcFyj2JhZ88rAT\/O86EcbuhA3G7gBAAMBwAFwXmAjG7pgImAgAQJgIfPIYC\/zvhA3G7joRxu6wE\/zvJhZ88lwXKPZcF574JhZP\/LATxf46EQAAhA0AABgLxf6YCE\/8AEAAwHEAXBcmFsbuJhaYCABAJhZ88rAT\/O86EcbuhA3G7hgL\/O+YCHzyYgco9mIHnviYCE\/8GAvF\/oQNAAA6EQAAsBPF\/iYWT\/wAQADAcgAEEJgIxu6YCAAAAECYCCj22Al88k4M\/O\/EDsbucBLG7gBAAMBzAPAU8BR88rAT\/O8EEMbuTgzG7pgI\/O9iB3zymAjo9BgLKPY6EWj3sBOe+PAUFPvwFE\/8sBPF\/gQQAABODAAAmAjF\/mIHT\/wAQADAdADEDtgJJObYCRT7GAvF\/oQNAAAEEAAAAEAsBsbuxA7G7gBAAMB1AFwXmAjG7pgIFPvYCcX+TgwAAAQQAABwEsX+JhYU+wBAJhbG7iYWAAAAQADAdgCwEywGxu6EDQAAAEDwFMbuhA0AAABAAMB3ABIbYgfG7k4MAAAAQDoRxu5ODAAAAEA6EcbuJhYAAABAEhvG7iYWAAAAQADAeADwFGIHxu7wFAAAAEDwFMbuYgcAAABAAMB5ALATLAbG7oQNAAAAQPAUxu6EDQAAGAvsBJgIYgcsBpgI7ASYCABAAMB6APAU8BTG7mIHAAAAQGIHxu7wFMbuAEBiBwAA8BQAAABAAMB7ADoRxA444U4MeOIYC7jj2Akk5tgJpOgYCxDrTgxQ7IQNxu6EDTzxGAuy8wBATgx44hgL7uQYC2TnTgza6YQNEOvEDpDtxA7874QNfPKYCOj0hA1o98QO1PnEDk\/8hA3F\/k4MAAAYC3YCGAvsBE4MYgcAQBgLKPaEDZ74hA0U+04Miv0YC8X+2Ak7AdgJsQMYCywGTgxiB8QOmAgAQADAfADYCZgIOOGYCJgIAEAAwH0AOhHYCTjhTgx44oQNuOPEDiTmxA6k6IQNEOtODFDsGAvG7hgLPPGEDbLzAEBODHjihA3u5IQNZOdODNrpGAsQ69gJkO3YCfzvGAt88gQQ6PQYC2j32AnU+dgJT\/wYC8X+TgwAAIQNdgKEDewETgxiBwBAhA0o9hgLnvgYCxT7TgyK\/YQNxf7EDjsBxA6xA4QNLAZODGIH2AmYCABAAMB+AIgdYgee+GIHKPaYCHzyGAs88YQNPPEEEHzy8BQo9lwXaPfcGWj3SBwo9ogdsvMAQGIHKPaYCLLzGAt88oQNfPIEELLz8BRo91wXnvjcGZ74SBxo94gdsvOIHTzxAEAAwA=="});

const ssidText = 'SSID: ' + ssid;
const pwText = 'Password: ' + password;
const ssidSize = text.size(turtle, ssidText, textSize);
const pwSize = text.size(turtle, pwText, textSize);

const interLineSpace = text.dimensions(textSize).capitalHeight / 3.5;

const textHeight = ssidSize.height + pwSize.height + interLineSpace + interLineSpace + interLineSpace;

if(textSize > 0) {
    turtle.jump(-ssidSize.width/2, 100 - (ssidSize.bbox[1][1] + interLineSpace + pwSize.height + interLineSpace));
    text.print(turtle, ssidText, textSize);
    turtle.jump(-pwSize.width/2, 100 - pwSize.bbox[1][1] - interLineSpace);
    text.print(turtle, pwText, textSize);
}

const logoPaths = getLogoPaths();

const getQR = (data, type, error_level, data_type) => {
    for(let i = 0; i <= 40; i++) {
        try {
            return create_qrcode(data, i, error_level, data_type).split('\n').map(line => Array.from({length: line.length / 2}).map((e,i,a) => line[i*2] == 'â–ˆ'? false: true));
        } catch (e) {
            if(i == 40) {
                throw e;
            }
        }
    }
}
const qr = getQR(url, 0, wifi_certified > 0? 'H': 'M', 'Byte');
const sg = new SquareGrid(qr.length, margin + textHeight / 2, 0, 200, [0,-textHeight/2]);
const gridIterator = sg.iterator();

const ratio = (200 - margin - margin - textHeight) / (200 - margin - margin);

const r = .4 * 100;
if(wifi_certified > 0) {
    for(let i = 0; i < qr.length**2-1; i++) {
        const coord = sg.getCell(i % qr.length, i / qr.length | 0).center;
        if(Math.hypot(coord[0] * .9 / ratio, (coord[1] + textHeight/2) * 1.3 / ratio) < r) {
            qr[i / qr.length | 0][i % qr.length] = false;
        }
    }
}

const corners = [[-.5,-.5],[.5,-.5],[.5,.5],[-.5,.5]].map((basePt,i,a,fPlus=i*Math.PI/2) =>
    [Math.max(10, sg.getCell(0,0).size * Math.PI / 4 | 0)].map(length =>
        Array.from({length: length + 1})
             .map((e,i,a,f=i*Math.PI*.5/length) => [
                .4 * -Math.cos(f + fPlus) + basePt[0]/5,
                .4 * -Math.sin(f + fPlus) + basePt[1]/5
             ])
    ).pop()
);
const angleDroit = [[-.5,-.5], [.5,-.5], [.5,.5], [-.5,.5]];

// The walk function will be called until it returns false.
function walk(i) {
    if(wifi_certified > 0 && i < logoPaths.length) {
        logoPaths[i][0].forEach((pts) => {
            const p = polygons.create();
            p.addPoints(...pts.map(pt => [pt[0]*.38*ratio, pt[1]*.38*ratio - textHeight / 2]));
            if(penThickness < 2 && logoPaths[i][1] == '000000') p.addHatching(1,penThickness);
            if(outlinesLogo == 1) p.addOutline();
            polygons.draw(turtle, p);
        });
        return true;
    }
    
    i -= logoPaths.length;

    const iteration = gridIterator.next();
    const cell = iteration.value;

 //   if(wifi_certified > 0 && qr[cell.row][cell.column] && Math.hypot(...cell.center) < r) return true;

    function add2(a, b) { return [a[0]+b[0], a[1]+b[1]]; }
    function scale2(a, s) { return [a[0]*s,a[1]*s]; }
    
    const cv = (row, col) => {
        if(row < 0 || col < 0 || row >= qr.length || col >= qr[0].length) {
            return false;
        }
        return qr[row][col];
    }
    
    if(qr[cell.row][cell.column]) {
        const p = polygons.create();
        p.addPoints(...[
            ...( cv(cell.row, cell.column - 1) === false && cv(cell.row - 1, cell.column) === false? corners[0]: [angleDroit[0]]),
            ...( cv(cell.row, cell.column + 1) === false && cv(cell.row - 1, cell.column) === false? corners[1]: [angleDroit[1]]),
            ...( cv(cell.row, cell.column + 1) === false && cv(cell.row + 1, cell.column) === false? corners[2]: [angleDroit[2]]),
            ...( cv(cell.row, cell.column - 1) === false && cv(cell.row + 1, cell.column) === false? corners[3]: [angleDroit[3]])
        ].map(v => add2(cell.center, scale2(v, cell.size))));
        if(penThickness < 2) p.addHatching(1, penThickness);
        if(outlineQr == 1) p.addOutline();
        polygons.draw(turtle, p);
    } else {
        [
            [[-1,0],[-1,-1],[0,-1]],
            [[0,-1],[1,-1],[1,0]],
            [[1,0],[1,1],[0,1]],
            [[0,1],[-1,1],[-1,0]],
        ].forEach((deltas, cornerIndex) => {
            if(deltas.every(delta => cv(cell.row + delta[1], cell.column + delta[0]))) {
                const p = polygons.create();
                p.addPoints(...[...corners[cornerIndex], angleDroit[cornerIndex]].map(v => add2(cell.center, scale2(v, cell.size))));
                if(penThickness < 2) p.addHatching(1, penThickness);
                if(outlineQr == 1) p.addOutline();
                polygons.draw(turtle, p);
            }
        });
    }
    
    return !iteration.done;
}

////////////////////////////////////////////////////////////////
// Square Grid utility code - Created by Jurgen Westerhof 2024
// https://turtletoy.net/turtle/f9fc3f2348
////////////////////////////////////////////////////////////////
function SquareGrid(grid, margin = 5, padding=2, canvasSize = 200, transpose = [0,0]) {
    class SquareGrid {
        constructor(grid, margin = 5, padding = 2, canvasSize = 200, transpose = [0,0]) { this.gridSize = grid;this.padding = padding; this.transpose = transpose;this.margin = margin; this.canvasSize = canvasSize; this.resetCellSize(); }
        resetCellSize() { this.cellSize = ((this.canvasSize - this.margin - this.margin - ((this.gridSize - 1) * this.padding)) / this.gridSize); }
        getColumnRow(i) { return [i % this.gridSize, i / this.gridSize | 0]; }
        getCellCenter(col, row) { return [col, row].map((v, i) => this.margin - 100 + (v * this.padding) + ((v + .5) * this.cellSize) + this.transpose[i]); }
        getCell(col, row) { return { center: this.getCellCenter(col, row), column: col, row: row, size: this.cellSize }}
        get length() { return this.gridSize**2; }
        *iterator() { let ptr = 0; while(ptr < this.length - 1) { yield this.getCell(...this.getColumnRow(ptr++)); } return this.getCell(...this.getColumnRow(ptr++)); }
    }
    return new SquareGrid(grid, margin, padding, canvasSize, transpose);
}


////////////////////////////////////////////////////////////////
// Polygon Clipping utility code - Created by Reinder Nijhoff 2019
// (Polygon binning by Lionel Lemarie 2021)
// https://turtletoy.net/turtle/a5befa1f8d
////////////////////////////////////////////////////////////////
function Polygons(){const t=[],s=25,e=Array.from({length:s**2},t=>[]),n=class{constructor(){this.cp=[],this.dp=[],this.aabb=[]}addPoints(...t){let s=1e5,e=-1e5,n=1e5,h=-1e5;(this.cp=[...this.cp,...t]).forEach(t=>{s=Math.min(s,t[0]),e=Math.max(e,t[0]),n=Math.min(n,t[1]),h=Math.max(h,t[1])}),this.aabb=[s,n,e,h]}addSegments(...t){t.forEach(t=>this.dp.push(t))}addOutline(){for(let t=0,s=this.cp.length;t<s;t++)this.dp.push(this.cp[t],this.cp[(t+1)%s])}draw(t){for(let s=0,e=this.dp.length;s<e;s+=2)t.jump(this.dp[s]),t.goto(this.dp[s+1])}addHatching(t,s){const e=new n;e.cp.push([-1e5,-1e5],[1e5,-1e5],[1e5,1e5],[-1e5,1e5]);const h=Math.sin(t)*s,o=Math.cos(t)*s,a=200*Math.sin(t),i=200*Math.cos(t);for(let t=.5;t<150/s;t++)e.dp.push([h*t+i,o*t-a],[h*t-i,o*t+a]),e.dp.push([-h*t+i,-o*t-a],[-h*t-i,-o*t+a]);e.boolean(this,!1),this.dp=[...this.dp,...e.dp]}inside(t){let s=0;for(let e=0,n=this.cp.length;e<n;e++)this.segment_intersect(t,[.1,-1e3],this.cp[e],this.cp[(e+1)%n])&&s++;return 1&s}boolean(t,s=!0){const e=[];for(let n=0,h=this.dp.length;n<h;n+=2){const h=this.dp[n],o=this.dp[n+1],a=[];for(let s=0,e=t.cp.length;s<e;s++){const n=this.segment_intersect(h,o,t.cp[s],t.cp[(s+1)%e]);!1!==n&&a.push(n)}if(0===a.length)s===!t.inside(h)&&e.push(h,o);else{a.push(h,o);const n=o[0]-h[0],i=o[1]-h[1];a.sort((t,s)=>(t[0]-h[0])*n+(t[1]-h[1])*i-(s[0]-h[0])*n-(s[1]-h[1])*i);for(let n=0;n<a.length-1;n++)(a[n][0]-a[n+1][0])**2+(a[n][1]-a[n+1][1])**2>=.001&&s===!t.inside([(a[n][0]+a[n+1][0])/2,(a[n][1]+a[n+1][1])/2])&&e.push(a[n],a[n+1])}}return(this.dp=e).length>0}segment_intersect(t,s,e,n){const h=(n[1]-e[1])*(s[0]-t[0])-(n[0]-e[0])*(s[1]-t[1]);if(0===h)return!1;const o=((n[0]-e[0])*(t[1]-e[1])-(n[1]-e[1])*(t[0]-e[0]))/h,a=((s[0]-t[0])*(t[1]-e[1])-(s[1]-t[1])*(t[0]-e[0]))/h;return o>=0&&o<=1&&a>=0&&a<=1&&[t[0]+o*(s[0]-t[0]),t[1]+o*(s[1]-t[1])]}};return{list:()=>t,create:()=>new n,draw:(n,h,o=!0)=>{reducedPolygonList=function(n){const h={},o=200/s;for(var a=0;a<s;a++){const c=a*o-100,r=[0,c,200,c+o];if(!(n[3]<r[1]||n[1]>r[3]))for(var i=0;i<s;i++){const c=i*o-100;r[0]=c,r[2]=c+o,n[0]>r[2]||n[2]<r[0]||e[i+a*s].forEach(s=>{const e=t[s];n[3]<e.aabb[1]||n[1]>e.aabb[3]||n[0]>e.aabb[2]||n[2]<e.aabb[0]||(h[s]=1)})}}return Array.from(Object.keys(h),s=>t[s])}(h.aabb);for(let t=0;t<reducedPolygonList.length&&h.boolean(reducedPolygonList[t]);t++);h.draw(n),o&&function(n){t.push(n);const h=t.length-1,o=200/s;e.forEach((t,e)=>{const a=e%s*o-100,i=(e/s|0)*o-100,c=[a,i,a+o,i+o];c[3]<n.aabb[1]||c[1]>n.aabb[3]||c[0]>n.aabb[2]||c[2]<n.aabb[0]||t.push(h)})}(h)}}}


////////////////////////////////////////////////////////////////
// Text utility code. Created by Reinder Nijhoff 2024
// https://turtletoy.net/turtle/0f84fd3ae4
// Modifications by Jurgen Westerhof 2024: https://turtletoy.net/turtle/9aef87b45e
// - Does not force turtle to operate in radians
// - Now respects turtle.isdown() and doesn't print if true
// - Text.size(turtle, str, scale = 1) returns properties of text str to be printed
// - Text.bbox(turtle, str, scale = 1) returns bounding box of text str to be printed
// - Text.dimensions(scale = 1) returns properties of fontData for scale
// - Text.bboxPrint(turtle, str, scale = 1) prints the text and returns the absolute bounding box
////////////////////////////////////////////////////////////////
function Text(fontData) {
    const decode = (data) => {
        const b = atob(data), a = new Int16Array(b.length / 2), g = {};
        for (let i = 0; i < b.length; i+=2) {
            a[i / 2 | 0] = b.charCodeAt(i) | (b.charCodeAt(i + 1) << 8);
        }
        for (let i = 0;i < a.length; i++) {
            let u = String.fromCharCode(a[i++]), x = a[i++], d = [], p = [];
            for (;a[i] !== -16384; i++) a[i] === 16384 ? (d.push(p), p = []) : p.push(a[i]);
            g[u] = { x, d };
        }
        return g;
    }
    const rotAdd = (a, b, h) => [Math.cos(h)*a[0] - Math.sin(h)*a[1] + b[0],
                                 Math.cos(h)*a[1] + Math.sin(h)*a[0] + b[1]];

    const data = Object.fromEntries(Object.entries(fontData).map(([key, value]) =>
        [key, key === 'glyphs' ? decode(value) : value]));

    class RangeFinderTurtle extends Turtle {
        constructor(x, y) {super(x, y);this.reset();}
        goto(x, y) {super.goto(x, y);const [a, b] = this.pos();this.rangeX = [Math.min(a, this.rangeX? this.rangeX[0]: a), Math.max(a, this.rangeX? this.rangeX[1]: a)];this.rangeY = [Math.min(b, this.rangeY? this.rangeY[0]: b), Math.max(b, this.rangeY? this.rangeY[1]: b)];}
        reset() {const [a, b] = this.pos();this.rangeX = [a, a];this.rangeY = [b, b];}
        bbox() { return [[this.rangeX[0], this.rangeY[0]], [this.rangeX[1], this.rangeY[1]]]; }
    }
    
    class Text {
        print (t, str, scale = 1) {
            const isDown = t && t.isdown();
            let pos = t ? [t.x(), t.y()] : [0,0], h = t ? t.h() * 2*Math.PI/t.fullCircle() : 0, o = pos, s = scale / data.unitsPerEm;
            str.split('').map(c => {
                if (c == '\n') {
                    pos = o = rotAdd([0, 10 * scale], o, h);
                    return;
                }
                const glyph = (data.glyphs[c] || data.glyphs[' ']), d = glyph.d;
                d.forEach( (p, k) => {
                    t && t.up();
                    for (let i=0; i<p.length; i+=2) {
                        t && t.goto(rotAdd([p[i]*s, p[i+1]*s], pos, h));
                        t && (!isDown || t.down());
                    }
                });
                pos = rotAdd([glyph.x*s, 0], pos, h);
            });
            if(isDown) t.down();
            return rotAdd([0, 10*scale], pos, h);
        }
        bboxPrint(t, str, scale = 1) {
            const rft = new RangeFinderTurtle(t.pos());
            rft.degrees(t.fullCircle());
            rft.seth(t.h());
            rft.up();
            this.print(rft, str, scale);
            this.print(t, str, scale);
            return rft.bbox();
        }
        size(t, str, scale = 1) {
            const rft = new RangeFinderTurtle();
            rft.up();
            this.print(rft, str, scale);
            return {
                width: rft.rangeX[1] - rft.rangeX[0],
                height: rft.rangeY[1] - rft.rangeY[0],
                bbox: t.h() === 0? rft.bbox(): this.bbox(t, str, scale)
            }
        }
        bbox(t, str, scale = 1) {
            const rft = new RangeFinderTurtle();
            rft.degrees(t.fullCircle());
            rft.seth(t.h());

            rft.up();
            this.print(rft, str, scale);
            return rft.bbox();
        }
        dimensions(scale = 1, standardCharacter = 'x') {
            const t = new Turtle();
            const x        = this.size(t, standardCharacter, scale);
            const allLower = this.size(t, 'abcdefghijklmnopqrstuvwxyz', scale);
            const allUpper = this.size(t, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', scale);
            // property names from: https://www.onlineprinters.co.uk/magazine/font-sizes/
            return {
                height: x.height,
                width: x.width,
                ascenders: Math.abs(allLower.bbox[0][1]) - x.height,
                descenders: Math.abs(allLower.bbox[1][1]),
                capitalHeight: Math.abs(allUpper.bbox[0][1]),
                capitalDescenders: Math.abs(allUpper.bbox[1][1])
            };
        }
    }

    return new Text();
}

function create_qrcode(text, typeNumber, errorCorrectionLevel, mode) {
//---------------------------------------------------------------------
// QR Code Generator for JavaScript
// Copyright (c) 2009 Kazuhiko Arase
// URL: http://www.d-project.com/
//
// Licensed under the MIT license:
//  http://www.opensource.org/licenses/mit-license.php
//
// The word 'QR Code' is registered trademark of
// DENSO WAVE INCORPORATED
//  http://www.denso-wave.com/qrcode/faqpatent-e.html
//---------------------------------------------------------------------
var qrcode = function() {
  //---------------------------------------------------------------------
  // qrcode
  //---------------------------------------------------------------------
  /**
   * qrcode
   * @param typeNumber 1 to 40
   * @param errorCorrectionLevel 'L','M','Q','H'
   */
  var qrcode = function(typeNumber, errorCorrectionLevel) {
    var PAD0 = 0xEC;
    var PAD1 = 0x11;

    var _typeNumber = typeNumber;
    var _errorCorrectionLevel = QRErrorCorrectionLevel[errorCorrectionLevel];
    var _modules = null;
    var _moduleCount = 0;
    var _dataCache = null;
    var _dataList = [];

    var _this = {};

    var makeImpl = function(test, maskPattern) {_moduleCount = _typeNumber * 4 + 17;_modules = function(moduleCount) {var modules = new Array(moduleCount);for (var row = 0; row < moduleCount; row += 1) {modules[row] = new Array(moduleCount);for (var col = 0; col < moduleCount; col += 1) {modules[row][col] = null;}}return modules;}(_moduleCount);setupPositionProbePattern(0, 0);setupPositionProbePattern(_moduleCount - 7, 0);setupPositionProbePattern(0, _moduleCount - 7);setupPositionAdjustPattern();setupTimingPattern();setupTypeInfo(test, maskPattern);if (_typeNumber >= 7) {setupTypeNumber(test);}if (_dataCache == null) {_dataCache = createData(_typeNumber, _errorCorrectionLevel, _dataList);}mapData(_dataCache, maskPattern);};
    var setupPositionProbePattern = function(row, col) {for (var r = -1; r <= 7; r += 1) {if (row + r <= -1 || _moduleCount <= row + r) continue;for (var c = -1; c <= 7; c += 1) {if (col + c <= -1 || _moduleCount <= col + c) continue;if ( (0 <= r && r <= 6 && (c == 0 || c == 6) )|| (0 <= c && c <= 6 && (r == 0 || r == 6) )|| (2 <= r && r <= 4 && 2 <= c && c <= 4) ) {_modules[row + r][col + c] = true;} else {_modules[row + r][col + c] = false;}}}};
    var getBestMaskPattern = function() {var minLostPoint = 0;var pattern = 0;for (var i = 0; i < 8; i += 1) {makeImpl(true, i);var lostPoint = QRUtil.getLostPoint(_this);if (i == 0 || minLostPoint > lostPoint) {minLostPoint = lostPoint;pattern = i;}}return pattern;};
    var setupTimingPattern = function() {for (var r = 8; r < _moduleCount - 8; r += 1) {if (_modules[r][6] != null) {continue;}_modules[r][6] = (r % 2 == 0);}for (var c = 8; c < _moduleCount - 8; c += 1) {if (_modules[6][c] != null) {continue;}_modules[6][c] = (c % 2 == 0);}};
    var setupPositionAdjustPattern = function() {var pos = QRUtil.getPatternPosition(_typeNumber);for (var i = 0; i < pos.length; i += 1) {for (var j = 0; j < pos.length; j += 1) {var row = pos[i];var col = pos[j];if (_modules[row][col] != null) {continue;}for (var r = -2; r <= 2; r += 1) {for (var c = -2; c <= 2; c += 1) {if (r == -2 || r == 2 || c == -2 || c == 2|| (r == 0 && c == 0) ) {_modules[row + r][col + c] = true;} else {_modules[row + r][col + c] = false;}}}}}};
    var setupTypeNumber = function(test) {var bits = QRUtil.getBCHTypeNumber(_typeNumber);for (var i = 0; i < 18; i += 1) {var mod = (!test && ( (bits >> i) & 1) == 1);_modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod;}for (var i = 0; i < 18; i += 1) {var mod = (!test && ( (bits >> i) & 1) == 1);_modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod;}};
    var setupTypeInfo = function(test, maskPattern) {var data = (_errorCorrectionLevel << 3) | maskPattern;var bits = QRUtil.getBCHTypeInfo(data);for (var i = 0; i < 15; i += 1) {var mod = (!test && ( (bits >> i) & 1) == 1);if (i < 6) {_modules[i][8] = mod;} else if (i < 8) {_modules[i + 1][8] = mod;} else {_modules[_moduleCount - 15 + i][8] = mod;}}for (var i = 0; i < 15; i += 1) {var mod = (!test && ( (bits >> i) & 1) == 1);if (i < 8) {_modules[8][_moduleCount - i - 1] = mod;} else if (i < 9) {_modules[8][15 - i - 1 + 1] = mod;} else {_modules[8][15 - i - 1] = mod;}}_modules[_moduleCount - 8][8] = (!test);};
    var mapData = function(data, maskPattern) {var inc = -1;var row = _moduleCount - 1;var bitIndex = 7;var byteIndex = 0;var maskFunc = QRUtil.getMaskFunction(maskPattern);for (var col = _moduleCount - 1; col > 0; col -= 2) {if (col == 6) col -= 1;while (true) {for (var c = 0; c < 2; c += 1) {if (_modules[row][col - c] == null) {var dark = false;if (byteIndex < data.length) {dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1);}var mask = maskFunc(row, col - c);if (mask) {dark = !dark;}_modules[row][col - c] = dark;bitIndex -= 1;if (bitIndex == -1) {byteIndex += 1;bitIndex = 7;}}}row += inc;if (row < 0 || _moduleCount <= row) {row -= inc;inc = -inc;break;}}}};
    var createBytes = function(buffer, rsBlocks) {var offset = 0;var maxDcCount = 0;var maxEcCount = 0;var dcdata = new Array(rsBlocks.length);var ecdata = new Array(rsBlocks.length);for (var r = 0; r < rsBlocks.length; r += 1) {var dcCount = rsBlocks[r].dataCount;var ecCount = rsBlocks[r].totalCount - dcCount;maxDcCount = Math.max(maxDcCount, dcCount);maxEcCount = Math.max(maxEcCount, ecCount);dcdata[r] = new Array(dcCount);for (var i = 0; i < dcdata[r].length; i += 1) {dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset];}offset += dcCount;var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);var rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1);var modPoly = rawPoly.mod(rsPoly);ecdata[r] = new Array(rsPoly.getLength() - 1);for (var i = 0; i < ecdata[r].length; i += 1) {var modIndex = i + modPoly.getLength() - ecdata[r].length;ecdata[r][i] = (modIndex >= 0)? modPoly.getAt(modIndex) : 0;}}var totalCodeCount = 0;for (var i = 0; i < rsBlocks.length; i += 1) {totalCodeCount += rsBlocks[i].totalCount;}var data = new Array(totalCodeCount);var index = 0;for (var i = 0; i < maxDcCount; i += 1) {for (var r = 0; r < rsBlocks.length; r += 1) {if (i < dcdata[r].length) {data[index] = dcdata[r][i];index += 1;}}}for (var i = 0; i < maxEcCount; i += 1) {for (var r = 0; r < rsBlocks.length; r += 1) {if (i < ecdata[r].length) {data[index] = ecdata[r][i];index += 1;}}}return data;};
    var createData = function(typeNumber, errorCorrectionLevel, dataList) {var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectionLevel);var buffer = qrBitBuffer();for (var i = 0; i < dataList.length; i += 1) {var data = dataList[i];buffer.put(data.getMode(), 4);buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) );data.write(buffer);}var totalDataCount = 0;for (var i = 0; i < rsBlocks.length; i += 1) {totalDataCount += rsBlocks[i].dataCount;}if (buffer.getLengthInBits() > totalDataCount * 8) {throw 'code length overflow. ('+ buffer.getLengthInBits()+ '>'+ totalDataCount * 8+ ')';}if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {buffer.put(0, 4);}while (buffer.getLengthInBits() % 8 != 0) {buffer.putBit(false);}while (true) {if (buffer.getLengthInBits() >= totalDataCount * 8) {break;}buffer.put(PAD0, 8);if (buffer.getLengthInBits() >= totalDataCount * 8) {break;}buffer.put(PAD1, 8);}return createBytes(buffer, rsBlocks);};

    _this.addData = function(data, mode) {mode = mode || 'Byte';var newData = null;switch(mode) {case 'Numeric' :newData = qrNumber(data);break;case 'Alphanumeric' :newData = qrAlphaNum(data);break;case 'Byte' :newData = qr8BitByte(data);break;case 'Kanji' :newData = qrKanji(data);break;default :throw 'mode:' + mode;}_dataList.push(newData);_dataCache = null;};
    _this.isDark = function(row, col) {if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) {throw row + ',' + col;}return _modules[row][col];};
    _this.getModuleCount = function() {return _moduleCount;};
    _this.make = function() {if (_typeNumber < 1) {var typeNumber = 1;for (; typeNumber < 40; typeNumber++) {var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, _errorCorrectionLevel);var buffer = qrBitBuffer();for (var i = 0; i < _dataList.length; i++) {var data = _dataList[i];buffer.put(data.getMode(), 4);buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) );data.write(buffer);}var totalDataCount = 0;for (var i = 0; i < rsBlocks.length; i++) {totalDataCount += rsBlocks[i].dataCount;}if (buffer.getLengthInBits() <= totalDataCount * 8) {break;}}_typeNumber = typeNumber;}makeImpl(false, getBestMaskPattern() );};
    _this.createTableTag = function(cellSize, margin) {cellSize = cellSize || 2;margin = (typeof margin == 'undefined')? cellSize * 4 : margin;var qrHtml = '';qrHtml += '<table style="';qrHtml += ' border-width: 0px; border-style: none;';qrHtml += ' border-collapse: collapse;';qrHtml += ' padding: 0px; margin: ' + margin + 'px;';qrHtml += '">';qrHtml += '<tbody>';for (var r = 0; r < _this.getModuleCount(); r += 1) {qrHtml += '<tr>';for (var c = 0; c < _this.getModuleCount(); c += 1) {qrHtml += '<td style="';qrHtml += ' border-width: 0px; border-style: none;';qrHtml += ' border-collapse: collapse;';qrHtml += ' padding: 0px; margin: 0px;';qrHtml += ' width: ' + cellSize + 'px;';qrHtml += ' height: ' + cellSize + 'px;';qrHtml += ' background-color: ';qrHtml += _this.isDark(r, c)? '#000000' : '#ffffff';qrHtml += ';';qrHtml += '"/>';}qrHtml += '</tr>';}qrHtml += '</tbody>';qrHtml += '</table>';return qrHtml;};
    _this.createSvgTag = function(cellSize, margin, alt, title) {var opts = {};if (typeof arguments[0] == 'object') {opts = arguments[0];cellSize = opts.cellSize;margin = opts.margin;alt = opts.alt;title = opts.title;}cellSize = cellSize || 2;margin = (typeof margin == 'undefined')? cellSize * 4 : margin;alt = (typeof alt === 'string') ? {text: alt} : alt || {};alt.text = alt.text || null;alt.id = (alt.text) ? alt.id || 'qrcode-description' : null;title = (typeof title === 'string') ? {text: title} : title || {};title.text = title.text || null;title.id = (title.text) ? title.id || 'qrcode-title' : null;var size = _this.getModuleCount() * cellSize + margin * 2;var c, mc, r, mr, qrSvg='', rect;rect = 'l' + cellSize + ',0 0,' + cellSize +' -' + cellSize + ',0 0,-' + cellSize + 'z ';qrSvg += '<svg version="1.1" xmlns="http://www.w3.org/2000/svg"';qrSvg += !opts.scalable ? ' width="' + size + 'px" height="' + size + 'px"' : '';qrSvg += ' viewBox="0 0 ' + size + ' ' + size + '" ';qrSvg += ' preserveAspectRatio="xMinYMin meet"';qrSvg += (title.text || alt.text) ? ' role="img" aria-labelledby="' +escapeXml([title.id, alt.id].join(' ').trim() ) + '"' : '';qrSvg += '>';qrSvg += (title.text) ? '<title id="' + escapeXml(title.id) + '">' +escapeXml(title.text) + '</title>' : '';qrSvg += (alt.text) ? '<description id="' + escapeXml(alt.id) + '">' +escapeXml(alt.text) + '</description>' : '';qrSvg += '<rect width="100%" height="100%" fill="white" cx="0" cy="0"/>';qrSvg += '<path d="';for (r = 0; r < _this.getModuleCount(); r += 1) {mr = r * cellSize + margin;for (c = 0; c < _this.getModuleCount(); c += 1) {if (_this.isDark(r, c) ) {mc = c*cellSize+margin;qrSvg += 'M' + mc + ',' + mr + rect;}}}qrSvg += '" stroke="transparent" fill="black"/>';qrSvg += '</svg>';return qrSvg;};
    _this.createDataURL = function(cellSize, margin) {cellSize = cellSize || 2;margin = (typeof margin == 'undefined')? cellSize * 4 : margin;var size = _this.getModuleCount() * cellSize + margin * 2;var min = margin;var max = size - margin;return createDataURL(size, size, function(x, y) {if (min <= x && x < max && min <= y && y < max) {var c = Math.floor( (x - min) / cellSize);var r = Math.floor( (y - min) / cellSize);return _this.isDark(r, c)? 0 : 1;} else {return 1;}});};
    _this.createImgTag = function(cellSize, margin, alt) {cellSize = cellSize || 2;margin = (typeof margin == 'undefined')? cellSize * 4 : margin;var size = _this.getModuleCount() * cellSize + margin * 2;var img = '';img += '<img';img += '\u0020src="';img += _this.createDataURL(cellSize, margin);img += '"';img += '\u0020width="';img += size;img += '"';img += '\u0020height="';img += size;img += '"';if (alt) {img += '\u0020alt="';img += escapeXml(alt);img += '"';}img += '/>';return img;};

    var escapeXml = function(s) {var escaped = '';for (var i = 0; i < s.length; i += 1) {var c = s.charAt(i);switch(c) {case '<': escaped += '&lt;'; break;case '>': escaped += '&gt;'; break;case '&': escaped += '&amp;'; break;case '"': escaped += '&quot;'; break;default : escaped += c; break;}}return escaped;};
    var _createHalfASCII = function(margin) {var cellSize = 1;margin = (typeof margin == 'undefined')? cellSize * 2 : margin;var size = _this.getModuleCount() * cellSize + margin * 2;var min = margin;var max = size - margin;var y, x, r1, r2, p;var blocks = {'██': '█','█ ': '▀',' █': '▄','  ': ' '};var blocksLastLineNoMargin = {'██': '▀','█ ': '▀',' █': ' ','  ': ' '};var ascii = '';for (y = 0; y < size; y += 2) {r1 = Math.floor((y - min) / cellSize);r2 = Math.floor((y + 1 - min) / cellSize);for (x = 0; x < size; x += 1) {p = '█';if (min <= x && x < max && min <= y && y < max && _this.isDark(r1, Math.floor((x - min) / cellSize))) {p = ' ';}if (min <= x && x < max && min <= y+1 && y+1 < max && _this.isDark(r2, Math.floor((x - min) / cellSize))) {p += ' ';}else {p += '█';}ascii += (margin < 1 && y+1 >= max) ? blocksLastLineNoMargin[p] : blocks[p];}ascii += '\n';}if (size % 2 && margin > 0) {return ascii.substring(0, ascii.length - size - 1) + Array(size+1).join('▀');}return ascii.substring(0, ascii.length-1);};

    _this.createASCII = function(cellSize, margin) {cellSize = cellSize || 1;if (cellSize < 2) {return _createHalfASCII(margin);}cellSize -= 1;margin = (typeof margin == 'undefined')? cellSize * 2 : margin;var size = _this.getModuleCount() * cellSize + margin * 2;var min = margin;var max = size - margin;var y, x, r, p;var white = Array(cellSize+1).join('██');var black = Array(cellSize+1).join('  ');var ascii = '';var line = '';for (y = 0; y < size; y += 1) {r = Math.floor( (y - min) / cellSize);line = '';for (x = 0; x < size; x += 1) {p = 1;if (min <= x && x < max && min <= y && y < max && _this.isDark(r, Math.floor((x - min) / cellSize))) {p = 0;}line += p ? white : black;}for (r = 0; r < cellSize; r += 1) {ascii += line + '\n';}}return ascii.substring(0, ascii.length-1);};
    _this.renderTo2dContext = function(context, cellSize) {cellSize = cellSize || 2;var length = _this.getModuleCount();for (var row = 0; row < length; row++) {for (var col = 0; col < length; col++) {context.fillStyle = _this.isDark(row, col) ? 'black' : 'white';context.fillRect(row * cellSize, col * cellSize, cellSize, cellSize);}}}

    return _this;
  };

  //---------------------------------------------------------------------
  // qrcode.stringToBytes
  //---------------------------------------------------------------------
  qrcode.stringToBytesFuncs = {'default' : function(s) {var bytes = [];for (var i = 0; i < s.length; i += 1) {var c = s.charCodeAt(i);bytes.push(c & 0xff);}return bytes;}};
  qrcode.stringToBytes = qrcode.stringToBytesFuncs['default'];
  //---------------------------------------------------------------------
  // qrcode.createStringToBytes
  //---------------------------------------------------------------------
  /**
   * @param unicodeData base64 string of byte array.
   * [16bit Unicode],[16bit Bytes], ...
   * @param numChars
   */
  qrcode.createStringToBytes = function(unicodeData, numChars) {var unicodeMap = function() {var bin = base64DecodeInputStream(unicodeData);var read = function() {var b = bin.read();if (b == -1) throw 'eof';return b;};var count = 0;var unicodeMap = {};while (true) {var b0 = bin.read();if (b0 == -1) break;var b1 = read();var b2 = read();var b3 = read();var k = String.fromCharCode( (b0 << 8) | b1);var v = (b2 << 8) | b3;unicodeMap[k] = v;count += 1;}if (count != numChars) {throw count + ' != ' + numChars;}return unicodeMap;}();var unknownChar = '?'.charCodeAt(0);return function(s) {var bytes = [];for (var i = 0; i < s.length; i += 1) {var c = s.charCodeAt(i);if (c < 128) {bytes.push(c);} else {var b = unicodeMap[s.charAt(i)];if (typeof b == 'number') {if ( (b & 0xff) == b) {bytes.push(b);} else {bytes.push(b >>> 8);bytes.push(b & 0xff);}} else {bytes.push(unknownChar);}}}return bytes;};};
  //---------------------------------------------------------------------
  // QRMode
  //---------------------------------------------------------------------
  var QRMode = {MODE_NUMBER :    1 << 0,MODE_ALPHA_NUM : 1 << 1,MODE_8BIT_BYTE : 1 << 2,MODE_KANJI :     1 << 3};
  //---------------------------------------------------------------------
  // QRErrorCorrectionLevel
  //---------------------------------------------------------------------
  var QRErrorCorrectionLevel = {L : 1,M : 0,Q : 3,H : 2};
  //---------------------------------------------------------------------
  // QRMaskPattern
  //---------------------------------------------------------------------
  var QRMaskPattern = {PATTERN000 : 0,PATTERN001 : 1,PATTERN010 : 2,PATTERN011 : 3,PATTERN100 : 4,PATTERN101 : 5,PATTERN110 : 6,PATTERN111 : 7};
  //---------------------------------------------------------------------
  // QRUtil
  //---------------------------------------------------------------------
  var QRUtil = function() {var PATTERN_POSITION_TABLE = [[],[6, 18],[6, 22],[6, 26],[6, 30],[6, 34],[6, 22, 38],[6, 24, 42],[6, 26, 46],[6, 28, 50],[6, 30, 54],[6, 32, 58],[6, 34, 62],[6, 26, 46, 66],[6, 26, 48, 70],[6, 26, 50, 74],[6, 30, 54, 78],[6, 30, 56, 82],[6, 30, 58, 86],[6, 34, 62, 90],[6, 28, 50, 72, 94],[6, 26, 50, 74, 98],[6, 30, 54, 78, 102],[6, 28, 54, 80, 106],[6, 32, 58, 84, 110],[6, 30, 58, 86, 114],[6, 34, 62, 90, 118],[6, 26, 50, 74, 98, 122],[6, 30, 54, 78, 102, 126],[6, 26, 52, 78, 104, 130],[6, 30, 56, 82, 108, 134],[6, 34, 60, 86, 112, 138],[6, 30, 58, 86, 114, 142],[6, 34, 62, 90, 118, 146],[6, 30, 54, 78, 102, 126, 150],[6, 24, 50, 76, 102, 128, 154],[6, 28, 54, 80, 106, 132, 158],[6, 32, 58, 84, 110, 136, 162],[6, 26, 54, 82, 110, 138, 166],[6, 30, 58, 86, 114, 142, 170]];var G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0);var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0);var G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1);var _this = {};var getBCHDigit = function(data) {var digit = 0;while (data != 0) {digit += 1;data >>>= 1;}return digit;};_this.getBCHTypeInfo = function(data) {var d = data << 10;while (getBCHDigit(d) - getBCHDigit(G15) >= 0) {d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) );}return ( (data << 10) | d) ^ G15_MASK;};_this.getBCHTypeNumber = function(data) {var d = data << 12;while (getBCHDigit(d) - getBCHDigit(G18) >= 0) {d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) );}return (data << 12) | d;};_this.getPatternPosition = function(typeNumber) {return PATTERN_POSITION_TABLE[typeNumber - 1];};_this.getMaskFunction = function(maskPattern) {switch (maskPattern) {case QRMaskPattern.PATTERN000 :return function(i, j) { return (i + j) % 2 == 0; };case QRMaskPattern.PATTERN001 :return function(i, j) { return i % 2 == 0; };case QRMaskPattern.PATTERN010 :return function(i, j) { return j % 3 == 0; };case QRMaskPattern.PATTERN011 :return function(i, j) { return (i + j) % 3 == 0; };case QRMaskPattern.PATTERN100 :return function(i, j) { return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; };case QRMaskPattern.PATTERN101 :return function(i, j) { return (i * j) % 2 + (i * j) % 3 == 0; };case QRMaskPattern.PATTERN110 :return function(i, j) { return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; };case QRMaskPattern.PATTERN111 :return function(i, j) { return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; };default :throw 'bad maskPattern:' + maskPattern;}};_this.getErrorCorrectPolynomial = function(errorCorrectLength) {var a = qrPolynomial([1], 0);for (var i = 0; i < errorCorrectLength; i += 1) {a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0) );}return a;};_this.getLengthInBits = function(mode, type) {if (1 <= type && type < 10) {switch(mode) {case QRMode.MODE_NUMBER    : return 10;case QRMode.MODE_ALPHA_NUM : return 9;case QRMode.MODE_8BIT_BYTE : return 8;case QRMode.MODE_KANJI     : return 8;default :throw 'mode:' + mode;}} else if (type < 27) {switch(mode) {case QRMode.MODE_NUMBER    : return 12;case QRMode.MODE_ALPHA_NUM : return 11;case QRMode.MODE_8BIT_BYTE : return 16;case QRMode.MODE_KANJI     : return 10;default :throw 'mode:' + mode;}} else if (type < 41) {switch(mode) {case QRMode.MODE_NUMBER    : return 14;case QRMode.MODE_ALPHA_NUM : return 13;case QRMode.MODE_8BIT_BYTE : return 16;case QRMode.MODE_KANJI     : return 12;default :throw 'mode:' + mode;}} else {throw 'type:' + type;}};_this.getLostPoint = function(qrcode) {var moduleCount = qrcode.getModuleCount();var lostPoint = 0;for (var row = 0; row < moduleCount; row += 1) {for (var col = 0; col < moduleCount; col += 1) {var sameCount = 0;var dark = qrcode.isDark(row, col);for (var r = -1; r <= 1; r += 1) {if (row + r < 0 || moduleCount <= row + r) {continue;}for (var c = -1; c <= 1; c += 1) {if (col + c < 0 || moduleCount <= col + c) {continue;}if (r == 0 && c == 0) {continue;}if (dark == qrcode.isDark(row + r, col + c) ) {sameCount += 1;}}}if (sameCount > 5) {lostPoint += (3 + sameCount - 5);}}};for (var row = 0; row < moduleCount - 1; row += 1) {for (var col = 0; col < moduleCount - 1; col += 1) {var count = 0;if (qrcode.isDark(row, col) ) count += 1;if (qrcode.isDark(row + 1, col) ) count += 1;if (qrcode.isDark(row, col + 1) ) count += 1;if (qrcode.isDark(row + 1, col + 1) ) count += 1;if (count == 0 || count == 4) {lostPoint += 3;}}}for (var row = 0; row < moduleCount; row += 1) {for (var col = 0; col < moduleCount - 6; col += 1) {if (qrcode.isDark(row, col)&& !qrcode.isDark(row, col + 1)&&  qrcode.isDark(row, col + 2)&&  qrcode.isDark(row, col + 3)&&  qrcode.isDark(row, col + 4)&& !qrcode.isDark(row, col + 5)&&  qrcode.isDark(row, col + 6) ) {lostPoint += 40;}}}for (var col = 0; col < moduleCount; col += 1) {for (var row = 0; row < moduleCount - 6; row += 1) {if (qrcode.isDark(row, col)&& !qrcode.isDark(row + 1, col)&&  qrcode.isDark(row + 2, col)&&  qrcode.isDark(row + 3, col)&&  qrcode.isDark(row + 4, col)&& !qrcode.isDark(row + 5, col)&&  qrcode.isDark(row + 6, col) ) {lostPoint += 40;}}}var darkCount = 0;for (var col = 0; col < moduleCount; col += 1) {for (var row = 0; row < moduleCount; row += 1) {if (qrcode.isDark(row, col) ) {darkCount += 1;}}}var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;lostPoint += ratio * 10;return lostPoint;};return _this;}();
  //---------------------------------------------------------------------
  // QRMath
  //---------------------------------------------------------------------
  var QRMath = function() {var EXP_TABLE = new Array(256);var LOG_TABLE = new Array(256);for (var i = 0; i < 8; i += 1) {EXP_TABLE[i] = 1 << i;}for (var i = 8; i < 256; i += 1) {EXP_TABLE[i] = EXP_TABLE[i - 4]^ EXP_TABLE[i - 5]^ EXP_TABLE[i - 6]^ EXP_TABLE[i - 8];}for (var i = 0; i < 255; i += 1) {LOG_TABLE[EXP_TABLE[i] ] = i;}var _this = {};_this.glog = function(n) {if (n < 1) {throw 'glog(' + n + ')';}return LOG_TABLE[n];};_this.gexp = function(n) {while (n < 0) {n += 255;}while (n >= 256) {n -= 255;}return EXP_TABLE[n];};return _this;}();
  //---------------------------------------------------------------------
  // qrPolynomial
  //---------------------------------------------------------------------
  function qrPolynomial(num, shift) {if (typeof num.length == 'undefined') {throw num.length + '/' + shift;}var _num = function() {var offset = 0;while (offset < num.length && num[offset] == 0) {offset += 1;}var _num = new Array(num.length - offset + shift);for (var i = 0; i < num.length - offset; i += 1) {_num[i] = num[i + offset];}return _num;}();var _this = {};_this.getAt = function(index) {return _num[index];};_this.getLength = function() {return _num.length;};_this.multiply = function(e) {var num = new Array(_this.getLength() + e.getLength() - 1);for (var i = 0; i < _this.getLength(); i += 1) {for (var j = 0; j < e.getLength(); j += 1) {num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i) ) + QRMath.glog(e.getAt(j) ) );}}return qrPolynomial(num, 0);};_this.mod = function(e) {if (_this.getLength() - e.getLength() < 0) {return _this;}var ratio = QRMath.glog(_this.getAt(0) ) - QRMath.glog(e.getAt(0) );var num = new Array(_this.getLength() );for (var i = 0; i < _this.getLength(); i += 1) {num[i] = _this.getAt(i);}for (var i = 0; i < e.getLength(); i += 1) {num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio);}return qrPolynomial(num, 0).mod(e);};return _this;};
  //---------------------------------------------------------------------
  // QRRSBlock
  //---------------------------------------------------------------------
  var QRRSBlock = function() {var RS_BLOCK_TABLE = [[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12,7,37,13],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];var qrRSBlock = function(totalCount, dataCount) {var _this = {};_this.totalCount = totalCount;_this.dataCount = dataCount;return _this;};var _this = {};var getRsBlockTable = function(typeNumber, errorCorrectionLevel) {switch(errorCorrectionLevel) {case QRErrorCorrectionLevel.L :return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];case QRErrorCorrectionLevel.M :return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];case QRErrorCorrectionLevel.Q :return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];case QRErrorCorrectionLevel.H :return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];default :return undefined;}};_this.getRSBlocks = function(typeNumber, errorCorrectionLevel) {var rsBlock = getRsBlockTable(typeNumber, errorCorrectionLevel);if (typeof rsBlock == 'undefined') {throw 'bad rs block @ typeNumber:' + typeNumber +'/errorCorrectionLevel:' + errorCorrectionLevel;}var length = rsBlock.length / 3;var list = [];for (var i = 0; i < length; i += 1) {var count = rsBlock[i * 3 + 0];var totalCount = rsBlock[i * 3 + 1];var dataCount = rsBlock[i * 3 + 2];for (var j = 0; j < count; j += 1) {list.push(qrRSBlock(totalCount, dataCount) );}}return list;};return _this;}();
  //---------------------------------------------------------------------
  // qrBitBuffer
  //---------------------------------------------------------------------
  var qrBitBuffer = function() {var _buffer = [];var _length = 0;var _this = {};_this.getBuffer = function() {return _buffer;};_this.getAt = function(index) {var bufIndex = Math.floor(index / 8);return ( (_buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1;};_this.put = function(num, length) {for (var i = 0; i < length; i += 1) {_this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1);}};_this.getLengthInBits = function() {return _length;};_this.putBit = function(bit) {var bufIndex = Math.floor(_length / 8);if (_buffer.length <= bufIndex) {_buffer.push(0);}if (bit) {_buffer[bufIndex] |= (0x80 >>> (_length % 8) );}_length += 1;};return _this;};
  //---------------------------------------------------------------------
  // qrNumber
  //---------------------------------------------------------------------
  var qrNumber = function(data) {var _mode = QRMode.MODE_NUMBER;var _data = data;var _this = {};_this.getMode = function() {return _mode;};_this.getLength = function(buffer) {return _data.length;};_this.write = function(buffer) {var data = _data;var i = 0;while (i + 2 < data.length) {buffer.put(strToNum(data.substring(i, i + 3) ), 10);i += 3;}if (i < data.length) {if (data.length - i == 1) {buffer.put(strToNum(data.substring(i, i + 1) ), 4);} else if (data.length - i == 2) {buffer.put(strToNum(data.substring(i, i + 2) ), 7);}}};var strToNum = function(s) {var num = 0;for (var i = 0; i < s.length; i += 1) {num = num * 10 + chatToNum(s.charAt(i) );}return num;};var chatToNum = function(c) {if ('0' <= c && c <= '9') {return c.charCodeAt(0) - '0'.charCodeAt(0);}throw 'illegal char :' + c;};return _this;};
  //---------------------------------------------------------------------
  // qrAlphaNum
  //---------------------------------------------------------------------
  var qrAlphaNum = function(data) {var _mode = QRMode.MODE_ALPHA_NUM;var _data = data;var _this = {};_this.getMode = function() {return _mode;};_this.getLength = function(buffer) {return _data.length;};_this.write = function(buffer) {var s = _data;var i = 0;while (i + 1 < s.length) {buffer.put(getCode(s.charAt(i) ) * 45 +getCode(s.charAt(i + 1) ), 11);i += 2;}if (i < s.length) {buffer.put(getCode(s.charAt(i) ), 6);}};var getCode = function(c) {if ('0' <= c && c <= '9') {return c.charCodeAt(0) - '0'.charCodeAt(0);} else if ('A' <= c && c <= 'Z') {return c.charCodeAt(0) - 'A'.charCodeAt(0) + 10;} else {switch (c) {case ' ' : return 36;case "$" : return 37;case '%' : return 38;case '*' : return 39;case '+' : return 40;case '-' : return 41;case '.' : return 42;case '/' : return 43;case ':' : return 44;default:throw 'illegal char :' + c;}}};return _this;};
  //---------------------------------------------------------------------
  // qr8BitByte
  //---------------------------------------------------------------------
  var qr8BitByte = function(data) {var _mode = QRMode.MODE_8BIT_BYTE;var _data = data;var _bytes = qrcode.stringToBytes(data);var _this = {};_this.getMode = function() {return _mode;};_this.getLength = function(buffer) {return _bytes.length;};_this.write = function(buffer) {for (var i = 0; i < _bytes.length; i += 1) {buffer.put(_bytes[i], 8);}};return _this;};
  //---------------------------------------------------------------------
  // qrKanji
  //---------------------------------------------------------------------
  var qrKanji = function(data) {var _mode = QRMode.MODE_KANJI;var _data = data;var stringToBytes = qrcode.stringToBytesFuncs['SJIS'];if (!stringToBytes) {throw 'sjis not supported.';}!function(c, code) {var test = stringToBytes(c);if (test.length != 2 || ( (test[0] << 8) | test[1]) != code) {throw 'sjis not supported.';}}('\u53cb', 0x9746);var _bytes = stringToBytes(data);var _this = {};_this.getMode = function() {return _mode;};_this.getLength = function(buffer) {return ~~(_bytes.length / 2);};_this.write = function(buffer) {var data = _bytes;var i = 0;while (i + 1 < data.length) {var c = ( (0xff & data[i]) << 8) | (0xff & data[i + 1]);if (0x8140 <= c && c <= 0x9FFC) {c -= 0x8140;} else if (0xE040 <= c && c <= 0xEBBF) {c -= 0xC140;} else {throw 'illegal char at ' + (i + 1) + '/' + c;}c = ( (c >>> 8) & 0xff) * 0xC0 + (c & 0xff);buffer.put(c, 13);i += 2;}if (i < data.length) {throw 'illegal char at ' + (i + 1);}};return _this;};

  
  //=====================================================================
  // GIF Support etc.
  //
  //---------------------------------------------------------------------
  // byteArrayOutputStream
  //---------------------------------------------------------------------
  var byteArrayOutputStream = function() {var _bytes = [];var _this = {};_this.writeByte = function(b) {_bytes.push(b & 0xff);};_this.writeShort = function(i) {_this.writeByte(i);_this.writeByte(i >>> 8);};_this.writeBytes = function(b, off, len) {off = off || 0;len = len || b.length;for (var i = 0; i < len; i += 1) {_this.writeByte(b[i + off]);}};_this.writeString = function(s) {for (var i = 0; i < s.length; i += 1) {_this.writeByte(s.charCodeAt(i) );}};_this.toByteArray = function() {return _bytes;};_this.toString = function() {var s = '';s += '[';for (var i = 0; i < _bytes.length; i += 1) {if (i > 0) {s += ',';}s += _bytes[i];}s += ']';return s;};return _this;};
  //---------------------------------------------------------------------
  // base64EncodeOutputStream
  //---------------------------------------------------------------------
  var base64EncodeOutputStream = function() {var _buffer = 0;var _buflen = 0;var _length = 0;var _base64 = '';var _this = {};var writeEncoded = function(b) {_base64 += String.fromCharCode(encode(b & 0x3f) );};var encode = function(n) {if (n < 0) {/*error*/} else if (n < 26) {return 0x41 + n;} else if (n < 52) {return 0x61 + (n - 26);} else if (n < 62) {return 0x30 + (n - 52);} else if (n == 62) {return 0x2b;} else if (n == 63) {return 0x2f;}throw 'n:' + n;};_this.writeByte = function(n) {_buffer = (_buffer << 8) | (n & 0xff);_buflen += 8;_length += 1;while (_buflen >= 6) {writeEncoded(_buffer >>> (_buflen - 6) );_buflen -= 6;}};_this.flush = function() {if (_buflen > 0) {writeEncoded(_buffer << (6 - _buflen) );_buffer = 0;_buflen = 0;}if (_length % 3 != 0) {var padlen = 3 - _length % 3;for (var i = 0; i < padlen; i += 1) {_base64 += '=';}}};_this.toString = function() {return _base64;};return _this;};
  //---------------------------------------------------------------------
  //---------------------------------------------------------------------
  // base64DecodeInputStream
  //---------------------------------------------------------------------
  var base64DecodeInputStream = function(str) {var _str = str;var _pos = 0;var _buffer = 0;var _buflen = 0;var _this = {};_this.read = function() {while (_buflen < 8) {if (_pos >= _str.length) {if (_buflen == 0) {return -1;}throw 'unexpected end of file./' + _buflen;}var c = _str.charAt(_pos);_pos += 1;if (c == '=') {_buflen = 0;return -1;} else if (c.match(/^\s$/) ) {continue;}_buffer = (_buffer << 6) | decode(c.charCodeAt(0) );_buflen += 6;}var n = (_buffer >>> (_buflen - 8) ) & 0xff;_buflen -= 8;return n;};var decode = function(c) {if (0x41 <= c && c <= 0x5a) {return c - 0x41;} else if (0x61 <= c && c <= 0x7a) {return c - 0x61 + 26;} else if (0x30 <= c && c <= 0x39) {return c - 0x30 + 52;} else if (c == 0x2b) {return 62;} else if (c == 0x2f) {return 63;} else {throw 'c:' + c;}};return _this;};
  //---------------------------------------------------------------------
  // gifImage (B/W)
  //---------------------------------------------------------------------
  var gifImage = function(width, height) {var _width = width;var _height = height;var _data = new Array(width * height);var _this = {};_this.setPixel = function(x, y, pixel) {_data[y * _width + x] = pixel;};_this.write = function(out) {out.writeString('GIF87a');out.writeShort(_width);out.writeShort(_height);out.writeByte(0x80);out.writeByte(0);out.writeByte(0);out.writeByte(0x00);out.writeByte(0x00);out.writeByte(0x00);out.writeByte(0xff);out.writeByte(0xff);out.writeByte(0xff);out.writeString(',');out.writeShort(0);out.writeShort(0);out.writeShort(_width);out.writeShort(_height);out.writeByte(0);var lzwMinCodeSize = 2;var raster = getLZWRaster(lzwMinCodeSize);out.writeByte(lzwMinCodeSize);var offset = 0;while (raster.length - offset > 255) {out.writeByte(255);out.writeBytes(raster, offset, 255);offset += 255;}out.writeByte(raster.length - offset);out.writeBytes(raster, offset, raster.length - offset);out.writeByte(0x00);out.writeString(';');};var bitOutputStream = function(out) {var _out = out;var _bitLength = 0;var _bitBuffer = 0;var _this = {};_this.write = function(data, length) {if ( (data >>> length) != 0) {throw 'length over';}while (_bitLength + length >= 8) {_out.writeByte(0xff & ( (data << _bitLength) | _bitBuffer) );length -= (8 - _bitLength);data >>>= (8 - _bitLength);_bitBuffer = 0;_bitLength = 0;}_bitBuffer = (data << _bitLength) | _bitBuffer;_bitLength = _bitLength + length;};_this.flush = function() {if (_bitLength > 0) {_out.writeByte(_bitBuffer);}};return _this;};var getLZWRaster = function(lzwMinCodeSize) {var clearCode = 1 << lzwMinCodeSize;var endCode = (1 << lzwMinCodeSize) + 1;var bitLength = lzwMinCodeSize + 1;var table = lzwTable();for (var i = 0; i < clearCode; i += 1) {table.add(String.fromCharCode(i) );}table.add(String.fromCharCode(clearCode) );table.add(String.fromCharCode(endCode) );var byteOut = byteArrayOutputStream();var bitOut = bitOutputStream(byteOut);bitOut.write(clearCode, bitLength);var dataIndex = 0;var s = String.fromCharCode(_data[dataIndex]);dataIndex += 1;while (dataIndex < _data.length) {var c = String.fromCharCode(_data[dataIndex]);dataIndex += 1;if (table.contains(s + c) ) {s = s + c;} else {bitOut.write(table.indexOf(s), bitLength);if (table.size() < 0xfff) {if (table.size() == (1 << bitLength) ) {bitLength += 1;}table.add(s + c);}s = c;}}bitOut.write(table.indexOf(s), bitLength);bitOut.write(endCode, bitLength);bitOut.flush();return byteOut.toByteArray();};var lzwTable = function() {var _map = {};var _size = 0;var _this = {};_this.add = function(key) {if (_this.contains(key) ) {throw 'dup key:' + key;}_map[key] = _size;_size += 1;};_this.size = function() {return _size;};_this.indexOf = function(key) {return _map[key];};_this.contains = function(key) {return typeof _map[key] != 'undefined';};return _this;};return _this;};
  var createDataURL = function(width, height, getPixel) {var gif = gifImage(width, height);for (var y = 0; y < height; y += 1) {for (var x = 0; x < width; x += 1) {gif.setPixel(x, y, getPixel(x, y) );}}var b = byteArrayOutputStream();gif.write(b);var base64 = base64EncodeOutputStream();var bytes = b.toByteArray();for (var i = 0; i < bytes.length; i += 1) {base64.writeByte(bytes[i]);}base64.flush();return 'data:image/gif;base64,' + base64;};

  // returns qrcode function.
  return qrcode;
}();

//  qrcode.stringToBytes = qrcode.stringToBytesFuncs['UTF-8'];

  var qr = qrcode(typeNumber || 4, errorCorrectionLevel || 'M');
  qr.addData(text, mode);
  qr.make();

//  return qr.createTableTag();
//  return qr.createSvgTag();
//  return qr.createImgTag();
  return qr.createASCII(2, 0);
};

function getLogoPaths() {
    const scale = [.26, .26];
    const offset = [-97, -161];
    const paths = initSVGData();

    class FakeTurtle extends Turtle {goto(...arg) {[this.isdown()].forEach(e => {this.penup();super.goto(...arg);if(e) this.pendown();});}}
    const ft = new FakeTurtle();

    const result = [];
    for(let i = 0; i < paths.length; i++) {
        result.push([handleSVG(ft, paths[i][0]), paths[i][1]]);
    }
    return result;

    function handleSVG(t, d) {
        let firstCommand = true;
        const inst = d.split(' ').reverse();
        let startPos = unscaleCoord(t.position());
        
        const points = [];
        
        do {
            const cmd = inst.pop();
            const currentPos = firstCommand ? [0,0] : unscaleCoord(t.position());
    
            switch(cmd) {
                case "M": // absolute move to
                    points.push([]);
                    t.penup();
                    t.goto(scaleCoord(popCoord(inst)));
                    t.pendown();
                    startPos = unscaleCoord(t.position());
                    points[points.length - 1].push(t.position());
                    break;
                case "m": {// relative move to
                        points.push([]);
                        const c = vecAdd(popCoord(inst),currentPos);
                        t.penup();
                        t.goto(scaleCoord(c));
                        t.pendown();
                        startPos = unscaleCoord(t.position());
                        points[points.length - 1].push(t.position());
                        break;
                    }
                case "C": // an absolute bezier curve
                    if(t.isdown()) { points[points.length - 1].push(t.position()); }
                    drawBezier(t, inst, true, points);
                    break;
                case "c": // a relative bezier curve
                    if(t.isdown()) { points[points.length - 1].push(t.position()); }
                    drawBezier(t, inst, firstCommand, points);
                    break;
                case "l": { // a relative move
                        const c = vecAdd(popCoord(inst),currentPos);
                        t.goto(scaleCoord(c));
                        if(t.isdown()) { points[points.length - 1].push(t.position()); }
                        break;
                    }
                case "L": { // an absolute move
                    const c = popCoord(inst);
                    t.goto(scaleCoord(c));
                    if(t.isdown()) { points[points.length - 1].push(t.position()); }
                    break;
                }
                case "z":
                case "Z": // close path
                    t.goto(scaleCoord(startPos));
                    if(t.isdown()) { points[points.length - 1].push(t.position()); }
                    break;
                case "v": // relative vertical line
                    t.sety(t.y() + (scale[1]*Number(inst.pop())));
                    break;
                case "h": // relative horizontal line
                    t.setx(t.x() + (scale[0]*Number(inst.pop())));
                    break;
                default:
                    break;
            }
            firstCommand = false;
        } while(inst.length > 0);
        return points;
    }
    
    function drawBezier(t, inst, abs, points) {
        const _p1 = unscaleCoord(t.position());
        let _c1 = [], _c2 = [], _p2 = [];
        
        while(1) {
            let c1 = popCoord(inst);
            let c2 = popCoord(inst);
            let p2 = popCoord(inst);
            
            _c1 = vecAdd(c1, abs ? [0,0] : _p1);
            _c2 = vecAdd(c2, abs ? [0,0] : _p1);
            _p2 = vecAdd(p2, abs ? [0,0] : _p1);
    
            for (let i=0; i<=1; i+=.1) {
                t.goto(scaleCoord(bezierAt(i, [_p1, _c1, _c2, _p2])));
                points[points.length - 1].push(t.position());
            }
            
            if (inst.length > 2 && inst[inst.length-1].length != 1) {
                _p1[0] = _p2[0];
                _p1[1] = _p2[1];
            } else {
                return;
            }
        }
    }
    
    function bezierAt(t, p) {
        const nt = 1 - t;
    
        const value = 
        [ 
            nt*nt*nt*p[0][0] + 3*t*nt*nt*p[1][0] + 3*t*t*nt*p[2][0] + t*t*t*p[3][0],
            nt*nt*nt*p[0][1] + 3*t*nt*nt*p[1][1] + 3*t*t*nt*p[2][1] + t*t*t*p[3][1]
        ];
    	return value;
    }
    
    function popCoord(d) {
        const c = d.pop();
        const coord = c.split(',');
        return [Number(coord[0]), Number(coord[1])];
    }
    
    function scaleCoord(c) {
        return [Number(c[0]*scale[0]+offset[0]), Number(c[1]*scale[1]+offset[1])];
    }
    
    function unscaleCoord(c) {
        return [(c[0]-offset[0])/scale[0], (c[1]-offset[1])/scale[1]];
    }
    
    function vecAdd(a,b) {
        return [a[0]+b[0],a[1]+b[1]];
    }
    
    function initSVGData() {
        const paths = [];
        const lines = svgData().split('/>');
        const reg = / d="(.*)"/g;
        const colorreg = / style=".*?fill:#([0-9a-fA-F]+).*?"/g;
        for (let i=0; i<lines.length; i++) {
            const p = lines[i].split(reg)[1];
            const c = lines[i].split(colorreg)[1];
            if (p) {
                paths.push([p, c?c:'000000']);
            }
        }
        return paths;
    }
    
    function svgData() { return ''+
        // last I leg
        '<path id="path126" style="fill:#000000" d="M 583.71278,682.43408 L 583.71278,579.25851 L 620.21813,579.25851 L 620.21813,682.43408 L 583.71278,682.43408 z" />'+
        // last I dot
        '<path id="path126" style="fill:#000000" d="M 601.96542,568.20905 C 590.00674,568.20905 581.05518,561.28554 581.05518,550.16602 C 581.05518,539.79256 590.00674,532.4962 601.96542,532.4962 C 614.53024,532.4962 623.24857,539.79256 623.24857,550.16602 C 623.24857,561.28554 614.53024,568.20905 601.96542,568.20905 z" />'+
        // F
        '<path id="path124" style="fill:#000000" d="M 477.34353,573.87361 L 477.34353,605.62355 L 552.91858,605.62355 L 552.91858,638.93529 L 477.34353,638.93529 L 477.34353,682.43408 L 438.18073,682.43408 L 438.18073,540.3987 L 560.96099,540.3987 L 560.96099,573.87361 L 477.34353,573.87361 z" />'+
        // first I leg
        '<path id="path122" style="fill:#ffffff" d="M 295.98219,682.43408 L 295.98219,579.25851 L 332.51087,579.25851 L 332.51087,682.43408 L 295.98219,682.43408 z" />'+
        // last I dot
        '<path id="path122" style="fill:#ffffff" d="M 314.25823,568.20905 C 302.27616,568.20905 293.348,561.28554 293.348,550.16602 C 293.348,539.79256 302.27616,532.4962 314.25823,532.4962 C 326.82298,532.4962 335.54139,539.79256 335.54139,550.16602 C 335.54139,561.28554 326.82298,568.20905 314.25823,568.20905 z" />'+
        // W
        '<path id="path120" style="fill:#ffffff" d="M 244.76732,682.43408 L 208.44847,682.43408 L 201.94468,651.59336 C 197.3057,629.70406 193.03978,603.10586 192.22388,592.77913 C 191.38465,603.10586 187.14206,629.70406 182.50308,651.59336 L 175.97595,682.43408 L 140.07668,682.43408 L 106.20545,540.3987 L 146.76697,540.3987 L 150.61331,564.15289 C 153.8769,584.24722 157.74657,609.00365 159.14522,625.83446 C 160.77701,609.19015 165.22943,584.62014 169.70517,564.31605 L 174.55398,540.3987 L 210.68634,540.3987 L 215.55833,564.31605 C 220.01089,584.62014 224.46331,609.19015 226.11836,625.83446 C 227.51701,609.00365 231.38682,584.24722 234.62702,564.15289 L 238.47336,540.3987 L 278.66196,540.3987 L 244.76732,682.43408 z" />'+
        // FI background
        '<path id="path118" style="fill:#ffffff" d="M 388.59773,648.30636 L 388.59773,582.5455 C 388.59773,533.9649 428.13352,494.42897 476.71413,494.42897 L 587.37262,494.42897 C 635.95323,494.42897 675.51235,533.9649 675.51235,582.5455 L 675.51235,648.30636 C 675.51235,696.88703 635.95323,736.4229 587.37262,736.4229 C 587.37262,736.4229 424.80008,736.4229 343.72356,736.4229 C 370.90451,716.56172 388.59773,684.46212 388.59773,648.30636 z" />'+
        // All background
        '<path id="path112" style="fill:#000000" d="M 374.53125,387.5 C 303.0031,387.5 239.29315,421.13575 198.34375,473.4375 L 160,473.4375 C 99.833783,473.43749 50.875,522.3649 50.875,582.53125 L 50.875,648.3125 C 50.875,708.47888 99.833784,757.4375 160,757.4375 L 205.375,757.4375 C 246.39505,804.825 306.98155,834.81252 374.53125,834.8125 C 442.08094,834.8125 502.66745,804.82499 543.6875,757.4375 L 587.375,757.4375 C 647.56455,757.43748 696.53125,708.47886 696.53125,648.3125 L 696.53125,582.53125 C 696.53126,522.36493 647.56455,473.4375 587.375,473.4375 L 550.71875,473.4375 C 509.76935,421.13575 446.0594,387.5 374.53125,387.5 z" />'+
        (wifi_certified == 2?
        // t
        '<path id="path136" style="fill:#000000"  d="M 711.76136,513.73066 L 711.76136,488.74107 L 702.87979,488.74107 L 702.87979,483.63585 L 726.70381,483.63585 L 726.70381,488.74107 L 717.79891,488.74107 L 717.79891,513.73066 L 711.76136,513.73066 z" />'+
        // m
        '<path id="path138" style="fill:#000000"  d="M 730.55015,513.73066 L 730.55015,483.63585 L 739.68814,483.63585 L 745.0731,504.17303 L 750.38807,483.63585 L 759.52599,483.63585 L 759.52599,513.73066 L 753.93141,513.73066 L 753.88483,490.04647 L 747.98697,513.73066 L 742.11258,513.73066 L 736.19153,490.04647 L 736.14487,513.73066 L 730.55015,513.73066 z" />'+
        '': '')+
        '';
    }
}