addressable-2.8.7/0000755000004100000410000000000014636033505014036 5ustar www-datawww-dataaddressable-2.8.7/data/0000755000004100000410000000000014636033505014747 5ustar www-datawww-dataaddressable-2.8.7/data/unicode.data0000644000004100000410000034203414636033505017236 0ustar www-datawww-data{iF[ ii000if0iG[ ii000ig0iH[ ii000ih0iI[ ii000ii0iJ[ ii000ij0iK[ ii000ik0iL[ ii000il0iM[ ii000im0iN[ ii000in0iO[ ii000io0iP[ ii000ip0iQ[ ii000iq0iR[ ii000ir0iS[ ii000is0iT[ ii000it0iU[ ii000iu0iV[ ii000iv0iW[ ii000iw0iX[ ii000ix0iY[ ii000iy0iZ[ ii000iz0i[[ ii000i{0i\[ ii000i|0i][ ii000i}0i^[ ii000i~0i_[ ii000i0if[ ii00iF0iFig[ ii00iG0iGih[ ii00iH0iHii[ ii00iI0iIij[ ii00iJ0iJik[ ii00iK0iKil[ ii00iL0iLim[ ii00iM0iMin[ ii00iN0iNio[ ii00iO0iOip[ ii00iP0iPiq[ ii00iQ0iQir[ ii00iR0iRis[ ii00iS0iSit[ ii00iT0iTiu[ ii00iU0iUiv[ ii00iV0iViw[ ii00iW0iWix[ ii00iX0iXiy[ ii00iY0iYiz[ ii00iZ0iZi{[ ii00i[0i[i|[ ii00i\0i\i}[ ii00i]0i]i~[ ii00i^0i^i[ ii00i_0i_i[ ii0I" :ET000i[ ii0I" ̈;T000i[ ii0I"a;T000i[ ii0I" ̄;T000i[ ii0I"2;T000i[ ii0I"3;T000i[ ii0I" ́;T000i[ ii0I"μ;Ti0ii[ ii0I" ̧;T000i[ ii0I"1;T000i[ ii0I"o;T000i[ ii0I" 1⁄4;T000i[ ii0I" 1⁄2;T000i[ ii0I" 3⁄4;T000i[ iiI"À;TI"À;T0i0i[ iiI"Á;TI"Á;T0i0i[ iiI"Â;TI"Â;T0i0i[ iiI"Ã;TI"Ã;T0i0i[ iiI"Ä;TI"Ä;T0i0i[ iiI"Å;TI"Å;T0i0i[ ii000i0i[ iiI"Ç;TI"Ç;T0i0i[ iiI"È;TI"È;T0i0i[ iiI"É;TI"É;T0i0i[ iiI"Ê;TI"Ê;T0i0i[ iiI"Ë;TI"Ë;T0i0i[ iiI"Ì;TI"Ì;T0i0i[ iiI"Í;TI"Í;T0i0i[ iiI"Î;TI"Î;T0i0i[ iiI"Ï;TI"Ï;T0i0i[ ii000i0i[ iiI"Ñ;TI"Ñ;T0i0i[ iiI"Ò;TI"Ò;T0i0i[ iiI"Ó;TI"Ó;T0i0i[ iiI"Ô;TI"Ô;T0i0i[ iiI"Õ;TI"Õ;T0i0i[ iiI"Ö;TI"Ö;T0i0i[ ii000i0i[ iiI"Ù;TI"Ù;T0i0i[ iiI"Ú;TI"Ú;T0i0i[ iiI"Û;TI"Û;T0i0i[ iiI"Ü;TI"Ü;T0i0i[ iiI"Ý;TI"Ý;T0i0i[ ii000i0i[ iiI"à;TI"à;Ti0ii[ iiI"á;TI"á;Ti0ii[ iiI"â;TI"â;Ti0ii[ iiI"ã;TI"ã;Ti0ii[ iiI"ä;TI"ä;Ti0ii[ iiI"å;TI"å;Ti0ii[ ii00i0ii[ iiI"ç;TI"ç;Ti0ii[ iiI"è;TI"è;Ti0ii[ iiI"é;TI"é;Ti0ii[ iiI"ê;TI"ê;Ti0ii[ iiI"ë;TI"ë;Ti0ii[ iiI"ì;TI"ì;Ti0ii[ iiI"í;TI"í;Ti0ii[ iiI"î;TI"î;Ti0ii[ iiI"ï;TI"ï;Ti0ii[ ii00i0ii[ iiI"ñ;TI"ñ;Ti0ii[ iiI"ò;TI"ò;Ti0ii[ iiI"ó;TI"ó;Ti0ii[ iiI"ô;TI"ô;Ti0ii[ iiI"õ;TI"õ;Ti0ii[ iiI"ö;TI"ö;Ti0ii[ ii00i0ii[ iiI"ù;TI"ù;Ti0ii[ iiI"ú;TI"ú;Ti0ii[ iiI"û;TI"û;Ti0ii[ iiI"ü;TI"ü;Ti0ii[ iiI"ý;TI"ý;Ti0ii[ ii00i0ii[ iiI"ÿ;TI"ÿ;Tix0ixi[ iiI"Ā;TI"Ā;T0i0i[ iiI"ā;TI"ā;Ti0ii[ iiI"Ă;TI"Ă;T0i0i[ iiI"ă;TI"ă;Ti0ii[ iiI"Ą;TI"Ą;T0i0i[ iiI"ą;TI"ą;Ti0ii[ iiI"Ć;TI"Ć;T0i0i[ iiI"ć;TI"ć;Ti0ii[ iiI"Ĉ;TI"Ĉ;T0i 0i [ iiI"ĉ;TI"ĉ;Ti0ii [ iiI"Ċ;TI"Ċ;T0i 0i [ iiI"ċ;TI"ċ;Ti 0i i [ iiI"Č;TI"Č;T0i 0i [ iiI"č;TI"č;Ti 0i i[ iiI"Ď;TI"Ď;T0i0i[ iiI"ď;TI"ď;Ti0ii[ ii000i0i[ ii00i0ii[ iiI"Ē;TI"Ē;T0i0i[ iiI"ē;TI"ē;Ti0ii[ iiI"Ĕ;TI"Ĕ;T0i0i[ iiI"ĕ;TI"ĕ;Ti0ii[ iiI"Ė;TI"Ė;T0i0i[ iiI"ė;TI"ė;Ti0ii[ iiI"Ę;TI"Ę;T0i0i[ iiI"ę;TI"ę;Ti0ii[ iiI"Ě;TI"Ě;T0i0i[ iiI"ě;TI"ě;Ti0ii[ iiI"Ĝ;TI"Ĝ;T0i0i[ iiI"ĝ;TI"ĝ;Ti0ii[ iiI"Ğ;TI"Ğ;T0i0i[ iiI"ğ;TI"ğ;Ti0ii [ iiI"Ġ;TI"Ġ;T0i!0i![ iiI"ġ;TI"ġ;Ti 0i i"[ iiI"Ģ;TI"Ģ;T0i#0i#[ iiI"ģ;TI"ģ;Ti"0i"i$[ iiI"Ĥ;TI"Ĥ;T0i%0i%[ iiI"ĥ;TI"ĥ;Ti$0i$i&[ ii000i'0i'[ ii00i&0i&i([ iiI"Ĩ;TI"Ĩ;T0i)0i)[ iiI"ĩ;TI"ĩ;Ti(0i(i*[ iiI"Ī;TI"Ī;T0i+0i+[ iiI"ī;TI"ī;Ti*0i*i,[ iiI"Ĭ;TI"Ĭ;T0i-0i-[ iiI"ĭ;TI"ĭ;Ti,0i,i.[ iiI"Į;TI"Į;T0i/0i/[ iiI"į;TI"į;Ti.0i.i0[ iiI"İ;TI"İ;T0in0i1[ ii00iN0iNi2[ ii0I"IJ;T0i30i3[ ii0I"ij;Ti20i2i4[ iiI"Ĵ;TI"Ĵ;T0i50i5[ iiI"ĵ;TI"ĵ;Ti40i4i6[ iiI"Ķ;TI"Ķ;T0i70i7[ iiI"ķ;TI"ķ;Ti60i6i9[ iiI"Ĺ;TI"Ĺ;T0i:0i:[ iiI"ĺ;TI"ĺ;Ti90i9i;[ iiI"Ļ;TI"Ļ;T0i<0i<[ iiI"ļ;TI"ļ;Ti;0i;i=[ iiI"Ľ;TI"Ľ;T0i>0i>[ iiI"ľ;TI"ľ;Ti=0i=i?[ ii0I"L·;T0i@0i@[ ii0I"l·;Ti?0i?iA[ ii000iB0iB[ ii00iA0iAiC[ iiI"Ń;TI"Ń;T0iD0iD[ iiI"ń;TI"ń;TiC0iCiE[ iiI"Ņ;TI"Ņ;T0iF0iF[ iiI"ņ;TI"ņ;TiE0iEiG[ iiI"Ň;TI"Ň;T0iH0iH[ iiI"ň;TI"ň;TiG0iGiI[ ii0I"ʼn;T000iJ[ ii000iK0iK[ ii00iJ0iJiL[ iiI"Ō;TI"Ō;T0iM0iM[ iiI"ō;TI"ō;TiL0iLiN[ iiI"Ŏ;TI"Ŏ;T0iO0iO[ iiI"ŏ;TI"ŏ;TiN0iNiP[ iiI"Ő;TI"Ő;T0iQ0iQ[ iiI"ő;TI"ő;TiP0iPiR[ ii000iS0iS[ ii00iR0iRiT[ iiI"Ŕ;TI"Ŕ;T0iU0iU[ iiI"ŕ;TI"ŕ;TiT0iTiV[ iiI"Ŗ;TI"Ŗ;T0iW0iW[ iiI"ŗ;TI"ŗ;TiV0iViX[ iiI"Ř;TI"Ř;T0iY0iY[ iiI"ř;TI"ř;TiX0iXiZ[ iiI"Ś;TI"Ś;T0i[0i[[ iiI"ś;TI"ś;TiZ0iZi\[ iiI"Ŝ;TI"Ŝ;T0i]0i][ iiI"ŝ;TI"ŝ;Ti\0i\i^[ iiI"Ş;TI"Ş;T0i_0i_[ iiI"ş;TI"ş;Ti^0i^i`[ iiI"Š;TI"Š;T0ia0ia[ iiI"š;TI"š;Ti`0i`ib[ iiI"Ţ;TI"Ţ;T0ic0ic[ iiI"ţ;TI"ţ;Tib0ibid[ iiI"Ť;TI"Ť;T0ie0ie[ iiI"ť;TI"ť;Tid0idif[ ii000ig0ig[ ii00if0ifih[ iiI"Ũ;TI"Ũ;T0ii0ii[ iiI"ũ;TI"ũ;Tih0ihij[ iiI"Ū;TI"Ū;T0ik0ik[ iiI"ū;TI"ū;Tij0ijil[ iiI"Ŭ;TI"Ŭ;T0im0im[ iiI"ŭ;TI"ŭ;Til0ilin[ iiI"Ů;TI"Ů;T0io0io[ iiI"ů;TI"ů;Tin0inip[ iiI"Ű;TI"Ű;T0iq0iq[ iiI"ű;TI"ű;Tip0ipir[ iiI"Ų;TI"Ų;T0is0is[ iiI"ų;TI"ų;Tir0irit[ iiI"Ŵ;TI"Ŵ;T0iu0iu[ iiI"ŵ;TI"ŵ;Tit0itiv[ iiI"Ŷ;TI"Ŷ;T0iw0iw[ iiI"ŷ;TI"ŷ;Tiv0ivix[ iiI"Ÿ;TI"Ÿ;T0i0iy[ iiI"Ź;TI"Ź;T0iz0iz[ iiI"ź;TI"ź;Tiy0iyi{[ iiI"Ż;TI"Ż;T0i|0i|[ iiI"ż;TI"ż;Ti{0i{i}[ iiI"Ž;TI"Ž;T0i~0i~[ iiI"ž;TI"ž;Ti}0i}i[ ii0I"s;TiX0iXi[ ii000iS0i[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000iT0i[ ii000i0i[ ii00i0ii[ ii000iV0i[ ii000iW0i[ ii000i0i[ ii00i0ii[ ii000i0i[ ii000iY0i[ ii000i[0i[ ii000i0i[ ii00i0ii[ ii000i`0i[ ii000ic0i[ ii00i0ii[ ii000ii0i[ ii000ih0i[ ii000i0i[ ii00i0ii[ ii000io0i[ ii000ir0i[ ii000iu0i[ iiI"Ơ;TI"Ơ;T0i0i[ iiI"ơ;TI"ơ;Ti0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii000i0i[ ii00i0ii[ ii000i0i[ ii000i0i[ ii00i0ii[ ii000i0i[ iiI"Ư;TI"Ư;T0i0i[ iiI"ư;TI"ư;Ti0ii[ ii000i0i[ ii000i0i[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii00i0ii[ ii0I"DŽ;T0iii[ ii0I"Dž;Tii0i[ ii0I"dž;Ti0ii[ ii0I"LJ;T0iii[ ii0I"Lj;Tii0i[ ii0I"lj;Ti0ii[ ii0I"NJ;T0iii[ ii0I"Nj;Tii0i[ ii0I"nj;Ti0ii[ iiI"Ǎ;TI"Ǎ;T0i0i[ iiI"ǎ;TI"ǎ;Ti0ii[ iiI"Ǐ;TI"Ǐ;T0i0i[ iiI"ǐ;TI"ǐ;Ti0ii[ iiI"Ǒ;TI"Ǒ;T0i0i[ iiI"ǒ;TI"ǒ;Ti0ii[ iiI"Ǔ;TI"Ǔ;T0i0i[ iiI"ǔ;TI"ǔ;Ti0ii[ iiI" Ǖ;TI" Ǖ;T0i0i[ iiI" ǖ;TI" ǖ;Ti0ii[ iiI" Ǘ;TI" Ǘ;T0i0i[ iiI" ǘ;TI" ǘ;Ti0ii[ iiI" Ǚ;TI" Ǚ;T0i0i[ iiI" ǚ;TI" ǚ;Ti0ii[ iiI" Ǜ;TI" Ǜ;T0i0i[ iiI" ǜ;TI" ǜ;Ti0ii[ ii00i0ii[ iiI" Ǟ;TI" Ǟ;T0i0i[ iiI" ǟ;TI" ǟ;Ti0ii[ iiI" Ǡ;TI" Ǡ;T0i0i[ iiI" ǡ;TI" ǡ;Ti0ii[ iiI" Ǣ;TI" Ǣ;T0i0i[ iiI" ǣ;TI" ǣ;Ti0ii[ ii000i0i[ ii00i0ii[ iiI"Ǧ;TI"Ǧ;T0i0i[ iiI"ǧ;TI"ǧ;Ti0ii[ iiI"Ǩ;TI"Ǩ;T0i0i[ iiI"ǩ;TI"ǩ;Ti0ii[ iiI"Ǫ;TI"Ǫ;T0i0i[ iiI"ǫ;TI"ǫ;Ti0ii[ iiI" Ǭ;TI" Ǭ;T0i0i[ iiI" ǭ;TI" ǭ;Ti0ii[ iiI" Ǯ;TI" Ǯ;T0i0i[ iiI" ǯ;TI" ǯ;Ti0ii[ iiI"ǰ;TI"ǰ;T000i[ ii0I"DZ;T0iii[ ii0I"Dz;Tii0i[ ii0I"dz;Ti0ii[ iiI"Ǵ;TI"Ǵ;T0i0i[ iiI"ǵ;TI"ǵ;Ti0ii[ ii000i0i[ ii000i0i[ iiI"Ǹ;TI"Ǹ;T0i0i[ iiI"ǹ;TI"ǹ;Ti0ii[ iiI" Ǻ;TI" Ǻ;T0i0i[ iiI" ǻ;TI" ǻ;Ti0ii[ iiI" Ǽ;TI" Ǽ;T0i0i[ iiI" ǽ;TI" ǽ;Ti0ii[ iiI" Ǿ;TI" Ǿ;T0i0i[ iiI" ǿ;TI" ǿ;Ti0ii[ iiI"Ȁ;TI"Ȁ;T0i0i[ iiI"ȁ;TI"ȁ;Ti0ii[ iiI"Ȃ;TI"Ȃ;T0i0i[ iiI"ȃ;TI"ȃ;Ti0ii[ iiI"Ȅ;TI"Ȅ;T0i0i[ iiI"ȅ;TI"ȅ;Ti0ii[ iiI"Ȇ;TI"Ȇ;T0i0i[ iiI"ȇ;TI"ȇ;Ti0ii[ iiI"Ȉ;TI"Ȉ;T0i 0i [ iiI"ȉ;TI"ȉ;Ti0ii [ iiI"Ȋ;TI"Ȋ;T0i 0i [ iiI"ȋ;TI"ȋ;Ti 0i i [ iiI"Ȍ;TI"Ȍ;T0i 0i [ iiI"ȍ;TI"ȍ;Ti 0i i[ iiI"Ȏ;TI"Ȏ;T0i0i[ iiI"ȏ;TI"ȏ;Ti0ii[ iiI"Ȑ;TI"Ȑ;T0i0i[ iiI"ȑ;TI"ȑ;Ti0ii[ iiI"Ȓ;TI"Ȓ;T0i0i[ iiI"ȓ;TI"ȓ;Ti0ii[ iiI"Ȕ;TI"Ȕ;T0i0i[ iiI"ȕ;TI"ȕ;Ti0ii[ iiI"Ȗ;TI"Ȗ;T0i0i[ iiI"ȗ;TI"ȗ;Ti0ii[ iiI"Ș;TI"Ș;T0i0i[ iiI"ș;TI"ș;Ti0ii[ iiI"Ț;TI"Ț;T0i0i[ iiI"ț;TI"ț;Ti0ii[ ii000i0i[ ii00i0ii[ iiI"Ȟ;TI"Ȟ;T0i0i[ iiI"ȟ;TI"ȟ;Ti0ii"[ ii000i#0i#[ ii00i"0i"i$[ ii000i%0i%[ ii00i$0i$i&[ iiI"Ȧ;TI"Ȧ;T0i'0i'[ iiI"ȧ;TI"ȧ;Ti&0i&i([ iiI"Ȩ;TI"Ȩ;T0i)0i)[ iiI"ȩ;TI"ȩ;Ti(0i(i*[ iiI" Ȫ;TI" Ȫ;T0i+0i+[ iiI" ȫ;TI" ȫ;Ti*0i*i,[ iiI" Ȭ;TI" Ȭ;T0i-0i-[ iiI" ȭ;TI" ȭ;Ti,0i,i.[ iiI"Ȯ;TI"Ȯ;T0i/0i/[ iiI"ȯ;TI"ȯ;Ti.0i.i0[ iiI" Ȱ;TI" Ȱ;T0i10i1[ iiI" ȱ;TI" ȱ;Ti00i0i2[ iiI"Ȳ;TI"Ȳ;T0i30i3[ iiI"ȳ;TI"ȳ;Ti20i2iS[ ii00i0iiT[ ii00i0iiV[ ii00i0iiW[ ii00i0iiY[ ii00i0ii[[ ii00i0ii`[ ii00i0iic[ ii00i0iih[ ii00i0iii[ ii00i0iio[ ii00i0iir[ ii00i0iiu[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii0I"h;T000i[ ii0I"ɦ;T000i[ ii0I"j;T000i[ ii0I"r;T000i[ ii0I"ɹ;T000i[ ii0I"ɻ;T000i[ ii0I"ʁ;T000i[ ii0I"w;T000i[ ii0I"y;T000i[ ii0I" ̆;T000i[ ii0I" ̇;T000i[ ii0I" ̊;T000i[ ii0I" ̨;T000i[ ii0I" ̃;T000i[ ii0I" ̋;T000i[ ii0I"ɣ;T000i[ ii0I"l;T000i[ ii0I"s;T000i[ ii0I"x;T000i[ ii0I"ʕ;T000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i [ ii00000i [ ii00000i [ ii00000i [ ii00000i [ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i [ ii00000i![ ii00000i"[ ii00000i#[ ii00000i$[ ii00000i%[ ii00000i&[ ii00000i'[ ii00000i([ ii00000i)[ ii00000i*[ ii00000i+[ ii00000i,[ ii00000i-[ ii00000i.[ ii00000i/[ ii00000i0[ ii00000i1[ ii00000i2[ ii00000i3[ ii00000i4[ ii00000i5[ ii00000i6[ ii00000i7[ ii00000i8[ ii00000i9[ ii00000i:[ ii00000i;[ ii00000i<[ ii00000i=[ ii00000i>[ ii00000i?[ ii00000i@[ iiI"̀;TI"̀;T000iA[ iiI"́;TI"́;T000iB[ ii00000iC[ iiI"̓;TI"̓;T000iD[ iiI" ̈́;TI" ̈́;T000iE[ ii00i0iiF[ ii00000iG[ ii00000iH[ ii00000iI[ ii00000iJ[ ii00000iK[ ii00000iL[ ii00000iM[ ii00000iN[ ii00000i`[ ii00000ia[ ii00000ib[ ii00000it[ iiI"ʹ;TI"ʹ;T000iz[ ii0I" ͅ;T000i~[ iiI";;TI";;T000i[ ii0I" ́;T000i[ iiI" ΅;TI" ΅;T000i[ iiI" Ά;TI" Ά;T0i0i[ iiI"·;TI"·;T000i[ iiI" Έ;TI" Έ;T0i0i[ iiI" Ή;TI" Ή;T0i0i[ iiI" Ί;TI" Ί;T0i0i[ iiI" Ό;TI" Ό;T0i0i[ iiI" Ύ;TI" Ύ;T0i0i[ iiI" Ώ;TI" Ώ;T0i0i[ iiI" ΐ;TI" ΐ;T000i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ ii000i0i[ iiI" Ϊ;TI" Ϊ;T0i0i[ iiI" Ϋ;TI" Ϋ;T0i0i[ iiI" ά;TI" ά;Ti0ii[ iiI" έ;TI" έ;Ti0ii[ iiI" ή;TI" ή;Ti0ii[ iiI" ί;TI" ί;Ti0ii[ iiI" ΰ;TI" ΰ;T000i[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ ii00i0ii[ iiI" ϊ;TI" ϊ;Ti0ii[ iiI" ϋ;TI" ϋ;Ti0ii[ iiI" ό;TI" ό;Ti0ii[ iiI" ύ;TI" ύ;Ti0ii[ iiI" ώ;TI" ώ;Ti0ii[ ii0I"β;Ti0ii[ ii0I"θ;Ti0ii[ ii0I"Υ;T000i[ iiI" ϓ;TI" ϓ;T000i[ iiI" ϔ;TI" ϔ;T000i[ ii0I"φ;Ti0ii[ ii0I"π;Ti0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii0I"κ;Ti0ii[ ii0I"ρ;Ti0ii[ ii0I"ς;Ti0ii[ iiI" Ѐ;TI" Ѐ;T0iP0i[ iiI" Ё;TI" Ё;T0iQ0i[ ii000iR0i[ iiI" Ѓ;TI" Ѓ;T0iS0i[ ii000iT0i[ ii000iU0i[ ii000iV0i[ iiI" Ї;TI" Ї;T0iW0i[ ii000iX0i [ ii000iY0i [ ii000iZ0i [ ii000i[0i [ iiI" Ќ;TI" Ќ;T0i\0i [ iiI" Ѝ;TI" Ѝ;T0i]0i[ iiI" Ў;TI" Ў;T0i^0i[ ii000i_0i[ ii000i00i[ ii000i10i[ ii000i20i[ ii000i30i[ ii000i40i[ ii000i50i[ ii000i60i[ ii000i70i[ ii000i80i[ iiI" Й;TI" Й;T0i90i[ ii000i:0i[ ii000i;0i[ ii000i<0i[ ii000i=0i[ ii000i>0i[ ii000i?0i [ ii000i@0i![ ii000iA0i"[ ii000iB0i#[ ii000iC0i$[ ii000iD0i%[ ii000iE0i&[ ii000iF0i'[ ii000iG0i([ ii000iH0i)[ ii000iI0i*[ ii000iJ0i+[ ii000iK0i,[ ii000iL0i-[ ii000iM0i.[ ii000iN0i/[ ii000iO0i0[ ii00i0ii1[ ii00i0ii2[ ii00i0ii3[ ii00i0ii4[ ii00i0ii5[ ii00i0ii6[ ii00i0ii7[ ii00i0ii8[ ii00i0ii9[ iiI" й;TI" й;Ti0ii:[ ii00i0ii;[ ii00i0ii<[ ii00i0ii=[ ii00i0ii>[ ii00i0ii?[ ii00i0ii@[ ii00i 0i iA[ ii00i!0i!iB[ ii00i"0i"iC[ ii00i#0i#iD[ ii00i$0i$iE[ ii00i%0i%iF[ ii00i&0i&iG[ ii00i'0i'iH[ ii00i(0i(iI[ ii00i)0i)iJ[ ii00i*0i*iK[ ii00i+0i+iL[ ii00i,0i,iM[ ii00i-0i-iN[ ii00i.0i.iO[ ii00i/0i/iP[ iiI" ѐ;TI" ѐ;Ti0iiQ[ iiI" ё;TI" ё;Ti0iiR[ ii00i0iiS[ iiI" ѓ;TI" ѓ;Ti0iiT[ ii00i0iiU[ ii00i0iiV[ ii00i0iiW[ iiI" ї;TI" ї;Ti0iiX[ ii00i0iiY[ ii00i 0i iZ[ ii00i 0i i[[ ii00i 0i i\[ iiI" ќ;TI" ќ;Ti 0i i][ iiI" ѝ;TI" ѝ;Ti 0i i^[ iiI" ў;TI" ў;Ti0ii_[ ii00i0ii`[ ii000ia0ia[ ii00i`0i`ib[ ii000ic0ic[ ii00ib0ibid[ ii000ie0ie[ ii00id0idif[ ii000ig0ig[ ii00if0ifih[ ii000ii0ii[ ii00ih0ihij[ ii000ik0ik[ ii00ij0ijil[ ii000im0im[ ii00il0ilin[ ii000io0io[ ii00in0inip[ ii000iq0iq[ ii00ip0ipir[ ii000is0is[ ii00ir0irit[ ii000iu0iu[ ii00it0itiv[ iiI" Ѷ;TI" Ѷ;T0iw0iw[ iiI" ѷ;TI" ѷ;Tiv0ivix[ ii000iy0iy[ ii00ix0ixiz[ ii000i{0i{[ ii00iz0izi|[ ii000i}0i}[ ii00i|0i|i~[ ii000i0i[ ii00i~0i~i[ ii000i0i[ ii00i0ii[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ iiI" Ӂ;TI" Ӂ;T0i0i[ iiI" ӂ;TI" ӂ;Ti0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ ii000i0i[ ii00i0ii[ iiI" Ӑ;TI" Ӑ;T0i0i[ iiI" ӑ;TI" ӑ;Ti0ii[ iiI" Ӓ;TI" Ӓ;T0i0i[ iiI" ӓ;TI" ӓ;Ti0ii[ ii000i0i[ ii00i0ii[ iiI" Ӗ;TI" Ӗ;T0i0i[ iiI" ӗ;TI" ӗ;Ti0ii[ ii000i0i[ ii00i0ii[ iiI" Ӛ;TI" Ӛ;T0i0i[ iiI" ӛ;TI" ӛ;Ti0ii[ iiI" Ӝ;TI" Ӝ;T0i0i[ iiI" ӝ;TI" ӝ;Ti0ii[ iiI" Ӟ;TI" Ӟ;T0i0i[ iiI" ӟ;TI" ӟ;Ti0ii[ ii000i0i[ ii00i0ii[ iiI" Ӣ;TI" Ӣ;T0i0i[ iiI" ӣ;TI" ӣ;Ti0ii[ iiI" Ӥ;TI" Ӥ;T0i0i[ iiI" ӥ;TI" ӥ;Ti0ii[ iiI" Ӧ;TI" Ӧ;T0i0i[ iiI" ӧ;TI" ӧ;Ti0ii[ ii000i0i[ ii00i0ii[ iiI" Ӫ;TI" Ӫ;T0i0i[ iiI" ӫ;TI" ӫ;Ti0ii[ iiI" Ӭ;TI" Ӭ;T0i0i[ iiI" ӭ;TI" ӭ;Ti0ii[ iiI" Ӯ;TI" Ӯ;T0i0i[ iiI" ӯ;TI" ӯ;Ti0ii[ iiI" Ӱ;TI" Ӱ;T0i0i[ iiI" ӱ;TI" ӱ;Ti0ii[ iiI" Ӳ;TI" Ӳ;T0i0i[ iiI" ӳ;TI" ӳ;Ti0ii[ iiI" Ӵ;TI" Ӵ;T0i0i[ iiI" ӵ;TI" ӵ;Ti0ii[ iiI" Ӹ;TI" Ӹ;T0i0i[ iiI" ӹ;TI" ӹ;Ti0ii1[ ii000ia0i2[ ii000ib0i3[ ii000ic0i4[ ii000id0i5[ ii000ie0i6[ ii000if0i7[ ii000ig0i8[ ii000ih0i9[ ii000ii0i:[ ii000ij0i;[ ii000ik0i<[ ii000il0i=[ ii000im0i>[ ii000in0i?[ ii000io0i@[ ii000ip0iA[ ii000iq0iB[ ii000ir0iC[ ii000is0iD[ ii000it0iE[ ii000iu0iF[ ii000iv0iG[ ii000iw0iH[ ii000ix0iI[ ii000iy0iJ[ ii000iz0iK[ ii000i{0iL[ ii000i|0iM[ ii000i}0iN[ ii000i~0iO[ ii000i0iP[ ii000i0iQ[ ii000i0iR[ ii000i0iS[ ii000i0iT[ ii000i0iU[ ii000i0iV[ ii000i0ia[ ii00i10i1ib[ ii00i20i2ic[ ii00i30i3id[ ii00i40i4ie[ ii00i50i5if[ ii00i60i6ig[ ii00i70i7ih[ ii00i80i8ii[ ii00i90i9ij[ ii00i:0i:ik[ ii00i;0i;il[ ii00i<0i<im[ ii00i=0i=in[ ii00i>0i>io[ ii00i?0i?ip[ ii00i@0i@iq[ ii00iA0iAir[ ii00iB0iBis[ ii00iC0iCit[ ii00iD0iDiu[ ii00iE0iEiv[ ii00iF0iFiw[ ii00iG0iGix[ ii00iH0iHiy[ ii00iI0iIiz[ ii00iJ0iJi{[ ii00iK0iKi|[ ii00iL0iLi}[ ii00iM0iMi~[ ii00iN0iNi[ ii00iO0iOi[ ii00iP0iPi[ ii00iQ0iQi[ ii00iR0iRi[ ii00iS0iSi[ ii00iT0iTi[ ii00iU0iUi[ ii00iV0iVi[ ii0I" եւ;T000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i"[ iiI" آ;TI" آ;T000i#[ iiI" أ;TI" أ;T000i$[ iiI" ؤ;TI" ؤ;T000i%[ iiI" إ;TI" إ;T000i&[ iiI" ئ;TI" ئ;T000iK[ i i00000iL[ i!i00000iM[ i"i00000iN[ i#i00000iO[ i$i00000iP[ i%i00000iQ[ i&i00000iR[ i'i00000iS[ ii00000iT[ ii00000iU[ ii00000ip[ i(i00000iu[ ii0I" اٴ;T000iv[ ii0I" وٴ;T000iw[ ii0I" ۇٴ;T000ix[ ii0I" يٴ;T000i[ iiI" ۀ;TI" ۀ;T000i[ iiI" ۂ;TI" ۂ;T000i[ iiI" ۓ;TI" ۓ;T000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ i)i00000i0[ ii00000i1[ ii00000i2[ ii00000i3[ ii00000i4[ ii00000i5[ ii00000i6[ ii00000i7[ ii00000i8[ ii00000i9[ ii00000i:[ ii00000i;[ ii00000i<[ ii00000i=[ ii00000i>[ ii00000i?[ ii00000i@[ ii00000iA[ ii00000iB[ ii00000iC[ ii00000iD[ ii00000iE[ ii00000iF[ ii00000iG[ ii00000iH[ ii00000iI[ ii00000iJ[ ii00000i) [ iiI" ऩ;TI" ऩ;T000i1 [ iiI" ऱ;TI" ऱ;T000i4 [ iiI" ऴ;TI" ऴ;T000i< [ i i00000iM [ ii00000iQ [ ii00000iR [ ii00000iS [ ii00000iT [ ii00000iX [ iiI" क़;TI" क़;T000iY [ iiI" ख़;TI" ख़;T000iZ [ iiI" ग़;TI" ग़;T000i[ [ iiI" ज़;TI" ज़;T000i\ [ iiI" ड़;TI" ड़;T000i] [ iiI" ढ़;TI" ढ़;T000i^ [ iiI" फ़;TI" फ़;T000i_ [ iiI" य़;TI" य़;T000i [ i i00000i [ iiI" ো;TI" ো;T000i [ iiI" ৌ;TI" ৌ;T000i [ ii00000i [ iiI" ড়;TI" ড়;T000i [ iiI" ঢ়;TI" ঢ়;T000i [ iiI" য়;TI" য়;T000i3 [ iiI" ਲ਼;TI" ਲ਼;T000i6 [ iiI" ਸ਼;TI" ਸ਼;T000i< [ i i00000iM [ ii00000iY [ iiI" ਖ਼;TI" ਖ਼;T000iZ [ iiI" ਗ਼;TI" ਗ਼;T000i[ [ iiI" ਜ਼;TI" ਜ਼;T000i^ [ iiI" ਫ਼;TI" ਫ਼;T000i [ i i00000i [ ii00000i< [ i i00000iH [ iiI" ୈ;TI" ୈ;T000iK [ iiI" ୋ;TI" ୋ;T000iL [ iiI" ୌ;TI" ୌ;T000iM [ ii00000i\ [ iiI" ଡ଼;TI" ଡ଼;T000i] [ iiI" ଢ଼;TI" ଢ଼;T000i [ iiI" ஔ;TI" ஔ;T000i [ iiI" ொ;TI" ொ;T000i [ iiI" ோ;TI" ோ;T000i [ iiI" ௌ;TI" ௌ;T000i [ ii00000iH [ iiI" ై;TI" ై;T000iM [ ii00000iU [ iYi00000iV [ i`i00000i [ iiI" ೀ;TI" ೀ;T000i [ iiI" ೇ;TI" ೇ;T000i [ iiI" ೈ;TI" ೈ;T000i [ iiI" ೊ;TI" ೊ;T000i [ iiI" ೋ;TI" ೋ;T000i [ ii00000iJ [ iiI" ൊ;TI" ൊ;T000iK [ iiI" ോ;TI" ോ;T000iL [ iiI" ൌ;TI" ൌ;T000iM [ ii00000i [ ii00000i [ iiI" ේ;TI" ේ;T000i [ iiI" ො;TI" ො;T000i [ iiI" ෝ;TI" ෝ;T000i [ iiI" ෞ;TI" ෞ;T000i3[ ii0I" ํา;T000i8[ ili00000i9[ ili00000i:[ ii00000iH[ ipi00000iI[ ipi00000iJ[ ipi00000iK[ ipi00000i[ ii0I" ໍາ;T000i[ i{i00000i[ i{i00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii0I" ຫນ;T000i[ ii0I" ຫມ;T000i [ ii0I"་;T000i[ ii00000i[ ii00000i5[ ii00000i7[ ii00000i9[ ii00000iC[ iiI" གྷ;TI" གྷ;T000iM[ iiI" ཌྷ;TI" ཌྷ;T000iR[ iiI" དྷ;TI" དྷ;T000iW[ iiI" བྷ;TI" བྷ;T000i\[ iiI" ཛྷ;TI" ཛྷ;T000ii[ iiI" ཀྵ;TI" ཀྵ;T000iq[ ii00000ir[ ii00000is[ iiI" ཱི;TI" ཱི;T000it[ ii00000iu[ iiI" ཱུ;TI" ཱུ;T000iv[ iiI" ྲྀ;TI" ྲྀ;T000iw[ ii0I" ྲཱྀ;T000ix[ iiI" ླྀ;TI" ླྀ;T000iy[ ii0I" ླཱྀ;T000iz[ ii00000i{[ ii00000i|[ ii00000i}[ ii00000i[ ii00000i[ iiI" ཱྀ;TI" ཱྀ;T000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ ii00000i[ iiI" ྒྷ;TI" ྒྷ;T000i[ iiI" ྜྷ;TI" ྜྷ;T000i[ iiI" ྡྷ;TI" ྡྷ;T000i[ iiI" ྦྷ;TI" ྦྷ;T000i[ iiI" ྫྷ;TI" ྫྷ;T000i[ iiI" ྐྵ;TI" ྐྵ;T000i[ ii00000i&[ iiI" ဦ;TI" ဦ;T000i7[ i i00000i9[ ii00000i[ ii00000i[ ii00000i[ iiI"Ḁ;TI"Ḁ;T0i0i[ iiI"ḁ;TI"ḁ;Ti0ii[ iiI"Ḃ;TI"Ḃ;T0i0i[ iiI"ḃ;TI"ḃ;Ti0ii[ iiI"Ḅ;TI"Ḅ;T0i0i[ iiI"ḅ;TI"ḅ;Ti0ii[ iiI"Ḇ;TI"Ḇ;T0i0i[ iiI"ḇ;TI"ḇ;Ti0ii[ iiI" Ḉ;TI" Ḉ;T0i 0i [ iiI" ḉ;TI" ḉ;Ti0ii [ iiI"Ḋ;TI"Ḋ;T0i 0i [ iiI"ḋ;TI"ḋ;Ti 0i i [ iiI"Ḍ;TI"Ḍ;T0i 0i [ iiI"ḍ;TI"ḍ;Ti 0i i[ iiI"Ḏ;TI"Ḏ;T0i0i[ iiI"ḏ;TI"ḏ;Ti0ii[ iiI"Ḑ;TI"Ḑ;T0i0i[ iiI"ḑ;TI"ḑ;Ti0ii[ iiI"Ḓ;TI"Ḓ;T0i0i[ iiI"ḓ;TI"ḓ;Ti0ii[ iiI" Ḕ;TI" Ḕ;T0i0i[ iiI" ḕ;TI" ḕ;Ti0ii[ iiI" Ḗ;TI" Ḗ;T0i0i[ iiI" ḗ;TI" ḗ;Ti0ii[ iiI"Ḙ;TI"Ḙ;T0i0i[ iiI"ḙ;TI"ḙ;Ti0ii[ iiI"Ḛ;TI"Ḛ;T0i0i[ iiI"ḛ;TI"ḛ;Ti0ii[ iiI" Ḝ;TI" Ḝ;T0i0i[ iiI" ḝ;TI" ḝ;Ti0ii[ iiI"Ḟ;TI"Ḟ;T0i0i[ iiI"ḟ;TI"ḟ;Ti0ii [ iiI"Ḡ;TI"Ḡ;T0i!0i![ iiI"ḡ;TI"ḡ;Ti 0i i"[ iiI"Ḣ;TI"Ḣ;T0i#0i#[ iiI"ḣ;TI"ḣ;Ti"0i"i$[ iiI"Ḥ;TI"Ḥ;T0i%0i%[ iiI"ḥ;TI"ḥ;Ti$0i$i&[ iiI"Ḧ;TI"Ḧ;T0i'0i'[ iiI"ḧ;TI"ḧ;Ti&0i&i([ iiI"Ḩ;TI"Ḩ;T0i)0i)[ iiI"ḩ;TI"ḩ;Ti(0i(i*[ iiI"Ḫ;TI"Ḫ;T0i+0i+[ iiI"ḫ;TI"ḫ;Ti*0i*i,[ iiI"Ḭ;TI"Ḭ;T0i-0i-[ iiI"ḭ;TI"ḭ;Ti,0i,i.[ iiI" Ḯ;TI" Ḯ;T0i/0i/[ iiI" ḯ;TI" ḯ;Ti.0i.i0[ iiI"Ḱ;TI"Ḱ;T0i10i1[ iiI"ḱ;TI"ḱ;Ti00i0i2[ iiI"Ḳ;TI"Ḳ;T0i30i3[ iiI"ḳ;TI"ḳ;Ti20i2i4[ iiI"Ḵ;TI"Ḵ;T0i50i5[ iiI"ḵ;TI"ḵ;Ti40i4i6[ iiI"Ḷ;TI"Ḷ;T0i70i7[ iiI"ḷ;TI"ḷ;Ti60i6i8[ iiI" Ḹ;TI" Ḹ;T0i90i9[ iiI" ḹ;TI" ḹ;Ti80i8i:[ iiI"Ḻ;TI"Ḻ;T0i;0i;[ iiI"ḻ;TI"ḻ;Ti:0i:i<[ iiI"Ḽ;TI"Ḽ;T0i=0i=[ iiI"ḽ;TI"ḽ;Ti<0i<i>[ iiI"Ḿ;TI"Ḿ;T0i?0i?[ iiI"ḿ;TI"ḿ;Ti>0i>i@[ iiI"Ṁ;TI"Ṁ;T0iA0iA[ iiI"ṁ;TI"ṁ;Ti@0i@iB[ iiI"Ṃ;TI"Ṃ;T0iC0iC[ iiI"ṃ;TI"ṃ;TiB0iBiD[ iiI"Ṅ;TI"Ṅ;T0iE0iE[ iiI"ṅ;TI"ṅ;TiD0iDiF[ iiI"Ṇ;TI"Ṇ;T0iG0iG[ iiI"ṇ;TI"ṇ;TiF0iFiH[ iiI"Ṉ;TI"Ṉ;T0iI0iI[ iiI"ṉ;TI"ṉ;TiH0iHiJ[ iiI"Ṋ;TI"Ṋ;T0iK0iK[ iiI"ṋ;TI"ṋ;TiJ0iJiL[ iiI" Ṍ;TI" Ṍ;T0iM0iM[ iiI" ṍ;TI" ṍ;TiL0iLiN[ iiI" Ṏ;TI" Ṏ;T0iO0iO[ iiI" ṏ;TI" ṏ;TiN0iNiP[ iiI" Ṑ;TI" Ṑ;T0iQ0iQ[ iiI" ṑ;TI" ṑ;TiP0iPiR[ iiI" Ṓ;TI" Ṓ;T0iS0iS[ iiI" ṓ;TI" ṓ;TiR0iRiT[ iiI"Ṕ;TI"Ṕ;T0iU0iU[ iiI"ṕ;TI"ṕ;TiT0iTiV[ iiI"Ṗ;TI"Ṗ;T0iW0iW[ iiI"ṗ;TI"ṗ;TiV0iViX[ iiI"Ṙ;TI"Ṙ;T0iY0iY[ iiI"ṙ;TI"ṙ;TiX0iXiZ[ iiI"Ṛ;TI"Ṛ;T0i[0i[[ iiI"ṛ;TI"ṛ;TiZ0iZi\[ iiI" Ṝ;TI" Ṝ;T0i]0i][ iiI" ṝ;TI" ṝ;Ti\0i\i^[ iiI"Ṟ;TI"Ṟ;T0i_0i_[ iiI"ṟ;TI"ṟ;Ti^0i^i`[ iiI"Ṡ;TI"Ṡ;T0ia0ia[ iiI"ṡ;TI"ṡ;Ti`0i`ib[ iiI"Ṣ;TI"Ṣ;T0ic0ic[ iiI"ṣ;TI"ṣ;Tib0ibid[ iiI" Ṥ;TI" Ṥ;T0ie0ie[ iiI" ṥ;TI" ṥ;Tid0idif[ iiI" Ṧ;TI" Ṧ;T0ig0ig[ iiI" ṧ;TI" ṧ;Tif0ifih[ iiI" Ṩ;TI" Ṩ;T0ii0ii[ iiI" ṩ;TI" ṩ;Tih0ihij[ iiI"Ṫ;TI"Ṫ;T0ik0ik[ iiI"ṫ;TI"ṫ;Tij0ijil[ iiI"Ṭ;TI"Ṭ;T0im0im[ iiI"ṭ;TI"ṭ;Til0ilin[ iiI"Ṯ;TI"Ṯ;T0io0io[ iiI"ṯ;TI"ṯ;Tin0inip[ iiI"Ṱ;TI"Ṱ;T0iq0iq[ iiI"ṱ;TI"ṱ;Tip0ipir[ iiI"Ṳ;TI"Ṳ;T0is0is[ iiI"ṳ;TI"ṳ;Tir0irit[ iiI"Ṵ;TI"Ṵ;T0iu0iu[ iiI"ṵ;TI"ṵ;Tit0itiv[ iiI"Ṷ;TI"Ṷ;T0iw0iw[ iiI"ṷ;TI"ṷ;Tiv0ivix[ iiI" Ṹ;TI" Ṹ;T0iy0iy[ iiI" ṹ;TI" ṹ;Tix0ixiz[ iiI" Ṻ;TI" Ṻ;T0i{0i{[ iiI" ṻ;TI" ṻ;Tiz0izi|[ iiI"Ṽ;TI"Ṽ;T0i}0i}[ iiI"ṽ;TI"ṽ;Ti|0i|i~[ iiI"Ṿ;TI"Ṿ;T0i0i[ iiI"ṿ;TI"ṿ;Ti~0i~i[ iiI"Ẁ;TI"Ẁ;T0i0i[ iiI"ẁ;TI"ẁ;Ti0ii[ iiI"Ẃ;TI"Ẃ;T0i0i[ iiI"ẃ;TI"ẃ;Ti0ii[ iiI"Ẅ;TI"Ẅ;T0i0i[ iiI"ẅ;TI"ẅ;Ti0ii[ iiI"Ẇ;TI"Ẇ;T0i0i[ iiI"ẇ;TI"ẇ;Ti0ii[ iiI"Ẉ;TI"Ẉ;T0i0i[ iiI"ẉ;TI"ẉ;Ti0ii[ iiI"Ẋ;TI"Ẋ;T0i0i[ iiI"ẋ;TI"ẋ;Ti0ii[ iiI"Ẍ;TI"Ẍ;T0i0i[ iiI"ẍ;TI"ẍ;Ti0ii[ iiI"Ẏ;TI"Ẏ;T0i0i[ iiI"ẏ;TI"ẏ;Ti0ii[ iiI"Ẑ;TI"Ẑ;T0i0i[ iiI"ẑ;TI"ẑ;Ti0ii[ iiI"Ẓ;TI"Ẓ;T0i0i[ iiI"ẓ;TI"ẓ;Ti0ii[ iiI"Ẕ;TI"Ẕ;T0i0i[ iiI"ẕ;TI"ẕ;Ti0ii[ iiI"ẖ;TI"ẖ;T000i[ iiI"ẗ;TI"ẗ;T000i[ iiI"ẘ;TI"ẘ;T000i[ iiI"ẙ;TI"ẙ;T000i[ ii0I"aʾ;T000i[ iiI" ẛ;TI" ẛ;Ti`0i`i[ iiI"Ạ;TI"Ạ;T0i0i[ iiI"ạ;TI"ạ;Ti0ii[ iiI"Ả;TI"Ả;T0i0i[ iiI"ả;TI"ả;Ti0ii[ iiI" Ấ;TI" Ấ;T0i0i[ iiI" ấ;TI" ấ;Ti0ii[ iiI" Ầ;TI" Ầ;T0i0i[ iiI" ầ;TI" ầ;Ti0ii[ iiI" Ẩ;TI" Ẩ;T0i0i[ iiI" ẩ;TI" ẩ;Ti0ii[ iiI" Ẫ;TI" Ẫ;T0i0i[ iiI" ẫ;TI" ẫ;Ti0ii[ iiI" Ậ;TI" Ậ;T0i0i[ iiI" ậ;TI" ậ;Ti0ii[ iiI" Ắ;TI" Ắ;T0i0i[ iiI" ắ;TI" ắ;Ti0ii[ iiI" Ằ;TI" Ằ;T0i0i[ iiI" ằ;TI" ằ;Ti0ii[ iiI" Ẳ;TI" Ẳ;T0i0i[ iiI" ẳ;TI" ẳ;Ti0ii[ iiI" Ẵ;TI" Ẵ;T0i0i[ iiI" ẵ;TI" ẵ;Ti0ii[ iiI" Ặ;TI" Ặ;T0i0i[ iiI" ặ;TI" ặ;Ti0ii[ iiI"Ẹ;TI"Ẹ;T0i0i[ iiI"ẹ;TI"ẹ;Ti0ii[ iiI"Ẻ;TI"Ẻ;T0i0i[ iiI"ẻ;TI"ẻ;Ti0ii[ iiI"Ẽ;TI"Ẽ;T0i0i[ iiI"ẽ;TI"ẽ;Ti0ii[ iiI" Ế;TI" Ế;T0i0i[ iiI" ế;TI" ế;Ti0ii[ iiI" Ề;TI" Ề;T0i0i[ iiI" ề;TI" ề;Ti0ii[ iiI" Ể;TI" Ể;T0i0i[ iiI" ể;TI" ể;Ti0ii[ iiI" Ễ;TI" Ễ;T0i0i[ iiI" ễ;TI" ễ;Ti0ii[ iiI" Ệ;TI" Ệ;T0i0i[ iiI" ệ;TI" ệ;Ti0ii[ iiI"Ỉ;TI"Ỉ;T0i0i[ iiI"ỉ;TI"ỉ;Ti0ii[ iiI"Ị;TI"Ị;T0i0i[ iiI"ị;TI"ị;Ti0ii[ iiI"Ọ;TI"Ọ;T0i0i[ iiI"ọ;TI"ọ;Ti0ii[ iiI"Ỏ;TI"Ỏ;T0i0i[ iiI"ỏ;TI"ỏ;Ti0ii[ iiI" Ố;TI" Ố;T0i0i[ iiI" ố;TI" ố;Ti0ii[ iiI" Ồ;TI" Ồ;T0i0i[ iiI" ồ;TI" ồ;Ti0ii[ iiI" Ổ;TI" Ổ;T0i0i[ iiI" ổ;TI" ổ;Ti0ii[ iiI" Ỗ;TI" Ỗ;T0i0i[ iiI" ỗ;TI" ỗ;Ti0ii[ iiI" Ộ;TI" Ộ;T0i0i[ iiI" ộ;TI" ộ;Ti0ii[ iiI" Ớ;TI" Ớ;T0i0i[ iiI" ớ;TI" ớ;Ti0ii[ iiI" Ờ;TI" Ờ;T0i0i[ iiI" ờ;TI" ờ;Ti0ii[ iiI" Ở;TI" Ở;T0i0i[ iiI" ở;TI" ở;Ti0ii[ iiI" Ỡ;TI" Ỡ;T0i0i[ iiI" ỡ;TI" ỡ;Ti0ii[ iiI" Ợ;TI" Ợ;T0i0i[ iiI" ợ;TI" ợ;Ti0ii[ iiI"Ụ;TI"Ụ;T0i0i[ iiI"ụ;TI"ụ;Ti0ii[ iiI"Ủ;TI"Ủ;T0i0i[ iiI"ủ;TI"ủ;Ti0ii[ iiI" Ứ;TI" Ứ;T0i0i[ iiI" ứ;TI" ứ;Ti0ii[ iiI" Ừ;TI" Ừ;T0i0i[ iiI" ừ;TI" ừ;Ti0ii[ iiI" Ử;TI" Ử;T0i0i[ iiI" ử;TI" ử;Ti0ii[ iiI" Ữ;TI" Ữ;T0i0i[ iiI" ữ;TI" ữ;Ti0ii[ iiI" Ự;TI" Ự;T0i0i[ iiI" ự;TI" ự;Ti0ii[ iiI"Ỳ;TI"Ỳ;T0i0i[ iiI"ỳ;TI"ỳ;Ti0ii[ iiI"Ỵ;TI"Ỵ;T0i0i[ iiI"ỵ;TI"ỵ;Ti0ii[ iiI"Ỷ;TI"Ỷ;T0i0i[ iiI"ỷ;TI"ỷ;Ti0ii[ iiI"Ỹ;TI"Ỹ;T0i0i[ iiI"ỹ;TI"ỹ;Ti0ii[ iiI" ἀ;TI" ἀ;Ti0ii[ iiI" ἁ;TI" ἁ;Ti 0i i[ iiI" ἂ;TI" ἂ;Ti 0i i[ iiI" ἃ;TI" ἃ;Ti 0i i[ iiI" ἄ;TI" ἄ;Ti 0i i[ iiI" ἅ;TI" ἅ;Ti 0i i[ iiI" ἆ;TI" ἆ;Ti0ii[ iiI" ἇ;TI" ἇ;Ti0ii[ iiI" Ἀ;TI" Ἀ;T0i0i [ iiI" Ἁ;TI" Ἁ;T0i0i [ iiI" Ἂ;TI" Ἂ;T0i0i [ iiI" Ἃ;TI" Ἃ;T0i0i [ iiI" Ἄ;TI" Ἄ;T0i0i [ iiI" Ἅ;TI" Ἅ;T0i0i[ iiI" Ἆ;TI" Ἆ;T0i0i[ iiI" Ἇ;TI" Ἇ;T0i0i[ iiI" ἐ;TI" ἐ;Ti0ii[ iiI" ἑ;TI" ἑ;Ti0ii[ iiI" ἒ;TI" ἒ;Ti0ii[ iiI" ἓ;TI" ἓ;Ti0ii[ iiI" ἔ;TI" ἔ;Ti0ii[ iiI" ἕ;TI" ἕ;Ti0ii[ iiI" Ἐ;TI" Ἐ;T0i0i[ iiI" Ἑ;TI" Ἑ;T0i0i[ iiI" Ἒ;TI" Ἒ;T0i0i[ iiI" Ἓ;TI" Ἓ;T0i0i[ iiI" Ἔ;TI" Ἔ;T0i0i[ iiI" Ἕ;TI" Ἕ;T0i0i [ iiI" ἠ;TI" ἠ;Ti(0i(i![ iiI" ἡ;TI" ἡ;Ti)0i)i"[ iiI" ἢ;TI" ἢ;Ti*0i*i#[ iiI" ἣ;TI" ἣ;Ti+0i+i$[ iiI" ἤ;TI" ἤ;Ti,0i,i%[ iiI" ἥ;TI" ἥ;Ti-0i-i&[ iiI" ἦ;TI" ἦ;Ti.0i.i'[ iiI" ἧ;TI" ἧ;Ti/0i/i([ iiI" Ἠ;TI" Ἠ;T0i 0i)[ iiI" Ἡ;TI" Ἡ;T0i!0i*[ iiI" Ἢ;TI" Ἢ;T0i"0i+[ iiI" Ἣ;TI" Ἣ;T0i#0i,[ iiI" Ἤ;TI" Ἤ;T0i$0i-[ iiI" Ἥ;TI" Ἥ;T0i%0i.[ iiI" Ἦ;TI" Ἦ;T0i&0i/[ iiI" Ἧ;TI" Ἧ;T0i'0i0[ iiI" ἰ;TI" ἰ;Ti80i8i1[ iiI" ἱ;TI" ἱ;Ti90i9i2[ iiI" ἲ;TI" ἲ;Ti:0i:i3[ iiI" ἳ;TI" ἳ;Ti;0i;i4[ iiI" ἴ;TI" ἴ;Ti<0i<i5[ iiI" ἵ;TI" ἵ;Ti=0i=i6[ iiI" ἶ;TI" ἶ;Ti>0i>i7[ iiI" ἷ;TI" ἷ;Ti?0i?i8[ iiI" Ἰ;TI" Ἰ;T0i00i9[ iiI" Ἱ;TI" Ἱ;T0i10i:[ iiI" Ἲ;TI" Ἲ;T0i20i;[ iiI" Ἳ;TI" Ἳ;T0i30i<[ iiI" Ἴ;TI" Ἴ;T0i40i=[ iiI" Ἵ;TI" Ἵ;T0i50i>[ iiI" Ἶ;TI" Ἶ;T0i60i?[ iiI" Ἷ;TI" Ἷ;T0i70i@[ iiI" ὀ;TI" ὀ;TiH0iHiA[ iiI" ὁ;TI" ὁ;TiI0iIiB[ iiI" ὂ;TI" ὂ;TiJ0iJiC[ iiI" ὃ;TI" ὃ;TiK0iKiD[ iiI" ὄ;TI" ὄ;TiL0iLiE[ iiI" ὅ;TI" ὅ;TiM0iMiH[ iiI" Ὀ;TI" Ὀ;T0i@0iI[ iiI" Ὁ;TI" Ὁ;T0iA0iJ[ iiI" Ὂ;TI" Ὂ;T0iB0iK[ iiI" Ὃ;TI" Ὃ;T0iC0iL[ iiI" Ὄ;TI" Ὄ;T0iD0iM[ iiI" Ὅ;TI" Ὅ;T0iE0iP[ iiI" ὐ;TI" ὐ;T000iQ[ iiI" ὑ;TI" ὑ;TiY0iYiR[ iiI" ὒ;TI" ὒ;T000iS[ iiI" ὓ;TI" ὓ;Ti[0i[iT[ iiI" ὔ;TI" ὔ;T000iU[ iiI" ὕ;TI" ὕ;Ti]0i]iV[ iiI" ὖ;TI" ὖ;T000iW[ iiI" ὗ;TI" ὗ;Ti_0i_iY[ iiI" Ὑ;TI" Ὑ;T0iQ0i[[ iiI" Ὓ;TI" Ὓ;T0iS0i][ iiI" Ὕ;TI" Ὕ;T0iU0i_[ iiI" Ὗ;TI" Ὗ;T0iW0i`[ iiI" ὠ;TI" ὠ;Tih0ihia[ iiI" ὡ;TI" ὡ;Tii0iiib[ iiI" ὢ;TI" ὢ;Tij0ijic[ iiI" ὣ;TI" ὣ;Tik0ikid[ iiI" ὤ;TI" ὤ;Til0ilie[ iiI" ὥ;TI" ὥ;Tim0imif[ iiI" ὦ;TI" ὦ;Tin0inig[ iiI" ὧ;TI" ὧ;Tio0ioih[ iiI" Ὠ;TI" Ὠ;T0i`0ii[ iiI" Ὡ;TI" Ὡ;T0ia0ij[ iiI" Ὢ;TI" Ὢ;T0ib0ik[ iiI" Ὣ;TI" Ὣ;T0ic0il[ iiI" Ὤ;TI" Ὤ;T0id0im[ iiI" Ὥ;TI" Ὥ;T0ie0in[ iiI" Ὦ;TI" Ὦ;T0if0io[ iiI" Ὧ;TI" Ὧ;T0ig0ip[ iiI" ὰ;TI" ὰ;Ti0iiq[ iiI"ά;TI"ά;Ti0iir[ iiI" ὲ;TI" ὲ;Ti0iis[ iiI"έ;TI"έ;Ti0iit[ iiI" ὴ;TI" ὴ;Ti0iiu[ iiI"ή;TI"ή;Ti0iiv[ iiI" ὶ;TI" ὶ;Ti0iiw[ iiI"ί;TI"ί;Ti0iix[ iiI" ὸ;TI" ὸ;Ti0iiy[ iiI"ό;TI"ό;Ti0iiz[ iiI" ὺ;TI" ὺ;Ti0ii{[ iiI"ύ;TI"ύ;Ti0ii|[ iiI" ὼ;TI" ὼ;Ti0ii}[ iiI"ώ;TI"ώ;Ti0ii[ iiI" ᾀ;TI" ᾀ;Ti0ii[ iiI" ᾁ;TI" ᾁ;Ti0ii[ iiI" ᾂ;TI" ᾂ;Ti0ii[ iiI" ᾃ;TI" ᾃ;Ti0ii[ iiI" ᾄ;TI" ᾄ;Ti0ii[ iiI" ᾅ;TI" ᾅ;Ti0ii[ iiI" ᾆ;TI" ᾆ;Ti0ii[ iiI" ᾇ;TI" ᾇ;Ti0ii[ iiI" ᾈ;TI" ᾈ;T0i0i[ iiI" ᾉ;TI" ᾉ;T0i0i[ iiI" ᾊ;TI" ᾊ;T0i0i[ iiI" ᾋ;TI" ᾋ;T0i0i[ iiI" ᾌ;TI" ᾌ;T0i0i[ iiI" ᾍ;TI" ᾍ;T0i0i[ iiI" ᾎ;TI" ᾎ;T0i0i[ iiI" ᾏ;TI" ᾏ;T0i0i[ iiI" ᾐ;TI" ᾐ;Ti0ii[ iiI" ᾑ;TI" ᾑ;Ti0ii[ iiI" ᾒ;TI" ᾒ;Ti0ii[ iiI" ᾓ;TI" ᾓ;Ti0ii[ iiI" ᾔ;TI" ᾔ;Ti0ii[ iiI" ᾕ;TI" ᾕ;Ti0ii[ iiI" ᾖ;TI" ᾖ;Ti0ii[ iiI" ᾗ;TI" ᾗ;Ti0ii[ iiI" ᾘ;TI" ᾘ;T0i0i[ iiI" ᾙ;TI" ᾙ;T0i0i[ iiI" ᾚ;TI" ᾚ;T0i0i[ iiI" ᾛ;TI" ᾛ;T0i0i[ iiI" ᾜ;TI" ᾜ;T0i0i[ iiI" ᾝ;TI" ᾝ;T0i0i[ iiI" ᾞ;TI" ᾞ;T0i0i[ iiI" ᾟ;TI" ᾟ;T0i0i[ iiI" ᾠ;TI" ᾠ;Ti0ii[ iiI" ᾡ;TI" ᾡ;Ti0ii[ iiI" ᾢ;TI" ᾢ;Ti0ii[ iiI" ᾣ;TI" ᾣ;Ti0ii[ iiI" ᾤ;TI" ᾤ;Ti0ii[ iiI" ᾥ;TI" ᾥ;Ti0ii[ iiI" ᾦ;TI" ᾦ;Ti0ii[ iiI" ᾧ;TI" ᾧ;Ti0ii[ iiI" ᾨ;TI" ᾨ;T0i0i[ iiI" ᾩ;TI" ᾩ;T0i0i[ iiI" ᾪ;TI" ᾪ;T0i0i[ iiI" ᾫ;TI" ᾫ;T0i0i[ iiI" ᾬ;TI" ᾬ;T0i0i[ iiI" ᾭ;TI" ᾭ;T0i0i[ iiI" ᾮ;TI" ᾮ;T0i0i[ iiI" ᾯ;TI" ᾯ;T0i0i[ iiI" ᾰ;TI" ᾰ;Ti0ii[ iiI" ᾱ;TI" ᾱ;Ti0ii[ iiI" ᾲ;TI" ᾲ;T000i[ iiI" ᾳ;TI" ᾳ;Ti0ii[ iiI" ᾴ;TI" ᾴ;T000i[ iiI" ᾶ;TI" ᾶ;T000i[ iiI" ᾷ;TI" ᾷ;T000i[ iiI" Ᾰ;TI" Ᾰ;T0i0i[ iiI" Ᾱ;TI" Ᾱ;T0i0i[ iiI" Ὰ;TI" Ὰ;T0ip0i[ iiI"Ά;TI"Ά;T0iq0i[ iiI" ᾼ;TI" ᾼ;T0i0i[ ii0I" ̓;T000i[ iiI"ι;TI"ι;Ti0ii[ ii0I" ̓;T000i[ ii0I" ͂;T000i[ iiI" ῁;TI" ῁;T000i[ iiI" ῂ;TI" ῂ;T000i[ iiI" ῃ;TI" ῃ;Ti0ii[ iiI" ῄ;TI" ῄ;T000i[ iiI" ῆ;TI" ῆ;T000i[ iiI" ῇ;TI" ῇ;T000i[ iiI" Ὲ;TI" Ὲ;T0ir0i[ iiI"Έ;TI"Έ;T0is0i[ iiI" Ὴ;TI" Ὴ;T0it0i[ iiI"Ή;TI"Ή;T0iu0i[ iiI" ῌ;TI" ῌ;T0i0i[ iiI" ῍;TI" ῍;T000i[ iiI" ῎;TI" ῎;T000i[ iiI" ῏;TI" ῏;T000i[ iiI" ῐ;TI" ῐ;Ti0ii[ iiI" ῑ;TI" ῑ;Ti0ii[ iiI" ῒ;TI" ῒ;T000i[ iiI"ΐ;TI"ΐ;T000i[ iiI" ῖ;TI" ῖ;T000i[ iiI" ῗ;TI" ῗ;T000i[ iiI" Ῐ;TI" Ῐ;T0i0i[ iiI" Ῑ;TI" Ῑ;T0i0i[ iiI" Ὶ;TI" Ὶ;T0iv0i[ iiI"Ί;TI"Ί;T0iw0i[ iiI" ῝;TI" ῝;T000i[ iiI" ῞;TI" ῞;T000i[ iiI" ῟;TI" ῟;T000i[ iiI" ῠ;TI" ῠ;Ti0ii[ iiI" ῡ;TI" ῡ;Ti0ii[ iiI" ῢ;TI" ῢ;T000i[ iiI"ΰ;TI"ΰ;T000i[ iiI" ῤ;TI" ῤ;T000i[ iiI" ῥ;TI" ῥ;Ti0ii[ iiI" ῦ;TI" ῦ;T000i[ iiI" ῧ;TI" ῧ;T000i[ iiI" Ῠ;TI" Ῠ;T0i0i[ iiI" Ῡ;TI" Ῡ;T0i0i[ iiI" Ὺ;TI" Ὺ;T0iz0i[ iiI"Ύ;TI"Ύ;T0i{0i[ iiI" Ῥ;TI" Ῥ;T0i0i[ iiI" ῭;TI" ῭;T000i[ iiI"΅;TI"΅;T000i[ iiI"`;TI"`;T000i[ iiI" ῲ;TI" ῲ;T000i[ iiI" ῳ;TI" ῳ;Ti0ii[ iiI" ῴ;TI" ῴ;T000i[ iiI" ῶ;TI" ῶ;T000i[ iiI" ῷ;TI" ῷ;T000i[ iiI" Ὸ;TI" Ὸ;T0ix0i[ iiI"Ό;TI"Ό;T0iy0i[ iiI" Ὼ;TI" Ὼ;T0i|0i[ iiI"Ώ;TI"Ώ;T0i}0i[ iiI" ῼ;TI" ῼ;T0i0i[ iiI"´;TI"´;T000i[ ii0I" ̔;T000i [ iiI" ;TI" ;T000i [ iiI" ;TI" ;T000i [ ii0I" ;T000i [ ii0I" ;T000i [ ii0I" ;T000i [ ii0I" ;T000i [ ii0I" ;T000i [ ii0I" ;T000i [ ii0I" ;T000i [ ii0I" ;T000i [ ii0I" ;T000i [ ii0I"‐;T000i [ ii0I" ̳;T000i$ [ ii0I".;T000i% [ ii0I"..;T000i& [ ii0I"...;T000i/ [ ii0I" ;T000i3 [ ii0I" ′′;T000i4 [ ii0I"′′′;T000i6 [ ii0I" ‵‵;T000i7 [ ii0I"‵‵‵;T000i< [ ii0I"!!;T000i> [ ii0I" ̅;T000iH [ ii0I"?!;T000iI [ ii0I"!?;T000ip [ ii0I"0;T000it [ ii0I"4;T000iu [ ii0I"5;T000iv [ ii0I"6;T000iw [ ii0I"7;T000ix [ ii0I"8;T000iy [ ii0I"9;T000iz [ ii0I"+;T000i{ [ ii0I"−;T000i| [ ii0I"=;T000i} [ ii0I"(;T000i~ [ ii0I");T000i [ ii0I"n;T000i [ ii0I"0;T000i [ ii0I"1;T000i [ ii0I"2;T000i [ ii0I"3;T000i [ ii0I"4;T000i [ ii0I"5;T000i [ ii0I"6;T000i [ ii0I"7;T000i [ ii0I"8;T000i [ ii0I"9;T000i [ ii0I"+;T000i [ ii0I"−;T000i [ ii0I"=;T000i [ ii0I"(;T000i [ ii0I");T000i [ ii0I"Rs;T000i [ ii00000i [ ii00000i [ ii00000i [ ii00000i [ ii00000i [ ii00000i [ ii00000i [ ii00000i [ ii00000i [ ii00000i [ ii00000i [ ii00000i [ ii00000i [ ii00000i![ ii0I"a/c;T000i![ ii0I"a/s;T000i![ ii0I"C;T000i![ ii0I"°C;T000i![ ii0I"c/o;T000i![ ii0I"c/u;T000i![ ii0I"Ɛ;T000i ![ ii0I"°F;T000i ![ ii0I"g;T000i ![ ii0I"H;T000i ![ ii0I"H;T000i ![ ii0I"H;T000i![ ii0I"h;T000i![ ii0I"ħ;T000i![ ii0I"I;T000i![ ii0I"I;T000i![ ii0I"L;T000i![ ii0I"l;T000i![ ii0I"N;T000i![ ii0I"No;T000i![ ii0I"P;T000i![ ii0I"Q;T000i![ ii0I"R;T000i![ ii0I"R;T000i![ ii0I"R;T000i ![ ii0I"SM;T000i!![ ii0I"TEL;T000i"![ ii0I"TM;T000i$![ ii0I"Z;T000i&![ iiI"Ω;TI"Ω;T0i0i(![ ii0I"Z;T000i*![ iiI"K;TI"K;T0ip0i+![ iiI"Å;TI"Å;T0i0i,![ ii0I"B;T000i-![ ii0I"C;T000i/![ ii0I"e;T000i0![ ii0I"E;T000i1![ ii0I"F;T000i3![ ii0I"M;T000i4![ ii0I"o;T000i5![ ii0I"א;T000i6![ ii0I"ב;T000i7![ ii0I"ג;T000i8![ ii0I"ד;T000i9![ ii0I"i;T000iS![ ii0I" 1⁄3;T000iT![ ii0I" 2⁄3;T000iU![ ii0I" 1⁄5;T000iV![ ii0I" 2⁄5;T000iW![ ii0I" 3⁄5;T000iX![ ii0I" 4⁄5;T000iY![ ii0I" 1⁄6;T000iZ![ ii0I" 5⁄6;T000i[![ ii0I" 1⁄8;T000i\![ ii0I" 3⁄8;T000i]![ ii0I" 5⁄8;T000i^![ ii0I" 7⁄8;T000i_![ ii0I" 1⁄;T000i`![ ii0I"I;T0ip!0ia![ ii0I"II;T0iq!0ib![ ii0I"III;T0ir!0ic![ ii0I"IV;T0is!0id![ ii0I"V;T0it!0ie![ ii0I"VI;T0iu!0if![ ii0I"VII;T0iv!0ig![ ii0I" VIII;T0iw!0ih![ ii0I"IX;T0ix!0ii![ ii0I"X;T0iy!0ij![ ii0I"XI;T0iz!0ik![ ii0I"XII;T0i{!0il![ ii0I"L;T0i|!0im![ ii0I"C;T0i}!0in![ ii0I"D;T0i~!0io![ ii0I"M;T0i!0ip![ ii0I"i;Ti`!0i`!iq![ ii0I"ii;Tia!0ia!ir![ ii0I"iii;Tib!0ib!is![ ii0I"iv;Tic!0ic!it![ ii0I"v;Tid!0id!iu![ ii0I"vi;Tie!0ie!iv![ ii0I"vii;Tif!0if!iw![ ii0I" viii;Tig!0ig!ix![ ii0I"ix;Tih!0ih!iy![ ii0I"x;Tii!0ii!iz![ ii0I"xi;Tij!0ij!i{![ ii0I"xii;Tik!0ik!i|![ ii0I"l;Til!0il!i}![ ii0I"c;Tim!0im!i~![ ii0I"d;Tin!0in!i![ ii0I"m;Tio!0io!i![ iiI" ↚;TI" ↚;T000i![ iiI" ↛;TI" ↛;T000i![ iiI" ↮;TI" ↮;T000i![ iiI" ⇍;TI" ⇍;T000i![ iiI" ⇎;TI" ⇎;T000i![ iiI" ⇏;TI" ⇏;T000i"[ iiI" ∄;TI" ∄;T000i "[ iiI" ∉;TI" ∉;T000i "[ iiI" ∌;TI" ∌;T000i$"[ iiI" ∤;TI" ∤;T000i&"[ iiI" ∦;TI" ∦;T000i,"[ ii0I" ∫∫;T000i-"[ ii0I"∫∫∫;T000i/"[ ii0I" ∮∮;T000i0"[ ii0I"∮∮∮;T000iA"[ iiI" ≁;TI" ≁;T000iD"[ iiI" ≄;TI" ≄;T000iG"[ iiI" ≇;TI" ≇;T000iI"[ iiI" ≉;TI" ≉;T000i`"[ iiI"≠;TI"≠;T000ib"[ iiI" ≢;TI" ≢;T000im"[ iiI" ≭;TI" ≭;T000in"[ iiI"≮;TI"≮;T000io"[ iiI"≯;TI"≯;T000ip"[ iiI" ≰;TI" ≰;T000iq"[ iiI" ≱;TI" ≱;T000it"[ iiI" ≴;TI" ≴;T000iu"[ iiI" ≵;TI" ≵;T000ix"[ iiI" ≸;TI" ≸;T000iy"[ iiI" ≹;TI" ≹;T000i"[ iiI" ⊀;TI" ⊀;T000i"[ iiI" ⊁;TI" ⊁;T000i"[ iiI" ⊄;TI" ⊄;T000i"[ iiI" ⊅;TI" ⊅;T000i"[ iiI" ⊈;TI" ⊈;T000i"[ iiI" ⊉;TI" ⊉;T000i"[ iiI" ⊬;TI" ⊬;T000i"[ iiI" ⊭;TI" ⊭;T000i"[ iiI" ⊮;TI" ⊮;T000i"[ iiI" ⊯;TI" ⊯;T000i"[ iiI" ⋠;TI" ⋠;T000i"[ iiI" ⋡;TI" ⋡;T000i"[ iiI" ⋢;TI" ⋢;T000i"[ iiI" ⋣;TI" ⋣;T000i"[ iiI" ⋪;TI" ⋪;T000i"[ iiI" ⋫;TI" ⋫;T000i"[ iiI" ⋬;TI" ⋬;T000i"[ iiI" ⋭;TI" ⋭;T000i)#[ iiI"〈;TI"〈;T000i*#[ iiI"〉;TI"〉;T000i`$[ ii0I"1;T000ia$[ ii0I"2;T000ib$[ ii0I"3;T000ic$[ ii0I"4;T000id$[ ii0I"5;T000ie$[ ii0I"6;T000if$[ ii0I"7;T000ig$[ ii0I"8;T000ih$[ ii0I"9;T000ii$[ ii0I"10;T000ij$[ ii0I"11;T000ik$[ ii0I"12;T000il$[ ii0I"13;T000im$[ ii0I"14;T000in$[ ii0I"15;T000io$[ ii0I"16;T000ip$[ ii0I"17;T000iq$[ ii0I"18;T000ir$[ ii0I"19;T000is$[ ii0I"20;T000it$[ ii0I"(1);T000iu$[ ii0I"(2);T000iv$[ ii0I"(3);T000iw$[ ii0I"(4);T000ix$[ ii0I"(5);T000iy$[ ii0I"(6);T000iz$[ ii0I"(7);T000i{$[ ii0I"(8);T000i|$[ ii0I"(9);T000i}$[ ii0I" (10);T000i~$[ ii0I" (11);T000i$[ ii0I" (12);T000i$[ ii0I" (13);T000i$[ ii0I" (14);T000i$[ ii0I" (15);T000i$[ ii0I" (16);T000i$[ ii0I" (17);T000i$[ ii0I" (18);T000i$[ ii0I" (19);T000i$[ ii0I" (20);T000i$[ ii0I"1.;T000i$[ ii0I"2.;T000i$[ ii0I"3.;T000i$[ ii0I"4.;T000i$[ ii0I"5.;T000i$[ ii0I"6.;T000i$[ ii0I"7.;T000i$[ ii0I"8.;T000i$[ ii0I"9.;T000i$[ ii0I"10.;T000i$[ ii0I"11.;T000i$[ ii0I"12.;T000i$[ ii0I"13.;T000i$[ ii0I"14.;T000i$[ ii0I"15.;T000i$[ ii0I"16.;T000i$[ ii0I"17.;T000i$[ ii0I"18.;T000i$[ ii0I"19.;T000i$[ ii0I"20.;T000i$[ ii0I"(a);T000i$[ ii0I"(b);T000i$[ ii0I"(c);T000i$[ ii0I"(d);T000i$[ ii0I"(e);T000i$[ ii0I"(f);T000i$[ ii0I"(g);T000i$[ ii0I"(h);T000i$[ ii0I"(i);T000i$[ ii0I"(j);T000i$[ ii0I"(k);T000i$[ ii0I"(l);T000i$[ ii0I"(m);T000i$[ ii0I"(n);T000i$[ ii0I"(o);T000i$[ ii0I"(p);T000i$[ ii0I"(q);T000i$[ ii0I"(r);T000i$[ ii0I"(s);T000i$[ ii0I"(t);T000i$[ ii0I"(u);T000i$[ ii0I"(v);T000i$[ ii0I"(w);T000i$[ ii0I"(x);T000i$[ ii0I"(y);T000i$[ ii0I"(z);T000i$[ ii0I"A;T0i$0i$[ ii0I"B;T0i$0i$[ ii0I"C;T0i$0i$[ ii0I"D;T0i$0i$[ ii0I"E;T0i$0i$[ ii0I"F;T0i$0i$[ ii0I"G;T0i$0i$[ ii0I"H;T0i$0i$[ ii0I"I;T0i$0i$[ ii0I"J;T0i$0i$[ ii0I"K;T0i$0i$[ ii0I"L;T0i$0i$[ ii0I"M;T0i$0i$[ ii0I"N;T0i$0i$[ ii0I"O;T0i$0i$[ ii0I"P;T0i$0i$[ ii0I"Q;T0i$0i$[ ii0I"R;T0i$0i$[ ii0I"S;T0i$0i$[ ii0I"T;T0i$0i$[ ii0I"U;T0i$0i$[ ii0I"V;T0i$0i$[ ii0I"W;T0i$0i$[ ii0I"X;T0i$0i$[ ii0I"Y;T0i$0i$[ ii0I"Z;T0i$0i$[ ii0I"a;Ti$0i$i$[ ii0I"b;Ti$0i$i$[ ii0I"c;Ti$0i$i$[ ii0I"d;Ti$0i$i$[ ii0I"e;Ti$0i$i$[ ii0I"f;Ti$0i$i$[ ii0I"g;Ti$0i$i$[ ii0I"h;Ti$0i$i$[ ii0I"i;Ti$0i$i$[ ii0I"j;Ti$0i$i$[ ii0I"k;Ti$0i$i$[ ii0I"l;Ti$0i$i$[ ii0I"m;Ti$0i$i$[ ii0I"n;Ti$0i$i$[ ii0I"o;Ti$0i$i$[ ii0I"p;Ti$0i$i$[ ii0I"q;Ti$0i$i$[ ii0I"r;Ti$0i$i$[ ii0I"s;Ti$0i$i$[ ii0I"t;Ti$0i$i$[ ii0I"u;Ti$0i$i$[ ii0I"v;Ti$0i$i$[ ii0I"w;Ti$0i$i$[ ii0I"x;Ti$0i$i$[ ii0I"y;Ti$0i$i$[ ii0I"z;Ti$0i$i$[ ii0I"0;T000i.[ ii0I"母;T000i.[ ii0I"龟;T000i/[ ii0I"一;T000i/[ ii0I"丨;T000i/[ ii0I"丶;T000i/[ ii0I"丿;T000i/[ ii0I"乙;T000i/[ ii0I"亅;T000i/[ ii0I"二;T000i/[ ii0I"亠;T000i/[ ii0I"人;T000i /[ ii0I"儿;T000i /[ ii0I"入;T000i /[ ii0I"八;T000i /[ ii0I"冂;T000i /[ ii0I"冖;T000i/[ ii0I"冫;T000i/[ ii0I"几;T000i/[ ii0I"凵;T000i/[ ii0I"刀;T000i/[ ii0I"力;T000i/[ ii0I"勹;T000i/[ ii0I"匕;T000i/[ ii0I"匚;T000i/[ ii0I"匸;T000i/[ ii0I"十;T000i/[ ii0I"卜;T000i/[ ii0I"卩;T000i/[ ii0I"厂;T000i/[ ii0I"厶;T000i/[ ii0I"又;T000i/[ ii0I"口;T000i/[ ii0I"囗;T000i/[ ii0I"土;T000i /[ ii0I"士;T000i!/[ ii0I"夂;T000i"/[ ii0I"夊;T000i#/[ ii0I"夕;T000i$/[ ii0I"大;T000i%/[ ii0I"女;T000i&/[ ii0I"子;T000i'/[ ii0I"宀;T000i(/[ ii0I"寸;T000i)/[ ii0I"小;T000i*/[ ii0I"尢;T000i+/[ ii0I"尸;T000i,/[ ii0I"屮;T000i-/[ ii0I"山;T000i./[ ii0I"巛;T000i//[ ii0I"工;T000i0/[ ii0I"己;T000i1/[ ii0I"巾;T000i2/[ ii0I"干;T000i3/[ ii0I"幺;T000i4/[ ii0I"广;T000i5/[ ii0I"廴;T000i6/[ ii0I"廾;T000i7/[ ii0I"弋;T000i8/[ ii0I"弓;T000i9/[ ii0I"彐;T000i:/[ ii0I"彡;T000i;/[ ii0I"彳;T000i/[ ii0I"戶;T000i?/[ ii0I"手;T000i@/[ ii0I"支;T000iA/[ ii0I"攴;T000iB/[ ii0I"文;T000iC/[ ii0I"斗;T000iD/[ ii0I"斤;T000iE/[ ii0I"方;T000iF/[ ii0I"无;T000iG/[ ii0I"日;T000iH/[ ii0I"曰;T000iI/[ ii0I"月;T000iJ/[ ii0I"木;T000iK/[ ii0I"欠;T000iL/[ ii0I"止;T000iM/[ ii0I"歹;T000iN/[ ii0I"殳;T000iO/[ ii0I"毋;T000iP/[ ii0I"比;T000iQ/[ ii0I"毛;T000iR/[ ii0I"氏;T000iS/[ ii0I"气;T000iT/[ ii0I"水;T000iU/[ ii0I"火;T000iV/[ ii0I"爪;T000iW/[ ii0I"父;T000iX/[ ii0I"爻;T000iY/[ ii0I"爿;T000iZ/[ ii0I"片;T000i[/[ ii0I"牙;T000i\/[ ii0I"牛;T000i]/[ ii0I"犬;T000i^/[ ii0I"玄;T000i_/[ ii0I"玉;T000i`/[ ii0I"瓜;T000ia/[ ii0I"瓦;T000ib/[ ii0I"甘;T000ic/[ ii0I"生;T000id/[ ii0I"用;T000ie/[ ii0I"田;T000if/[ ii0I"疋;T000ig/[ ii0I"疒;T000ih/[ ii0I"癶;T000ii/[ ii0I"白;T000ij/[ ii0I"皮;T000ik/[ ii0I"皿;T000il/[ ii0I"目;T000im/[ ii0I"矛;T000in/[ ii0I"矢;T000io/[ ii0I"石;T000ip/[ ii0I"示;T000iq/[ ii0I"禸;T000ir/[ ii0I"禾;T000is/[ ii0I"穴;T000it/[ ii0I"立;T000iu/[ ii0I"竹;T000iv/[ ii0I"米;T000iw/[ ii0I"糸;T000ix/[ ii0I"缶;T000iy/[ ii0I"网;T000iz/[ ii0I"羊;T000i{/[ ii0I"羽;T000i|/[ ii0I"老;T000i}/[ ii0I"而;T000i~/[ ii0I"耒;T000i/[ ii0I"耳;T000i/[ ii0I"聿;T000i/[ ii0I"肉;T000i/[ ii0I"臣;T000i/[ ii0I"自;T000i/[ ii0I"至;T000i/[ ii0I"臼;T000i/[ ii0I"舌;T000i/[ ii0I"舛;T000i/[ ii0I"舟;T000i/[ ii0I"艮;T000i/[ ii0I"色;T000i/[ ii0I"艸;T000i/[ ii0I"虍;T000i/[ ii0I"虫;T000i/[ ii0I"血;T000i/[ ii0I"行;T000i/[ ii0I"衣;T000i/[ ii0I"襾;T000i/[ ii0I"見;T000i/[ ii0I"角;T000i/[ ii0I"言;T000i/[ ii0I"谷;T000i/[ ii0I"豆;T000i/[ ii0I"豕;T000i/[ ii0I"豸;T000i/[ ii0I"貝;T000i/[ ii0I"赤;T000i/[ ii0I"走;T000i/[ ii0I"足;T000i/[ ii0I"身;T000i/[ ii0I"車;T000i/[ ii0I"辛;T000i/[ ii0I"辰;T000i/[ ii0I"辵;T000i/[ ii0I"邑;T000i/[ ii0I"酉;T000i/[ ii0I"釆;T000i/[ ii0I"里;T000i/[ ii0I"金;T000i/[ ii0I"長;T000i/[ ii0I"門;T000i/[ ii0I"阜;T000i/[ ii0I"隶;T000i/[ ii0I"隹;T000i/[ ii0I"雨;T000i/[ ii0I"靑;T000i/[ ii0I"非;T000i/[ ii0I"面;T000i/[ ii0I"革;T000i/[ ii0I"韋;T000i/[ ii0I"韭;T000i/[ ii0I"音;T000i/[ ii0I"頁;T000i/[ ii0I"風;T000i/[ ii0I"飛;T000i/[ ii0I"食;T000i/[ ii0I"首;T000i/[ ii0I"香;T000i/[ ii0I"馬;T000i/[ ii0I"骨;T000i/[ ii0I"高;T000i/[ ii0I"髟;T000i/[ ii0I"鬥;T000i/[ ii0I"鬯;T000i/[ ii0I"鬲;T000i/[ ii0I"鬼;T000i/[ ii0I"魚;T000i/[ ii0I"鳥;T000i/[ ii0I"鹵;T000i/[ ii0I"鹿;T000i/[ ii0I"麥;T000i/[ ii0I"麻;T000i/[ ii0I"黃;T000i/[ ii0I"黍;T000i/[ ii0I"黑;T000i/[ ii0I"黹;T000i/[ ii0I"黽;T000i/[ ii0I"鼎;T000i/[ ii0I"鼓;T000i/[ ii0I"鼠;T000i/[ ii0I"鼻;T000i/[ ii0I"齊;T000i/[ ii0I"齒;T000i/[ ii0I"龍;T000i/[ ii0I"龜;T000i/[ ii0I"龠;T000i0[ ii0I" ;T000i*0[ ii00000i+0[ ii00000i,0[ ii00000i-0[ ii00000i.0[ ii00000i/0[ ii00000i60[ ii0I"〒;T000i80[ ii0I"十;T000i90[ ii0I"卄;T000i:0[ ii0I"卅;T000iL0[ iiI" が;TI" が;T000iN0[ iiI" ぎ;TI" ぎ;T000iP0[ iiI" ぐ;TI" ぐ;T000iR0[ iiI" げ;TI" げ;T000iT0[ iiI" ご;TI" ご;T000iV0[ iiI" ざ;TI" ざ;T000iX0[ iiI" じ;TI" じ;T000iZ0[ iiI" ず;TI" ず;T000i\0[ iiI" ぜ;TI" ぜ;T000i^0[ iiI" ぞ;TI" ぞ;T000i`0[ iiI" だ;TI" だ;T000ib0[ iiI" ぢ;TI" ぢ;T000ie0[ iiI" づ;TI" づ;T000ig0[ iiI" で;TI" で;T000ii0[ iiI" ど;TI" ど;T000ip0[ iiI" ば;TI" ば;T000iq0[ iiI" ぱ;TI" ぱ;T000is0[ iiI" び;TI" び;T000it0[ iiI" ぴ;TI" ぴ;T000iv0[ iiI" ぶ;TI" ぶ;T000iw0[ iiI" ぷ;TI" ぷ;T000iy0[ iiI" べ;TI" べ;T000iz0[ iiI" ぺ;TI" ぺ;T000i|0[ iiI" ぼ;TI" ぼ;T000i}0[ iiI" ぽ;TI" ぽ;T000i0[ iiI" ゔ;TI" ゔ;T000i0[ i i00000i0[ i i00000i0[ ii0I" ゙;T000i0[ ii0I" ゚;T000i0[ iiI" ゞ;TI" ゞ;T000i0[ iiI" ガ;TI" ガ;T000i0[ iiI" ギ;TI" ギ;T000i0[ iiI" グ;TI" グ;T000i0[ iiI" ゲ;TI" ゲ;T000i0[ iiI" ゴ;TI" ゴ;T000i0[ iiI" ザ;TI" ザ;T000i0[ iiI" ジ;TI" ジ;T000i0[ iiI" ズ;TI" ズ;T000i0[ iiI" ゼ;TI" ゼ;T000i0[ iiI" ゾ;TI" ゾ;T000i0[ iiI" ダ;TI" ダ;T000i0[ iiI" ヂ;TI" ヂ;T000i0[ iiI" ヅ;TI" ヅ;T000i0[ iiI" デ;TI" デ;T000i0[ iiI" ド;TI" ド;T000i0[ iiI" バ;TI" バ;T000i0[ iiI" パ;TI" パ;T000i0[ iiI" ビ;TI" ビ;T000i0[ iiI" ピ;TI" ピ;T000i0[ iiI" ブ;TI" ブ;T000i0[ iiI" プ;TI" プ;T000i0[ iiI" ベ;TI" ベ;T000i0[ iiI" ペ;TI" ペ;T000i0[ iiI" ボ;TI" ボ;T000i0[ iiI" ポ;TI" ポ;T000i0[ iiI" ヴ;TI" ヴ;T000i0[ iiI" ヷ;TI" ヷ;T000i0[ iiI" ヸ;TI" ヸ;T000i0[ iiI" ヹ;TI" ヹ;T000i0[ iiI" ヺ;TI" ヺ;T000i0[ iiI" ヾ;TI" ヾ;T000i11[ ii0I"ᄀ;T000i21[ ii0I"ᄁ;T000i31[ ii0I"ᆪ;T000i41[ ii0I"ᄂ;T000i51[ ii0I"ᆬ;T000i61[ ii0I"ᆭ;T000i71[ ii0I"ᄃ;T000i81[ ii0I"ᄄ;T000i91[ ii0I"ᄅ;T000i:1[ ii0I"ᆰ;T000i;1[ ii0I"ᆱ;T000i<1[ ii0I"ᆲ;T000i=1[ ii0I"ᆳ;T000i>1[ ii0I"ᆴ;T000i?1[ ii0I"ᆵ;T000i@1[ ii0I"ᄚ;T000iA1[ ii0I"ᄆ;T000iB1[ ii0I"ᄇ;T000iC1[ ii0I"ᄈ;T000iD1[ ii0I"ᄡ;T000iE1[ ii0I"ᄉ;T000iF1[ ii0I"ᄊ;T000iG1[ ii0I"ᄋ;T000iH1[ ii0I"ᄌ;T000iI1[ ii0I"ᄍ;T000iJ1[ ii0I"ᄎ;T000iK1[ ii0I"ᄏ;T000iL1[ ii0I"ᄐ;T000iM1[ ii0I"ᄑ;T000iN1[ ii0I"ᄒ;T000iO1[ ii0I"ᅡ;T000iP1[ ii0I"ᅢ;T000iQ1[ ii0I"ᅣ;T000iR1[ ii0I"ᅤ;T000iS1[ ii0I"ᅥ;T000iT1[ ii0I"ᅦ;T000iU1[ ii0I"ᅧ;T000iV1[ ii0I"ᅨ;T000iW1[ ii0I"ᅩ;T000iX1[ ii0I"ᅪ;T000iY1[ ii0I"ᅫ;T000iZ1[ ii0I"ᅬ;T000i[1[ ii0I"ᅭ;T000i\1[ ii0I"ᅮ;T000i]1[ ii0I"ᅯ;T000i^1[ ii0I"ᅰ;T000i_1[ ii0I"ᅱ;T000i`1[ ii0I"ᅲ;T000ia1[ ii0I"ᅳ;T000ib1[ ii0I"ᅴ;T000ic1[ ii0I"ᅵ;T000id1[ ii0I"ᅠ;T000ie1[ ii0I"ᄔ;T000if1[ ii0I"ᄕ;T000ig1[ ii0I"ᇇ;T000ih1[ ii0I"ᇈ;T000ii1[ ii0I"ᇌ;T000ij1[ ii0I"ᇎ;T000ik1[ ii0I"ᇓ;T000il1[ ii0I"ᇗ;T000im1[ ii0I"ᇙ;T000in1[ ii0I"ᄜ;T000io1[ ii0I"ᇝ;T000ip1[ ii0I"ᇟ;T000iq1[ ii0I"ᄝ;T000ir1[ ii0I"ᄞ;T000is1[ ii0I"ᄠ;T000it1[ ii0I"ᄢ;T000iu1[ ii0I"ᄣ;T000iv1[ ii0I"ᄧ;T000iw1[ ii0I"ᄩ;T000ix1[ ii0I"ᄫ;T000iy1[ ii0I"ᄬ;T000iz1[ ii0I"ᄭ;T000i{1[ ii0I"ᄮ;T000i|1[ ii0I"ᄯ;T000i}1[ ii0I"ᄲ;T000i~1[ ii0I"ᄶ;T000i1[ ii0I"ᅀ;T000i1[ ii0I"ᅇ;T000i1[ ii0I"ᅌ;T000i1[ ii0I"ᇱ;T000i1[ ii0I"ᇲ;T000i1[ ii0I"ᅗ;T000i1[ ii0I"ᅘ;T000i1[ ii0I"ᅙ;T000i1[ ii0I"ᆄ;T000i1[ ii0I"ᆅ;T000i1[ ii0I"ᆈ;T000i1[ ii0I"ᆑ;T000i1[ ii0I"ᆒ;T000i1[ ii0I"ᆔ;T000i1[ ii0I"ᆞ;T000i1[ ii0I"ᆡ;T000i1[ ii0I"一;T000i1[ ii0I"二;T000i1[ ii0I"三;T000i1[ ii0I"四;T000i1[ ii0I"上;T000i1[ ii0I"中;T000i1[ ii0I"下;T000i1[ ii0I"甲;T000i1[ ii0I"乙;T000i1[ ii0I"丙;T000i1[ ii0I"丁;T000i1[ ii0I"天;T000i1[ ii0I"地;T000i1[ ii0I"人;T000i2[ ii0I" (ᄀ);T000i2[ ii0I" (ᄂ);T000i2[ ii0I" (ᄃ);T000i2[ ii0I" (ᄅ);T000i2[ ii0I" (ᄆ);T000i2[ ii0I" (ᄇ);T000i2[ ii0I" (ᄉ);T000i2[ ii0I" (ᄋ);T000i2[ ii0I" (ᄌ);T000i 2[ ii0I" (ᄎ);T000i 2[ ii0I" (ᄏ);T000i 2[ ii0I" (ᄐ);T000i 2[ ii0I" (ᄑ);T000i 2[ ii0I" (ᄒ);T000i2[ ii0I" (가);T000i2[ ii0I" (나);T000i2[ ii0I" (다);T000i2[ ii0I" (라);T000i2[ ii0I" (마);T000i2[ ii0I" (바);T000i2[ ii0I" (사);T000i2[ ii0I" (아);T000i2[ ii0I" (자);T000i2[ ii0I" (차);T000i2[ ii0I" (카);T000i2[ ii0I" (타);T000i2[ ii0I" (파);T000i2[ ii0I" (하);T000i2[ ii0I" (주);T000i 2[ ii0I" (一);T000i!2[ ii0I" (二);T000i"2[ ii0I" (三);T000i#2[ ii0I" (四);T000i$2[ ii0I" (五);T000i%2[ ii0I" (六);T000i&2[ ii0I" (七);T000i'2[ ii0I" (八);T000i(2[ ii0I" (九);T000i)2[ ii0I" (十);T000i*2[ ii0I" (月);T000i+2[ ii0I" (火);T000i,2[ ii0I" (水);T000i-2[ ii0I" (木);T000i.2[ ii0I" (金);T000i/2[ ii0I" (土);T000i02[ ii0I" (日);T000i12[ ii0I" (株);T000i22[ ii0I" (有);T000i32[ ii0I" (社);T000i42[ ii0I" (名);T000i52[ ii0I" (特);T000i62[ ii0I" (財);T000i72[ ii0I" (祝);T000i82[ ii0I" (労);T000i92[ ii0I" (代);T000i:2[ ii0I" (呼);T000i;2[ ii0I" (学);T000i<2[ ii0I" (監);T000i=2[ ii0I" (企);T000i>2[ ii0I" (資);T000i?2[ ii0I" (協);T000i@2[ ii0I" (祭);T000iA2[ ii0I" (休);T000iB2[ ii0I" (自);T000iC2[ ii0I" (至);T000i`2[ ii0I"ᄀ;T000ia2[ ii0I"ᄂ;T000ib2[ ii0I"ᄃ;T000ic2[ ii0I"ᄅ;T000id2[ ii0I"ᄆ;T000ie2[ ii0I"ᄇ;T000if2[ ii0I"ᄉ;T000ig2[ ii0I"ᄋ;T000ih2[ ii0I"ᄌ;T000ii2[ ii0I"ᄎ;T000ij2[ ii0I"ᄏ;T000ik2[ ii0I"ᄐ;T000il2[ ii0I"ᄑ;T000im2[ ii0I"ᄒ;T000in2[ ii0I" 가;T000io2[ ii0I" 나;T000ip2[ ii0I" 다;T000iq2[ ii0I" 라;T000ir2[ ii0I" 마;T000is2[ ii0I" 바;T000it2[ ii0I" 사;T000iu2[ ii0I" 아;T000iv2[ ii0I" 자;T000iw2[ ii0I" 차;T000ix2[ ii0I" 카;T000iy2[ ii0I" 타;T000iz2[ ii0I" 파;T000i{2[ ii0I" 하;T000i2[ ii0I"一;T000i2[ ii0I"二;T000i2[ ii0I"三;T000i2[ ii0I"四;T000i2[ ii0I"五;T000i2[ ii0I"六;T000i2[ ii0I"七;T000i2[ ii0I"八;T000i2[ ii0I"九;T000i2[ ii0I"十;T000i2[ ii0I"月;T000i2[ ii0I"火;T000i2[ ii0I"水;T000i2[ ii0I"木;T000i2[ ii0I"金;T000i2[ ii0I"土;T000i2[ ii0I"日;T000i2[ ii0I"株;T000i2[ ii0I"有;T000i2[ ii0I"社;T000i2[ ii0I"名;T000i2[ ii0I"特;T000i2[ ii0I"財;T000i2[ ii0I"祝;T000i2[ ii0I"労;T000i2[ ii0I"秘;T000i2[ ii0I"男;T000i2[ ii0I"女;T000i2[ ii0I"適;T000i2[ ii0I"優;T000i2[ ii0I"印;T000i2[ ii0I"注;T000i2[ ii0I"項;T000i2[ ii0I"休;T000i2[ ii0I"写;T000i2[ ii0I"正;T000i2[ ii0I"上;T000i2[ ii0I"中;T000i2[ ii0I"下;T000i2[ ii0I"左;T000i2[ ii0I"右;T000i2[ ii0I"医;T000i2[ ii0I"宗;T000i2[ ii0I"学;T000i2[ ii0I"監;T000i2[ ii0I"企;T000i2[ ii0I"資;T000i2[ ii0I"協;T000i2[ ii0I"夜;T000i2[ ii0I" 1月;T000i2[ ii0I" 2月;T000i2[ ii0I" 3月;T000i2[ ii0I" 4月;T000i2[ ii0I" 5月;T000i2[ ii0I" 6月;T000i2[ ii0I" 7月;T000i2[ ii0I" 8月;T000i2[ ii0I" 9月;T000i2[ ii0I" 10月;T000i2[ ii0I" 11月;T000i2[ ii0I" 12月;T000i2[ ii0I"ア;T000i2[ ii0I"イ;T000i2[ ii0I"ウ;T000i2[ ii0I"エ;T000i2[ ii0I"オ;T000i2[ ii0I"カ;T000i2[ ii0I"キ;T000i2[ ii0I"ク;T000i2[ ii0I"ケ;T000i2[ ii0I"コ;T000i2[ ii0I"サ;T000i2[ ii0I"シ;T000i2[ ii0I"ス;T000i2[ ii0I"セ;T000i2[ ii0I"ソ;T000i2[ ii0I"タ;T000i2[ ii0I"チ;T000i2[ ii0I"ツ;T000i2[ ii0I"テ;T000i2[ ii0I"ト;T000i2[ ii0I"ナ;T000i2[ ii0I"ニ;T000i2[ ii0I"ヌ;T000i2[ ii0I"ネ;T000i2[ ii0I"ノ;T000i2[ ii0I"ハ;T000i2[ ii0I"ヒ;T000i2[ ii0I"フ;T000i2[ ii0I"ヘ;T000i2[ ii0I"ホ;T000i2[ ii0I"マ;T000i2[ ii0I"ミ;T000i2[ ii0I"ム;T000i2[ ii0I"メ;T000i2[ ii0I"モ;T000i2[ ii0I"ヤ;T000i2[ ii0I"ユ;T000i2[ ii0I"ヨ;T000i2[ ii0I"ラ;T000i2[ ii0I"リ;T000i2[ ii0I"ル;T000i2[ ii0I"レ;T000i2[ ii0I"ロ;T000i2[ ii0I"ワ;T000i2[ ii0I"ヰ;T000i2[ ii0I"ヱ;T000i2[ ii0I"ヲ;T000i3[ ii0I"アパート;T000i3[ ii0I"アルファ;T000i3[ ii0I"アンペア;T000i3[ ii0I"アール;T000i3[ ii0I"イニング;T000i3[ ii0I"インチ;T000i3[ ii0I"ウォン;T000i3[ ii0I"エスクード;T000i3[ ii0I"エーカー;T000i 3[ ii0I"オンス;T000i 3[ ii0I"オーム;T000i 3[ ii0I"カイリ;T000i 3[ ii0I"カラット;T000i 3[ ii0I"カロリー;T000i3[ ii0I"ガロン;T000i3[ ii0I"ガンマ;T000i3[ ii0I" ギガ;T000i3[ ii0I"ギニー;T000i3[ ii0I"キュリー;T000i3[ ii0I"ギルダー;T000i3[ ii0I" キロ;T000i3[ ii0I"キログラム;T000i3[ ii0I"キロメートル;T000i3[ ii0I"キロワット;T000i3[ ii0I"グラム;T000i3[ ii0I"グラムトン;T000i3[ ii0I"クルゼイロ;T000i3[ ii0I"クローネ;T000i3[ ii0I"ケース;T000i3[ ii0I"コルナ;T000i3[ ii0I"コーポ;T000i3[ ii0I"サイクル;T000i 3[ ii0I"サンチーム;T000i!3[ ii0I"シリング;T000i"3[ ii0I"センチ;T000i#3[ ii0I"セント;T000i$3[ ii0I"ダース;T000i%3[ ii0I" デシ;T000i&3[ ii0I" ドル;T000i'3[ ii0I" トン;T000i(3[ ii0I" ナノ;T000i)3[ ii0I"ノット;T000i*3[ ii0I"ハイツ;T000i+3[ ii0I"パーセント;T000i,3[ ii0I"パーツ;T000i-3[ ii0I"バーレル;T000i.3[ ii0I"ピアストル;T000i/3[ ii0I"ピクル;T000i03[ ii0I" ピコ;T000i13[ ii0I" ビル;T000i23[ ii0I"ファラッド;T000i33[ ii0I"フィート;T000i43[ ii0I"ブッシェル;T000i53[ ii0I"フラン;T000i63[ ii0I"ヘクタール;T000i73[ ii0I" ペソ;T000i83[ ii0I"ペニヒ;T000i93[ ii0I"ヘルツ;T000i:3[ ii0I"ペンス;T000i;3[ ii0I"ページ;T000i<3[ ii0I"ベータ;T000i=3[ ii0I"ポイント;T000i>3[ ii0I"ボルト;T000i?3[ ii0I" ホン;T000i@3[ ii0I"ポンド;T000iA3[ ii0I"ホール;T000iB3[ ii0I"ホーン;T000iC3[ ii0I"マイクロ;T000iD3[ ii0I"マイル;T000iE3[ ii0I"マッハ;T000iF3[ ii0I"マルク;T000iG3[ ii0I"マンション;T000iH3[ ii0I"ミクロン;T000iI3[ ii0I" ミリ;T000iJ3[ ii0I"ミリバール;T000iK3[ ii0I" メガ;T000iL3[ ii0I"メガトン;T000iM3[ ii0I"メートル;T000iN3[ ii0I"ヤード;T000iO3[ ii0I"ヤール;T000iP3[ ii0I"ユアン;T000iQ3[ ii0I"リットル;T000iR3[ ii0I" リラ;T000iS3[ ii0I"ルピー;T000iT3[ ii0I"ルーブル;T000iU3[ ii0I" レム;T000iV3[ ii0I"レントゲン;T000iW3[ ii0I"ワット;T000iX3[ ii0I" 0点;T000iY3[ ii0I" 1点;T000iZ3[ ii0I" 2点;T000i[3[ ii0I" 3点;T000i\3[ ii0I" 4点;T000i]3[ ii0I" 5点;T000i^3[ ii0I" 6点;T000i_3[ ii0I" 7点;T000i`3[ ii0I" 8点;T000ia3[ ii0I" 9点;T000ib3[ ii0I" 10点;T000ic3[ ii0I" 11点;T000id3[ ii0I" 12点;T000ie3[ ii0I" 13点;T000if3[ ii0I" 14点;T000ig3[ ii0I" 15点;T000ih3[ ii0I" 16点;T000ii3[ ii0I" 17点;T000ij3[ ii0I" 18点;T000ik3[ ii0I" 19点;T000il3[ ii0I" 20点;T000im3[ ii0I" 21点;T000in3[ ii0I" 22点;T000io3[ ii0I" 23点;T000ip3[ ii0I" 24点;T000iq3[ ii0I"hPa;T000ir3[ ii0I"da;T000is3[ ii0I"AU;T000it3[ ii0I"bar;T000iu3[ ii0I"oV;T000iv3[ ii0I"pc;T000i{3[ ii0I" 平成;T000i|3[ ii0I" 昭和;T000i}3[ ii0I" 大正;T000i~3[ ii0I" 明治;T000i3[ ii0I"株式会社;T000i3[ ii0I"pA;T000i3[ ii0I"nA;T000i3[ ii0I"μA;T000i3[ ii0I"mA;T000i3[ ii0I"kA;T000i3[ ii0I"KB;T000i3[ ii0I"MB;T000i3[ ii0I"GB;T000i3[ ii0I"cal;T000i3[ ii0I" kcal;T000i3[ ii0I"pF;T000i3[ ii0I"nF;T000i3[ ii0I"μF;T000i3[ ii0I"μg;T000i3[ ii0I"mg;T000i3[ ii0I"kg;T000i3[ ii0I"Hz;T000i3[ ii0I"kHz;T000i3[ ii0I"MHz;T000i3[ ii0I"GHz;T000i3[ ii0I"THz;T000i3[ ii0I" μℓ;T000i3[ ii0I" mℓ;T000i3[ ii0I" dℓ;T000i3[ ii0I" kℓ;T000i3[ ii0I"fm;T000i3[ ii0I"nm;T000i3[ ii0I"μm;T000i3[ ii0I"mm;T000i3[ ii0I"cm;T000i3[ ii0I"km;T000i3[ ii0I" mm²;T000i3[ ii0I" cm²;T000i3[ ii0I"m²;T000i3[ ii0I" km²;T000i3[ ii0I" mm³;T000i3[ ii0I" cm³;T000i3[ ii0I"m³;T000i3[ ii0I" km³;T000i3[ ii0I" m∕s;T000i3[ ii0I" m∕s²;T000i3[ ii0I"Pa;T000i3[ ii0I"kPa;T000i3[ ii0I"MPa;T000i3[ ii0I"GPa;T000i3[ ii0I"rad;T000i3[ ii0I" rad∕s;T000i3[ ii0I"rad∕s²;T000i3[ ii0I"ps;T000i3[ ii0I"ns;T000i3[ ii0I"μs;T000i3[ ii0I"ms;T000i3[ ii0I"pV;T000i3[ ii0I"nV;T000i3[ ii0I"μV;T000i3[ ii0I"mV;T000i3[ ii0I"kV;T000i3[ ii0I"MV;T000i3[ ii0I"pW;T000i3[ ii0I"nW;T000i3[ ii0I"μW;T000i3[ ii0I"mW;T000i3[ ii0I"kW;T000i3[ ii0I"MW;T000i3[ ii0I"kΩ;T000i3[ ii0I"MΩ;T000i3[ ii0I" a.m.;T000i3[ ii0I"Bq;T000i3[ ii0I"cc;T000i3[ ii0I"cd;T000i3[ ii0I" C∕kg;T000i3[ ii0I"Co.;T000i3[ ii0I"dB;T000i3[ ii0I"Gy;T000i3[ ii0I"ha;T000i3[ ii0I"HP;T000i3[ ii0I"in;T000i3[ ii0I"KK;T000i3[ ii0I"KM;T000i3[ ii0I"kt;T000i3[ ii0I"lm;T000i3[ ii0I"ln;T000i3[ ii0I"log;T000i3[ ii0I"lx;T000i3[ ii0I"mb;T000i3[ ii0I"mil;T000i3[ ii0I"mol;T000i3[ ii0I"PH;T000i3[ ii0I" p.m.;T000i3[ ii0I"PPM;T000i3[ ii0I"PR;T000i3[ ii0I"sr;T000i3[ ii0I"Sv;T000i3[ ii0I"Wb;T000i3[ ii0I" 1日;T000i3[ ii0I" 2日;T000i3[ ii0I" 3日;T000i3[ ii0I" 4日;T000i3[ ii0I" 5日;T000i3[ ii0I" 6日;T000i3[ ii0I" 7日;T000i3[ ii0I" 8日;T000i3[ ii0I" 9日;T000i3[ ii0I" 10日;T000i3[ ii0I" 11日;T000i3[ ii0I" 12日;T000i3[ ii0I" 13日;T000i3[ ii0I" 14日;T000i3[ ii0I" 15日;T000i3[ ii0I" 16日;T000i3[ ii0I" 17日;T000i3[ ii0I" 18日;T000i3[ ii0I" 19日;T000i3[ ii0I" 20日;T000i3[ ii0I" 21日;T000i3[ ii0I" 22日;T000i3[ ii0I" 23日;T000i3[ ii0I" 24日;T000i3[ ii0I" 25日;T000i3[ ii0I" 26日;T000i3[ ii0I" 27日;T000i3[ ii0I" 28日;T000i3[ ii0I" 29日;T000i3[ ii0I" 30日;T000i3[ ii0I" 31日;T000i[ iiI"豈;TI"豈;T000i[ iiI"更;TI"更;T000i[ iiI"車;TI"車;T000i[ iiI"賈;TI"賈;T000i[ iiI"滑;TI"滑;T000i[ iiI"串;TI"串;T000i[ iiI"句;TI"句;T000i[ iiI"龜;TI"龜;T000i[ iiI"龜;TI"龜;T000i [ iiI"契;TI"契;T000i [ iiI"金;TI"金;T000i [ iiI"喇;TI"喇;T000i [ iiI"奈;TI"奈;T000i [ iiI"懶;TI"懶;T000i[ iiI"癩;TI"癩;T000i[ iiI"羅;TI"羅;T000i[ iiI"蘿;TI"蘿;T000i[ iiI"螺;TI"螺;T000i[ iiI"裸;TI"裸;T000i[ iiI"邏;TI"邏;T000i[ iiI"樂;TI"樂;T000i[ iiI"洛;TI"洛;T000i[ iiI"烙;TI"烙;T000i[ iiI"珞;TI"珞;T000i[ iiI"落;TI"落;T000i[ iiI"酪;TI"酪;T000i[ iiI"駱;TI"駱;T000i[ iiI"亂;TI"亂;T000i[ iiI"卵;TI"卵;T000i[ iiI"欄;TI"欄;T000i[ iiI"爛;TI"爛;T000i[ iiI"蘭;TI"蘭;T000i [ iiI"鸞;TI"鸞;T000i![ iiI"嵐;TI"嵐;T000i"[ iiI"濫;TI"濫;T000i#[ iiI"藍;TI"藍;T000i$[ iiI"襤;TI"襤;T000i%[ iiI"拉;TI"拉;T000i&[ iiI"臘;TI"臘;T000i'[ iiI"蠟;TI"蠟;T000i([ iiI"廊;TI"廊;T000i)[ iiI"朗;TI"朗;T000i*[ iiI"浪;TI"浪;T000i+[ iiI"狼;TI"狼;T000i,[ iiI"郎;TI"郎;T000i-[ iiI"來;TI"來;T000i.[ iiI"冷;TI"冷;T000i/[ iiI"勞;TI"勞;T000i0[ iiI"擄;TI"擄;T000i1[ iiI"櫓;TI"櫓;T000i2[ iiI"爐;TI"爐;T000i3[ iiI"盧;TI"盧;T000i4[ iiI"老;TI"老;T000i5[ iiI"蘆;TI"蘆;T000i6[ iiI"虜;TI"虜;T000i7[ iiI"路;TI"路;T000i8[ iiI"露;TI"露;T000i9[ iiI"魯;TI"魯;T000i:[ iiI"鷺;TI"鷺;T000i;[ iiI"碌;TI"碌;T000i<[ iiI"祿;TI"祿;T000i=[ iiI"綠;TI"綠;T000i>[ iiI"菉;TI"菉;T000i?[ iiI"錄;TI"錄;T000i@[ iiI"鹿;TI"鹿;T000iA[ iiI"論;TI"論;T000iB[ iiI"壟;TI"壟;T000iC[ iiI"弄;TI"弄;T000iD[ iiI"籠;TI"籠;T000iE[ iiI"聾;TI"聾;T000iF[ iiI"牢;TI"牢;T000iG[ iiI"磊;TI"磊;T000iH[ iiI"賂;TI"賂;T000iI[ iiI"雷;TI"雷;T000iJ[ iiI"壘;TI"壘;T000iK[ iiI"屢;TI"屢;T000iL[ iiI"樓;TI"樓;T000iM[ iiI"淚;TI"淚;T000iN[ iiI"漏;TI"漏;T000iO[ iiI"累;TI"累;T000iP[ iiI"縷;TI"縷;T000iQ[ iiI"電;TI"電;T000iR[ iiI"勒;TI"勒;T000iS[ iiI"肋;TI"肋;T000iT[ iiI"凜;TI"凜;T000iU[ iiI"凌;TI"凌;T000iV[ iiI"稜;TI"稜;T000iW[ iiI"綾;TI"綾;T000iX[ iiI"菱;TI"菱;T000iY[ iiI"陵;TI"陵;T000iZ[ iiI"讀;TI"讀;T000i[[ iiI"拏;TI"拏;T000i\[ iiI"樂;TI"樂;T000i][ iiI"諾;TI"諾;T000i^[ iiI"丹;TI"丹;T000i_[ iiI"寧;TI"寧;T000i`[ iiI"怒;TI"怒;T000ia[ iiI"率;TI"率;T000ib[ iiI"異;TI"異;T000ic[ iiI"北;TI"北;T000id[ iiI"磻;TI"磻;T000ie[ iiI"便;TI"便;T000if[ iiI"復;TI"復;T000ig[ iiI"不;TI"不;T000ih[ iiI"泌;TI"泌;T000ii[ iiI"數;TI"數;T000ij[ iiI"索;TI"索;T000ik[ iiI"參;TI"參;T000il[ iiI"塞;TI"塞;T000im[ iiI"省;TI"省;T000in[ iiI"葉;TI"葉;T000io[ iiI"說;TI"說;T000ip[ iiI"殺;TI"殺;T000iq[ iiI"辰;TI"辰;T000ir[ iiI"沈;TI"沈;T000is[ iiI"拾;TI"拾;T000it[ iiI"若;TI"若;T000iu[ iiI"掠;TI"掠;T000iv[ iiI"略;TI"略;T000iw[ iiI"亮;TI"亮;T000ix[ iiI"兩;TI"兩;T000iy[ iiI"凉;TI"凉;T000iz[ iiI"梁;TI"梁;T000i{[ iiI"糧;TI"糧;T000i|[ iiI"良;TI"良;T000i}[ iiI"諒;TI"諒;T000i~[ iiI"量;TI"量;T000i[ iiI"勵;TI"勵;T000i[ iiI"呂;TI"呂;T000i[ iiI"女;TI"女;T000i[ iiI"廬;TI"廬;T000i[ iiI"旅;TI"旅;T000i[ iiI"濾;TI"濾;T000i[ iiI"礪;TI"礪;T000i[ iiI"閭;TI"閭;T000i[ iiI"驪;TI"驪;T000i[ iiI"麗;TI"麗;T000i[ iiI"黎;TI"黎;T000i[ iiI"力;TI"力;T000i[ iiI"曆;TI"曆;T000i[ iiI"歷;TI"歷;T000i[ iiI"轢;TI"轢;T000i[ iiI"年;TI"年;T000i[ iiI"憐;TI"憐;T000i[ iiI"戀;TI"戀;T000i[ iiI"撚;TI"撚;T000i[ iiI"漣;TI"漣;T000i[ iiI"煉;TI"煉;T000i[ iiI"璉;TI"璉;T000i[ iiI"秊;TI"秊;T000i[ iiI"練;TI"練;T000i[ iiI"聯;TI"聯;T000i[ iiI"輦;TI"輦;T000i[ iiI"蓮;TI"蓮;T000i[ iiI"連;TI"連;T000i[ iiI"鍊;TI"鍊;T000i[ iiI"列;TI"列;T000i[ iiI"劣;TI"劣;T000i[ iiI"咽;TI"咽;T000i[ iiI"烈;TI"烈;T000i[ iiI"裂;TI"裂;T000i[ iiI"說;TI"說;T000i[ iiI"廉;TI"廉;T000i[ iiI"念;TI"念;T000i[ iiI"捻;TI"捻;T000i[ iiI"殮;TI"殮;T000i[ iiI"簾;TI"簾;T000i[ iiI"獵;TI"獵;T000i[ iiI"令;TI"令;T000i[ iiI"囹;TI"囹;T000i[ iiI"寧;TI"寧;T000i[ iiI"嶺;TI"嶺;T000i[ iiI"怜;TI"怜;T000i[ iiI"玲;TI"玲;T000i[ iiI"瑩;TI"瑩;T000i[ iiI"羚;TI"羚;T000i[ iiI"聆;TI"聆;T000i[ iiI"鈴;TI"鈴;T000i[ iiI"零;TI"零;T000i[ iiI"靈;TI"靈;T000i[ iiI"領;TI"領;T000i[ iiI"例;TI"例;T000i[ iiI"禮;TI"禮;T000i[ iiI"醴;TI"醴;T000i[ iiI"隸;TI"隸;T000i[ iiI"惡;TI"惡;T000i[ iiI"了;TI"了;T000i[ iiI"僚;TI"僚;T000i[ iiI"寮;TI"寮;T000i[ iiI"尿;TI"尿;T000i[ iiI"料;TI"料;T000i[ iiI"樂;TI"樂;T000i[ iiI"燎;TI"燎;T000i[ iiI"療;TI"療;T000i[ iiI"蓼;TI"蓼;T000i[ iiI"遼;TI"遼;T000i[ iiI"龍;TI"龍;T000i[ iiI"暈;TI"暈;T000i[ iiI"阮;TI"阮;T000i[ iiI"劉;TI"劉;T000i[ iiI"杻;TI"杻;T000i[ iiI"柳;TI"柳;T000i[ iiI"流;TI"流;T000i[ iiI"溜;TI"溜;T000i[ iiI"琉;TI"琉;T000i[ iiI"留;TI"留;T000i[ iiI"硫;TI"硫;T000i[ iiI"紐;TI"紐;T000i[ iiI"類;TI"類;T000i[ iiI"六;TI"六;T000i[ iiI"戮;TI"戮;T000i[ iiI"陸;TI"陸;T000i[ iiI"倫;TI"倫;T000i[ iiI"崙;TI"崙;T000i[ iiI"淪;TI"淪;T000i[ iiI"輪;TI"輪;T000i[ iiI"律;TI"律;T000i[ iiI"慄;TI"慄;T000i[ iiI"栗;TI"栗;T000i[ iiI"率;TI"率;T000i[ iiI"隆;TI"隆;T000i[ iiI"利;TI"利;T000i[ iiI"吏;TI"吏;T000i[ iiI"履;TI"履;T000i[ iiI"易;TI"易;T000i[ iiI"李;TI"李;T000i[ iiI"梨;TI"梨;T000i[ iiI"泥;TI"泥;T000i[ iiI"理;TI"理;T000i[ iiI"痢;TI"痢;T000i[ iiI"罹;TI"罹;T000i[ iiI"裏;TI"裏;T000i[ iiI"裡;TI"裡;T000i[ iiI"里;TI"里;T000i[ iiI"離;TI"離;T000i[ iiI"匿;TI"匿;T000i[ iiI"溺;TI"溺;T000i[ iiI"吝;TI"吝;T000i[ iiI"燐;TI"燐;T000i[ iiI"璘;TI"璘;T000i[ iiI"藺;TI"藺;T000i[ iiI"隣;TI"隣;T000i[ iiI"鱗;TI"鱗;T000i[ iiI"麟;TI"麟;T000i[ iiI"林;TI"林;T000i[ iiI"淋;TI"淋;T000i[ iiI"臨;TI"臨;T000i[ iiI"立;TI"立;T000i[ iiI"笠;TI"笠;T000i[ iiI"粒;TI"粒;T000i[ iiI"狀;TI"狀;T000i[ iiI"炙;TI"炙;T000i[ iiI"識;TI"識;T000i[ iiI"什;TI"什;T000i[ iiI"茶;TI"茶;T000i[ iiI"刺;TI"刺;T000i[ iiI"切;TI"切;T000i[ iiI"度;TI"度;T000i[ iiI"拓;TI"拓;T000i[ iiI"糖;TI"糖;T000i[ iiI"宅;TI"宅;T000i[ iiI"洞;TI"洞;T000i[ iiI"暴;TI"暴;T000i[ iiI"輻;TI"輻;T000i[ iiI"行;TI"行;T000i [ iiI"降;TI"降;T000i [ iiI"見;TI"見;T000i [ iiI"廓;TI"廓;T000i [ iiI"兀;TI"兀;T000i [ iiI"嗀;TI"嗀;T000i[ iiI"塚;TI"塚;T000i[ iiI"晴;TI"晴;T000i[ iiI"凞;TI"凞;T000i[ iiI"猪;TI"猪;T000i[ iiI"益;TI"益;T000i[ iiI"礼;TI"礼;T000i[ iiI"神;TI"神;T000i[ iiI"祥;TI"祥;T000i[ iiI"福;TI"福;T000i[ iiI"靖;TI"靖;T000i[ iiI"精;TI"精;T000i[ iiI"羽;TI"羽;T000i [ iiI"蘒;TI"蘒;T000i"[ iiI"諸;TI"諸;T000i%[ iiI"逸;TI"逸;T000i&[ iiI"都;TI"都;T000i*[ iiI"飯;TI"飯;T000i+[ iiI"飼;TI"飼;T000i,[ iiI"館;TI"館;T000i-[ iiI"鶴;TI"鶴;T000i[ ii0I"ff;T000i[ ii0I"fi;T000i[ ii0I"fl;T000i[ ii0I"ffi;T000i[ ii0I"ffl;T000i[ ii0I"ſt;T000i[ ii0I"st;T000i[ ii0I" մն;T000i[ ii0I" մե;T000i[ ii0I" մի;T000i[ ii0I" վն;T000i[ ii0I" մխ;T000i[ iiI" יִ;TI" יִ;T000i[ ii00000i[ iiI" ײַ;TI" ײַ;T000i [ ii0I"ע;T000i![ ii0I"א;T000i"[ ii0I"ד;T000i#[ ii0I"ה;T000i$[ ii0I"כ;T000i%[ ii0I"ל;T000i&[ ii0I"ם;T000i'[ ii0I"ר;T000i([ ii0I"ת;T000i)[ ii0I"+;T000i*[ iiI" שׁ;TI" שׁ;T000i+[ iiI" שׂ;TI" שׂ;T000i,[ iiI" שּׁ;TI" שּׁ;T000i-[ iiI" שּׂ;TI" שּׂ;T000i.[ iiI" אַ;TI" אַ;T000i/[ iiI" אָ;TI" אָ;T000i0[ iiI" אּ;TI" אּ;T000i1[ iiI" בּ;TI" בּ;T000i2[ iiI" גּ;TI" גּ;T000i3[ iiI" דּ;TI" דּ;T000i4[ iiI" הּ;TI" הּ;T000i5[ iiI" וּ;TI" וּ;T000i6[ iiI" זּ;TI" זּ;T000i8[ iiI" טּ;TI" טּ;T000i9[ iiI" יּ;TI" יּ;T000i:[ iiI" ךּ;TI" ךּ;T000i;[ iiI" כּ;TI" כּ;T000i<[ iiI" לּ;TI" לּ;T000i>[ iiI" מּ;TI" מּ;T000i@[ iiI" נּ;TI" נּ;T000iA[ iiI" סּ;TI" סּ;T000iC[ iiI" ףּ;TI" ףּ;T000iD[ iiI" פּ;TI" פּ;T000iF[ iiI" צּ;TI" צּ;T000iG[ iiI" קּ;TI" קּ;T000iH[ iiI" רּ;TI" רּ;T000iI[ iiI" שּ;TI" שּ;T000iJ[ iiI" תּ;TI" תּ;T000iK[ iiI" וֹ;TI" וֹ;T000iL[ iiI" בֿ;TI" בֿ;T000iM[ iiI" כֿ;TI" כֿ;T000iN[ iiI" פֿ;TI" פֿ;T000iO[ ii0I" אל;T000iP[ ii0I"ٱ;T000iQ[ ii0I"ٱ;T000iR[ ii0I"ٻ;T000iS[ ii0I"ٻ;T000iT[ ii0I"ٻ;T000iU[ ii0I"ٻ;T000iV[ ii0I"پ;T000iW[ ii0I"پ;T000iX[ ii0I"پ;T000iY[ ii0I"پ;T000iZ[ ii0I"ڀ;T000i[[ ii0I"ڀ;T000i\[ ii0I"ڀ;T000i][ ii0I"ڀ;T000i^[ ii0I"ٺ;T000i_[ ii0I"ٺ;T000i`[ ii0I"ٺ;T000ia[ ii0I"ٺ;T000ib[ ii0I"ٿ;T000ic[ ii0I"ٿ;T000id[ ii0I"ٿ;T000ie[ ii0I"ٿ;T000if[ ii0I"ٹ;T000ig[ ii0I"ٹ;T000ih[ ii0I"ٹ;T000ii[ ii0I"ٹ;T000ij[ ii0I"ڤ;T000ik[ ii0I"ڤ;T000il[ ii0I"ڤ;T000im[ ii0I"ڤ;T000in[ ii0I"ڦ;T000io[ ii0I"ڦ;T000ip[ ii0I"ڦ;T000iq[ ii0I"ڦ;T000ir[ ii0I"ڄ;T000is[ ii0I"ڄ;T000it[ ii0I"ڄ;T000iu[ ii0I"ڄ;T000iv[ ii0I"ڃ;T000iw[ ii0I"ڃ;T000ix[ ii0I"ڃ;T000iy[ ii0I"ڃ;T000iz[ ii0I"چ;T000i{[ ii0I"چ;T000i|[ ii0I"چ;T000i}[ ii0I"چ;T000i~[ ii0I"ڇ;T000i[ ii0I"ڇ;T000i[ ii0I"ڇ;T000i[ ii0I"ڇ;T000i[ ii0I"ڍ;T000i[ ii0I"ڍ;T000i[ ii0I"ڌ;T000i[ ii0I"ڌ;T000i[ ii0I"ڎ;T000i[ ii0I"ڎ;T000i[ ii0I"ڈ;T000i[ ii0I"ڈ;T000i[ ii0I"ژ;T000i[ ii0I"ژ;T000i[ ii0I"ڑ;T000i[ ii0I"ڑ;T000i[ ii0I"ک;T000i[ ii0I"ک;T000i[ ii0I"ک;T000i[ ii0I"ک;T000i[ ii0I"گ;T000i[ ii0I"گ;T000i[ ii0I"گ;T000i[ ii0I"گ;T000i[ ii0I"ڳ;T000i[ ii0I"ڳ;T000i[ ii0I"ڳ;T000i[ ii0I"ڳ;T000i[ ii0I"ڱ;T000i[ ii0I"ڱ;T000i[ ii0I"ڱ;T000i[ ii0I"ڱ;T000i[ ii0I"ں;T000i[ ii0I"ں;T000i[ ii0I"ڻ;T000i[ ii0I"ڻ;T000i[ ii0I"ڻ;T000i[ ii0I"ڻ;T000i[ ii0I"ۀ;T000i[ ii0I"ۀ;T000i[ ii0I"ہ;T000i[ ii0I"ہ;T000i[ ii0I"ہ;T000i[ ii0I"ہ;T000i[ ii0I"ھ;T000i[ ii0I"ھ;T000i[ ii0I"ھ;T000i[ ii0I"ھ;T000i[ ii0I"ے;T000i[ ii0I"ے;T000i[ ii0I"ۓ;T000i[ ii0I"ۓ;T000i[ ii0I"ڭ;T000i[ ii0I"ڭ;T000i[ ii0I"ڭ;T000i[ ii0I"ڭ;T000i[ ii0I"ۇ;T000i[ ii0I"ۇ;T000i[ ii0I"ۆ;T000i[ ii0I"ۆ;T000i[ ii0I"ۈ;T000i[ ii0I"ۈ;T000i[ ii0I"ٷ;T000i[ ii0I"ۋ;T000i[ ii0I"ۋ;T000i[ ii0I"ۅ;T000i[ ii0I"ۅ;T000i[ ii0I"ۉ;T000i[ ii0I"ۉ;T000i[ ii0I"ې;T000i[ ii0I"ې;T000i[ ii0I"ې;T000i[ ii0I"ې;T000i[ ii0I"ى;T000i[ ii0I"ى;T000i[ ii0I" ئا;T000i[ ii0I" ئا;T000i[ ii0I" ئە;T000i[ ii0I" ئە;T000i[ ii0I" ئو;T000i[ ii0I" ئو;T000i[ ii0I" ئۇ;T000i[ ii0I" ئۇ;T000i[ ii0I" ئۆ;T000i[ ii0I" ئۆ;T000i[ ii0I" ئۈ;T000i[ ii0I" ئۈ;T000i[ ii0I" ئې;T000i[ ii0I" ئې;T000i[ ii0I" ئې;T000i[ ii0I" ئى;T000i[ ii0I" ئى;T000i[ ii0I" ئى;T000i[ ii0I"ی;T000i[ ii0I"ی;T000i[ ii0I"ی;T000i[ ii0I"ی;T000i[ ii0I" ئج;T000i[ ii0I" ئح;T000i[ ii0I" ئم;T000i[ ii0I" ئى;T000i[ ii0I" ئي;T000i[ ii0I" بج;T000i[ ii0I" بح;T000i[ ii0I" بخ;T000i[ ii0I" بم;T000i [ ii0I" بى;T000i [ ii0I" بي;T000i [ ii0I" تج;T000i [ ii0I" تح;T000i [ ii0I" تخ;T000i[ ii0I" تم;T000i[ ii0I" تى;T000i[ ii0I" تي;T000i[ ii0I" ثج;T000i[ ii0I" ثم;T000i[ ii0I" ثى;T000i[ ii0I" ثي;T000i[ ii0I" جح;T000i[ ii0I" جم;T000i[ ii0I" حج;T000i[ ii0I" حم;T000i[ ii0I" خج;T000i[ ii0I" خح;T000i[ ii0I" خم;T000i[ ii0I" سج;T000i[ ii0I" سح;T000i[ ii0I" سخ;T000i[ ii0I" سم;T000i [ ii0I" صح;T000i![ ii0I" صم;T000i"[ ii0I" ضج;T000i#[ ii0I" ضح;T000i$[ ii0I" ضخ;T000i%[ ii0I" ضم;T000i&[ ii0I" طح;T000i'[ ii0I" طم;T000i([ ii0I" ظم;T000i)[ ii0I" عج;T000i*[ ii0I" عم;T000i+[ ii0I" غج;T000i,[ ii0I" غم;T000i-[ ii0I" فج;T000i.[ ii0I" فح;T000i/[ ii0I" فخ;T000i0[ ii0I" فم;T000i1[ ii0I" فى;T000i2[ ii0I" في;T000i3[ ii0I" قح;T000i4[ ii0I" قم;T000i5[ ii0I" قى;T000i6[ ii0I" قي;T000i7[ ii0I" كا;T000i8[ ii0I" كج;T000i9[ ii0I" كح;T000i:[ ii0I" كخ;T000i;[ ii0I" كل;T000i<[ ii0I" كم;T000i=[ ii0I" كى;T000i>[ ii0I" كي;T000i?[ ii0I" لج;T000i@[ ii0I" لح;T000iA[ ii0I" لخ;T000iB[ ii0I" لم;T000iC[ ii0I" لى;T000iD[ ii0I" لي;T000iE[ ii0I" مج;T000iF[ ii0I" مح;T000iG[ ii0I" مخ;T000iH[ ii0I" مم;T000iI[ ii0I" مى;T000iJ[ ii0I" مي;T000iK[ ii0I" نج;T000iL[ ii0I" نح;T000iM[ ii0I" نخ;T000iN[ ii0I" نم;T000iO[ ii0I" نى;T000iP[ ii0I" ني;T000iQ[ ii0I" هج;T000iR[ ii0I" هم;T000iS[ ii0I" هى;T000iT[ ii0I" هي;T000iU[ ii0I" يج;T000iV[ ii0I" يح;T000iW[ ii0I" يخ;T000iX[ ii0I" يم;T000iY[ ii0I" يى;T000iZ[ ii0I" يي;T000i[[ ii0I" ذٰ;T000i\[ ii0I" رٰ;T000i][ ii0I" ىٰ;T000i^[ ii0I" ٌّ;T000i_[ ii0I" ٍّ;T000i`[ ii0I" َّ;T000ia[ ii0I" ُّ;T000ib[ ii0I" ِّ;T000ic[ ii0I" ّٰ;T000id[ ii0I" ئر;T000ie[ ii0I" ئز;T000if[ ii0I" ئم;T000ig[ ii0I" ئن;T000ih[ ii0I" ئى;T000ii[ ii0I" ئي;T000ij[ ii0I" بر;T000ik[ ii0I" بز;T000il[ ii0I" بم;T000im[ ii0I" بن;T000in[ ii0I" بى;T000io[ ii0I" بي;T000ip[ ii0I" تر;T000iq[ ii0I" تز;T000ir[ ii0I" تم;T000is[ ii0I" تن;T000it[ ii0I" تى;T000iu[ ii0I" تي;T000iv[ ii0I" ثر;T000iw[ ii0I" ثز;T000ix[ ii0I" ثم;T000iy[ ii0I" ثن;T000iz[ ii0I" ثى;T000i{[ ii0I" ثي;T000i|[ ii0I" فى;T000i}[ ii0I" في;T000i~[ ii0I" قى;T000i[ ii0I" قي;T000i[ ii0I" كا;T000i[ ii0I" كل;T000i[ ii0I" كم;T000i[ ii0I" كى;T000i[ ii0I" كي;T000i[ ii0I" لم;T000i[ ii0I" لى;T000i[ ii0I" لي;T000i[ ii0I" ما;T000i[ ii0I" مم;T000i[ ii0I" نر;T000i[ ii0I" نز;T000i[ ii0I" نم;T000i[ ii0I" نن;T000i[ ii0I" نى;T000i[ ii0I" ني;T000i[ ii0I" ىٰ;T000i[ ii0I" ير;T000i[ ii0I" يز;T000i[ ii0I" يم;T000i[ ii0I" ين;T000i[ ii0I" يى;T000i[ ii0I" يي;T000i[ ii0I" ئج;T000i[ ii0I" ئح;T000i[ ii0I" ئخ;T000i[ ii0I" ئم;T000i[ ii0I" ئه;T000i[ ii0I" بج;T000i[ ii0I" بح;T000i[ ii0I" بخ;T000i[ ii0I" بم;T000i[ ii0I" به;T000i[ ii0I" تج;T000i[ ii0I" تح;T000i[ ii0I" تخ;T000i[ ii0I" تم;T000i[ ii0I" ته;T000i[ ii0I" ثم;T000i[ ii0I" جح;T000i[ ii0I" جم;T000i[ ii0I" حج;T000i[ ii0I" حم;T000i[ ii0I" خج;T000i[ ii0I" خم;T000i[ ii0I" سج;T000i[ ii0I" سح;T000i[ ii0I" سخ;T000i[ ii0I" سم;T000i[ ii0I" صح;T000i[ ii0I" صخ;T000i[ ii0I" صم;T000i[ ii0I" ضج;T000i[ ii0I" ضح;T000i[ ii0I" ضخ;T000i[ ii0I" ضم;T000i[ ii0I" طح;T000i[ ii0I" ظم;T000i[ ii0I" عج;T000i[ ii0I" عم;T000i[ ii0I" غج;T000i[ ii0I" غم;T000i[ ii0I" فج;T000i[ ii0I" فح;T000i[ ii0I" فخ;T000i[ ii0I" فم;T000i[ ii0I" قح;T000i[ ii0I" قم;T000i[ ii0I" كج;T000i[ ii0I" كح;T000i[ ii0I" كخ;T000i[ ii0I" كل;T000i[ ii0I" كم;T000i[ ii0I" لج;T000i[ ii0I" لح;T000i[ ii0I" لخ;T000i[ ii0I" لم;T000i[ ii0I" له;T000i[ ii0I" مج;T000i[ ii0I" مح;T000i[ ii0I" مخ;T000i[ ii0I" مم;T000i[ ii0I" نج;T000i[ ii0I" نح;T000i[ ii0I" نخ;T000i[ ii0I" نم;T000i[ ii0I" نه;T000i[ ii0I" هج;T000i[ ii0I" هم;T000i[ ii0I" هٰ;T000i[ ii0I" يج;T000i[ ii0I" يح;T000i[ ii0I" يخ;T000i[ ii0I" يم;T000i[ ii0I" يه;T000i[ ii0I" ئم;T000i[ ii0I" ئه;T000i[ ii0I" بم;T000i[ ii0I" به;T000i[ ii0I" تم;T000i[ ii0I" ته;T000i[ ii0I" ثم;T000i[ ii0I" ثه;T000i[ ii0I" سم;T000i[ ii0I" سه;T000i[ ii0I" شم;T000i[ ii0I" شه;T000i[ ii0I" كل;T000i[ ii0I" كم;T000i[ ii0I" لم;T000i[ ii0I" نم;T000i[ ii0I" نه;T000i[ ii0I" يم;T000i[ ii0I" يه;T000i[ ii0I" ـَّ;T000i[ ii0I" ـُّ;T000i[ ii0I" ـِّ;T000i[ ii0I" طى;T000i[ ii0I" طي;T000i[ ii0I" عى;T000i[ ii0I" عي;T000i[ ii0I" غى;T000i[ ii0I" غي;T000i[ ii0I" سى;T000i[ ii0I" سي;T000i[ ii0I" شى;T000i[ ii0I" شي;T000i[ ii0I" حى;T000i[ ii0I" حي;T000i[ ii0I" جى;T000i[ ii0I" جي;T000i[ ii0I" خى;T000i[ ii0I" خي;T000i[ ii0I" صى;T000i[ ii0I" صي;T000i[ ii0I" ضى;T000i[ ii0I" ضي;T000i [ ii0I" شج;T000i [ ii0I" شح;T000i [ ii0I" شخ;T000i [ ii0I" شم;T000i [ ii0I" شر;T000i[ ii0I" سر;T000i[ ii0I" صر;T000i[ ii0I" ضر;T000i[ ii0I" طى;T000i[ ii0I" طي;T000i[ ii0I" عى;T000i[ ii0I" عي;T000i[ ii0I" غى;T000i[ ii0I" غي;T000i[ ii0I" سى;T000i[ ii0I" سي;T000i[ ii0I" شى;T000i[ ii0I" شي;T000i[ ii0I" حى;T000i[ ii0I" حي;T000i[ ii0I" جى;T000i[ ii0I" جي;T000i[ ii0I" خى;T000i [ ii0I" خي;T000i![ ii0I" صى;T000i"[ ii0I" صي;T000i#[ ii0I" ضى;T000i$[ ii0I" ضي;T000i%[ ii0I" شج;T000i&[ ii0I" شح;T000i'[ ii0I" شخ;T000i([ ii0I" شم;T000i)[ ii0I" شر;T000i*[ ii0I" سر;T000i+[ ii0I" صر;T000i,[ ii0I" ضر;T000i-[ ii0I" شج;T000i.[ ii0I" شح;T000i/[ ii0I" شخ;T000i0[ ii0I" شم;T000i1[ ii0I" سه;T000i2[ ii0I" شه;T000i3[ ii0I" طم;T000i4[ ii0I" سج;T000i5[ ii0I" سح;T000i6[ ii0I" سخ;T000i7[ ii0I" شج;T000i8[ ii0I" شح;T000i9[ ii0I" شخ;T000i:[ ii0I" طم;T000i;[ ii0I" ظم;T000i<[ ii0I" اً;T000i=[ ii0I" اً;T000iP[ ii0I" تجم;T000iQ[ ii0I" تحج;T000iR[ ii0I" تحج;T000iS[ ii0I" تحم;T000iT[ ii0I" تخم;T000iU[ ii0I" تمج;T000iV[ ii0I" تمح;T000iW[ ii0I" تمخ;T000iX[ ii0I" جمح;T000iY[ ii0I" جمح;T000iZ[ ii0I" حمي;T000i[[ ii0I" حمى;T000i\[ ii0I" سحج;T000i][ ii0I" سجح;T000i^[ ii0I" سجى;T000i_[ ii0I" سمح;T000i`[ ii0I" سمح;T000ia[ ii0I" سمج;T000ib[ ii0I" سمم;T000ic[ ii0I" سمم;T000id[ ii0I" صحح;T000ie[ ii0I" صحح;T000if[ ii0I" صمم;T000ig[ ii0I" شحم;T000ih[ ii0I" شحم;T000ii[ ii0I" شجي;T000ij[ ii0I" شمخ;T000ik[ ii0I" شمخ;T000il[ ii0I" شمم;T000im[ ii0I" شمم;T000in[ ii0I" ضحى;T000io[ ii0I" ضخم;T000ip[ ii0I" ضخم;T000iq[ ii0I" طمح;T000ir[ ii0I" طمح;T000is[ ii0I" طمم;T000it[ ii0I" طمي;T000iu[ ii0I" عجم;T000iv[ ii0I" عمم;T000iw[ ii0I" عمم;T000ix[ ii0I" عمى;T000iy[ ii0I" غمم;T000iz[ ii0I" غمي;T000i{[ ii0I" غمى;T000i|[ ii0I" فخم;T000i}[ ii0I" فخم;T000i~[ ii0I" قمح;T000i[ ii0I" قمم;T000i[ ii0I" لحم;T000i[ ii0I" لحي;T000i[ ii0I" لحى;T000i[ ii0I" لجج;T000i[ ii0I" لجج;T000i[ ii0I" لخم;T000i[ ii0I" لخم;T000i[ ii0I" لمح;T000i[ ii0I" لمح;T000i[ ii0I" محج;T000i[ ii0I" محم;T000i[ ii0I" محي;T000i[ ii0I" مجح;T000i[ ii0I" مجم;T000i[ ii0I" مخج;T000i[ ii0I" مخم;T000i[ ii0I" مجخ;T000i[ ii0I" همج;T000i[ ii0I" همم;T000i[ ii0I" نحم;T000i[ ii0I" نحى;T000i[ ii0I" نجم;T000i[ ii0I" نجم;T000i[ ii0I" نجى;T000i[ ii0I" نمي;T000i[ ii0I" نمى;T000i[ ii0I" يمم;T000i[ ii0I" يمم;T000i[ ii0I" بخي;T000i[ ii0I" تجي;T000i[ ii0I" تجى;T000i[ ii0I" تخي;T000i[ ii0I" تخى;T000i[ ii0I" تمي;T000i[ ii0I" تمى;T000i[ ii0I" جمي;T000i[ ii0I" جحى;T000i[ ii0I" جمى;T000i[ ii0I" سخى;T000i[ ii0I" صحي;T000i[ ii0I" شحي;T000i[ ii0I" ضحي;T000i[ ii0I" لجي;T000i[ ii0I" لمي;T000i[ ii0I" يحي;T000i[ ii0I" يجي;T000i[ ii0I" يمي;T000i[ ii0I" ممي;T000i[ ii0I" قمي;T000i[ ii0I" نحي;T000i[ ii0I" قمح;T000i[ ii0I" لحم;T000i[ ii0I" عمي;T000i[ ii0I" كمي;T000i[ ii0I" نجح;T000i[ ii0I" مخي;T000i[ ii0I" لجم;T000i[ ii0I" كمم;T000i[ ii0I" لجم;T000i[ ii0I" نجح;T000i[ ii0I" جحي;T000i[ ii0I" حجي;T000i[ ii0I" مجي;T000i[ ii0I" فمي;T000i[ ii0I" بحي;T000i[ ii0I" كمم;T000i[ ii0I" عجم;T000i[ ii0I" صمم;T000i[ ii0I" سخي;T000i[ ii0I" نجي;T000i[ ii0I" صلے;T000i[ ii0I" قلے;T000i[ ii0I" الله;T000i[ ii0I" اكبر;T000i[ ii0I" محمد;T000i[ ii0I" صلعم;T000i[ ii0I" رسول;T000i[ ii0I" عليه;T000i[ ii0I" وسلم;T000i[ ii0I" صلى;T000i[ ii0I"&صلى الله عليه وسلم;T000i[ ii0I"جل جلاله;T000i [ ii00000i![ ii00000i"[ ii00000i#[ ii00000i0[ ii0I"‥;T000i1[ ii0I"—;T000i2[ ii0I"–;T000i3[ ii0I"_;T000i4[ ii0I"_;T000i5[ ii0I"(;T000i6[ ii0I");T000i7[ ii0I"{;T000i8[ ii0I"};T000i9[ ii0I"〔;T000i:[ ii0I"〕;T000i;[ ii0I"【;T000i<[ ii0I"】;T000i=[ ii0I"《;T000i>[ ii0I"》;T000i?[ ii0I"〈;T000i@[ ii0I"〉;T000iA[ ii0I"「;T000iB[ ii0I"」;T000iC[ ii0I"『;T000iD[ ii0I"』;T000iI[ ii0I"‾;T000iJ[ ii0I"‾;T000iK[ ii0I"‾;T000iL[ ii0I"‾;T000iM[ ii0I"_;T000iN[ ii0I"_;T000iO[ ii0I"_;T000iP[ ii0I",;T000iQ[ ii0I"、;T000iR[ ii0I".;T000iT[ ii0I";;T000iU[ ii0I":;T000iV[ ii0I"?;T000iW[ ii0I"!;T000iX[ ii0I"—;T000iY[ ii0I"(;T000iZ[ ii0I");T000i[[ ii0I"{;T000i\[ ii0I"};T000i][ ii0I"〔;T000i^[ ii0I"〕;T000i_[ ii0I"#;T000i`[ ii0I"&;T000ia[ ii0I"*;T000ib[ ii0I"+;T000ic[ ii0I"-;T000id[ ii0I"<;T000ie[ ii0I">;T000if[ ii0I"=;T000ih[ ii0I"\;T000ii[ ii0I"$;T000ij[ ii0I"%;T000ik[ ii0I"@;T000ip[ ii0I" ً;T000iq[ ii0I" ـً;T000ir[ ii0I" ٌ;T000it[ ii0I" ٍ;T000iv[ ii0I" َ;T000iw[ ii0I" ـَ;T000ix[ ii0I" ُ;T000iy[ ii0I" ـُ;T000iz[ ii0I" ِ;T000i{[ ii0I" ـِ;T000i|[ ii0I" ّ;T000i}[ ii0I" ـّ;T000i~[ ii0I" ْ;T000i[ ii0I" ـْ;T000i[ ii0I"ء;T000i[ ii0I"آ;T000i[ ii0I"آ;T000i[ ii0I"أ;T000i[ ii0I"أ;T000i[ ii0I"ؤ;T000i[ ii0I"ؤ;T000i[ ii0I"إ;T000i[ ii0I"إ;T000i[ ii0I"ئ;T000i[ ii0I"ئ;T000i[ ii0I"ئ;T000i[ ii0I"ئ;T000i[ ii0I"ا;T000i[ ii0I"ا;T000i[ ii0I"ب;T000i[ ii0I"ب;T000i[ ii0I"ب;T000i[ ii0I"ب;T000i[ ii0I"ة;T000i[ ii0I"ة;T000i[ ii0I"ت;T000i[ ii0I"ت;T000i[ ii0I"ت;T000i[ ii0I"ت;T000i[ ii0I"ث;T000i[ ii0I"ث;T000i[ ii0I"ث;T000i[ ii0I"ث;T000i[ ii0I"ج;T000i[ ii0I"ج;T000i[ ii0I"ج;T000i[ ii0I"ج;T000i[ ii0I"ح;T000i[ ii0I"ح;T000i[ ii0I"ح;T000i[ ii0I"ح;T000i[ ii0I"خ;T000i[ ii0I"خ;T000i[ ii0I"خ;T000i[ ii0I"خ;T000i[ ii0I"د;T000i[ ii0I"د;T000i[ ii0I"ذ;T000i[ ii0I"ذ;T000i[ ii0I"ر;T000i[ ii0I"ر;T000i[ ii0I"ز;T000i[ ii0I"ز;T000i[ ii0I"س;T000i[ ii0I"س;T000i[ ii0I"س;T000i[ ii0I"س;T000i[ ii0I"ش;T000i[ ii0I"ش;T000i[ ii0I"ش;T000i[ ii0I"ش;T000i[ ii0I"ص;T000i[ ii0I"ص;T000i[ ii0I"ص;T000i[ ii0I"ص;T000i[ ii0I"ض;T000i[ ii0I"ض;T000i[ ii0I"ض;T000i[ ii0I"ض;T000i[ ii0I"ط;T000i[ ii0I"ط;T000i[ ii0I"ط;T000i[ ii0I"ط;T000i[ ii0I"ظ;T000i[ ii0I"ظ;T000i[ ii0I"ظ;T000i[ ii0I"ظ;T000i[ ii0I"ع;T000i[ ii0I"ع;T000i[ ii0I"ع;T000i[ ii0I"ع;T000i[ ii0I"غ;T000i[ ii0I"غ;T000i[ ii0I"غ;T000i[ ii0I"غ;T000i[ ii0I"ف;T000i[ ii0I"ف;T000i[ ii0I"ف;T000i[ ii0I"ف;T000i[ ii0I"ق;T000i[ ii0I"ق;T000i[ ii0I"ق;T000i[ ii0I"ق;T000i[ ii0I"ك;T000i[ ii0I"ك;T000i[ ii0I"ك;T000i[ ii0I"ك;T000i[ ii0I"ل;T000i[ ii0I"ل;T000i[ ii0I"ل;T000i[ ii0I"ل;T000i[ ii0I"م;T000i[ ii0I"م;T000i[ ii0I"م;T000i[ ii0I"م;T000i[ ii0I"ن;T000i[ ii0I"ن;T000i[ ii0I"ن;T000i[ ii0I"ن;T000i[ ii0I"ه;T000i[ ii0I"ه;T000i[ ii0I"ه;T000i[ ii0I"ه;T000i[ ii0I"و;T000i[ ii0I"و;T000i[ ii0I"ى;T000i[ ii0I"ى;T000i[ ii0I"ي;T000i[ ii0I"ي;T000i[ ii0I"ي;T000i[ ii0I"ي;T000i[ ii0I" لآ;T000i[ ii0I" لآ;T000i[ ii0I" لأ;T000i[ ii0I" لأ;T000i[ ii0I" لإ;T000i[ ii0I" لإ;T000i[ ii0I" لا;T000i[ ii0I" لا;T000i[ ii0I"!;T000i[ ii0I"";T000i[ ii0I"#;T000i[ ii0I"$;T000i[ ii0I"%;T000i[ ii0I"&;T000i[ ii0I"';T000i[ ii0I"(;T000i [ ii0I");T000i [ ii0I"*;T000i [ ii0I"+;T000i [ ii0I",;T000i [ ii0I"-;T000i[ ii0I".;T000i[ ii0I"/;T000i[ ii0I"0;T000i[ ii0I"1;T000i[ ii0I"2;T000i[ ii0I"3;T000i[ ii0I"4;T000i[ ii0I"5;T000i[ ii0I"6;T000i[ ii0I"7;T000i[ ii0I"8;T000i[ ii0I"9;T000i[ ii0I":;T000i[ ii0I";;T000i[ ii0I"<;T000i[ ii0I"=;T000i[ ii0I">;T000i[ ii0I"?;T000i [ ii0I"@;T000i![ ii0I"A;T0iA0i"[ ii0I"B;T0iB0i#[ ii0I"C;T0iC0i$[ ii0I"D;T0iD0i%[ ii0I"E;T0iE0i&[ ii0I"F;T0iF0i'[ ii0I"G;T0iG0i([ ii0I"H;T0iH0i)[ ii0I"I;T0iI0i*[ ii0I"J;T0iJ0i+[ ii0I"K;T0iK0i,[ ii0I"L;T0iL0i-[ ii0I"M;T0iM0i.[ ii0I"N;T0iN0i/[ ii0I"O;T0iO0i0[ ii0I"P;T0iP0i1[ ii0I"Q;T0iQ0i2[ ii0I"R;T0iR0i3[ ii0I"S;T0iS0i4[ ii0I"T;T0iT0i5[ ii0I"U;T0iU0i6[ ii0I"V;T0iV0i7[ ii0I"W;T0iW0i8[ ii0I"X;T0iX0i9[ ii0I"Y;T0iY0i:[ ii0I"Z;T0iZ0i;[ ii0I"[;T000i<[ ii0I"\;T000i=[ ii0I"];T000i>[ ii0I"^;T000i?[ ii0I"_;T000i@[ ii0I"`;T000iA[ ii0I"a;Ti!0i!iB[ ii0I"b;Ti"0i"iC[ ii0I"c;Ti#0i#iD[ ii0I"d;Ti$0i$iE[ ii0I"e;Ti%0i%iF[ ii0I"f;Ti&0i&iG[ ii0I"g;Ti'0i'iH[ ii0I"h;Ti(0i(iI[ ii0I"i;Ti)0i)iJ[ ii0I"j;Ti*0i*iK[ ii0I"k;Ti+0i+iL[ ii0I"l;Ti,0i,iM[ ii0I"m;Ti-0i-iN[ ii0I"n;Ti.0i.iO[ ii0I"o;Ti/0i/iP[ ii0I"p;Ti00i0iQ[ ii0I"q;Ti10i1iR[ ii0I"r;Ti20i2iS[ ii0I"s;Ti30i3iT[ ii0I"t;Ti40i4iU[ ii0I"u;Ti50i5iV[ ii0I"v;Ti60i6iW[ ii0I"w;Ti70i7iX[ ii0I"x;Ti80i8iY[ ii0I"y;Ti90i9iZ[ ii0I"z;Ti:0i:i[[ ii0I"{;T000i\[ ii0I"|;T000i][ ii0I"};T000i^[ ii0I"~;T000ia[ ii0I"。;T000ib[ ii0I"「;T000ic[ ii0I"」;T000id[ ii0I"、;T000ie[ ii0I"・;T000if[ ii0I"ヲ;T000ig[ ii0I"ァ;T000ih[ ii0I"ィ;T000ii[ ii0I"ゥ;T000ij[ ii0I"ェ;T000ik[ ii0I"ォ;T000il[ ii0I"ャ;T000im[ ii0I"ュ;T000in[ ii0I"ョ;T000io[ ii0I"ッ;T000ip[ ii0I"ー;T000iq[ ii0I"ア;T000ir[ ii0I"イ;T000is[ ii0I"ウ;T000it[ ii0I"エ;T000iu[ ii0I"オ;T000iv[ ii0I"カ;T000iw[ ii0I"キ;T000ix[ ii0I"ク;T000iy[ ii0I"ケ;T000iz[ ii0I"コ;T000i{[ ii0I"サ;T000i|[ ii0I"シ;T000i}[ ii0I"ス;T000i~[ ii0I"セ;T000i[ ii0I"ソ;T000i[ ii0I"タ;T000i[ ii0I"チ;T000i[ ii0I"ツ;T000i[ ii0I"テ;T000i[ ii0I"ト;T000i[ ii0I"ナ;T000i[ ii0I"ニ;T000i[ ii0I"ヌ;T000i[ ii0I"ネ;T000i[ ii0I"ノ;T000i[ ii0I"ハ;T000i[ ii0I"ヒ;T000i[ ii0I"フ;T000i[ ii0I"ヘ;T000i[ ii0I"ホ;T000i[ ii0I"マ;T000i[ ii0I"ミ;T000i[ ii0I"ム;T000i[ ii0I"メ;T000i[ ii0I"モ;T000i[ ii0I"ヤ;T000i[ ii0I"ユ;T000i[ ii0I"ヨ;T000i[ ii0I"ラ;T000i[ ii0I"リ;T000i[ ii0I"ル;T000i[ ii0I"レ;T000i[ ii0I"ロ;T000i[ ii0I"ワ;T000i[ ii0I"ン;T000i[ ii0I"゙;T000i[ ii0I"゚;T000i[ ii0I"ㅤ;T000i[ ii0I"ㄱ;T000i[ ii0I"ㄲ;T000i[ ii0I"ㄳ;T000i[ ii0I"ㄴ;T000i[ ii0I"ㄵ;T000i[ ii0I"ㄶ;T000i[ ii0I"ㄷ;T000i[ ii0I"ㄸ;T000i[ ii0I"ㄹ;T000i[ ii0I"ㄺ;T000i[ ii0I"ㄻ;T000i[ ii0I"ㄼ;T000i[ ii0I"ㄽ;T000i[ ii0I"ㄾ;T000i[ ii0I"ㄿ;T000i[ ii0I"ㅀ;T000i[ ii0I"ㅁ;T000i[ ii0I"ㅂ;T000i[ ii0I"ㅃ;T000i[ ii0I"ㅄ;T000i[ ii0I"ㅅ;T000i[ ii0I"ㅆ;T000i[ ii0I"ㅇ;T000i[ ii0I"ㅈ;T000i[ ii0I"ㅉ;T000i[ ii0I"ㅊ;T000i[ ii0I"ㅋ;T000i[ ii0I"ㅌ;T000i[ ii0I"ㅍ;T000i[ ii0I"ㅎ;T000i[ ii0I"ㅏ;T000i[ ii0I"ㅐ;T000i[ ii0I"ㅑ;T000i[ ii0I"ㅒ;T000i[ ii0I"ㅓ;T000i[ ii0I"ㅔ;T000i[ ii0I"ㅕ;T000i[ ii0I"ㅖ;T000i[ ii0I"ㅗ;T000i[ ii0I"ㅘ;T000i[ ii0I"ㅙ;T000i[ ii0I"ㅚ;T000i[ ii0I"ㅛ;T000i[ ii0I"ㅜ;T000i[ ii0I"ㅝ;T000i[ ii0I"ㅞ;T000i[ ii0I"ㅟ;T000i[ ii0I"ㅠ;T000i[ ii0I"ㅡ;T000i[ ii0I"ㅢ;T000i[ ii0I"ㅣ;T000i[ ii0I"¢;T000i[ ii0I"£;T000i[ ii0I"¬;T000i[ ii0I"¯;T000i[ ii0I"¦;T000i[ ii0I"¥;T000i[ ii0I"₩;T000i[ ii0I"│;T000i[ ii0I"←;T000i[ ii0I"↑;T000i[ ii0I"→;T000i[ ii0I"↓;T000i[ ii0I"■;T000i[ ii0I"○;T000addressable-2.8.7/tasks/0000755000004100000410000000000014636033505015163 5ustar www-datawww-dataaddressable-2.8.7/tasks/git.rake0000644000004100000410000000242714636033505016617 0ustar www-datawww-data# frozen_string_literal: true namespace :git do namespace :tag do desc "List tags from the Git repository" task :list do tags = `git tag -l` tags.gsub!("\r", "") tags = tags.split("\n").sort {|a, b| b <=> a } puts tags.join("\n") end desc "Create a new tag in the Git repository" task :create do changelog = File.open("CHANGELOG.md", "r") { |file| file.read } puts "-" * 80 puts changelog puts "-" * 80 puts v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z" abort "Versions don't match #{v} vs #{PKG_VERSION}" if v != PKG_VERSION git_status = `git status` if git_status !~ /^nothing to commit/ abort "Working directory isn't clean." end tag = "#{PKG_NAME}-#{PKG_VERSION}" msg = "Release #{PKG_NAME}-#{PKG_VERSION}" existing_tags = `git tag -l #{PKG_NAME}-*`.split('\n') if existing_tags.include?(tag) warn("Tag already exists, deleting...") unless system "git tag -d #{tag}" abort "Tag deletion failed." end end puts "Creating git tag '#{tag}'..." unless system "git tag -a -m \"#{msg}\" #{tag}" abort "Tag creation failed." end end end end task "gem:release" => "git:tag:create" addressable-2.8.7/tasks/yard.rake0000644000004100000410000000125514636033505016771 0ustar www-datawww-data# frozen_string_literal: true require "rake" begin require "yard" require "yard/rake/yardoc_task" namespace :doc do desc "Generate Yardoc documentation" YARD::Rake::YardocTask.new do |yardoc| yardoc.name = "yard" yardoc.options = ["--verbose", "--markup", "markdown"] yardoc.files = FileList[ "lib/**/*.rb", "ext/**/*.c", "README.md", "CHANGELOG.md", "LICENSE.txt" ].exclude(/idna/) end end task "clobber" => ["doc:clobber_yard"] desc "Alias to doc:yard" task "doc" => "doc:yard" rescue LoadError # If yard isn't available, it's not the end of the world desc "Alias to doc:rdoc" task "doc" => "doc:rdoc" end addressable-2.8.7/tasks/rspec.rake0000644000004100000410000000105514636033505017144 0ustar www-datawww-data# frozen_string_literal: true require "rspec/core/rake_task" namespace :spec do RSpec::Core::RakeTask.new(:simplecov) do |t| t.pattern = FileList['spec/**/*_spec.rb'] t.rspec_opts = %w[--color --format documentation] unless ENV["CI"] end namespace :simplecov do desc "Browse the code coverage report." task :browse => "spec:simplecov" do require "launchy" Launchy.open("coverage/index.html") end end end desc "Alias to spec:simplecov" task "spec" => "spec:simplecov" task "clobber" => ["spec:clobber_simplecov"] addressable-2.8.7/tasks/metrics.rake0000644000004100000410000000117214636033505017476 0ustar www-datawww-data# frozen_string_literal: true namespace :metrics do task :lines do lines, codelines, total_lines, total_codelines = 0, 0, 0, 0 for file_name in FileList["lib/**/*.rb"] f = File.open(file_name) while line = f.gets lines += 1 next if line =~ /^\s*$/ next if line =~ /^\s*#/ codelines += 1 end puts "L: #{sprintf("%4d", lines)}, " + "LOC #{sprintf("%4d", codelines)} | #{file_name}" total_lines += lines total_codelines += codelines lines, codelines = 0, 0 end puts "Total: Lines #{total_lines}, LOC #{total_codelines}" end end addressable-2.8.7/tasks/profile.rake0000644000004100000410000000431714636033505017474 0ustar www-datawww-data# frozen_string_literal: true namespace :profile do desc "Profile Template match memory allocations" task :template_match_memory do require "memory_profiler" require "addressable/template" start_at = Time.now.to_f template = Addressable::Template.new("http://example.com/{?one,two,three}") report = MemoryProfiler.report do 30_000.times do template.match( "http://example.com/?one=one&two=floo&three=me" ) end end end_at = Time.now.to_f print_options = { scale_bytes: true, normalize_paths: true } puts "\n\n" if ENV["CI"] report.pretty_print(print_options) else t_allocated = report.scale_bytes(report.total_allocated_memsize) t_retained = report.scale_bytes(report.total_retained_memsize) puts "Total allocated: #{t_allocated} (#{report.total_allocated} objects)" puts "Total retained: #{t_retained} (#{report.total_retained} objects)" puts "Took #{end_at - start_at} seconds" FileUtils.mkdir_p("tmp") report.pretty_print(to_file: "tmp/memprof.txt", **print_options) end end desc "Profile URI parse memory allocations" task :memory do require "memory_profiler" require "addressable/uri" if ENV["IDNA_MODE"] == "pure" Addressable.send(:remove_const, :IDNA) load "addressable/idna/pure.rb" end start_at = Time.now.to_f report = MemoryProfiler.report do 30_000.times do Addressable::URI.parse( "http://google.com/stuff/../?with_lots=of¶ms=asdff#!stuff" ).normalize end end end_at = Time.now.to_f print_options = { scale_bytes: true, normalize_paths: true } puts "\n\n" if ENV["CI"] report.pretty_print(**print_options) else t_allocated = report.scale_bytes(report.total_allocated_memsize) t_retained = report.scale_bytes(report.total_retained_memsize) puts "Total allocated: #{t_allocated} (#{report.total_allocated} objects)" puts "Total retained: #{t_retained} (#{report.total_retained} objects)" puts "Took #{end_at - start_at} seconds" FileUtils.mkdir_p("tmp") report.pretty_print(to_file: "tmp/memprof.txt", **print_options) end end end addressable-2.8.7/tasks/clobber.rake0000644000004100000410000000011714636033505017436 0ustar www-datawww-data# frozen_string_literal: true desc "Remove all build products" task "clobber" addressable-2.8.7/tasks/gem.rake0000644000004100000410000000472314636033505016605 0ustar www-datawww-data# frozen_string_literal: true require "rubygems/package_task" namespace :gem do GEM_SPEC = Gem::Specification.new do |s| s.name = PKG_NAME s.version = PKG_VERSION s.summary = PKG_SUMMARY s.description = PKG_DESCRIPTION s.files = PKG_FILES.to_a s.extra_rdoc_files = %w( README.md ) s.rdoc_options.concat ["--main", "README.md"] if !s.respond_to?(:add_development_dependency) puts "Cannot build Gem with this version of RubyGems." exit(1) end s.required_ruby_version = ">= 2.2" s.add_runtime_dependency "public_suffix", ">= 2.0.2", "< 7.0" s.add_development_dependency "bundler", ">= 1.0", "< 3.0" s.require_path = "lib" s.author = "Bob Aman" s.email = "bob@sporkmonger.com" s.homepage = "https://github.com/sporkmonger/addressable" s.license = "Apache-2.0" s.metadata = { "changelog_uri" => "https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md#v#{PKG_VERSION}" } end Gem::PackageTask.new(GEM_SPEC) do |p| p.gem_spec = GEM_SPEC p.need_tar = true p.need_zip = true end desc "Generates .gemspec file" task :gemspec do spec_string = GEM_SPEC.to_ruby File.open("#{GEM_SPEC.name}.gemspec", "w") do |file| file.write spec_string end end desc "Show information about the gem" task :debug do puts GEM_SPEC.to_ruby end desc "Install the gem" task :install => ["clobber", "gem:package"] do sh "gem install --local ./pkg/#{GEM_SPEC.full_name}.gem" end desc "Uninstall the gem" task :uninstall do installed_list = Gem.source_index.find_name(PKG_NAME) if installed_list && (installed_list.collect { |s| s.version.to_s}.include?(PKG_VERSION)) sh( "gem uninstall --version '#{PKG_VERSION}' " + "--ignore-dependencies --executables #{PKG_NAME}" ) end end desc "Reinstall the gem" task :reinstall => [:uninstall, :install] desc "Package for release" task :release => ["gem:package", "gem:gemspec"] do |t| v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z" abort "Versions don't match #{v} vs #{PROJ.version}" if v != PKG_VERSION pkg = "pkg/#{GEM_SPEC.full_name}" changelog = File.open("CHANGELOG.md") { |file| file.read } puts "Releasing #{PKG_NAME} v. #{PKG_VERSION}" Rake::Task["git:tag:create"].invoke end end desc "Alias to gem:package" task "gem" => "gem:package" task "gem:release" => "gem:gemspec" task "clobber" => ["gem:clobber_package"] addressable-2.8.7/lib/0000755000004100000410000000000014636033505014604 5ustar www-datawww-dataaddressable-2.8.7/lib/addressable.rb0000644000004100000410000000013014636033505017374 0ustar www-datawww-data# frozen_string_literal: true require 'addressable/uri' require 'addressable/template' addressable-2.8.7/lib/addressable/0000755000004100000410000000000014636033505017055 5ustar www-datawww-dataaddressable-2.8.7/lib/addressable/idna.rb0000644000004100000410000000147414636033505020323 0ustar www-datawww-data# frozen_string_literal: true #-- # Copyright (C) Bob Aman # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #++ begin require "addressable/idna/native" rescue LoadError # libidn or the idn gem was not available, fall back on a pure-Ruby # implementation... require "addressable/idna/pure" end addressable-2.8.7/lib/addressable/idna/0000755000004100000410000000000014636033505017770 5ustar www-datawww-dataaddressable-2.8.7/lib/addressable/idna/pure.rb0000644000004100000410000003576214636033505021305 0ustar www-datawww-data# frozen_string_literal: true #-- # Copyright (C) Bob Aman # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #++ module Addressable module IDNA # This module is loosely based on idn_actionmailer by Mick Staugaard, # the unicode library by Yoshida Masato, and the punycode implementation # by Kazuhiro Nishiyama. Most of the code was copied verbatim, but # some reformatting was done, and some translation from C was done. # # Without their code to work from as a base, we'd all still be relying # on the presence of libidn. Which nobody ever seems to have installed. # # Original sources: # http://github.com/staugaard/idn_actionmailer # http://www.yoshidam.net/Ruby.html#unicode # http://rubyforge.org/frs/?group_id=2550 UNICODE_TABLE = File.expand_path( File.join(File.dirname(__FILE__), '../../..', 'data/unicode.data') ) ACE_PREFIX = "xn--" UTF8_REGEX = /\A(?: [\x09\x0A\x0D\x20-\x7E] # ASCII | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 | [\xF1-\xF3][\x80-\xBF]{3} # planes 4nil5 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 )*\z/mnx UTF8_REGEX_MULTIBYTE = /(?: [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 | [\xF1-\xF3][\x80-\xBF]{3} # planes 4nil5 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 )/mnx # :startdoc: # Converts from a Unicode internationalized domain name to an ASCII # domain name as described in RFC 3490. def self.to_ascii(input) input = input.to_s unless input.is_a?(String) input = input.dup.force_encoding(Encoding::UTF_8).unicode_normalize(:nfkc) if input.respond_to?(:force_encoding) input.force_encoding(Encoding::ASCII_8BIT) end if input =~ UTF8_REGEX && input =~ UTF8_REGEX_MULTIBYTE parts = unicode_downcase(input).split('.') parts.map! do |part| if part.respond_to?(:force_encoding) part.force_encoding(Encoding::ASCII_8BIT) end if part =~ UTF8_REGEX && part =~ UTF8_REGEX_MULTIBYTE ACE_PREFIX + punycode_encode(part) else part end end parts.join('.') else input end end # Converts from an ASCII domain name to a Unicode internationalized # domain name as described in RFC 3490. def self.to_unicode(input) input = input.to_s unless input.is_a?(String) parts = input.split('.') parts.map! do |part| if part =~ /^#{ACE_PREFIX}(.+)/ begin punycode_decode(part[/^#{ACE_PREFIX}(.+)/, 1]) rescue Addressable::IDNA::PunycodeBadInput # toUnicode is explicitly defined as never-fails by the spec part end else part end end output = parts.join('.') if output.respond_to?(:force_encoding) output.force_encoding(Encoding::UTF_8) end output end class << self # @deprecated Use {String#unicode_normalize(:nfkc)} instead def unicode_normalize_kc(value) value.to_s.unicode_normalize(:nfkc) end extend Gem::Deprecate deprecate :unicode_normalize_kc, "String#unicode_normalize(:nfkc)", 2023, 4 end ## # Unicode aware downcase method. # # @api private # @param [String] input # The input string. # @return [String] The downcased result. def self.unicode_downcase(input) input = input.to_s unless input.is_a?(String) unpacked = input.unpack("U*") unpacked.map! { |codepoint| lookup_unicode_lowercase(codepoint) } return unpacked.pack("U*") end private_class_method :unicode_downcase def self.lookup_unicode_lowercase(codepoint) codepoint_data = UNICODE_DATA[codepoint] (codepoint_data ? (codepoint_data[UNICODE_DATA_LOWERCASE] || codepoint) : codepoint) end private_class_method :lookup_unicode_lowercase UNICODE_DATA_COMBINING_CLASS = 0 UNICODE_DATA_EXCLUSION = 1 UNICODE_DATA_CANONICAL = 2 UNICODE_DATA_COMPATIBILITY = 3 UNICODE_DATA_UPPERCASE = 4 UNICODE_DATA_LOWERCASE = 5 UNICODE_DATA_TITLECASE = 6 begin if defined?(FakeFS) fakefs_state = FakeFS.activated? FakeFS.deactivate! end # This is a sparse Unicode table. Codepoints without entries are # assumed to have the value: [0, 0, nil, nil, nil, nil, nil] UNICODE_DATA = File.open(UNICODE_TABLE, "rb") do |file| Marshal.load(file.read) end ensure if defined?(FakeFS) FakeFS.activate! if fakefs_state end end COMPOSITION_TABLE = {} UNICODE_DATA.each do |codepoint, data| canonical = data[UNICODE_DATA_CANONICAL] exclusion = data[UNICODE_DATA_EXCLUSION] if canonical && exclusion == 0 COMPOSITION_TABLE[canonical.unpack("C*")] = codepoint end end UNICODE_MAX_LENGTH = 256 ACE_MAX_LENGTH = 256 PUNYCODE_BASE = 36 PUNYCODE_TMIN = 1 PUNYCODE_TMAX = 26 PUNYCODE_SKEW = 38 PUNYCODE_DAMP = 700 PUNYCODE_INITIAL_BIAS = 72 PUNYCODE_INITIAL_N = 0x80 PUNYCODE_DELIMITER = 0x2D PUNYCODE_MAXINT = 1 << 64 PUNYCODE_PRINT_ASCII = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + " !\"\#$%&'()*+,-./" + "0123456789:;<=>?" + "@ABCDEFGHIJKLMNO" + "PQRSTUVWXYZ[\\]^_" + "`abcdefghijklmno" + "pqrstuvwxyz{|}~\n" # Input is invalid. class PunycodeBadInput < StandardError; end # Output would exceed the space provided. class PunycodeBigOutput < StandardError; end # Input needs wider integers to process. class PunycodeOverflow < StandardError; end def self.punycode_encode(unicode) unicode = unicode.to_s unless unicode.is_a?(String) input = unicode.unpack("U*") output = [0] * (ACE_MAX_LENGTH + 1) input_length = input.size output_length = [ACE_MAX_LENGTH] # Initialize the state n = PUNYCODE_INITIAL_N delta = out = 0 max_out = output_length[0] bias = PUNYCODE_INITIAL_BIAS # Handle the basic code points: input_length.times do |j| if punycode_basic?(input[j]) if max_out - out < 2 raise PunycodeBigOutput, "Output would exceed the space provided." end output[out] = input[j] out += 1 end end h = b = out # h is the number of code points that have been handled, b is the # number of basic code points, and out is the number of characters # that have been output. if b > 0 output[out] = PUNYCODE_DELIMITER out += 1 end # Main encoding loop: while h < input_length # All non-basic code points < n have been # handled already. Find the next larger one: m = PUNYCODE_MAXINT input_length.times do |j| m = input[j] if (n...m) === input[j] end # Increase delta enough to advance the decoder's # state to , but guard against overflow: if m - n > (PUNYCODE_MAXINT - delta) / (h + 1) raise PunycodeOverflow, "Input needs wider integers to process." end delta += (m - n) * (h + 1) n = m input_length.times do |j| # Punycode does not need to check whether input[j] is basic: if input[j] < n delta += 1 if delta == 0 raise PunycodeOverflow, "Input needs wider integers to process." end end if input[j] == n # Represent delta as a generalized variable-length integer: q = delta; k = PUNYCODE_BASE while true if out >= max_out raise PunycodeBigOutput, "Output would exceed the space provided." end t = ( if k <= bias PUNYCODE_TMIN elsif k >= bias + PUNYCODE_TMAX PUNYCODE_TMAX else k - bias end ) break if q < t output[out] = punycode_encode_digit(t + (q - t) % (PUNYCODE_BASE - t)) out += 1 q = (q - t) / (PUNYCODE_BASE - t) k += PUNYCODE_BASE end output[out] = punycode_encode_digit(q) out += 1 bias = punycode_adapt(delta, h + 1, h == b) delta = 0 h += 1 end end delta += 1 n += 1 end output_length[0] = out outlen = out outlen.times do |j| c = output[j] unless c >= 0 && c <= 127 raise StandardError, "Invalid output char." end unless PUNYCODE_PRINT_ASCII[c] raise PunycodeBadInput, "Input is invalid." end end output[0..outlen].map { |x| x.chr }.join("").sub(/\0+\z/, "") end private_class_method :punycode_encode def self.punycode_decode(punycode) input = [] output = [] if ACE_MAX_LENGTH * 2 < punycode.size raise PunycodeBigOutput, "Output would exceed the space provided." end punycode.each_byte do |c| unless c >= 0 && c <= 127 raise PunycodeBadInput, "Input is invalid." end input.push(c) end input_length = input.length output_length = [UNICODE_MAX_LENGTH] # Initialize the state n = PUNYCODE_INITIAL_N out = i = 0 max_out = output_length[0] bias = PUNYCODE_INITIAL_BIAS # Handle the basic code points: Let b be the number of input code # points before the last delimiter, or 0 if there is none, then # copy the first b code points to the output. b = 0 input_length.times do |j| b = j if punycode_delimiter?(input[j]) end if b > max_out raise PunycodeBigOutput, "Output would exceed the space provided." end b.times do |j| unless punycode_basic?(input[j]) raise PunycodeBadInput, "Input is invalid." end output[out] = input[j] out+=1 end # Main decoding loop: Start just after the last delimiter if any # basic code points were copied; start at the beginning otherwise. in_ = b > 0 ? b + 1 : 0 while in_ < input_length # in_ is the index of the next character to be consumed, and # out is the number of code points in the output array. # Decode a generalized variable-length integer into delta, # which gets added to i. The overflow checking is easier # if we increase i as we go, then subtract off its starting # value at the end to obtain delta. oldi = i; w = 1; k = PUNYCODE_BASE while true if in_ >= input_length raise PunycodeBadInput, "Input is invalid." end digit = punycode_decode_digit(input[in_]) in_+=1 if digit >= PUNYCODE_BASE raise PunycodeBadInput, "Input is invalid." end if digit > (PUNYCODE_MAXINT - i) / w raise PunycodeOverflow, "Input needs wider integers to process." end i += digit * w t = ( if k <= bias PUNYCODE_TMIN elsif k >= bias + PUNYCODE_TMAX PUNYCODE_TMAX else k - bias end ) break if digit < t if w > PUNYCODE_MAXINT / (PUNYCODE_BASE - t) raise PunycodeOverflow, "Input needs wider integers to process." end w *= PUNYCODE_BASE - t k += PUNYCODE_BASE end bias = punycode_adapt(i - oldi, out + 1, oldi == 0) # I was supposed to wrap around from out + 1 to 0, # incrementing n each time, so we'll fix that now: if i / (out + 1) > PUNYCODE_MAXINT - n raise PunycodeOverflow, "Input needs wider integers to process." end n += i / (out + 1) i %= out + 1 # Insert n at position i of the output: # not needed for Punycode: # raise PUNYCODE_INVALID_INPUT if decode_digit(n) <= base if out >= max_out raise PunycodeBigOutput, "Output would exceed the space provided." end #memmove(output + i + 1, output + i, (out - i) * sizeof *output) output[i + 1, out - i] = output[i, out - i] output[i] = n i += 1 out += 1 end output_length[0] = out output.pack("U*") end private_class_method :punycode_decode def self.punycode_basic?(codepoint) codepoint < 0x80 end private_class_method :punycode_basic? def self.punycode_delimiter?(codepoint) codepoint == PUNYCODE_DELIMITER end private_class_method :punycode_delimiter? def self.punycode_encode_digit(d) d + 22 + 75 * ((d < 26) ? 1 : 0) end private_class_method :punycode_encode_digit # Returns the numeric value of a basic codepoint # (for use in representing integers) in the range 0 to # base - 1, or PUNYCODE_BASE if codepoint does not represent a value. def self.punycode_decode_digit(codepoint) if codepoint - 48 < 10 codepoint - 22 elsif codepoint - 65 < 26 codepoint - 65 elsif codepoint - 97 < 26 codepoint - 97 else PUNYCODE_BASE end end private_class_method :punycode_decode_digit # Bias adaptation method def self.punycode_adapt(delta, numpoints, firsttime) delta = firsttime ? delta / PUNYCODE_DAMP : delta >> 1 # delta >> 1 is a faster way of doing delta / 2 delta += delta / numpoints difference = PUNYCODE_BASE - PUNYCODE_TMIN k = 0 while delta > (difference * PUNYCODE_TMAX) / 2 delta /= difference k += PUNYCODE_BASE end k + (difference + 1) * delta / (delta + PUNYCODE_SKEW) end private_class_method :punycode_adapt end # :startdoc: end addressable-2.8.7/lib/addressable/idna/native.rb0000644000004100000410000000337514636033505021613 0ustar www-datawww-data# frozen_string_literal: true #-- # Copyright (C) Bob Aman # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #++ require "idn" module Addressable module IDNA def self.punycode_encode(value) IDN::Punycode.encode(value.to_s) end def self.punycode_decode(value) IDN::Punycode.decode(value.to_s) end class << self # @deprecated Use {String#unicode_normalize(:nfkc)} instead def unicode_normalize_kc(value) value.to_s.unicode_normalize(:nfkc) end extend Gem::Deprecate deprecate :unicode_normalize_kc, "String#unicode_normalize(:nfkc)", 2023, 4 end def self.to_ascii(value) value.to_s.split('.', -1).map do |segment| if segment.size > 0 && segment.size < 64 IDN::Idna.toASCII(segment, IDN::Idna::ALLOW_UNASSIGNED) elsif segment.size >= 64 segment else '' end end.join('.') end def self.to_unicode(value) value.to_s.split('.', -1).map do |segment| if segment.size > 0 && segment.size < 64 IDN::Idna.toUnicode(segment, IDN::Idna::ALLOW_UNASSIGNED) elsif segment.size >= 64 segment else '' end end.join('.') end end end addressable-2.8.7/lib/addressable/version.rb0000644000004100000410000000157714636033505021101 0ustar www-datawww-data# frozen_string_literal: true #-- # Copyright (C) Bob Aman # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #++ # Used to prevent the class/module from being loaded more than once if !defined?(Addressable::VERSION) module Addressable module VERSION MAJOR = 2 MINOR = 8 TINY = 7 STRING = [MAJOR, MINOR, TINY].join('.') end end end addressable-2.8.7/lib/addressable/template.rb0000644000004100000410000010645414636033505021227 0ustar www-datawww-data# frozen_string_literal: true #-- # Copyright (C) Bob Aman # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #++ require "addressable/version" require "addressable/uri" module Addressable ## # This is an implementation of a URI template based on # RFC 6570 (http://tools.ietf.org/html/rfc6570). class Template # Constants used throughout the template code. anything = Addressable::URI::CharacterClasses::RESERVED + Addressable::URI::CharacterClasses::UNRESERVED variable_char_class = Addressable::URI::CharacterClasses::ALPHA + Addressable::URI::CharacterClasses::DIGIT + '_' var_char = "(?>(?:[#{variable_char_class}]|%[a-fA-F0-9][a-fA-F0-9])+)" RESERVED = "(?:[#{anything}]|%[a-fA-F0-9][a-fA-F0-9])" UNRESERVED = "(?:[#{ Addressable::URI::CharacterClasses::UNRESERVED }]|%[a-fA-F0-9][a-fA-F0-9])" variable = "(?:#{var_char}(?:\\.?#{var_char})*)" varspec = "(?:(#{variable})(\\*|:\\d+)?)" VARNAME = /^#{variable}$/ VARSPEC = /^#{varspec}$/ VARIABLE_LIST = /^#{varspec}(?:,#{varspec})*$/ operator = "+#./;?&=,!@|" EXPRESSION = /\{([#{operator}])?(#{varspec}(?:,#{varspec})*)\}/ LEADERS = { '?' => '?', '/' => '/', '#' => '#', '.' => '.', ';' => ';', '&' => '&' } JOINERS = { '?' => '&', '.' => '.', ';' => ';', '&' => '&', '/' => '/' } ## # Raised if an invalid template value is supplied. class InvalidTemplateValueError < StandardError end ## # Raised if an invalid template operator is used in a pattern. class InvalidTemplateOperatorError < StandardError end ## # Raised if an invalid template operator is used in a pattern. class TemplateOperatorAbortedError < StandardError end ## # This class represents the data that is extracted when a Template # is matched against a URI. class MatchData ## # Creates a new MatchData object. # MatchData objects should never be instantiated directly. # # @param [Addressable::URI] uri # The URI that the template was matched against. def initialize(uri, template, mapping) @uri = uri.dup.freeze @template = template @mapping = mapping.dup.freeze end ## # @return [Addressable::URI] # The URI that the Template was matched against. attr_reader :uri ## # @return [Addressable::Template] # The Template used for the match. attr_reader :template ## # @return [Hash] # The mapping that resulted from the match. # Note that this mapping does not include keys or values for # variables that appear in the Template, but are not present # in the URI. attr_reader :mapping ## # @return [Array] # The list of variables that were present in the Template. # Note that this list will include variables which do not appear # in the mapping because they were not present in URI. def variables self.template.variables end alias_method :keys, :variables alias_method :names, :variables ## # @return [Array] # The list of values that were captured by the Template. # Note that this list will include nils for any variables which # were in the Template, but did not appear in the URI. def values @values ||= self.variables.inject([]) do |accu, key| accu << self.mapping[key] accu end end alias_method :captures, :values ## # Accesses captured values by name or by index. # # @param [String, Symbol, Fixnum] key # Capture index or name. Note that when accessing by with index # of 0, the full URI will be returned. The intention is to mimic # the ::MatchData#[] behavior. # # @param [#to_int, nil] len # If provided, an array of values will be returned with the given # parameter used as length. # # @return [Array, String, nil] # The captured value corresponding to the index or name. If the # value was not provided or the key is unknown, nil will be # returned. # # If the second parameter is provided, an array of that length will # be returned instead. def [](key, len = nil) if len to_a[key, len] elsif String === key or Symbol === key mapping[key.to_s] else to_a[key] end end ## # @return [Array] # Array with the matched URI as first element followed by the captured # values. def to_a [to_s, *values] end ## # @return [String] # The matched URI as String. def to_s uri.to_s end alias_method :string, :to_s # Returns multiple captured values at once. # # @param [String, Symbol, Fixnum] *indexes # Indices of the captures to be returned # # @return [Array] # Values corresponding to given indices. # # @see Addressable::Template::MatchData#[] def values_at(*indexes) indexes.map { |i| self[i] } end ## # Returns a String representation of the MatchData's state. # # @return [String] The MatchData's state, as a String. def inspect sprintf("#<%s:%#0x RESULT:%s>", self.class.to_s, self.object_id, self.mapping.inspect) end ## # Dummy method for code expecting a ::MatchData instance # # @return [String] An empty string. def pre_match "" end alias_method :post_match, :pre_match end ## # Creates a new Addressable::Template object. # # @param [#to_str] pattern The URI Template pattern. # # @return [Addressable::Template] The initialized Template object. def initialize(pattern) if !pattern.respond_to?(:to_str) raise TypeError, "Can't convert #{pattern.class} into String." end @pattern = pattern.to_str.dup.freeze end ## # Freeze URI, initializing instance variables. # # @return [Addressable::URI] The frozen URI object. def freeze self.variables self.variable_defaults self.named_captures super end ## # @return [String] The Template object's pattern. attr_reader :pattern ## # Returns a String representation of the Template object's state. # # @return [String] The Template object's state, as a String. def inspect sprintf("#<%s:%#0x PATTERN:%s>", self.class.to_s, self.object_id, self.pattern) end ## # Returns true if the Template objects are equal. This method # does NOT normalize either Template before doing the comparison. # # @param [Object] template The Template to compare. # # @return [TrueClass, FalseClass] # true if the Templates are equivalent, false # otherwise. def ==(template) return false unless template.kind_of?(Template) return self.pattern == template.pattern end ## # Addressable::Template makes no distinction between `==` and `eql?`. # # @see #== alias_method :eql?, :== ## # Extracts a mapping from the URI using a URI Template pattern. # # @param [Addressable::URI, #to_str] uri # The URI to extract from. # # @param [#restore, #match] processor # A template processor object may optionally be supplied. # # The object should respond to either the restore or # match messages or both. The restore method should # take two parameters: `[String] name` and `[String] value`. # The restore method should reverse any transformations that # have been performed on the value to ensure a valid URI. # The match method should take a single # parameter: `[String] name`. The match method should return # a String containing a regular expression capture group for # matching on that particular variable. The default value is `".*?"`. # The match method has no effect on multivariate operator # expansions. # # @return [Hash, NilClass] # The Hash mapping that was extracted from the URI, or # nil if the URI didn't match the template. # # @example # class ExampleProcessor # def self.restore(name, value) # return value.gsub(/\+/, " ") if name == "query" # return value # end # # def self.match(name) # return ".*?" if name == "first" # return ".*" # end # end # # uri = Addressable::URI.parse( # "http://example.com/search/an+example+search+query/" # ) # Addressable::Template.new( # "http://example.com/search/{query}/" # ).extract(uri, ExampleProcessor) # #=> {"query" => "an example search query"} # # uri = Addressable::URI.parse("http://example.com/a/b/c/") # Addressable::Template.new( # "http://example.com/{first}/{second}/" # ).extract(uri, ExampleProcessor) # #=> {"first" => "a", "second" => "b/c"} # # uri = Addressable::URI.parse("http://example.com/a/b/c/") # Addressable::Template.new( # "http://example.com/{first}/{-list|/|second}/" # ).extract(uri) # #=> {"first" => "a", "second" => ["b", "c"]} def extract(uri, processor=nil) match_data = self.match(uri, processor) return (match_data ? match_data.mapping : nil) end ## # Extracts match data from the URI using a URI Template pattern. # # @param [Addressable::URI, #to_str] uri # The URI to extract from. # # @param [#restore, #match] processor # A template processor object may optionally be supplied. # # The object should respond to either the restore or # match messages or both. The restore method should # take two parameters: `[String] name` and `[String] value`. # The restore method should reverse any transformations that # have been performed on the value to ensure a valid URI. # The match method should take a single # parameter: `[String] name`. The match method should return # a String containing a regular expression capture group for # matching on that particular variable. The default value is `".*?"`. # The match method has no effect on multivariate operator # expansions. # # @return [Hash, NilClass] # The Hash mapping that was extracted from the URI, or # nil if the URI didn't match the template. # # @example # class ExampleProcessor # def self.restore(name, value) # return value.gsub(/\+/, " ") if name == "query" # return value # end # # def self.match(name) # return ".*?" if name == "first" # return ".*" # end # end # # uri = Addressable::URI.parse( # "http://example.com/search/an+example+search+query/" # ) # match = Addressable::Template.new( # "http://example.com/search/{query}/" # ).match(uri, ExampleProcessor) # match.variables # #=> ["query"] # match.captures # #=> ["an example search query"] # # uri = Addressable::URI.parse("http://example.com/a/b/c/") # match = Addressable::Template.new( # "http://example.com/{first}/{+second}/" # ).match(uri, ExampleProcessor) # match.variables # #=> ["first", "second"] # match.captures # #=> ["a", "b/c"] # # uri = Addressable::URI.parse("http://example.com/a/b/c/") # match = Addressable::Template.new( # "http://example.com/{first}{/second*}/" # ).match(uri) # match.variables # #=> ["first", "second"] # match.captures # #=> ["a", ["b", "c"]] def match(uri, processor=nil) uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI) mapping = {} # First, we need to process the pattern, and extract the values. expansions, expansion_regexp = parse_template_pattern(pattern, processor) return nil unless uri.to_str.match(expansion_regexp) unparsed_values = uri.to_str.scan(expansion_regexp).flatten if uri.to_str == pattern return Addressable::Template::MatchData.new(uri, self, mapping) elsif expansions.size > 0 index = 0 expansions.each do |expansion| _, operator, varlist = *expansion.match(EXPRESSION) varlist.split(',').each do |varspec| _, name, modifier = *varspec.match(VARSPEC) mapping[name] ||= nil case operator when nil, '+', '#', '/', '.' unparsed_value = unparsed_values[index] name = varspec[VARSPEC, 1] value = unparsed_value value = value.split(JOINERS[operator]) if value && modifier == '*' when ';', '?', '&' if modifier == '*' if unparsed_values[index] value = unparsed_values[index].split(JOINERS[operator]) value = value.inject({}) do |acc, v| key, val = v.split('=') val = "" if val.nil? acc[key] = val acc end end else if (unparsed_values[index]) name, value = unparsed_values[index].split('=') value = "" if value.nil? end end end if processor != nil && processor.respond_to?(:restore) value = processor.restore(name, value) end if processor == nil if value.is_a?(Hash) value = value.inject({}){|acc, (k, v)| acc[Addressable::URI.unencode_component(k)] = Addressable::URI.unencode_component(v) acc } elsif value.is_a?(Array) value = value.map{|v| Addressable::URI.unencode_component(v) } else value = Addressable::URI.unencode_component(value) end end if !mapping.has_key?(name) || mapping[name].nil? # Doesn't exist, set to value (even if value is nil) mapping[name] = value end index = index + 1 end end return Addressable::Template::MatchData.new(uri, self, mapping) else return nil end end ## # Expands a URI template into another URI template. # # @param [Hash] mapping The mapping that corresponds to the pattern. # @param [#validate, #transform] processor # An optional processor object may be supplied. # @param [Boolean] normalize_values # Optional flag to enable/disable unicode normalization. Default: true # # The object should respond to either the validate or # transform messages or both. Both the validate and # transform methods should take two parameters: name and # value. The validate method should return true # or false; true if the value of the variable is valid, # false otherwise. An InvalidTemplateValueError # exception will be raised if the value is invalid. The transform # method should return the transformed variable value as a String. # If a transform method is used, the value will not be percent # encoded automatically. Unicode normalization will be performed both # before and after sending the value to the transform method. # # @return [Addressable::Template] The partially expanded URI template. # # @example # Addressable::Template.new( # "http://example.com/{one}/{two}/" # ).partial_expand({"one" => "1"}).pattern # #=> "http://example.com/1/{two}/" # # Addressable::Template.new( # "http://example.com/{?one,two}/" # ).partial_expand({"one" => "1"}).pattern # #=> "http://example.com/?one=1{&two}/" # # Addressable::Template.new( # "http://example.com/{?one,two,three}/" # ).partial_expand({"one" => "1", "three" => 3}).pattern # #=> "http://example.com/?one=1{&two}&three=3" def partial_expand(mapping, processor=nil, normalize_values=true) result = self.pattern.dup mapping = normalize_keys(mapping) result.gsub!( EXPRESSION ) do |capture| transform_partial_capture(mapping, capture, processor, normalize_values) end return Addressable::Template.new(result) end ## # Expands a URI template into a full URI. # # @param [Hash] mapping The mapping that corresponds to the pattern. # @param [#validate, #transform] processor # An optional processor object may be supplied. # @param [Boolean] normalize_values # Optional flag to enable/disable unicode normalization. Default: true # # The object should respond to either the validate or # transform messages or both. Both the validate and # transform methods should take two parameters: name and # value. The validate method should return true # or false; true if the value of the variable is valid, # false otherwise. An InvalidTemplateValueError # exception will be raised if the value is invalid. The transform # method should return the transformed variable value as a String. # If a transform method is used, the value will not be percent # encoded automatically. Unicode normalization will be performed both # before and after sending the value to the transform method. # # @return [Addressable::URI] The expanded URI template. # # @example # class ExampleProcessor # def self.validate(name, value) # return !!(value =~ /^[\w ]+$/) if name == "query" # return true # end # # def self.transform(name, value) # return value.gsub(/ /, "+") if name == "query" # return value # end # end # # Addressable::Template.new( # "http://example.com/search/{query}/" # ).expand( # {"query" => "an example search query"}, # ExampleProcessor # ).to_str # #=> "http://example.com/search/an+example+search+query/" # # Addressable::Template.new( # "http://example.com/search/{query}/" # ).expand( # {"query" => "an example search query"} # ).to_str # #=> "http://example.com/search/an%20example%20search%20query/" # # Addressable::Template.new( # "http://example.com/search/{query}/" # ).expand( # {"query" => "bogus!"}, # ExampleProcessor # ).to_str # #=> Addressable::Template::InvalidTemplateValueError def expand(mapping, processor=nil, normalize_values=true) result = self.pattern.dup mapping = normalize_keys(mapping) result.gsub!( EXPRESSION ) do |capture| transform_capture(mapping, capture, processor, normalize_values) end return Addressable::URI.parse(result) end ## # Returns an Array of variables used within the template pattern. # The variables are listed in the Array in the order they appear within # the pattern. Multiple occurrences of a variable within a pattern are # not represented in this Array. # # @return [Array] The variables present in the template's pattern. def variables @variables ||= ordered_variable_defaults.map { |var, val| var }.uniq end alias_method :keys, :variables alias_method :names, :variables ## # Returns a mapping of variables to their default values specified # in the template. Variables without defaults are not returned. # # @return [Hash] Mapping of template variables to their defaults def variable_defaults @variable_defaults ||= Hash[*ordered_variable_defaults.reject { |k, v| v.nil? }.flatten] end ## # Coerces a template into a `Regexp` object. This regular expression will # behave very similarly to the actual template, and should match the same # URI values, but it cannot fully handle, for example, values that would # extract to an `Array`. # # @return [Regexp] A regular expression which should match the template. def to_regexp _, source = parse_template_pattern(pattern) Regexp.new(source) end ## # Returns the source of the coerced `Regexp`. # # @return [String] The source of the `Regexp` given by {#to_regexp}. # # @api private def source self.to_regexp.source end ## # Returns the named captures of the coerced `Regexp`. # # @return [Hash] The named captures of the `Regexp` given by {#to_regexp}. # # @api private def named_captures self.to_regexp.named_captures end private def ordered_variable_defaults @ordered_variable_defaults ||= begin expansions, _ = parse_template_pattern(pattern) expansions.flat_map do |capture| _, _, varlist = *capture.match(EXPRESSION) varlist.split(',').map do |varspec| varspec[VARSPEC, 1] end end end end ## # Loops through each capture and expands any values available in mapping # # @param [Hash] mapping # Set of keys to expand # @param [String] capture # The expression to expand # @param [#validate, #transform] processor # An optional processor object may be supplied. # @param [Boolean] normalize_values # Optional flag to enable/disable unicode normalization. Default: true # # The object should respond to either the validate or # transform messages or both. Both the validate and # transform methods should take two parameters: name and # value. The validate method should return true # or false; true if the value of the variable is valid, # false otherwise. An InvalidTemplateValueError exception # will be raised if the value is invalid. The transform method # should return the transformed variable value as a String. If a # transform method is used, the value will not be percent encoded # automatically. Unicode normalization will be performed both before and # after sending the value to the transform method. # # @return [String] The expanded expression def transform_partial_capture(mapping, capture, processor = nil, normalize_values = true) _, operator, varlist = *capture.match(EXPRESSION) vars = varlist.split(",") if operator == "?" # partial expansion of form style query variables sometimes requires a # slight reordering of the variables to produce a valid url. first_to_expand = vars.find { |varspec| _, name, _ = *varspec.match(VARSPEC) mapping.key?(name) && !mapping[name].nil? } vars = [first_to_expand] + vars.reject {|varspec| varspec == first_to_expand} if first_to_expand end vars. inject("".dup) do |acc, varspec| _, name, _ = *varspec.match(VARSPEC) next_val = if mapping.key? name transform_capture(mapping, "{#{operator}#{varspec}}", processor, normalize_values) else "{#{operator}#{varspec}}" end # If we've already expanded at least one '?' operator with non-empty # value, change to '&' operator = "&" if (operator == "?") && (next_val != "") acc << next_val end end ## # Transforms a mapped value so that values can be substituted into the # template. # # @param [Hash] mapping The mapping to replace captures # @param [String] capture # The expression to replace # @param [#validate, #transform] processor # An optional processor object may be supplied. # @param [Boolean] normalize_values # Optional flag to enable/disable unicode normalization. Default: true # # # The object should respond to either the validate or # transform messages or both. Both the validate and # transform methods should take two parameters: name and # value. The validate method should return true # or false; true if the value of the variable is valid, # false otherwise. An InvalidTemplateValueError exception # will be raised if the value is invalid. The transform method # should return the transformed variable value as a String. If a # transform method is used, the value will not be percent encoded # automatically. Unicode normalization will be performed both before and # after sending the value to the transform method. # # @return [String] The expanded expression def transform_capture(mapping, capture, processor=nil, normalize_values=true) _, operator, varlist = *capture.match(EXPRESSION) return_value = varlist.split(',').inject([]) do |acc, varspec| _, name, modifier = *varspec.match(VARSPEC) value = mapping[name] unless value == nil || value == {} allow_reserved = %w(+ #).include?(operator) # Common primitives where the .to_s output is well-defined if Numeric === value || Symbol === value || value == true || value == false value = value.to_s end length = modifier.gsub(':', '').to_i if modifier =~ /^:\d+/ unless (Hash === value) || value.respond_to?(:to_ary) || value.respond_to?(:to_str) raise TypeError, "Can't convert #{value.class} into String or Array." end value = normalize_value(value) if normalize_values if processor == nil || !processor.respond_to?(:transform) # Handle percent escaping if allow_reserved encode_map = Addressable::URI::CharacterClasses::RESERVED + Addressable::URI::CharacterClasses::UNRESERVED else encode_map = Addressable::URI::CharacterClasses::UNRESERVED end if value.kind_of?(Array) transformed_value = value.map do |val| if length Addressable::URI.encode_component(val[0...length], encode_map) else Addressable::URI.encode_component(val, encode_map) end end unless modifier == "*" transformed_value = transformed_value.join(',') end elsif value.kind_of?(Hash) transformed_value = value.map do |key, val| if modifier == "*" "#{ Addressable::URI.encode_component( key, encode_map) }=#{ Addressable::URI.encode_component( val, encode_map) }" else "#{ Addressable::URI.encode_component( key, encode_map) },#{ Addressable::URI.encode_component( val, encode_map) }" end end unless modifier == "*" transformed_value = transformed_value.join(',') end else if length transformed_value = Addressable::URI.encode_component( value[0...length], encode_map) else transformed_value = Addressable::URI.encode_component( value, encode_map) end end end # Process, if we've got a processor if processor != nil if processor.respond_to?(:validate) if !processor.validate(name, value) display_value = value.kind_of?(Array) ? value.inspect : value raise InvalidTemplateValueError, "#{name}=#{display_value} is an invalid template value." end end if processor.respond_to?(:transform) transformed_value = processor.transform(name, value) if normalize_values transformed_value = normalize_value(transformed_value) end end end acc << [name, transformed_value] end acc end return "" if return_value.empty? join_values(operator, return_value) end ## # Takes a set of values, and joins them together based on the # operator. # # @param [String, Nil] operator One of the operators from the set # (?,&,+,#,;,/,.), or nil if there wasn't one. # @param [Array] return_value # The set of return values (as [variable_name, value] tuples) that will # be joined together. # # @return [String] The transformed mapped value def join_values(operator, return_value) leader = LEADERS.fetch(operator, '') joiner = JOINERS.fetch(operator, ',') case operator when '&', '?' leader + return_value.map{|k,v| if v.is_a?(Array) && v.first =~ /=/ v.join(joiner) elsif v.is_a?(Array) v.map{|inner_value| "#{k}=#{inner_value}"}.join(joiner) else "#{k}=#{v}" end }.join(joiner) when ';' return_value.map{|k,v| if v.is_a?(Array) && v.first =~ /=/ ';' + v.join(";") elsif v.is_a?(Array) ';' + v.map{|inner_value| "#{k}=#{inner_value}"}.join(";") else v && v != '' ? ";#{k}=#{v}" : ";#{k}" end }.join else leader + return_value.map{|k,v| v}.join(joiner) end end ## # Takes a set of values, and joins them together based on the # operator. # # @param [Hash, Array, String] value # Normalizes unicode keys and values with String#unicode_normalize (NFC) # # @return [Hash, Array, String] The normalized values def normalize_value(value) # Handle unicode normalization if value.respond_to?(:to_ary) value.to_ary.map! { |val| normalize_value(val) } elsif value.kind_of?(Hash) value = value.inject({}) { |acc, (k, v)| acc[normalize_value(k)] = normalize_value(v) acc } else value = value.to_s if !value.kind_of?(String) if value.encoding != Encoding::UTF_8 value = value.dup.force_encoding(Encoding::UTF_8) end value = value.unicode_normalize(:nfc) end value end ## # Generates a hash with string keys # # @param [Hash] mapping A mapping hash to normalize # # @return [Hash] # A hash with stringified keys def normalize_keys(mapping) return mapping.inject({}) do |accu, pair| name, value = pair if Symbol === name name = name.to_s elsif name.respond_to?(:to_str) name = name.to_str else raise TypeError, "Can't convert #{name.class} into String." end accu[name] = value accu end end ## # Generates the Regexp that parses a template pattern. Memoizes the # value if template processor not set (processors may not be deterministic) # # @param [String] pattern The URI template pattern. # @param [#match] processor The template processor to use. # # @return [Array, Regexp] # An array of expansion variables nad a regular expression which may be # used to parse a template pattern def parse_template_pattern(pattern, processor = nil) if processor.nil? && pattern == @pattern @cached_template_parse ||= parse_new_template_pattern(pattern, processor) else parse_new_template_pattern(pattern, processor) end end ## # Generates the Regexp that parses a template pattern. # # @param [String] pattern The URI template pattern. # @param [#match] processor The template processor to use. # # @return [Array, Regexp] # An array of expansion variables nad a regular expression which may be # used to parse a template pattern def parse_new_template_pattern(pattern, processor = nil) # Escape the pattern. The two gsubs restore the escaped curly braces # back to their original form. Basically, escape everything that isn't # within an expansion. escaped_pattern = Regexp.escape( pattern ).gsub(/\\\{(.*?)\\\}/) do |escaped| escaped.gsub(/\\(.)/, "\\1") end expansions = [] # Create a regular expression that captures the values of the # variables in the URI. regexp_string = escaped_pattern.gsub( EXPRESSION ) do |expansion| expansions << expansion _, operator, varlist = *expansion.match(EXPRESSION) leader = Regexp.escape(LEADERS.fetch(operator, '')) joiner = Regexp.escape(JOINERS.fetch(operator, ',')) combined = varlist.split(',').map do |varspec| _, name, modifier = *varspec.match(VARSPEC) result = processor && processor.respond_to?(:match) ? processor.match(name) : nil if result "(?<#{name}>#{ result })" else group = case operator when '+' "#{ RESERVED }*?" when '#' "#{ RESERVED }*?" when '/' "#{ UNRESERVED }*?" when '.' "#{ UNRESERVED.gsub('\.', '') }*?" when ';' "#{ UNRESERVED }*=?#{ UNRESERVED }*?" when '?' "#{ UNRESERVED }*=#{ UNRESERVED }*?" when '&' "#{ UNRESERVED }*=#{ UNRESERVED }*?" else "#{ UNRESERVED }*?" end if modifier == '*' "(?<#{name}>#{group}(?:#{joiner}?#{group})*)?" else "(?<#{name}>#{group})?" end end end.join("#{joiner}?") "(?:|#{leader}#{combined})" end # Ensure that the regular expression matches the whole URI. regexp_string = "\\A#{regexp_string}\\z" return expansions, Regexp.new(regexp_string) end end end addressable-2.8.7/lib/addressable/uri.rb0000644000004100000410000024630014636033505020206 0ustar www-datawww-data# frozen_string_literal: true #-- # Copyright (C) Bob Aman # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #++ require "addressable/version" require "addressable/idna" require "public_suffix" ## # Addressable is a library for processing links and URIs. module Addressable ## # This is an implementation of a URI parser based on # RFC 3986, # RFC 3987. class URI ## # Raised if something other than a uri is supplied. class InvalidURIError < StandardError end ## # Container for the character classes specified in # RFC 3986. # # Note: Concatenated and interpolated `String`s are not affected by the # `frozen_string_literal` directive and must be frozen explicitly. # # Interpolated `String`s *were* frozen this way before Ruby 3.0: # https://bugs.ruby-lang.org/issues/17104 module CharacterClasses ALPHA = "a-zA-Z" DIGIT = "0-9" GEN_DELIMS = "\\:\\/\\?\\#\\[\\]\\@" SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=" RESERVED = (GEN_DELIMS + SUB_DELIMS).freeze UNRESERVED = (ALPHA + DIGIT + "\\-\\.\\_\\~").freeze RESERVED_AND_UNRESERVED = RESERVED + UNRESERVED PCHAR = (UNRESERVED + SUB_DELIMS + "\\:\\@").freeze SCHEME = (ALPHA + DIGIT + "\\-\\+\\.").freeze HOST = (UNRESERVED + SUB_DELIMS + "\\[\\:\\]").freeze AUTHORITY = (PCHAR + "\\[\\]").freeze PATH = (PCHAR + "\\/").freeze QUERY = (PCHAR + "\\/\\?").freeze FRAGMENT = (PCHAR + "\\/\\?").freeze end module NormalizeCharacterClasses HOST = /[^#{CharacterClasses::HOST}]/ UNRESERVED = /[^#{CharacterClasses::UNRESERVED}]/ PCHAR = /[^#{CharacterClasses::PCHAR}]/ SCHEME = /[^#{CharacterClasses::SCHEME}]/ FRAGMENT = /[^#{CharacterClasses::FRAGMENT}]/ QUERY = %r{[^a-zA-Z0-9\-\.\_\~\!\$\'\(\)\*\+\,\=\:\@\/\?%]|%(?!2B|2b)} end module CharacterClassesRegexps AUTHORITY = /[^#{CharacterClasses::AUTHORITY}]/ FRAGMENT = /[^#{CharacterClasses::FRAGMENT}]/ HOST = /[^#{CharacterClasses::HOST}]/ PATH = /[^#{CharacterClasses::PATH}]/ QUERY = /[^#{CharacterClasses::QUERY}]/ RESERVED = /[^#{CharacterClasses::RESERVED}]/ RESERVED_AND_UNRESERVED = /[^#{CharacterClasses::RESERVED_AND_UNRESERVED}]/ SCHEME = /[^#{CharacterClasses::SCHEME}]/ UNRESERVED = /[^#{CharacterClasses::UNRESERVED}]/ end SLASH = '/' EMPTY_STR = '' URIREGEX = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/ PORT_MAPPING = { "http" => 80, "https" => 443, "ftp" => 21, "tftp" => 69, "sftp" => 22, "ssh" => 22, "svn+ssh" => 22, "telnet" => 23, "nntp" => 119, "gopher" => 70, "wais" => 210, "ldap" => 389, "prospero" => 1525 }.freeze ## # Returns a URI object based on the parsed string. # # @param [String, Addressable::URI, #to_str] uri # The URI string to parse. # No parsing is performed if the object is already an # Addressable::URI. # # @return [Addressable::URI] The parsed URI. def self.parse(uri) # If we were given nil, return nil. return nil unless uri # If a URI object is passed, just return itself. return uri.dup if uri.kind_of?(self) # If a URI object of the Ruby standard library variety is passed, # convert it to a string, then parse the string. # We do the check this way because we don't want to accidentally # cause a missing constant exception to be thrown. if uri.class.name =~ /^URI\b/ uri = uri.to_s end # Otherwise, convert to a String begin uri = uri.to_str rescue TypeError, NoMethodError raise TypeError, "Can't convert #{uri.class} into String." end unless uri.is_a?(String) # This Regexp supplied as an example in RFC 3986, and it works great. scan = uri.scan(URIREGEX) fragments = scan[0] scheme = fragments[1] authority = fragments[3] path = fragments[4] query = fragments[6] fragment = fragments[8] user = nil password = nil host = nil port = nil if authority != nil # The Regexp above doesn't split apart the authority. userinfo = authority[/^([^\[\]]*)@/, 1] if userinfo != nil user = userinfo.strip[/^([^:]*):?/, 1] password = userinfo.strip[/:(.*)$/, 1] end host = authority.sub( /^([^\[\]]*)@/, EMPTY_STR ).sub( /:([^:@\[\]]*?)$/, EMPTY_STR ) port = authority[/:([^:@\[\]]*?)$/, 1] port = nil if port == EMPTY_STR end return new( :scheme => scheme, :user => user, :password => password, :host => host, :port => port, :path => path, :query => query, :fragment => fragment ) end ## # Converts an input to a URI. The input does not have to be a valid # URI — the method will use heuristics to guess what URI was intended. # This is not standards-compliant, merely user-friendly. # # @param [String, Addressable::URI, #to_str] uri # The URI string to parse. # No parsing is performed if the object is already an # Addressable::URI. # @param [Hash] hints # A Hash of hints to the heuristic parser. # Defaults to {:scheme => "http"}. # # @return [Addressable::URI] The parsed URI. def self.heuristic_parse(uri, hints={}) # If we were given nil, return nil. return nil unless uri # If a URI object is passed, just return itself. return uri.dup if uri.kind_of?(self) # If a URI object of the Ruby standard library variety is passed, # convert it to a string, then parse the string. # We do the check this way because we don't want to accidentally # cause a missing constant exception to be thrown. if uri.class.name =~ /^URI\b/ uri = uri.to_s end unless uri.respond_to?(:to_str) raise TypeError, "Can't convert #{uri.class} into String." end # Otherwise, convert to a String uri = uri.to_str.dup.strip hints = { :scheme => "http" }.merge(hints) case uri when /^http:\//i uri.sub!(/^http:\/+/i, "http://") when /^https:\//i uri.sub!(/^https:\/+/i, "https://") when /^feed:\/+http:\//i uri.sub!(/^feed:\/+http:\/+/i, "feed:http://") when /^feed:\//i uri.sub!(/^feed:\/+/i, "feed://") when %r[^file:/{4}]i uri.sub!(%r[^file:/+]i, "file:////") when %r[^file://localhost/]i uri.sub!(%r[^file://localhost/+]i, "file:///") when %r[^file:/+]i uri.sub!(%r[^file:/+]i, "file:///") when /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ uri.sub!(/^/, hints[:scheme] + "://") when /\A\d+\..*:\d+\z/ uri = "#{hints[:scheme]}://#{uri}" end match = uri.match(URIREGEX) fragments = match.captures authority = fragments[3] if authority && authority.length > 0 new_authority = authority.tr("\\", "/").gsub(" ", "%20") # NOTE: We want offset 4, not 3! offset = match.offset(4) uri = uri.dup uri[offset[0]...offset[1]] = new_authority end parsed = self.parse(uri) if parsed.scheme =~ /^[^\/?#\.]+\.[^\/?#]+$/ parsed = self.parse(hints[:scheme] + "://" + uri) end if parsed.path.include?(".") if parsed.path[/\b@\b/] parsed.scheme = "mailto" unless parsed.scheme elsif new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1] parsed.defer_validation do new_path = parsed.path.sub( Regexp.new("^" + Regexp.escape(new_host)), EMPTY_STR) parsed.host = new_host parsed.path = new_path parsed.scheme = hints[:scheme] unless parsed.scheme end end end return parsed end ## # Converts a path to a file scheme URI. If the path supplied is # relative, it will be returned as a relative URI. If the path supplied # is actually a non-file URI, it will parse the URI as if it had been # parsed with Addressable::URI.parse. Handles all of the # various Microsoft-specific formats for specifying paths. # # @param [String, Addressable::URI, #to_str] path # Typically a String path to a file or directory, but # will return a sensible return value if an absolute URI is supplied # instead. # # @return [Addressable::URI] # The parsed file scheme URI or the original URI if some other URI # scheme was provided. # # @example # base = Addressable::URI.convert_path("/absolute/path/") # uri = Addressable::URI.convert_path("relative/path") # (base + uri).to_s # #=> "file:///absolute/path/relative/path" # # Addressable::URI.convert_path( # "c:\\windows\\My Documents 100%20\\foo.txt" # ).to_s # #=> "file:///c:/windows/My%20Documents%20100%20/foo.txt" # # Addressable::URI.convert_path("http://example.com/").to_s # #=> "http://example.com/" def self.convert_path(path) # If we were given nil, return nil. return nil unless path # If a URI object is passed, just return itself. return path if path.kind_of?(self) unless path.respond_to?(:to_str) raise TypeError, "Can't convert #{path.class} into String." end # Otherwise, convert to a String path = path.to_str.strip path.sub!(/^file:\/?\/?/, EMPTY_STR) if path =~ /^file:\/?\/?/ path = SLASH + path if path =~ /^([a-zA-Z])[\|:]/ uri = self.parse(path) if uri.scheme == nil # Adjust windows-style uris uri.path.sub!(/^\/?([a-zA-Z])[\|:][\\\/]/) do "/#{$1.downcase}:/" end uri.path.tr!("\\", SLASH) if File.exist?(uri.path) && File.stat(uri.path).directory? uri.path.chomp!(SLASH) uri.path = uri.path + '/' end # If the path is absolute, set the scheme and host. if uri.path.start_with?(SLASH) uri.scheme = "file" uri.host = EMPTY_STR end uri.normalize! end return uri end ## # Joins several URIs together. # # @param [String, Addressable::URI, #to_str] *uris # The URIs to join. # # @return [Addressable::URI] The joined URI. # # @example # base = "http://example.com/" # uri = Addressable::URI.parse("relative/path") # Addressable::URI.join(base, uri) # #=> # def self.join(*uris) uri_objects = uris.collect do |uri| unless uri.respond_to?(:to_str) raise TypeError, "Can't convert #{uri.class} into String." end uri.kind_of?(self) ? uri : self.parse(uri.to_str) end result = uri_objects.shift.dup uri_objects.each do |uri| result.join!(uri) end return result end ## # Tables used to optimize encoding operations in `self.encode_component` # and `self.normalize_component` SEQUENCE_ENCODING_TABLE = (0..255).map do |byte| format("%02x", byte).freeze end.freeze SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE = (0..255).map do |byte| format("%%%02X", byte).freeze end.freeze ## # Percent encodes a URI component. # # @param [String, #to_str] component The URI component to encode. # # @param [String, Regexp] character_class # The characters which are not percent encoded. If a String # is passed, the String must be formatted as a regular # expression character class. (Do not include the surrounding square # brackets.) For example, "b-zB-Z0-9" would cause # everything but the letters 'b' through 'z' and the numbers '0' through # '9' to be percent encoded. If a Regexp is passed, the # value /[^b-zB-Z0-9]/ would have the same effect. A set of # useful String values may be found in the # Addressable::URI::CharacterClasses module. The default # value is the reserved plus unreserved character classes specified in # RFC 3986. # # @param [Regexp] upcase_encoded # A string of characters that may already be percent encoded, and whose # encodings should be upcased. This allows normalization of percent # encodings for characters not included in the # character_class. # # @return [String] The encoded component. # # @example # Addressable::URI.encode_component("simple/example", "b-zB-Z0-9") # => "simple%2Fex%61mple" # Addressable::URI.encode_component("simple/example", /[^b-zB-Z0-9]/) # => "simple%2Fex%61mple" # Addressable::URI.encode_component( # "simple/example", Addressable::URI::CharacterClasses::UNRESERVED # ) # => "simple%2Fexample" def self.encode_component(component, character_class=CharacterClassesRegexps::RESERVED_AND_UNRESERVED, upcase_encoded='') return nil if component.nil? begin if component.kind_of?(Symbol) || component.kind_of?(Numeric) || component.kind_of?(TrueClass) || component.kind_of?(FalseClass) component = component.to_s else component = component.to_str end rescue TypeError, NoMethodError raise TypeError, "Can't convert #{component.class} into String." end if !component.is_a? String if ![String, Regexp].include?(character_class.class) raise TypeError, "Expected String or Regexp, got #{character_class.inspect}" end if character_class.kind_of?(String) character_class = /[^#{character_class}]/ end # We can't perform regexps on invalid UTF sequences, but # here we need to, so switch to ASCII. component = component.dup component.force_encoding(Encoding::ASCII_8BIT) # Avoiding gsub! because there are edge cases with frozen strings component = component.gsub(character_class) do |char| SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE[char.ord] end if upcase_encoded.length > 0 upcase_encoded_chars = upcase_encoded.bytes.map do |byte| SEQUENCE_ENCODING_TABLE[byte] end component = component.gsub(/%(#{upcase_encoded_chars.join('|')})/, &:upcase) end return component end class << self alias_method :escape_component, :encode_component end ## # Unencodes any percent encoded characters within a URI component. # This method may be used for unencoding either components or full URIs, # however, it is recommended to use the unencode_component # alias when unencoding components. # # @param [String, Addressable::URI, #to_str] uri # The URI or component to unencode. # # @param [Class] return_type # The type of object to return. # This value may only be set to String or # Addressable::URI. All other values are invalid. Defaults # to String. # # @param [String] leave_encoded # A string of characters to leave encoded. If a percent encoded character # in this list is encountered then it will remain percent encoded. # # @return [String, Addressable::URI] # The unencoded component or URI. # The return type is determined by the return_type # parameter. def self.unencode(uri, return_type=String, leave_encoded='') return nil if uri.nil? begin uri = uri.to_str rescue NoMethodError, TypeError raise TypeError, "Can't convert #{uri.class} into String." end if !uri.is_a? String if ![String, ::Addressable::URI].include?(return_type) raise TypeError, "Expected Class (String or Addressable::URI), " + "got #{return_type.inspect}" end result = uri.gsub(/%[0-9a-f]{2}/i) do |sequence| c = sequence[1..3].to_i(16).chr c.force_encoding(sequence.encoding) leave_encoded.include?(c) ? sequence : c end result.force_encoding(Encoding::UTF_8) if return_type == String return result elsif return_type == ::Addressable::URI return ::Addressable::URI.parse(result) end end class << self alias_method :unescape, :unencode alias_method :unencode_component, :unencode alias_method :unescape_component, :unencode end ## # Normalizes the encoding of a URI component. # # @param [String, #to_str] component The URI component to encode. # # @param [String, Regexp] character_class # The characters which are not percent encoded. If a String # is passed, the String must be formatted as a regular # expression character class. (Do not include the surrounding square # brackets.) For example, "b-zB-Z0-9" would cause # everything but the letters 'b' through 'z' and the numbers '0' # through '9' to be percent encoded. If a Regexp is passed, # the value /[^b-zB-Z0-9]/ would have the same effect. A # set of useful String values may be found in the # Addressable::URI::CharacterClasses module. The default # value is the reserved plus unreserved character classes specified in # RFC 3986. # # @param [String] leave_encoded # When character_class is a String then # leave_encoded is a string of characters that should remain # percent encoded while normalizing the component; if they appear percent # encoded in the original component, then they will be upcased ("%2f" # normalized to "%2F") but otherwise left alone. # # @return [String] The normalized component. # # @example # Addressable::URI.normalize_component("simpl%65/%65xampl%65", "b-zB-Z") # => "simple%2Fex%61mple" # Addressable::URI.normalize_component( # "simpl%65/%65xampl%65", /[^b-zB-Z]/ # ) # => "simple%2Fex%61mple" # Addressable::URI.normalize_component( # "simpl%65/%65xampl%65", # Addressable::URI::CharacterClasses::UNRESERVED # ) # => "simple%2Fexample" # Addressable::URI.normalize_component( # "one%20two%2fthree%26four", # "0-9a-zA-Z &/", # "/" # ) # => "one two%2Fthree&four" def self.normalize_component(component, character_class= CharacterClassesRegexps::RESERVED_AND_UNRESERVED, leave_encoded='') return nil if component.nil? begin component = component.to_str rescue NoMethodError, TypeError raise TypeError, "Can't convert #{component.class} into String." end if !component.is_a? String if ![String, Regexp].include?(character_class.class) raise TypeError, "Expected String or Regexp, got #{character_class.inspect}" end if character_class.kind_of?(String) leave_re = if leave_encoded.length > 0 character_class = "#{character_class}%" unless character_class.include?('%') bytes = leave_encoded.bytes leave_encoded_pattern = bytes.map { |b| SEQUENCE_ENCODING_TABLE[b] }.join('|') "|%(?!#{leave_encoded_pattern}|#{leave_encoded_pattern.upcase})" end character_class = if leave_re /[^#{character_class}]#{leave_re}/ else /[^#{character_class}]/ end end # We can't perform regexps on invalid UTF sequences, but # here we need to, so switch to ASCII. component = component.dup component.force_encoding(Encoding::ASCII_8BIT) unencoded = self.unencode_component(component, String, leave_encoded) begin encoded = self.encode_component( unencoded.unicode_normalize(:nfc), character_class, leave_encoded ) rescue ArgumentError encoded = self.encode_component(unencoded) end encoded.force_encoding(Encoding::UTF_8) return encoded end ## # Percent encodes any special characters in the URI. # # @param [String, Addressable::URI, #to_str] uri # The URI to encode. # # @param [Class] return_type # The type of object to return. # This value may only be set to String or # Addressable::URI. All other values are invalid. Defaults # to String. # # @return [String, Addressable::URI] # The encoded URI. # The return type is determined by the return_type # parameter. def self.encode(uri, return_type=String) return nil if uri.nil? begin uri = uri.to_str rescue NoMethodError, TypeError raise TypeError, "Can't convert #{uri.class} into String." end if !uri.is_a? String if ![String, ::Addressable::URI].include?(return_type) raise TypeError, "Expected Class (String or Addressable::URI), " + "got #{return_type.inspect}" end uri_object = uri.kind_of?(self) ? uri : self.parse(uri) encoded_uri = Addressable::URI.new( :scheme => self.encode_component(uri_object.scheme, Addressable::URI::CharacterClassesRegexps::SCHEME), :authority => self.encode_component(uri_object.authority, Addressable::URI::CharacterClassesRegexps::AUTHORITY), :path => self.encode_component(uri_object.path, Addressable::URI::CharacterClassesRegexps::PATH), :query => self.encode_component(uri_object.query, Addressable::URI::CharacterClassesRegexps::QUERY), :fragment => self.encode_component(uri_object.fragment, Addressable::URI::CharacterClassesRegexps::FRAGMENT) ) if return_type == String return encoded_uri.to_s elsif return_type == ::Addressable::URI return encoded_uri end end class << self alias_method :escape, :encode end ## # Normalizes the encoding of a URI. Characters within a hostname are # not percent encoded to allow for internationalized domain names. # # @param [String, Addressable::URI, #to_str] uri # The URI to encode. # # @param [Class] return_type # The type of object to return. # This value may only be set to String or # Addressable::URI. All other values are invalid. Defaults # to String. # # @return [String, Addressable::URI] # The encoded URI. # The return type is determined by the return_type # parameter. def self.normalized_encode(uri, return_type=String) begin uri = uri.to_str rescue NoMethodError, TypeError raise TypeError, "Can't convert #{uri.class} into String." end if !uri.is_a? String if ![String, ::Addressable::URI].include?(return_type) raise TypeError, "Expected Class (String or Addressable::URI), " + "got #{return_type.inspect}" end uri_object = uri.kind_of?(self) ? uri : self.parse(uri) components = { :scheme => self.unencode_component(uri_object.scheme), :user => self.unencode_component(uri_object.user), :password => self.unencode_component(uri_object.password), :host => self.unencode_component(uri_object.host), :port => (uri_object.port.nil? ? nil : uri_object.port.to_s), :path => self.unencode_component(uri_object.path), :query => self.unencode_component(uri_object.query), :fragment => self.unencode_component(uri_object.fragment) } components.each do |key, value| if value != nil begin components[key] = value.to_str.unicode_normalize(:nfc) rescue ArgumentError # Likely a malformed UTF-8 character, skip unicode normalization components[key] = value.to_str end end end encoded_uri = Addressable::URI.new( :scheme => self.encode_component(components[:scheme], Addressable::URI::CharacterClassesRegexps::SCHEME), :user => self.encode_component(components[:user], Addressable::URI::CharacterClassesRegexps::UNRESERVED), :password => self.encode_component(components[:password], Addressable::URI::CharacterClassesRegexps::UNRESERVED), :host => components[:host], :port => components[:port], :path => self.encode_component(components[:path], Addressable::URI::CharacterClassesRegexps::PATH), :query => self.encode_component(components[:query], Addressable::URI::CharacterClassesRegexps::QUERY), :fragment => self.encode_component(components[:fragment], Addressable::URI::CharacterClassesRegexps::FRAGMENT) ) if return_type == String return encoded_uri.to_s elsif return_type == ::Addressable::URI return encoded_uri end end ## # Encodes a set of key/value pairs according to the rules for the # application/x-www-form-urlencoded MIME type. # # @param [#to_hash, #to_ary] form_values # The form values to encode. # # @param [TrueClass, FalseClass] sort # Sort the key/value pairs prior to encoding. # Defaults to false. # # @return [String] # The encoded value. def self.form_encode(form_values, sort=false) if form_values.respond_to?(:to_hash) form_values = form_values.to_hash.to_a elsif form_values.respond_to?(:to_ary) form_values = form_values.to_ary else raise TypeError, "Can't convert #{form_values.class} into Array." end form_values = form_values.inject([]) do |accu, (key, value)| if value.kind_of?(Array) value.each do |v| accu << [key.to_s, v.to_s] end else accu << [key.to_s, value.to_s] end accu end if sort # Useful for OAuth and optimizing caching systems form_values = form_values.sort end escaped_form_values = form_values.map do |(key, value)| # Line breaks are CRLF pairs [ self.encode_component( key.gsub(/(\r\n|\n|\r)/, "\r\n"), CharacterClassesRegexps::UNRESERVED ).gsub("%20", "+"), self.encode_component( value.gsub(/(\r\n|\n|\r)/, "\r\n"), CharacterClassesRegexps::UNRESERVED ).gsub("%20", "+") ] end return escaped_form_values.map do |(key, value)| "#{key}=#{value}" end.join("&") end ## # Decodes a String according to the rules for the # application/x-www-form-urlencoded MIME type. # # @param [String, #to_str] encoded_value # The form values to decode. # # @return [Array] # The decoded values. # This is not a Hash because of the possibility for # duplicate keys. def self.form_unencode(encoded_value) if !encoded_value.respond_to?(:to_str) raise TypeError, "Can't convert #{encoded_value.class} into String." end encoded_value = encoded_value.to_str split_values = encoded_value.split("&").map do |pair| pair.split("=", 2) end return split_values.map do |(key, value)| [ key ? self.unencode_component( key.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n") : nil, value ? (self.unencode_component( value.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n")) : nil ] end end ## # Creates a new uri object from component parts. # # @option [String, #to_str] scheme The scheme component. # @option [String, #to_str] user The user component. # @option [String, #to_str] password The password component. # @option [String, #to_str] userinfo # The userinfo component. If this is supplied, the user and password # components must be omitted. # @option [String, #to_str] host The host component. # @option [String, #to_str] port The port component. # @option [String, #to_str] authority # The authority component. If this is supplied, the user, password, # userinfo, host, and port components must be omitted. # @option [String, #to_str] path The path component. # @option [String, #to_str] query The query component. # @option [String, #to_str] fragment The fragment component. # # @return [Addressable::URI] The constructed URI object. def initialize(options={}) if options.has_key?(:authority) if (options.keys & [:userinfo, :user, :password, :host, :port]).any? raise ArgumentError, "Cannot specify both an authority and any of the components " + "within the authority." end end if options.has_key?(:userinfo) if (options.keys & [:user, :password]).any? raise ArgumentError, "Cannot specify both a userinfo and either the user or password." end end reset_ivs defer_validation do # Bunch of crazy logic required because of the composite components # like userinfo and authority. self.scheme = options[:scheme] if options[:scheme] self.user = options[:user] if options[:user] self.password = options[:password] if options[:password] self.userinfo = options[:userinfo] if options[:userinfo] self.host = options[:host] if options[:host] self.port = options[:port] if options[:port] self.authority = options[:authority] if options[:authority] self.path = options[:path] if options[:path] self.query = options[:query] if options[:query] self.query_values = options[:query_values] if options[:query_values] self.fragment = options[:fragment] if options[:fragment] end to_s # force path validation end ## # Freeze URI, initializing instance variables. # # @return [Addressable::URI] The frozen URI object. def freeze self.normalized_scheme self.normalized_user self.normalized_password self.normalized_userinfo self.normalized_host self.normalized_port self.normalized_authority self.normalized_site self.normalized_path self.normalized_query self.normalized_fragment self.hash super end ## # The scheme component for this URI. # # @return [String] The scheme component. attr_reader :scheme ## # The scheme component for this URI, normalized. # # @return [String] The scheme component, normalized. def normalized_scheme return nil unless self.scheme if @normalized_scheme == NONE @normalized_scheme = if self.scheme =~ /^\s*ssh\+svn\s*$/i "svn+ssh".dup else Addressable::URI.normalize_component( self.scheme.strip.downcase, Addressable::URI::NormalizeCharacterClasses::SCHEME ) end end # All normalized values should be UTF-8 force_utf8_encoding_if_needed(@normalized_scheme) @normalized_scheme end ## # Sets the scheme component for this URI. # # @param [String, #to_str] new_scheme The new scheme component. def scheme=(new_scheme) if new_scheme && !new_scheme.respond_to?(:to_str) raise TypeError, "Can't convert #{new_scheme.class} into String." elsif new_scheme new_scheme = new_scheme.to_str end if new_scheme && new_scheme !~ /\A[a-z][a-z0-9\.\+\-]*\z/i raise InvalidURIError, "Invalid scheme format: '#{new_scheme}'" end @scheme = new_scheme @scheme = nil if @scheme.to_s.strip.empty? # Reset dependent values @normalized_scheme = NONE remove_composite_values # Ensure we haven't created an invalid URI validate() end ## # The user component for this URI. # # @return [String] The user component. attr_reader :user ## # The user component for this URI, normalized. # # @return [String] The user component, normalized. def normalized_user return nil unless self.user return @normalized_user unless @normalized_user == NONE @normalized_user = begin if normalized_scheme =~ /https?/ && self.user.strip.empty? && (!self.password || self.password.strip.empty?) nil else Addressable::URI.normalize_component( self.user.strip, Addressable::URI::NormalizeCharacterClasses::UNRESERVED ) end end # All normalized values should be UTF-8 force_utf8_encoding_if_needed(@normalized_user) @normalized_user end ## # Sets the user component for this URI. # # @param [String, #to_str] new_user The new user component. def user=(new_user) if new_user && !new_user.respond_to?(:to_str) raise TypeError, "Can't convert #{new_user.class} into String." end @user = new_user ? new_user.to_str : nil # You can't have a nil user with a non-nil password if password != nil @user = EMPTY_STR unless user end # Reset dependent values @userinfo = nil @normalized_userinfo = NONE @authority = nil @normalized_user = NONE remove_composite_values # Ensure we haven't created an invalid URI validate() end ## # The password component for this URI. # # @return [String] The password component. attr_reader :password ## # The password component for this URI, normalized. # # @return [String] The password component, normalized. def normalized_password return nil unless self.password return @normalized_password unless @normalized_password == NONE @normalized_password = begin if self.normalized_scheme =~ /https?/ && self.password.strip.empty? && (!self.user || self.user.strip.empty?) nil else Addressable::URI.normalize_component( self.password.strip, Addressable::URI::NormalizeCharacterClasses::UNRESERVED ) end end # All normalized values should be UTF-8 force_utf8_encoding_if_needed(@normalized_password) @normalized_password end ## # Sets the password component for this URI. # # @param [String, #to_str] new_password The new password component. def password=(new_password) if new_password && !new_password.respond_to?(:to_str) raise TypeError, "Can't convert #{new_password.class} into String." end @password = new_password ? new_password.to_str : nil # You can't have a nil user with a non-nil password if @password != nil self.user = EMPTY_STR if user.nil? end # Reset dependent values @userinfo = nil @normalized_userinfo = NONE @authority = nil @normalized_password = NONE remove_composite_values # Ensure we haven't created an invalid URI validate() end ## # The userinfo component for this URI. # Combines the user and password components. # # @return [String] The userinfo component. def userinfo current_user = self.user current_password = self.password (current_user || current_password) && @userinfo ||= begin if current_user && current_password "#{current_user}:#{current_password}" elsif current_user && !current_password "#{current_user}" end end end ## # The userinfo component for this URI, normalized. # # @return [String] The userinfo component, normalized. def normalized_userinfo return nil unless self.userinfo return @normalized_userinfo unless @normalized_userinfo == NONE @normalized_userinfo = begin current_user = self.normalized_user current_password = self.normalized_password if !current_user && !current_password nil elsif current_user && current_password "#{current_user}:#{current_password}".dup elsif current_user && !current_password "#{current_user}".dup end end # All normalized values should be UTF-8 force_utf8_encoding_if_needed(@normalized_userinfo) @normalized_userinfo end ## # Sets the userinfo component for this URI. # # @param [String, #to_str] new_userinfo The new userinfo component. def userinfo=(new_userinfo) if new_userinfo && !new_userinfo.respond_to?(:to_str) raise TypeError, "Can't convert #{new_userinfo.class} into String." end new_user, new_password = if new_userinfo [ new_userinfo.to_str.strip[/^(.*):/, 1], new_userinfo.to_str.strip[/:(.*)$/, 1] ] else [nil, nil] end # Password assigned first to ensure validity in case of nil self.password = new_password self.user = new_user # Reset dependent values @authority = nil remove_composite_values # Ensure we haven't created an invalid URI validate() end ## # The host component for this URI. # # @return [String] The host component. attr_reader :host ## # The host component for this URI, normalized. # # @return [String] The host component, normalized. def normalized_host return nil unless self.host @normalized_host ||= begin if !self.host.strip.empty? result = ::Addressable::IDNA.to_ascii( URI.unencode_component(self.host.strip.downcase) ) if result =~ /[^\.]\.$/ # Single trailing dots are unnecessary. result = result[0...-1] end result = Addressable::URI.normalize_component( result, NormalizeCharacterClasses::HOST ) result else EMPTY_STR.dup end end # All normalized values should be UTF-8 force_utf8_encoding_if_needed(@normalized_host) @normalized_host end ## # Sets the host component for this URI. # # @param [String, #to_str] new_host The new host component. def host=(new_host) if new_host && !new_host.respond_to?(:to_str) raise TypeError, "Can't convert #{new_host.class} into String." end @host = new_host ? new_host.to_str : nil # Reset dependent values @authority = nil @normalized_host = nil remove_composite_values # Ensure we haven't created an invalid URI validate() end ## # This method is same as URI::Generic#host except # brackets for IPv6 (and 'IPvFuture') addresses are removed. # # @see Addressable::URI#host # # @return [String] The hostname for this URI. def hostname v = self.host /\A\[(.*)\]\z/ =~ v ? $1 : v end ## # This method is same as URI::Generic#host= except # the argument can be a bare IPv6 address (or 'IPvFuture'). # # @see Addressable::URI#host= # # @param [String, #to_str] new_hostname The new hostname for this URI. def hostname=(new_hostname) if new_hostname && (new_hostname.respond_to?(:ipv4?) || new_hostname.respond_to?(:ipv6?)) new_hostname = new_hostname.to_s elsif new_hostname && !new_hostname.respond_to?(:to_str) raise TypeError, "Can't convert #{new_hostname.class} into String." end v = new_hostname ? new_hostname.to_str : nil v = "[#{v}]" if /\A\[.*\]\z/ !~ v && /:/ =~ v self.host = v end ## # Returns the top-level domain for this host. # # @example # Addressable::URI.parse("http://www.example.co.uk").tld # => "co.uk" def tld PublicSuffix.parse(self.host, ignore_private: true).tld end ## # Sets the top-level domain for this URI. # # @param [String, #to_str] new_tld The new top-level domain. def tld=(new_tld) replaced_tld = host.sub(/#{tld}\z/, new_tld) self.host = PublicSuffix::Domain.new(replaced_tld).to_s end ## # Returns the public suffix domain for this host. # # @example # Addressable::URI.parse("http://www.example.co.uk").domain # => "example.co.uk" def domain PublicSuffix.domain(self.host, ignore_private: true) end ## # The authority component for this URI. # Combines the user, password, host, and port components. # # @return [String] The authority component. def authority self.host && @authority ||= begin authority = String.new if self.userinfo != nil authority << "#{self.userinfo}@" end authority << self.host if self.port != nil authority << ":#{self.port}" end authority end end ## # The authority component for this URI, normalized. # # @return [String] The authority component, normalized. def normalized_authority return nil unless self.authority @normalized_authority ||= begin authority = String.new if self.normalized_userinfo != nil authority << "#{self.normalized_userinfo}@" end authority << self.normalized_host if self.normalized_port != nil authority << ":#{self.normalized_port}" end authority end # All normalized values should be UTF-8 force_utf8_encoding_if_needed(@normalized_authority) @normalized_authority end ## # Sets the authority component for this URI. # # @param [String, #to_str] new_authority The new authority component. def authority=(new_authority) if new_authority if !new_authority.respond_to?(:to_str) raise TypeError, "Can't convert #{new_authority.class} into String." end new_authority = new_authority.to_str new_userinfo = new_authority[/^([^\[\]]*)@/, 1] if new_userinfo new_user = new_userinfo.strip[/^([^:]*):?/, 1] new_password = new_userinfo.strip[/:(.*)$/, 1] end new_host = new_authority.sub( /^([^\[\]]*)@/, EMPTY_STR ).sub( /:([^:@\[\]]*?)$/, EMPTY_STR ) new_port = new_authority[/:([^:@\[\]]*?)$/, 1] end # Password assigned first to ensure validity in case of nil self.password = new_password self.user = new_user self.host = new_host self.port = new_port # Reset dependent values @userinfo = nil @normalized_userinfo = NONE remove_composite_values # Ensure we haven't created an invalid URI validate() end ## # The origin for this URI, serialized to ASCII, as per # RFC 6454, section 6.2. # # @return [String] The serialized origin. def origin if self.scheme && self.authority if self.normalized_port "#{self.normalized_scheme}://#{self.normalized_host}" + ":#{self.normalized_port}" else "#{self.normalized_scheme}://#{self.normalized_host}" end else "null" end end ## # Sets the origin for this URI, serialized to ASCII, as per # RFC 6454, section 6.2. This assignment will reset the `userinfo` # component. # # @param [String, #to_str] new_origin The new origin component. def origin=(new_origin) if new_origin if !new_origin.respond_to?(:to_str) raise TypeError, "Can't convert #{new_origin.class} into String." end new_origin = new_origin.to_str new_scheme = new_origin[/^([^:\/?#]+):\/\//, 1] unless new_scheme raise InvalidURIError, 'An origin cannot omit the scheme.' end new_host = new_origin[/:\/\/([^\/?#:]+)/, 1] unless new_host raise InvalidURIError, 'An origin cannot omit the host.' end new_port = new_origin[/:([^:@\[\]\/]*?)$/, 1] end self.scheme = new_scheme self.host = new_host self.port = new_port self.userinfo = nil # Reset dependent values @userinfo = nil @normalized_userinfo = NONE @authority = nil @normalized_authority = nil remove_composite_values # Ensure we haven't created an invalid URI validate() end # Returns an array of known ip-based schemes. These schemes typically # use a similar URI form: # //:@:/ def self.ip_based_schemes return self.port_mapping.keys end # Returns a hash of common IP-based schemes and their default port # numbers. Adding new schemes to this hash, as necessary, will allow # for better URI normalization. def self.port_mapping PORT_MAPPING end ## # The port component for this URI. # This is the port number actually given in the URI. This does not # infer port numbers from default values. # # @return [Integer] The port component. attr_reader :port ## # The port component for this URI, normalized. # # @return [Integer] The port component, normalized. def normalized_port return nil unless self.port return @normalized_port unless @normalized_port == NONE @normalized_port = begin if URI.port_mapping[self.normalized_scheme] == self.port nil else self.port end end end ## # Sets the port component for this URI. # # @param [String, Integer, #to_s] new_port The new port component. def port=(new_port) if new_port != nil && new_port.respond_to?(:to_str) new_port = Addressable::URI.unencode_component(new_port.to_str) end if new_port.respond_to?(:valid_encoding?) && !new_port.valid_encoding? raise InvalidURIError, "Invalid encoding in port" end if new_port != nil && !(new_port.to_s =~ /^\d+$/) raise InvalidURIError, "Invalid port number: #{new_port.inspect}" end @port = new_port.to_s.to_i @port = nil if @port == 0 # Reset dependent values @authority = nil @normalized_port = NONE remove_composite_values # Ensure we haven't created an invalid URI validate() end ## # The inferred port component for this URI. # This method will normalize to the default port for the URI's scheme if # the port isn't explicitly specified in the URI. # # @return [Integer] The inferred port component. def inferred_port if self.port.to_i == 0 self.default_port else self.port.to_i end end ## # The default port for this URI's scheme. # This method will always returns the default port for the URI's scheme # regardless of the presence of an explicit port in the URI. # # @return [Integer] The default port. def default_port URI.port_mapping[self.scheme.strip.downcase] if self.scheme end ## # The combination of components that represent a site. # Combines the scheme, user, password, host, and port components. # Primarily useful for HTTP and HTTPS. # # For example, "http://example.com/path?query" would have a # site value of "http://example.com". # # @return [String] The components that identify a site. def site (self.scheme || self.authority) && @site ||= begin site_string = "".dup site_string << "#{self.scheme}:" if self.scheme != nil site_string << "//#{self.authority}" if self.authority != nil site_string end end ## # The normalized combination of components that represent a site. # Combines the scheme, user, password, host, and port components. # Primarily useful for HTTP and HTTPS. # # For example, "http://example.com/path?query" would have a # site value of "http://example.com". # # @return [String] The normalized components that identify a site. def normalized_site return nil unless self.site @normalized_site ||= begin site_string = "".dup if self.normalized_scheme != nil site_string << "#{self.normalized_scheme}:" end if self.normalized_authority != nil site_string << "//#{self.normalized_authority}" end site_string end # All normalized values should be UTF-8 force_utf8_encoding_if_needed(@normalized_site) @normalized_site end ## # Sets the site value for this URI. # # @param [String, #to_str] new_site The new site value. def site=(new_site) if new_site if !new_site.respond_to?(:to_str) raise TypeError, "Can't convert #{new_site.class} into String." end new_site = new_site.to_str # These two regular expressions derived from the primary parsing # expression self.scheme = new_site[/^(?:([^:\/?#]+):)?(?:\/\/(?:[^\/?#]*))?$/, 1] self.authority = new_site[ /^(?:(?:[^:\/?#]+):)?(?:\/\/([^\/?#]*))?$/, 1 ] else self.scheme = nil self.authority = nil end end ## # The path component for this URI. # # @return [String] The path component. attr_reader :path NORMPATH = /^(?!\/)[^\/:]*:.*$/ ## # The path component for this URI, normalized. # # @return [String] The path component, normalized. def normalized_path @normalized_path ||= begin path = self.path.to_s if self.scheme == nil && path =~ NORMPATH # Relative paths with colons in the first segment are ambiguous. path = path.sub(":", "%2F") end # String#split(delimiter, -1) uses the more strict splitting behavior # found by default in Python. result = path.strip.split(SLASH, -1).map do |segment| Addressable::URI.normalize_component( segment, Addressable::URI::NormalizeCharacterClasses::PCHAR ) end.join(SLASH) result = URI.normalize_path(result) if result.empty? && ["http", "https", "ftp", "tftp"].include?(self.normalized_scheme) result = SLASH.dup end result end # All normalized values should be UTF-8 force_utf8_encoding_if_needed(@normalized_path) @normalized_path end ## # Sets the path component for this URI. # # @param [String, #to_str] new_path The new path component. def path=(new_path) if new_path && !new_path.respond_to?(:to_str) raise TypeError, "Can't convert #{new_path.class} into String." end @path = (new_path || EMPTY_STR).to_str if !@path.empty? && @path[0..0] != SLASH && host != nil @path = "/#{@path}" end # Reset dependent values @normalized_path = nil remove_composite_values # Ensure we haven't created an invalid URI validate() end ## # The basename, if any, of the file in the path component. # # @return [String] The path's basename. def basename # Path cannot be nil return File.basename(self.path).sub(/;[^\/]*$/, EMPTY_STR) end ## # The extname, if any, of the file in the path component. # Empty string if there is no extension. # # @return [String] The path's extname. def extname return nil unless self.path return File.extname(self.basename) end ## # The query component for this URI. # # @return [String] The query component. attr_reader :query ## # The query component for this URI, normalized. # # @return [String] The query component, normalized. def normalized_query(*flags) return nil unless self.query return @normalized_query unless @normalized_query == NONE @normalized_query = begin modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup # Make sure possible key-value pair delimiters are escaped. modified_query_class.sub!("\\&", "").sub!("\\;", "") pairs = (query || "").split("&", -1) pairs.delete_if(&:empty?).uniq! if flags.include?(:compacted) pairs.sort! if flags.include?(:sorted) component = pairs.map do |pair| Addressable::URI.normalize_component( pair, Addressable::URI::NormalizeCharacterClasses::QUERY, "+" ) end.join("&") component == "" ? nil : component end # All normalized values should be UTF-8 force_utf8_encoding_if_needed(@normalized_query) @normalized_query end ## # Sets the query component for this URI. # # @param [String, #to_str] new_query The new query component. def query=(new_query) if new_query && !new_query.respond_to?(:to_str) raise TypeError, "Can't convert #{new_query.class} into String." end @query = new_query ? new_query.to_str : nil # Reset dependent values @normalized_query = NONE remove_composite_values end ## # Converts the query component to a Hash value. # # @param [Class] return_type The return type desired. Value must be either # `Hash` or `Array`. # # @return [Hash, Array, nil] The query string parsed as a Hash or Array # or nil if the query string is blank. # # @example # Addressable::URI.parse("?one=1&two=2&three=3").query_values # #=> {"one" => "1", "two" => "2", "three" => "3"} # Addressable::URI.parse("?one=two&one=three").query_values(Array) # #=> [["one", "two"], ["one", "three"]] # Addressable::URI.parse("?one=two&one=three").query_values(Hash) # #=> {"one" => "three"} # Addressable::URI.parse("?").query_values # #=> {} # Addressable::URI.parse("").query_values # #=> nil def query_values(return_type=Hash) empty_accumulator = Array == return_type ? [] : {} if return_type != Hash && return_type != Array raise ArgumentError, "Invalid return type. Must be Hash or Array." end return nil if self.query == nil split_query = self.query.split("&").map do |pair| pair.split("=", 2) if pair && !pair.empty? end.compact return split_query.inject(empty_accumulator.dup) do |accu, pair| # I'd rather use key/value identifiers instead of array lookups, # but in this case I really want to maintain the exact pair structure, # so it's best to make all changes in-place. pair[0] = URI.unencode_component(pair[0]) if pair[1].respond_to?(:to_str) value = pair[1].to_str # I loathe the fact that I have to do this. Stupid HTML 4.01. # Treating '+' as a space was just an unbelievably bad idea. # There was nothing wrong with '%20'! # If it ain't broke, don't fix it! value = value.tr("+", " ") if ["http", "https", nil].include?(scheme) pair[1] = URI.unencode_component(value) end if return_type == Hash accu[pair[0]] = pair[1] else accu << pair end accu end end ## # Sets the query component for this URI from a Hash object. # An empty Hash or Array will result in an empty query string. # # @param [Hash, #to_hash, Array] new_query_values The new query values. # # @example # uri.query_values = {:a => "a", :b => ["c", "d", "e"]} # uri.query # # => "a=a&b=c&b=d&b=e" # uri.query_values = [['a', 'a'], ['b', 'c'], ['b', 'd'], ['b', 'e']] # uri.query # # => "a=a&b=c&b=d&b=e" # uri.query_values = [['a', 'a'], ['b', ['c', 'd', 'e']]] # uri.query # # => "a=a&b=c&b=d&b=e" # uri.query_values = [['flag'], ['key', 'value']] # uri.query # # => "flag&key=value" def query_values=(new_query_values) if new_query_values == nil self.query = nil return nil end if !new_query_values.is_a?(Array) if !new_query_values.respond_to?(:to_hash) raise TypeError, "Can't convert #{new_query_values.class} into Hash." end new_query_values = new_query_values.to_hash new_query_values = new_query_values.map do |key, value| key = key.to_s if key.kind_of?(Symbol) [key, value] end # Useful default for OAuth and caching. # Only to be used for non-Array inputs. Arrays should preserve order. new_query_values.sort! end # new_query_values have form [['key1', 'value1'], ['key2', 'value2']] buffer = "".dup new_query_values.each do |key, value| encoded_key = URI.encode_component( key, CharacterClassesRegexps::UNRESERVED ) if value == nil buffer << "#{encoded_key}&" elsif value.kind_of?(Array) value.each do |sub_value| encoded_value = URI.encode_component( sub_value, CharacterClassesRegexps::UNRESERVED ) buffer << "#{encoded_key}=#{encoded_value}&" end else encoded_value = URI.encode_component( value, CharacterClassesRegexps::UNRESERVED ) buffer << "#{encoded_key}=#{encoded_value}&" end end self.query = buffer.chop end ## # The HTTP request URI for this URI. This is the path and the # query string. # # @return [String] The request URI required for an HTTP request. def request_uri return nil if self.absolute? && self.scheme !~ /^https?$/i return ( (!self.path.empty? ? self.path : SLASH) + (self.query ? "?#{self.query}" : EMPTY_STR) ) end ## # Sets the HTTP request URI for this URI. # # @param [String, #to_str] new_request_uri The new HTTP request URI. def request_uri=(new_request_uri) if !new_request_uri.respond_to?(:to_str) raise TypeError, "Can't convert #{new_request_uri.class} into String." end if self.absolute? && self.scheme !~ /^https?$/i raise InvalidURIError, "Cannot set an HTTP request URI for a non-HTTP URI." end new_request_uri = new_request_uri.to_str path_component = new_request_uri[/^([^\?]*)\??(?:.*)$/, 1] query_component = new_request_uri[/^(?:[^\?]*)\?(.*)$/, 1] path_component = path_component.to_s path_component = (!path_component.empty? ? path_component : SLASH) self.path = path_component self.query = query_component # Reset dependent values remove_composite_values end ## # The fragment component for this URI. # # @return [String] The fragment component. attr_reader :fragment ## # The fragment component for this URI, normalized. # # @return [String] The fragment component, normalized. def normalized_fragment return nil unless self.fragment return @normalized_fragment unless @normalized_fragment == NONE @normalized_fragment = begin component = Addressable::URI.normalize_component( self.fragment, Addressable::URI::NormalizeCharacterClasses::FRAGMENT ) component == "" ? nil : component end # All normalized values should be UTF-8 force_utf8_encoding_if_needed(@normalized_fragment) @normalized_fragment end ## # Sets the fragment component for this URI. # # @param [String, #to_str] new_fragment The new fragment component. def fragment=(new_fragment) if new_fragment && !new_fragment.respond_to?(:to_str) raise TypeError, "Can't convert #{new_fragment.class} into String." end @fragment = new_fragment ? new_fragment.to_str : nil # Reset dependent values @normalized_fragment = NONE remove_composite_values # Ensure we haven't created an invalid URI validate() end ## # Determines if the scheme indicates an IP-based protocol. # # @return [TrueClass, FalseClass] # true if the scheme indicates an IP-based protocol. # false otherwise. def ip_based? if self.scheme return URI.ip_based_schemes.include?( self.scheme.strip.downcase) end return false end ## # Determines if the URI is relative. # # @return [TrueClass, FalseClass] # true if the URI is relative. false # otherwise. def relative? return self.scheme.nil? end ## # Determines if the URI is absolute. # # @return [TrueClass, FalseClass] # true if the URI is absolute. false # otherwise. def absolute? return !relative? end ## # Joins two URIs together. # # @param [String, Addressable::URI, #to_str] The URI to join with. # # @return [Addressable::URI] The joined URI. def join(uri) if !uri.respond_to?(:to_str) raise TypeError, "Can't convert #{uri.class} into String." end if !uri.kind_of?(URI) # Otherwise, convert to a String, then parse. uri = URI.parse(uri.to_str) end if uri.to_s.empty? return self.dup end joined_scheme = nil joined_user = nil joined_password = nil joined_host = nil joined_port = nil joined_path = nil joined_query = nil joined_fragment = nil # Section 5.2.2 of RFC 3986 if uri.scheme != nil joined_scheme = uri.scheme joined_user = uri.user joined_password = uri.password joined_host = uri.host joined_port = uri.port joined_path = URI.normalize_path(uri.path) joined_query = uri.query else if uri.authority != nil joined_user = uri.user joined_password = uri.password joined_host = uri.host joined_port = uri.port joined_path = URI.normalize_path(uri.path) joined_query = uri.query else if uri.path == nil || uri.path.empty? joined_path = self.path if uri.query != nil joined_query = uri.query else joined_query = self.query end else if uri.path[0..0] == SLASH joined_path = URI.normalize_path(uri.path) else base_path = self.path.dup base_path = EMPTY_STR if base_path == nil base_path = URI.normalize_path(base_path) # Section 5.2.3 of RFC 3986 # # Removes the right-most path segment from the base path. if base_path.include?(SLASH) base_path.sub!(/\/[^\/]+$/, SLASH) else base_path = EMPTY_STR end # If the base path is empty and an authority segment has been # defined, use a base path of SLASH if base_path.empty? && self.authority != nil base_path = SLASH end joined_path = URI.normalize_path(base_path + uri.path) end joined_query = uri.query end joined_user = self.user joined_password = self.password joined_host = self.host joined_port = self.port end joined_scheme = self.scheme end joined_fragment = uri.fragment return self.class.new( :scheme => joined_scheme, :user => joined_user, :password => joined_password, :host => joined_host, :port => joined_port, :path => joined_path, :query => joined_query, :fragment => joined_fragment ) end alias_method :+, :join ## # Destructive form of join. # # @param [String, Addressable::URI, #to_str] The URI to join with. # # @return [Addressable::URI] The joined URI. # # @see Addressable::URI#join def join!(uri) replace_self(self.join(uri)) end ## # Merges a URI with a Hash of components. # This method has different behavior from join. Any # components present in the hash parameter will override the # original components. The path component is not treated specially. # # @param [Hash, Addressable::URI, #to_hash] The components to merge with. # # @return [Addressable::URI] The merged URI. # # @see Hash#merge def merge(hash) unless hash.respond_to?(:to_hash) raise TypeError, "Can't convert #{hash.class} into Hash." end hash = hash.to_hash if hash.has_key?(:authority) if (hash.keys & [:userinfo, :user, :password, :host, :port]).any? raise ArgumentError, "Cannot specify both an authority and any of the components " + "within the authority." end end if hash.has_key?(:userinfo) if (hash.keys & [:user, :password]).any? raise ArgumentError, "Cannot specify both a userinfo and either the user or password." end end uri = self.class.new uri.defer_validation do # Bunch of crazy logic required because of the composite components # like userinfo and authority. uri.scheme = hash.has_key?(:scheme) ? hash[:scheme] : self.scheme if hash.has_key?(:authority) uri.authority = hash.has_key?(:authority) ? hash[:authority] : self.authority end if hash.has_key?(:userinfo) uri.userinfo = hash.has_key?(:userinfo) ? hash[:userinfo] : self.userinfo end if !hash.has_key?(:userinfo) && !hash.has_key?(:authority) uri.user = hash.has_key?(:user) ? hash[:user] : self.user uri.password = hash.has_key?(:password) ? hash[:password] : self.password end if !hash.has_key?(:authority) uri.host = hash.has_key?(:host) ? hash[:host] : self.host uri.port = hash.has_key?(:port) ? hash[:port] : self.port end uri.path = hash.has_key?(:path) ? hash[:path] : self.path uri.query = hash.has_key?(:query) ? hash[:query] : self.query uri.fragment = hash.has_key?(:fragment) ? hash[:fragment] : self.fragment end return uri end ## # Destructive form of merge. # # @param [Hash, Addressable::URI, #to_hash] The components to merge with. # # @return [Addressable::URI] The merged URI. # # @see Addressable::URI#merge def merge!(uri) replace_self(self.merge(uri)) end ## # Returns the shortest normalized relative form of this URI that uses the # supplied URI as a base for resolution. Returns an absolute URI if # necessary. This is effectively the opposite of route_to. # # @param [String, Addressable::URI, #to_str] uri The URI to route from. # # @return [Addressable::URI] # The normalized relative URI that is equivalent to the original URI. def route_from(uri) uri = URI.parse(uri).normalize normalized_self = self.normalize if normalized_self.relative? raise ArgumentError, "Expected absolute URI, got: #{self.to_s}" end if uri.relative? raise ArgumentError, "Expected absolute URI, got: #{uri.to_s}" end if normalized_self == uri return Addressable::URI.parse("##{normalized_self.fragment}") end components = normalized_self.to_hash if normalized_self.scheme == uri.scheme components[:scheme] = nil if normalized_self.authority == uri.authority components[:user] = nil components[:password] = nil components[:host] = nil components[:port] = nil if normalized_self.path == uri.path components[:path] = nil if normalized_self.query == uri.query components[:query] = nil end else if uri.path != SLASH and components[:path] self_splitted_path = split_path(components[:path]) uri_splitted_path = split_path(uri.path) self_dir = self_splitted_path.shift uri_dir = uri_splitted_path.shift while !self_splitted_path.empty? && !uri_splitted_path.empty? and self_dir == uri_dir self_dir = self_splitted_path.shift uri_dir = uri_splitted_path.shift end components[:path] = (uri_splitted_path.fill('..') + [self_dir] + self_splitted_path).join(SLASH) end end end end # Avoid network-path references. if components[:host] != nil components[:scheme] = normalized_self.scheme end return Addressable::URI.new( :scheme => components[:scheme], :user => components[:user], :password => components[:password], :host => components[:host], :port => components[:port], :path => components[:path], :query => components[:query], :fragment => components[:fragment] ) end ## # Returns the shortest normalized relative form of the supplied URI that # uses this URI as a base for resolution. Returns an absolute URI if # necessary. This is effectively the opposite of route_from. # # @param [String, Addressable::URI, #to_str] uri The URI to route to. # # @return [Addressable::URI] # The normalized relative URI that is equivalent to the supplied URI. def route_to(uri) return URI.parse(uri).route_from(self) end ## # Returns a normalized URI object. # # NOTE: This method does not attempt to fully conform to specifications. # It exists largely to correct other people's failures to read the # specifications, and also to deal with caching issues since several # different URIs may represent the same resource and should not be # cached multiple times. # # @return [Addressable::URI] The normalized URI. def normalize # This is a special exception for the frequently misused feed # URI scheme. if normalized_scheme == "feed" if self.to_s =~ /^feed:\/*http:\/*/ return URI.parse( self.to_s[/^feed:\/*(http:\/*.*)/, 1] ).normalize end end return self.class.new( :scheme => normalized_scheme, :authority => normalized_authority, :path => normalized_path, :query => normalized_query, :fragment => normalized_fragment ) end ## # Destructively normalizes this URI object. # # @return [Addressable::URI] The normalized URI. # # @see Addressable::URI#normalize def normalize! replace_self(self.normalize) end ## # Creates a URI suitable for display to users. If semantic attacks are # likely, the application should try to detect these and warn the user. # See RFC 3986, # section 7.6 for more information. # # @return [Addressable::URI] A URI suitable for display purposes. def display_uri display_uri = self.normalize display_uri.host = ::Addressable::IDNA.to_unicode(display_uri.host) return display_uri end ## # Returns true if the URI objects are equal. This method # normalizes both URIs before doing the comparison, and allows comparison # against Strings. # # @param [Object] uri The URI to compare. # # @return [TrueClass, FalseClass] # true if the URIs are equivalent, false # otherwise. def ===(uri) if uri.respond_to?(:normalize) uri_string = uri.normalize.to_s else begin uri_string = ::Addressable::URI.parse(uri).normalize.to_s rescue InvalidURIError, TypeError return false end end return self.normalize.to_s == uri_string end ## # Returns true if the URI objects are equal. This method # normalizes both URIs before doing the comparison. # # @param [Object] uri The URI to compare. # # @return [TrueClass, FalseClass] # true if the URIs are equivalent, false # otherwise. def ==(uri) return false unless uri.kind_of?(URI) return self.normalize.to_s == uri.normalize.to_s end ## # Returns true if the URI objects are equal. This method # does NOT normalize either URI before doing the comparison. # # @param [Object] uri The URI to compare. # # @return [TrueClass, FalseClass] # true if the URIs are equivalent, false # otherwise. def eql?(uri) return false unless uri.kind_of?(URI) return self.to_s == uri.to_s end ## # A hash value that will make a URI equivalent to its normalized # form. # # @return [Integer] A hash of the URI. def hash @hash ||= self.to_s.hash * -1 end ## # Clones the URI object. # # @return [Addressable::URI] The cloned URI. def dup duplicated_uri = self.class.new( :scheme => self.scheme ? self.scheme.dup : nil, :user => self.user ? self.user.dup : nil, :password => self.password ? self.password.dup : nil, :host => self.host ? self.host.dup : nil, :port => self.port, :path => self.path ? self.path.dup : nil, :query => self.query ? self.query.dup : nil, :fragment => self.fragment ? self.fragment.dup : nil ) return duplicated_uri end ## # Omits components from a URI. # # @param [Symbol] *components The components to be omitted. # # @return [Addressable::URI] The URI with components omitted. # # @example # uri = Addressable::URI.parse("http://example.com/path?query") # #=> # # uri.omit(:scheme, :authority) # #=> # def omit(*components) invalid_components = components - [ :scheme, :user, :password, :userinfo, :host, :port, :authority, :path, :query, :fragment ] unless invalid_components.empty? raise ArgumentError, "Invalid component names: #{invalid_components.inspect}." end duplicated_uri = self.dup duplicated_uri.defer_validation do components.each do |component| duplicated_uri.send((component.to_s + "=").to_sym, nil) end duplicated_uri.user = duplicated_uri.normalized_user end duplicated_uri end ## # Destructive form of omit. # # @param [Symbol] *components The components to be omitted. # # @return [Addressable::URI] The URI with components omitted. # # @see Addressable::URI#omit def omit!(*components) replace_self(self.omit(*components)) end ## # Determines if the URI is an empty string. # # @return [TrueClass, FalseClass] # Returns true if empty, false otherwise. def empty? return self.to_s.empty? end ## # Converts the URI to a String. # # @return [String] The URI's String representation. def to_s if self.scheme == nil && self.path != nil && !self.path.empty? && self.path =~ NORMPATH raise InvalidURIError, "Cannot assemble URI string with ambiguous path: '#{self.path}'" end @uri_string ||= begin uri_string = String.new uri_string << "#{self.scheme}:" if self.scheme != nil uri_string << "//#{self.authority}" if self.authority != nil uri_string << self.path.to_s uri_string << "?#{self.query}" if self.query != nil uri_string << "##{self.fragment}" if self.fragment != nil uri_string.force_encoding(Encoding::UTF_8) uri_string end end ## # URI's are glorified Strings. Allow implicit conversion. alias_method :to_str, :to_s ## # Returns a Hash of the URI components. # # @return [Hash] The URI as a Hash of components. def to_hash return { :scheme => self.scheme, :user => self.user, :password => self.password, :host => self.host, :port => self.port, :path => self.path, :query => self.query, :fragment => self.fragment } end ## # Returns a String representation of the URI object's state. # # @return [String] The URI object's state, as a String. def inspect sprintf("#<%s:%#0x URI:%s>", URI.to_s, self.object_id, self.to_s) end ## # This method allows you to make several changes to a URI simultaneously, # which separately would cause validation errors, but in conjunction, # are valid. The URI will be revalidated as soon as the entire block has # been executed. # # @param [Proc] block # A set of operations to perform on a given URI. def defer_validation raise LocalJumpError, "No block given." unless block_given? @validation_deferred = true yield @validation_deferred = false validate ensure @validation_deferred = false end def encode_with(coder) instance_variables.each do |ivar| value = instance_variable_get(ivar) if value != NONE key = ivar.to_s.slice(1..-1) coder[key] = value end end nil end def init_with(coder) reset_ivs coder.map.each do |key, value| instance_variable_set("@#{key}", value) end nil end protected SELF_REF = '.' PARENT = '..' RULE_2A = /\/\.\/|\/\.$/ RULE_2B_2C = /\/([^\/]*)\/\.\.\/|\/([^\/]*)\/\.\.$/ RULE_2D = /^\.\.?\/?/ RULE_PREFIXED_PARENT = /^\/\.\.?\/|^(\/\.\.?)+\/?$/ ## # Resolves paths to their simplest form. # # @param [String] path The path to normalize. # # @return [String] The normalized path. def self.normalize_path(path) # Section 5.2.4 of RFC 3986 return if path.nil? normalized_path = path.dup loop do mod ||= normalized_path.gsub!(RULE_2A, SLASH) pair = normalized_path.match(RULE_2B_2C) if pair parent = pair[1] current = pair[2] else parent = nil current = nil end regexp = "/#{Regexp.escape(parent.to_s)}/\\.\\./|" regexp += "(/#{Regexp.escape(current.to_s)}/\\.\\.$)" if pair && ((parent != SELF_REF && parent != PARENT) || (current != SELF_REF && current != PARENT)) mod ||= normalized_path.gsub!(Regexp.new(regexp), SLASH) end mod ||= normalized_path.gsub!(RULE_2D, EMPTY_STR) # Non-standard, removes prefixed dotted segments from path. mod ||= normalized_path.gsub!(RULE_PREFIXED_PARENT, SLASH) break if mod.nil? end normalized_path end ## # Ensures that the URI is valid. def validate return if !!@validation_deferred if self.scheme != nil && self.ip_based? && (self.host == nil || self.host.empty?) && (self.path == nil || self.path.empty?) raise InvalidURIError, "Absolute URI missing hierarchical segment: '#{self.to_s}'" end if self.host == nil if self.port != nil || self.user != nil || self.password != nil raise InvalidURIError, "Hostname not supplied: '#{self.to_s}'" end end if self.path != nil && !self.path.empty? && self.path[0..0] != SLASH && self.authority != nil raise InvalidURIError, "Cannot have a relative path with an authority set: '#{self.to_s}'" end if self.path != nil && !self.path.empty? && self.path[0..1] == SLASH + SLASH && self.authority == nil raise InvalidURIError, "Cannot have a path with two leading slashes " + "without an authority set: '#{self.to_s}'" end unreserved = CharacterClasses::UNRESERVED sub_delims = CharacterClasses::SUB_DELIMS if !self.host.nil? && (self.host =~ /[<>{}\/\\\?\#\@"[[:space:]]]/ || (self.host[/^\[(.*)\]$/, 1] != nil && self.host[/^\[(.*)\]$/, 1] !~ Regexp.new("^[#{unreserved}#{sub_delims}:]*$"))) raise InvalidURIError, "Invalid character in host: '#{self.host.to_s}'" end return nil end ## # Replaces the internal state of self with the specified URI's state. # Used in destructive operations to avoid massive code repetition. # # @param [Addressable::URI] uri The URI to replace self with. # # @return [Addressable::URI] self. def replace_self(uri) # Reset dependent values reset_ivs @scheme = uri.scheme @user = uri.user @password = uri.password @host = uri.host @port = uri.port @path = uri.path @query = uri.query @fragment = uri.fragment return self end ## # Splits path string with "/" (slash). # It is considered that there is empty string after last slash when # path ends with slash. # # @param [String] path The path to split. # # @return [Array] An array of parts of path. def split_path(path) splitted = path.split(SLASH) splitted << EMPTY_STR if path.end_with? SLASH splitted end ## # Resets composite values for the entire URI # # @api private def remove_composite_values @uri_string = nil @hash = nil end ## # Converts the string to be UTF-8 if it is not already UTF-8 # # @api private def force_utf8_encoding_if_needed(str) if str && str.encoding != Encoding::UTF_8 str.force_encoding(Encoding::UTF_8) end end private ## # Resets instance variables # # @api private def reset_ivs @scheme = nil @user = nil @normalized_scheme = NONE @normalized_user = NONE @uri_string = nil @hash = nil @userinfo = nil @normalized_userinfo = NONE @authority = nil @password = nil @normalized_authority = nil @port = nil @normalized_password = NONE @host = nil @normalized_host = nil @normalized_port = NONE @path = EMPTY_STR @normalized_path = nil @normalized_query = NONE @fragment = nil @normalized_fragment = NONE @query = nil end NONE = Module.new.freeze private_constant :NONE end end addressable-2.8.7/LICENSE.txt0000644000004100000410000002514314636033505015666 0ustar www-datawww-data Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. addressable-2.8.7/spec/0000755000004100000410000000000014636033505014770 5ustar www-datawww-dataaddressable-2.8.7/spec/spec_helper.rb0000644000004100000410000000121414636033505017604 0ustar www-datawww-data# frozen_string_literal: true require 'bundler/setup' require 'rspec/its' begin require 'coveralls' Coveralls.wear! do add_filter "spec/" add_filter "vendor/" end rescue LoadError warn "warning: coveralls gem not found; skipping Coveralls" require 'simplecov' SimpleCov.start do add_filter "spec/" add_filter "vendor/" end end if Gem.loaded_specs.key?("simplecov") class TestHelper def self.native_supported? mri = RUBY_ENGINE == "ruby" windows = RUBY_PLATFORM.include?("mingw") mri && !windows end end RSpec.configure do |config| config.warnings = true config.filter_run_when_matching :focus end addressable-2.8.7/spec/addressable/0000755000004100000410000000000014636033505017241 5ustar www-datawww-dataaddressable-2.8.7/spec/addressable/uri_spec.rb0000644000004100000410000056765614636033505021430 0ustar www-datawww-data# frozen_string_literal: true # Copyright (C) Bob Aman # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "spec_helper" require "addressable/uri" require "uri" require "ipaddr" require "yaml" if !"".respond_to?("force_encoding") class String def force_encoding(encoding) @encoding = encoding end def encoding @encoding ||= Encoding::ASCII_8BIT end end class Encoding def initialize(name) @name = name end def to_s return @name end UTF_8 = Encoding.new("UTF-8") ASCII_8BIT = Encoding.new("US-ASCII") end end module Fake module URI class HTTP def initialize(uri) @uri = uri end def to_s return @uri.to_s end alias :to_str :to_s end end end describe Addressable::URI, "when created with a non-numeric port number" do it "should raise an error" do expect do Addressable::URI.new(:port => "bogus") end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when created with a invalid encoded port number" do it "should raise an error" do expect do Addressable::URI.new(:port => "%eb") end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when created with a non-string scheme" do it "should raise an error" do expect do Addressable::URI.new(:scheme => :bogus) end.to raise_error(TypeError) end end describe Addressable::URI, "when created with a non-string user" do it "should raise an error" do expect do Addressable::URI.new(:user => :bogus) end.to raise_error(TypeError) end end describe Addressable::URI, "when created with a non-string password" do it "should raise an error" do expect do Addressable::URI.new(:password => :bogus) end.to raise_error(TypeError) end end describe Addressable::URI, "when created with a non-string userinfo" do it "should raise an error" do expect do Addressable::URI.new(:userinfo => :bogus) end.to raise_error(TypeError) end end describe Addressable::URI, "when created with a non-string host" do it "should raise an error" do expect do Addressable::URI.new(:host => :bogus) end.to raise_error(TypeError) end end describe Addressable::URI, "when created with a non-string authority" do it "should raise an error" do expect do Addressable::URI.new(:authority => :bogus) end.to raise_error(TypeError) end end describe Addressable::URI, "when created with a non-string path" do it "should raise an error" do expect do Addressable::URI.new(:path => :bogus) end.to raise_error(TypeError) end end describe Addressable::URI, "when created with a non-string query" do it "should raise an error" do expect do Addressable::URI.new(:query => :bogus) end.to raise_error(TypeError) end end describe Addressable::URI, "when created with a non-string fragment" do it "should raise an error" do expect do Addressable::URI.new(:fragment => :bogus) end.to raise_error(TypeError) end end describe Addressable::URI, "when created with a scheme but no hierarchical " + "segment" do it "should raise an error" do expect do Addressable::URI.parse("http:") end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "quote handling" do describe 'in host name' do it "should raise an error for single quote" do expect do Addressable::URI.parse("http://local\"host/") end.to raise_error(Addressable::URI::InvalidURIError) end end end describe Addressable::URI, "newline normalization" do it "should not accept newlines in scheme" do expect do Addressable::URI.parse("ht%0atp://localhost/") end.to raise_error(Addressable::URI::InvalidURIError) end it "should not unescape newline in path" do uri = Addressable::URI.parse("http://localhost/%0a").normalize expect(uri.to_s).to eq("http://localhost/%0A") end it "should not unescape newline in hostname" do uri = Addressable::URI.parse("http://local%0ahost/").normalize expect(uri.to_s).to eq("http://local%0Ahost/") end it "should not unescape newline in username" do uri = Addressable::URI.parse("http://foo%0abar@localhost/").normalize expect(uri.to_s).to eq("http://foo%0Abar@localhost/") end it "should not unescape newline in username" do uri = Addressable::URI.parse("http://example:foo%0abar@example/").normalize expect(uri.to_s).to eq("http://example:foo%0Abar@example/") end it "should not accept newline in hostname" do uri = Addressable::URI.parse("http://localhost/") expect do uri.host = "local\nhost" end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when created with ambiguous path" do it "should raise an error" do expect do Addressable::URI.parse("::http") end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when created with an invalid host" do it "should raise an error" do expect do Addressable::URI.new(:host => "") end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when created with a host consisting of " + "sub-delims characters" do it "should not raise an error" do expect do Addressable::URI.new( :host => Addressable::URI::CharacterClasses::SUB_DELIMS.gsub(/\\/, '') ) end.not_to raise_error end end describe Addressable::URI, "when created with a host consisting of " + "unreserved characters" do it "should not raise an error" do expect do Addressable::URI.new( :host => Addressable::URI::CharacterClasses::UNRESERVED.gsub(/\\/, '') ) end.not_to raise_error end end describe Addressable::URI, "when created from nil components" do before do @uri = Addressable::URI.new end it "should have a nil site value" do expect(@uri.site).to eq(nil) end it "should have an empty path" do expect(@uri.path).to eq("") end it "should be an empty uri" do expect(@uri.to_s).to eq("") end it "should have a nil default port" do expect(@uri.default_port).to eq(nil) end it "should be empty" do expect(@uri).to be_empty end it "should raise an error if the scheme is set to whitespace" do expect do @uri.scheme = "\t \n" end.to raise_error(Addressable::URI::InvalidURIError, /'\t \n'/) end it "should raise an error if the scheme is set to all digits" do expect do @uri.scheme = "123" end.to raise_error(Addressable::URI::InvalidURIError, /'123'/) end it "should raise an error if the scheme begins with a digit" do expect do @uri.scheme = "1scheme" end.to raise_error(Addressable::URI::InvalidURIError, /'1scheme'/) end it "should raise an error if the scheme begins with a plus" do expect do @uri.scheme = "+scheme" end.to raise_error(Addressable::URI::InvalidURIError, /'\+scheme'/) end it "should raise an error if the scheme begins with a dot" do expect do @uri.scheme = ".scheme" end.to raise_error(Addressable::URI::InvalidURIError, /'\.scheme'/) end it "should raise an error if the scheme begins with a dash" do expect do @uri.scheme = "-scheme" end.to raise_error(Addressable::URI::InvalidURIError, /'-scheme'/) end it "should raise an error if the scheme contains an illegal character" do expect do @uri.scheme = "scheme!" end.to raise_error(Addressable::URI::InvalidURIError, /'scheme!'/) end it "should raise an error if the scheme contains whitespace" do expect do @uri.scheme = "sch eme" end.to raise_error(Addressable::URI::InvalidURIError, /'sch eme'/) end it "should raise an error if the scheme contains a newline" do expect do @uri.scheme = "sch\neme" end.to raise_error(Addressable::URI::InvalidURIError) end it "should raise an error if set into an invalid state" do expect do @uri.user = "user" end.to raise_error(Addressable::URI::InvalidURIError) end it "should raise an error if set into an invalid state" do expect do @uri.password = "pass" end.to raise_error(Addressable::URI::InvalidURIError) end it "should raise an error if set into an invalid state" do expect do @uri.scheme = "http" @uri.fragment = "fragment" end.to raise_error(Addressable::URI::InvalidURIError) end it "should raise an error if set into an invalid state" do expect do @uri.fragment = "fragment" @uri.scheme = "http" end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when initialized from individual components" do before do @uri = Addressable::URI.new( :scheme => "http", :user => "user", :password => "password", :host => "example.com", :port => 8080, :path => "/path", :query => "query=value", :fragment => "fragment" ) end it "returns 'http' for #scheme" do expect(@uri.scheme).to eq("http") end it "returns 'http' for #normalized_scheme" do expect(@uri.normalized_scheme).to eq("http") end it "returns 'user' for #user" do expect(@uri.user).to eq("user") end it "returns 'user' for #normalized_user" do expect(@uri.normalized_user).to eq("user") end it "returns 'password' for #password" do expect(@uri.password).to eq("password") end it "returns 'password' for #normalized_password" do expect(@uri.normalized_password).to eq("password") end it "returns 'user:password' for #userinfo" do expect(@uri.userinfo).to eq("user:password") end it "returns 'user:password' for #normalized_userinfo" do expect(@uri.normalized_userinfo).to eq("user:password") end it "returns 'example.com' for #host" do expect(@uri.host).to eq("example.com") end it "returns 'example.com' for #normalized_host" do expect(@uri.normalized_host).to eq("example.com") end it "returns 'com' for #tld" do expect(@uri.tld).to eq("com") end it "returns 'user:password@example.com:8080' for #authority" do expect(@uri.authority).to eq("user:password@example.com:8080") end it "returns 'user:password@example.com:8080' for #normalized_authority" do expect(@uri.normalized_authority).to eq("user:password@example.com:8080") end it "returns 8080 for #port" do expect(@uri.port).to eq(8080) end it "returns 8080 for #normalized_port" do expect(@uri.normalized_port).to eq(8080) end it "returns 80 for #default_port" do expect(@uri.default_port).to eq(80) end it "returns 'http://user:password@example.com:8080' for #site" do expect(@uri.site).to eq("http://user:password@example.com:8080") end it "returns 'http://user:password@example.com:8080' for #normalized_site" do expect(@uri.normalized_site).to eq("http://user:password@example.com:8080") end it "returns '/path' for #path" do expect(@uri.path).to eq("/path") end it "returns '/path' for #normalized_path" do expect(@uri.normalized_path).to eq("/path") end it "returns 'query=value' for #query" do expect(@uri.query).to eq("query=value") end it "returns 'query=value' for #normalized_query" do expect(@uri.normalized_query).to eq("query=value") end it "returns 'fragment' for #fragment" do expect(@uri.fragment).to eq("fragment") end it "returns 'fragment' for #normalized_fragment" do expect(@uri.normalized_fragment).to eq("fragment") end it "returns #hash" do expect(@uri.hash).not_to be nil end it "returns #to_s" do expect(@uri.to_s).to eq( "http://user:password@example.com:8080/path?query=value#fragment" ) end it "should not be empty" do expect(@uri).not_to be_empty end it "should not be frozen" do expect(@uri).not_to be_frozen end it "should allow destructive operations" do expect { @uri.normalize! }.not_to raise_error end end describe Addressable::URI, "when initialized from " + "frozen individual components" do before do @uri = Addressable::URI.new( :scheme => "http".freeze, :user => "user".freeze, :password => "password".freeze, :host => "example.com".freeze, :port => "8080".freeze, :path => "/path".freeze, :query => "query=value".freeze, :fragment => "fragment".freeze ) end it "returns 'http' for #scheme" do expect(@uri.scheme).to eq("http") end it "returns 'http' for #normalized_scheme" do expect(@uri.normalized_scheme).to eq("http") end it "returns 'user' for #user" do expect(@uri.user).to eq("user") end it "returns 'user' for #normalized_user" do expect(@uri.normalized_user).to eq("user") end it "returns 'password' for #password" do expect(@uri.password).to eq("password") end it "returns 'password' for #normalized_password" do expect(@uri.normalized_password).to eq("password") end it "returns 'user:password' for #userinfo" do expect(@uri.userinfo).to eq("user:password") end it "returns 'user:password' for #normalized_userinfo" do expect(@uri.normalized_userinfo).to eq("user:password") end it "returns 'example.com' for #host" do expect(@uri.host).to eq("example.com") end it "returns 'example.com' for #normalized_host" do expect(@uri.normalized_host).to eq("example.com") end it "returns 'user:password@example.com:8080' for #authority" do expect(@uri.authority).to eq("user:password@example.com:8080") end it "returns 'user:password@example.com:8080' for #normalized_authority" do expect(@uri.normalized_authority).to eq("user:password@example.com:8080") end it "returns 8080 for #port" do expect(@uri.port).to eq(8080) end it "returns 8080 for #normalized_port" do expect(@uri.normalized_port).to eq(8080) end it "returns 80 for #default_port" do expect(@uri.default_port).to eq(80) end it "returns 'http://user:password@example.com:8080' for #site" do expect(@uri.site).to eq("http://user:password@example.com:8080") end it "returns 'http://user:password@example.com:8080' for #normalized_site" do expect(@uri.normalized_site).to eq("http://user:password@example.com:8080") end it "returns '/path' for #path" do expect(@uri.path).to eq("/path") end it "returns '/path' for #normalized_path" do expect(@uri.normalized_path).to eq("/path") end it "returns 'query=value' for #query" do expect(@uri.query).to eq("query=value") end it "returns 'query=value' for #normalized_query" do expect(@uri.normalized_query).to eq("query=value") end it "returns 'fragment' for #fragment" do expect(@uri.fragment).to eq("fragment") end it "returns 'fragment' for #normalized_fragment" do expect(@uri.normalized_fragment).to eq("fragment") end it "returns #hash" do expect(@uri.hash).not_to be nil end it "returns #to_s" do expect(@uri.to_s).to eq( "http://user:password@example.com:8080/path?query=value#fragment" ) end it "should not be empty" do expect(@uri).not_to be_empty end it "should not be frozen" do expect(@uri).not_to be_frozen end it "should allow destructive operations" do expect { @uri.normalize! }.not_to raise_error end end describe Addressable::URI, "when parsed from a frozen string" do before do @uri = Addressable::URI.parse( "http://user:password@example.com:8080/path?query=value#fragment".freeze ) end it "returns 'http' for #scheme" do expect(@uri.scheme).to eq("http") end it "returns 'http' for #normalized_scheme" do expect(@uri.normalized_scheme).to eq("http") end it "returns 'user' for #user" do expect(@uri.user).to eq("user") end it "returns 'user' for #normalized_user" do expect(@uri.normalized_user).to eq("user") end it "returns 'password' for #password" do expect(@uri.password).to eq("password") end it "returns 'password' for #normalized_password" do expect(@uri.normalized_password).to eq("password") end it "returns 'user:password' for #userinfo" do expect(@uri.userinfo).to eq("user:password") end it "returns 'user:password' for #normalized_userinfo" do expect(@uri.normalized_userinfo).to eq("user:password") end it "returns 'example.com' for #host" do expect(@uri.host).to eq("example.com") end it "returns 'example.com' for #normalized_host" do expect(@uri.normalized_host).to eq("example.com") end it "returns 'user:password@example.com:8080' for #authority" do expect(@uri.authority).to eq("user:password@example.com:8080") end it "returns 'user:password@example.com:8080' for #normalized_authority" do expect(@uri.normalized_authority).to eq("user:password@example.com:8080") end it "returns 8080 for #port" do expect(@uri.port).to eq(8080) end it "returns 8080 for #normalized_port" do expect(@uri.normalized_port).to eq(8080) end it "returns 80 for #default_port" do expect(@uri.default_port).to eq(80) end it "returns 'http://user:password@example.com:8080' for #site" do expect(@uri.site).to eq("http://user:password@example.com:8080") end it "returns 'http://user:password@example.com:8080' for #normalized_site" do expect(@uri.normalized_site).to eq("http://user:password@example.com:8080") end it "returns '/path' for #path" do expect(@uri.path).to eq("/path") end it "returns '/path' for #normalized_path" do expect(@uri.normalized_path).to eq("/path") end it "returns 'query=value' for #query" do expect(@uri.query).to eq("query=value") end it "returns 'query=value' for #normalized_query" do expect(@uri.normalized_query).to eq("query=value") end it "returns 'fragment' for #fragment" do expect(@uri.fragment).to eq("fragment") end it "returns 'fragment' for #normalized_fragment" do expect(@uri.normalized_fragment).to eq("fragment") end it "returns #hash" do expect(@uri.hash).not_to be nil end it "returns #to_s" do expect(@uri.to_s).to eq( "http://user:password@example.com:8080/path?query=value#fragment" ) end it "should not be empty" do expect(@uri).not_to be_empty end it "should not be frozen" do expect(@uri).not_to be_frozen end it "should allow destructive operations" do expect { @uri.normalize! }.not_to raise_error end end describe Addressable::URI, "when frozen" do before do @uri = Addressable::URI.new.freeze end it "returns nil for #scheme" do expect(@uri.scheme).to eq(nil) end it "returns nil for #normalized_scheme" do expect(@uri.normalized_scheme).to eq(nil) end it "returns nil for #user" do expect(@uri.user).to eq(nil) end it "returns nil for #normalized_user" do expect(@uri.normalized_user).to eq(nil) end it "returns nil for #password" do expect(@uri.password).to eq(nil) end it "returns nil for #normalized_password" do expect(@uri.normalized_password).to eq(nil) end it "returns nil for #userinfo" do expect(@uri.userinfo).to eq(nil) end it "returns nil for #normalized_userinfo" do expect(@uri.normalized_userinfo).to eq(nil) end it "returns nil for #host" do expect(@uri.host).to eq(nil) end it "returns nil for #normalized_host" do expect(@uri.normalized_host).to eq(nil) end it "returns nil for #authority" do expect(@uri.authority).to eq(nil) end it "returns nil for #normalized_authority" do expect(@uri.normalized_authority).to eq(nil) end it "returns nil for #port" do expect(@uri.port).to eq(nil) end it "returns nil for #normalized_port" do expect(@uri.normalized_port).to eq(nil) end it "returns nil for #default_port" do expect(@uri.default_port).to eq(nil) end it "returns nil for #site" do expect(@uri.site).to eq(nil) end it "returns nil for #normalized_site" do expect(@uri.normalized_site).to eq(nil) end it "returns '' for #path" do expect(@uri.path).to eq('') end it "returns '' for #normalized_path" do expect(@uri.normalized_path).to eq('') end it "returns nil for #query" do expect(@uri.query).to eq(nil) end it "returns nil for #normalized_query" do expect(@uri.normalized_query).to eq(nil) end it "returns nil for #fragment" do expect(@uri.fragment).to eq(nil) end it "returns nil for #normalized_fragment" do expect(@uri.normalized_fragment).to eq(nil) end it "returns #hash" do expect(@uri.hash).not_to be nil end it "returns #to_s" do expect(@uri.to_s).to eq('') end it "should be empty" do expect(@uri).to be_empty end it "should be frozen" do expect(@uri).to be_frozen end it "should not be frozen after duping" do expect(@uri.dup).not_to be_frozen end it "should not allow destructive operations" do expect { @uri.normalize! }.to raise_error { |error| expect(error.message).to match(/can't modify frozen/) expect(error).to satisfy { |e| RuntimeError === e || TypeError === e } } end end describe Addressable::URI, "when frozen" do before do @uri = Addressable::URI.parse( "HTTP://example.com.:%38%30/%70a%74%68?a=%31#1%323" ).freeze end it "returns 'HTTP' for #scheme" do expect(@uri.scheme).to eq("HTTP") end it "returns 'http' for #normalized_scheme" do expect(@uri.normalized_scheme).to eq("http") expect(@uri.normalize.scheme).to eq("http") end it "returns nil for #user" do expect(@uri.user).to eq(nil) end it "returns nil for #normalized_user" do expect(@uri.normalized_user).to eq(nil) end it "returns nil for #password" do expect(@uri.password).to eq(nil) end it "returns nil for #normalized_password" do expect(@uri.normalized_password).to eq(nil) end it "returns nil for #userinfo" do expect(@uri.userinfo).to eq(nil) end it "returns nil for #normalized_userinfo" do expect(@uri.normalized_userinfo).to eq(nil) end it "returns 'example.com.' for #host" do expect(@uri.host).to eq("example.com.") end it "returns nil for #normalized_host" do expect(@uri.normalized_host).to eq("example.com") expect(@uri.normalize.host).to eq("example.com") end it "returns 'example.com.:80' for #authority" do expect(@uri.authority).to eq("example.com.:80") end it "returns 'example.com:80' for #normalized_authority" do expect(@uri.normalized_authority).to eq("example.com") expect(@uri.normalize.authority).to eq("example.com") end it "returns 80 for #port" do expect(@uri.port).to eq(80) end it "returns nil for #normalized_port" do expect(@uri.normalized_port).to eq(nil) expect(@uri.normalize.port).to eq(nil) end it "returns 80 for #default_port" do expect(@uri.default_port).to eq(80) end it "returns 'HTTP://example.com.:80' for #site" do expect(@uri.site).to eq("HTTP://example.com.:80") end it "returns 'http://example.com' for #normalized_site" do expect(@uri.normalized_site).to eq("http://example.com") expect(@uri.normalize.site).to eq("http://example.com") end it "returns '/%70a%74%68' for #path" do expect(@uri.path).to eq("/%70a%74%68") end it "returns '/path' for #normalized_path" do expect(@uri.normalized_path).to eq("/path") expect(@uri.normalize.path).to eq("/path") end it "returns 'a=%31' for #query" do expect(@uri.query).to eq("a=%31") end it "returns 'a=1' for #normalized_query" do expect(@uri.normalized_query).to eq("a=1") expect(@uri.normalize.query).to eq("a=1") end it "returns '/%70a%74%68?a=%31' for #request_uri" do expect(@uri.request_uri).to eq("/%70a%74%68?a=%31") end it "returns '1%323' for #fragment" do expect(@uri.fragment).to eq("1%323") end it "returns '123' for #normalized_fragment" do expect(@uri.normalized_fragment).to eq("123") expect(@uri.normalize.fragment).to eq("123") end it "returns #hash" do expect(@uri.hash).not_to be nil end it "returns #to_s" do expect(@uri.to_s).to eq('HTTP://example.com.:80/%70a%74%68?a=%31#1%323') expect(@uri.normalize.to_s).to eq('http://example.com/path?a=1#123') end it "should not be empty" do expect(@uri).not_to be_empty end it "should be frozen" do expect(@uri).to be_frozen end it "should not be frozen after duping" do expect(@uri.dup).not_to be_frozen end it "should not allow destructive operations" do expect { @uri.normalize! }.to raise_error { |error| expect(error.message).to match(/can't modify frozen/) expect(error).to satisfy { |e| RuntimeError === e || TypeError === e } } end end describe Addressable::URI, "when normalized and then deeply frozen" do before do @uri = Addressable::URI.parse( "http://user:password@example.com:8080/path?query=value#fragment" ).normalize! @uri.instance_variables.each do |var| @uri.instance_variable_set(var, @uri.instance_variable_get(var).freeze) end @uri.freeze end it "#normalized_scheme should not error" do expect { @uri.normalized_scheme }.not_to raise_error end it "#normalized_user should not error" do expect { @uri.normalized_user }.not_to raise_error end it "#normalized_password should not error" do expect { @uri.normalized_password }.not_to raise_error end it "#normalized_userinfo should not error" do expect { @uri.normalized_userinfo }.not_to raise_error end it "#normalized_host should not error" do expect { @uri.normalized_host }.not_to raise_error end it "#normalized_authority should not error" do expect { @uri.normalized_authority }.not_to raise_error end it "#normalized_port should not error" do expect { @uri.normalized_port }.not_to raise_error end it "#normalized_site should not error" do expect { @uri.normalized_site }.not_to raise_error end it "#normalized_path should not error" do expect { @uri.normalized_path }.not_to raise_error end it "#normalized_query should not error" do expect { @uri.normalized_query }.not_to raise_error end it "#normalized_fragment should not error" do expect { @uri.normalized_fragment }.not_to raise_error end it "should be frozen" do expect(@uri).to be_frozen end it "should not allow destructive operations" do expect { @uri.normalize! }.to raise_error(RuntimeError) end end describe Addressable::URI, "when created from string components" do before do @uri = Addressable::URI.new( :scheme => "http", :host => "example.com" ) end it "should have a site value of 'http://example.com'" do expect(@uri.site).to eq("http://example.com") end it "should be equal to the equivalent parsed URI" do expect(@uri).to eq(Addressable::URI.parse("http://example.com")) end it "should raise an error if invalid components omitted" do expect do @uri.omit(:bogus) end.to raise_error(ArgumentError) expect do @uri.omit(:scheme, :bogus, :path) end.to raise_error(ArgumentError) end end describe Addressable::URI, "when created with a nil host but " + "non-nil authority components" do it "should raise an error" do expect do Addressable::URI.new(:user => "user", :password => "pass", :port => 80) end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when created with both an authority and a user" do it "should raise an error" do expect do Addressable::URI.new( :user => "user", :authority => "user@example.com:80" ) end.to raise_error(ArgumentError) end end describe Addressable::URI, "when created with an authority and no port" do before do @uri = Addressable::URI.new(:authority => "user@example.com") end it "should not infer a port" do expect(@uri.port).to eq(nil) expect(@uri.default_port).to eq(nil) expect(@uri.inferred_port).to eq(nil) end it "should have a site value of '//user@example.com'" do expect(@uri.site).to eq("//user@example.com") end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end describe Addressable::URI, "when created with a host with trailing dots" do before do @uri = Addressable::URI.new(:authority => "example...") end it "should have a stable normalized form" do expect(@uri.normalize.normalize.normalize.host).to eq( @uri.normalize.host ) end end describe Addressable::URI, "when created with a host with a backslash" do it "should raise an error" do expect do Addressable::URI.new(:authority => "example\\example") end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when created with a host with a slash" do it "should raise an error" do expect do Addressable::URI.new(:authority => "example/example") end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when created with a host with a space" do it "should raise an error" do expect do Addressable::URI.new(:authority => "example example") end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when created with both a userinfo and a user" do it "should raise an error" do expect do Addressable::URI.new(:user => "user", :userinfo => "user:pass") end.to raise_error(ArgumentError) end end describe Addressable::URI, "when created with a path that hasn't been " + "prefixed with a '/' but a host specified" do before do @uri = Addressable::URI.new( :scheme => "http", :host => "example.com", :path => "path" ) end it "should prefix a '/' to the path" do expect(@uri).to eq(Addressable::URI.parse("http://example.com/path")) end it "should have a site value of 'http://example.com'" do expect(@uri.site).to eq("http://example.com") end it "should have an origin of 'http://example.com" do expect(@uri.origin).to eq('http://example.com') end end describe Addressable::URI, "when created with a path that hasn't been " + "prefixed with a '/' but no host specified" do before do @uri = Addressable::URI.new( :scheme => "http", :path => "path" ) end it "should not prefix a '/' to the path" do expect(@uri).to eq(Addressable::URI.parse("http:path")) end it "should have a site value of 'http:'" do expect(@uri.site).to eq("http:") end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end describe Addressable::URI, "when parsed from an Addressable::URI object" do it "should not have unexpected side-effects" do original_uri = Addressable::URI.parse("http://example.com/") new_uri = Addressable::URI.parse(original_uri) new_uri.host = 'www.example.com' expect(new_uri.host).to eq('www.example.com') expect(new_uri.to_s).to eq('http://www.example.com/') expect(original_uri.host).to eq('example.com') expect(original_uri.to_s).to eq('http://example.com/') end it "should not have unexpected side-effects" do original_uri = Addressable::URI.parse("http://example.com/") new_uri = Addressable::URI.heuristic_parse(original_uri) new_uri.host = 'www.example.com' expect(new_uri.host).to eq('www.example.com') expect(new_uri.to_s).to eq('http://www.example.com/') expect(original_uri.host).to eq('example.com') expect(original_uri.to_s).to eq('http://example.com/') end it "should not have unexpected side-effects" do original_uri = Addressable::URI.parse("http://example.com/") new_uri = Addressable::URI.parse(original_uri) new_uri.origin = 'https://www.example.com:8080' expect(new_uri.host).to eq('www.example.com') expect(new_uri.to_s).to eq('https://www.example.com:8080/') expect(original_uri.host).to eq('example.com') expect(original_uri.to_s).to eq('http://example.com/') end it "should not have unexpected side-effects" do original_uri = Addressable::URI.parse("http://example.com/") new_uri = Addressable::URI.heuristic_parse(original_uri) new_uri.origin = 'https://www.example.com:8080' expect(new_uri.host).to eq('www.example.com') expect(new_uri.to_s).to eq('https://www.example.com:8080/') expect(original_uri.host).to eq('example.com') expect(original_uri.to_s).to eq('http://example.com/') end end describe Addressable::URI, "when parsed from something that looks " + "like a URI object" do it "should parse without error" do uri = Addressable::URI.parse(Fake::URI::HTTP.new("http://example.com/")) expect do Addressable::URI.parse(uri) end.not_to raise_error end end describe Addressable::URI, "when parsed from a standard library URI object" do it "should parse without error" do uri = Addressable::URI.parse(URI.parse("http://example.com/")) expect do Addressable::URI.parse(uri) end.not_to raise_error end end describe Addressable::URI, "when parsed from ''" do before do @uri = Addressable::URI.parse("") end it "should have no scheme" do expect(@uri.scheme).to eq(nil) end it "should not be considered to be ip-based" do expect(@uri).not_to be_ip_based end it "should have a path of ''" do expect(@uri.path).to eq("") end it "should have a request URI of '/'" do expect(@uri.request_uri).to eq("/") end it "should be considered relative" do expect(@uri).to be_relative end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end # Section 1.1.2 of RFC 3986 describe Addressable::URI, "when parsed from " + "'ftp://ftp.is.co.za/rfc/rfc1808.txt'" do before do @uri = Addressable::URI.parse("ftp://ftp.is.co.za/rfc/rfc1808.txt") end it "should use the 'ftp' scheme" do expect(@uri.scheme).to eq("ftp") end it "should be considered to be ip-based" do expect(@uri).to be_ip_based end it "should have a host of 'ftp.is.co.za'" do expect(@uri.host).to eq("ftp.is.co.za") end it "should have inferred_port of 21" do expect(@uri.inferred_port).to eq(21) end it "should have a path of '/rfc/rfc1808.txt'" do expect(@uri.path).to eq("/rfc/rfc1808.txt") end it "should not have a request URI" do expect(@uri.request_uri).to eq(nil) end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should have an origin of 'ftp://ftp.is.co.za'" do expect(@uri.origin).to eq('ftp://ftp.is.co.za') end end # Section 1.1.2 of RFC 3986 describe Addressable::URI, "when parsed from " + "'http://www.ietf.org/rfc/rfc2396.txt'" do before do @uri = Addressable::URI.parse("http://www.ietf.org/rfc/rfc2396.txt") end it "should use the 'http' scheme" do expect(@uri.scheme).to eq("http") end it "should be considered to be ip-based" do expect(@uri).to be_ip_based end it "should have a host of 'www.ietf.org'" do expect(@uri.host).to eq("www.ietf.org") end it "should have inferred_port of 80" do expect(@uri.inferred_port).to eq(80) end it "should have a path of '/rfc/rfc2396.txt'" do expect(@uri.path).to eq("/rfc/rfc2396.txt") end it "should have a request URI of '/rfc/rfc2396.txt'" do expect(@uri.request_uri).to eq("/rfc/rfc2396.txt") end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should correctly omit components" do expect(@uri.omit(:scheme).to_s).to eq("//www.ietf.org/rfc/rfc2396.txt") expect(@uri.omit(:path).to_s).to eq("http://www.ietf.org") end it "should correctly omit components destructively" do @uri.omit!(:scheme) expect(@uri.to_s).to eq("//www.ietf.org/rfc/rfc2396.txt") end it "should have an origin of 'http://www.ietf.org'" do expect(@uri.origin).to eq('http://www.ietf.org') end end # Section 1.1.2 of RFC 3986 describe Addressable::URI, "when parsed from " + "'ldap://[2001:db8::7]/c=GB?objectClass?one'" do before do @uri = Addressable::URI.parse("ldap://[2001:db8::7]/c=GB?objectClass?one") end it "should use the 'ldap' scheme" do expect(@uri.scheme).to eq("ldap") end it "should be considered to be ip-based" do expect(@uri).to be_ip_based end it "should have a host of '[2001:db8::7]'" do expect(@uri.host).to eq("[2001:db8::7]") end it "should have inferred_port of 389" do expect(@uri.inferred_port).to eq(389) end it "should have a path of '/c=GB'" do expect(@uri.path).to eq("/c=GB") end it "should not have a request URI" do expect(@uri.request_uri).to eq(nil) end it "should not allow request URI assignment" do expect do @uri.request_uri = "/" end.to raise_error(Addressable::URI::InvalidURIError) end it "should have a query of 'objectClass?one'" do expect(@uri.query).to eq("objectClass?one") end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should correctly omit components" do expect(@uri.omit(:scheme, :authority).to_s).to eq("/c=GB?objectClass?one") expect(@uri.omit(:path).to_s).to eq("ldap://[2001:db8::7]?objectClass?one") end it "should correctly omit components destructively" do @uri.omit!(:scheme, :authority) expect(@uri.to_s).to eq("/c=GB?objectClass?one") end it "should raise an error if omission would create an invalid URI" do expect do @uri.omit(:authority, :path) end.to raise_error(Addressable::URI::InvalidURIError) end it "should have an origin of 'ldap://[2001:db8::7]'" do expect(@uri.origin).to eq('ldap://[2001:db8::7]') end end # Section 1.1.2 of RFC 3986 describe Addressable::URI, "when parsed from " + "'mailto:John.Doe@example.com'" do before do @uri = Addressable::URI.parse("mailto:John.Doe@example.com") end it "should use the 'mailto' scheme" do expect(@uri.scheme).to eq("mailto") end it "should not be considered to be ip-based" do expect(@uri).not_to be_ip_based end it "should not have an inferred_port" do expect(@uri.inferred_port).to eq(nil) end it "should have a path of 'John.Doe@example.com'" do expect(@uri.path).to eq("John.Doe@example.com") end it "should not have a request URI" do expect(@uri.request_uri).to eq(nil) end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end # Section 2 of RFC 6068 describe Addressable::URI, "when parsed from " + "'mailto:?to=addr1@an.example,addr2@an.example'" do before do @uri = Addressable::URI.parse( "mailto:?to=addr1@an.example,addr2@an.example" ) end it "should use the 'mailto' scheme" do expect(@uri.scheme).to eq("mailto") end it "should not be considered to be ip-based" do expect(@uri).not_to be_ip_based end it "should not have an inferred_port" do expect(@uri.inferred_port).to eq(nil) end it "should have a path of ''" do expect(@uri.path).to eq("") end it "should not have a request URI" do expect(@uri.request_uri).to eq(nil) end it "should have the To: field value parameterized" do expect(@uri.query_values(Hash)["to"]).to eq( "addr1@an.example,addr2@an.example" ) end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end # Section 1.1.2 of RFC 3986 describe Addressable::URI, "when parsed from " + "'news:comp.infosystems.www.servers.unix'" do before do @uri = Addressable::URI.parse("news:comp.infosystems.www.servers.unix") end it "should use the 'news' scheme" do expect(@uri.scheme).to eq("news") end it "should not have an inferred_port" do expect(@uri.inferred_port).to eq(nil) end it "should not be considered to be ip-based" do expect(@uri).not_to be_ip_based end it "should have a path of 'comp.infosystems.www.servers.unix'" do expect(@uri.path).to eq("comp.infosystems.www.servers.unix") end it "should not have a request URI" do expect(@uri.request_uri).to eq(nil) end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end # Section 1.1.2 of RFC 3986 describe Addressable::URI, "when parsed from " + "'tel:+1-816-555-1212'" do before do @uri = Addressable::URI.parse("tel:+1-816-555-1212") end it "should use the 'tel' scheme" do expect(@uri.scheme).to eq("tel") end it "should not be considered to be ip-based" do expect(@uri).not_to be_ip_based end it "should not have an inferred_port" do expect(@uri.inferred_port).to eq(nil) end it "should have a path of '+1-816-555-1212'" do expect(@uri.path).to eq("+1-816-555-1212") end it "should not have a request URI" do expect(@uri.request_uri).to eq(nil) end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end # Section 1.1.2 of RFC 3986 describe Addressable::URI, "when parsed from " + "'telnet://192.0.2.16:80/'" do before do @uri = Addressable::URI.parse("telnet://192.0.2.16:80/") end it "should use the 'telnet' scheme" do expect(@uri.scheme).to eq("telnet") end it "should have a host of '192.0.2.16'" do expect(@uri.host).to eq("192.0.2.16") end it "should have a port of 80" do expect(@uri.port).to eq(80) end it "should have a inferred_port of 80" do expect(@uri.inferred_port).to eq(80) end it "should have a default_port of 23" do expect(@uri.default_port).to eq(23) end it "should be considered to be ip-based" do expect(@uri).to be_ip_based end it "should have a path of '/'" do expect(@uri.path).to eq("/") end it "should not have a request URI" do expect(@uri.request_uri).to eq(nil) end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should have an origin of 'telnet://192.0.2.16:80'" do expect(@uri.origin).to eq('telnet://192.0.2.16:80') end end # Section 1.1.2 of RFC 3986 describe Addressable::URI, "when parsed from " + "'urn:oasis:names:specification:docbook:dtd:xml:4.1.2'" do before do @uri = Addressable::URI.parse( "urn:oasis:names:specification:docbook:dtd:xml:4.1.2") end it "should use the 'urn' scheme" do expect(@uri.scheme).to eq("urn") end it "should not have an inferred_port" do expect(@uri.inferred_port).to eq(nil) end it "should not be considered to be ip-based" do expect(@uri).not_to be_ip_based end it "should have a path of " + "'oasis:names:specification:docbook:dtd:xml:4.1.2'" do expect(@uri.path).to eq("oasis:names:specification:docbook:dtd:xml:4.1.2") end it "should not have a request URI" do expect(@uri.request_uri).to eq(nil) end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end describe Addressable::URI, "when heuristically parsed from " + "'192.0.2.16:8000/path'" do before do @uri = Addressable::URI.heuristic_parse("192.0.2.16:8000/path") end it "should use the 'http' scheme" do expect(@uri.scheme).to eq("http") end it "should have a host of '192.0.2.16'" do expect(@uri.host).to eq("192.0.2.16") end it "should have a port of '8000'" do expect(@uri.port).to eq(8000) end it "should be considered to be ip-based" do expect(@uri).to be_ip_based end it "should have a path of '/path'" do expect(@uri.path).to eq("/path") end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should have an origin of 'http://192.0.2.16:8000'" do expect(@uri.origin).to eq('http://192.0.2.16:8000') end end describe Addressable::URI, "when parsed from " + "'http://example.com'" do before do @uri = Addressable::URI.parse("http://example.com") end it "when inspected, should have the correct URI" do expect(@uri.inspect).to include("http://example.com") end it "when inspected, should have the correct class name" do expect(@uri.inspect).to include("Addressable::URI") end it "when inspected, should have the correct object id" do expect(@uri.inspect).to include("%#0x" % @uri.object_id) end it "should use the 'http' scheme" do expect(@uri.scheme).to eq("http") end it "should be considered to be ip-based" do expect(@uri).to be_ip_based end it "should have an authority segment of 'example.com'" do expect(@uri.authority).to eq("example.com") end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should be considered ip-based" do expect(@uri).to be_ip_based end it "should have no username" do expect(@uri.user).to eq(nil) end it "should have no password" do expect(@uri.password).to eq(nil) end it "should use port 80" do expect(@uri.inferred_port).to eq(80) end it "should not have a specified port" do expect(@uri.port).to eq(nil) end it "should have an empty path" do expect(@uri.path).to eq("") end it "should have no query string" do expect(@uri.query).to eq(nil) expect(@uri.query_values).to eq(nil) end it "should have a request URI of '/'" do expect(@uri.request_uri).to eq("/") end it "should have no fragment" do expect(@uri.fragment).to eq(nil) end it "should be considered absolute" do expect(@uri).to be_absolute end it "should not be considered relative" do expect(@uri).not_to be_relative end it "should not be exactly equal to 42" do expect(@uri.eql?(42)).to eq(false) end it "should not be equal to 42" do expect(@uri == 42).to eq(false) end it "should not be roughly equal to 42" do expect(@uri === 42).to eq(false) end it "should be exactly equal to http://example.com" do expect(@uri.eql?(Addressable::URI.parse("http://example.com"))).to eq(true) end it "should be roughly equal to http://example.com/" do expect(@uri === Addressable::URI.parse("http://example.com/")).to eq(true) end it "should be roughly equal to the string 'http://example.com/'" do expect(@uri === "http://example.com/").to eq(true) end it "should not be roughly equal to the string " + "'http://example.com:bogus/'" do expect do expect(@uri === "http://example.com:bogus/").to eq(false) end.not_to raise_error end it "should result in itself when joined with itself" do expect(@uri.join(@uri).to_s).to eq("http://example.com") expect(@uri.join!(@uri).to_s).to eq("http://example.com") end it "should be equivalent to http://EXAMPLE.com" do expect(@uri).to eq(Addressable::URI.parse("http://EXAMPLE.com")) end it "should be equivalent to http://EXAMPLE.com:80/" do expect(@uri).to eq(Addressable::URI.parse("http://EXAMPLE.com:80/")) end it "should have the same hash as http://example.com" do expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com").hash) end it "should have the same hash as http://EXAMPLE.com after assignment" do @uri.origin = "http://EXAMPLE.com" expect(@uri.hash).to eq(Addressable::URI.parse("http://EXAMPLE.com").hash) end it "should have a different hash from http://EXAMPLE.com" do expect(@uri.hash).not_to eq(Addressable::URI.parse("http://EXAMPLE.com").hash) end it "should not allow origin assignment without scheme" do expect do @uri.origin = "example.com" end.to raise_error(Addressable::URI::InvalidURIError) end it "should not allow origin assignment without host" do expect do @uri.origin = "http://" end.to raise_error(Addressable::URI::InvalidURIError) end it "should not allow origin assignment with bogus type" do expect do @uri.origin = :bogus end.to raise_error(TypeError) end # Section 6.2.3 of RFC 3986 it "should be equivalent to http://example.com/" do expect(@uri).to eq(Addressable::URI.parse("http://example.com/")) end # Section 6.2.3 of RFC 3986 it "should be equivalent to http://example.com:/" do expect(@uri).to eq(Addressable::URI.parse("http://example.com:/")) end # Section 6.2.3 of RFC 3986 it "should be equivalent to http://example.com:80/" do expect(@uri).to eq(Addressable::URI.parse("http://example.com:80/")) end # Section 6.2.2.1 of RFC 3986 it "should be equivalent to http://EXAMPLE.COM/" do expect(@uri).to eq(Addressable::URI.parse("http://EXAMPLE.COM/")) end it "should have a route of '/path/' to 'http://example.com/path/'" do expect(@uri.route_to("http://example.com/path/")).to eq( Addressable::URI.parse("/path/") ) end it "should have a route of '..' from 'http://example.com/path/'" do expect(@uri.route_from("http://example.com/path/")).to eq( Addressable::URI.parse("..") ) end it "should have a route of '#' to 'http://example.com/'" do expect(@uri.route_to("http://example.com/")).to eq( Addressable::URI.parse("#") ) end it "should have a route of 'http://elsewhere.com/' to " + "'http://elsewhere.com/'" do expect(@uri.route_to("http://elsewhere.com/")).to eq( Addressable::URI.parse("http://elsewhere.com/") ) end it "when joined with 'relative/path' should be " + "'http://example.com/relative/path'" do expect(@uri.join('relative/path')).to eq( Addressable::URI.parse("http://example.com/relative/path") ) end it "when joined with a bogus object a TypeError should be raised" do expect do @uri.join(42) end.to raise_error(TypeError) end it "should have the correct username after assignment" do @uri.user = "newuser" expect(@uri.user).to eq("newuser") expect(@uri.password).to eq(nil) expect(@uri.to_s).to eq("http://newuser@example.com") end it "should have the correct username after assignment" do @uri.user = "user@123!" expect(@uri.user).to eq("user@123!") expect(@uri.normalized_user).to eq("user%40123%21") expect(@uri.password).to eq(nil) expect(@uri.normalize.to_s).to eq("http://user%40123%21@example.com/") end it "should have the correct password after assignment" do @uri.password = "newpass" expect(@uri.password).to eq("newpass") expect(@uri.user).to eq("") expect(@uri.to_s).to eq("http://:newpass@example.com") end it "should have the correct password after assignment" do @uri.password = "#secret@123!" expect(@uri.password).to eq("#secret@123!") expect(@uri.normalized_password).to eq("%23secret%40123%21") expect(@uri.user).to eq("") expect(@uri.normalize.to_s).to eq("http://:%23secret%40123%21@example.com/") expect(@uri.omit(:password).to_s).to eq("http://example.com") end it "should have the correct user/pass after repeated assignment" do @uri.user = nil expect(@uri.user).to eq(nil) @uri.password = "newpass" expect(@uri.password).to eq("newpass") # Username cannot be nil if the password is set expect(@uri.user).to eq("") expect(@uri.to_s).to eq("http://:newpass@example.com") @uri.user = "newuser" expect(@uri.user).to eq("newuser") @uri.password = nil expect(@uri.password).to eq(nil) expect(@uri.to_s).to eq("http://newuser@example.com") @uri.user = "newuser" expect(@uri.user).to eq("newuser") @uri.password = "" expect(@uri.password).to eq("") expect(@uri.to_s).to eq("http://newuser:@example.com") @uri.password = "newpass" expect(@uri.password).to eq("newpass") @uri.user = nil # Username cannot be nil if the password is set expect(@uri.user).to eq("") expect(@uri.to_s).to eq("http://:newpass@example.com") end it "should have the correct user/pass after userinfo assignment" do @uri.user = "newuser" expect(@uri.user).to eq("newuser") @uri.password = "newpass" expect(@uri.password).to eq("newpass") @uri.userinfo = nil expect(@uri.userinfo).to eq(nil) expect(@uri.user).to eq(nil) expect(@uri.password).to eq(nil) end it "should correctly convert to a hash" do expect(@uri.to_hash).to eq({ :scheme => "http", :user => nil, :password => nil, :host => "example.com", :port => nil, :path => "", :query => nil, :fragment => nil }) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end it "should have an origin of 'http://example.com'" do expect(@uri.origin).to eq('http://example.com') end end # Section 5.1.2 of RFC 2616 describe Addressable::URI, "when parsed from " + "'HTTP://www.w3.org/pub/WWW/TheProject.html'" do before do @uri = Addressable::URI.parse("HTTP://www.w3.org/pub/WWW/TheProject.html") end it "should have the correct request URI" do expect(@uri.request_uri).to eq("/pub/WWW/TheProject.html") end it "should have the correct request URI after assignment" do @uri.request_uri = "/pub/WWW/TheProject.html?" expect(@uri.request_uri).to eq("/pub/WWW/TheProject.html?") expect(@uri.path).to eq("/pub/WWW/TheProject.html") expect(@uri.query).to eq("") end it "should have the correct request URI after assignment" do @uri.request_uri = "/some/where/else.html" expect(@uri.request_uri).to eq("/some/where/else.html") expect(@uri.path).to eq("/some/where/else.html") expect(@uri.query).to eq(nil) end it "should have the correct request URI after assignment" do @uri.request_uri = "/some/where/else.html?query?string" expect(@uri.request_uri).to eq("/some/where/else.html?query?string") expect(@uri.path).to eq("/some/where/else.html") expect(@uri.query).to eq("query?string") end it "should have the correct request URI after assignment" do @uri.request_uri = "?x=y" expect(@uri.request_uri).to eq("/?x=y") expect(@uri.path).to eq("/") expect(@uri.query).to eq("x=y") end it "should raise an error if the site value is set to something bogus" do expect do @uri.site = 42 end.to raise_error(TypeError) end it "should raise an error if the request URI is set to something bogus" do expect do @uri.request_uri = 42 end.to raise_error(TypeError) end it "should correctly convert to a hash" do expect(@uri.to_hash).to eq({ :scheme => "HTTP", :user => nil, :password => nil, :host => "www.w3.org", :port => nil, :path => "/pub/WWW/TheProject.html", :query => nil, :fragment => nil }) end it "should have an origin of 'http://www.w3.org'" do expect(@uri.origin).to eq('http://www.w3.org') end end describe Addressable::URI, "when parsing IPv6 addresses" do it "should not raise an error for " + "'http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/'" do Addressable::URI.parse("http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/") end it "should not raise an error for " + "'http://[fe80:0:0:0:200:f8ff:fe21:67cf]/'" do Addressable::URI.parse("http://[fe80:0:0:0:200:f8ff:fe21:67cf]/") end it "should not raise an error for " + "'http://[fe80::200:f8ff:fe21:67cf]/'" do Addressable::URI.parse("http://[fe80::200:f8ff:fe21:67cf]/") end it "should not raise an error for " + "'http://[::1]/'" do Addressable::URI.parse("http://[::1]/") end it "should not raise an error for " + "'http://[fe80::1]/'" do Addressable::URI.parse("http://[fe80::1]/") end it "should raise an error for " + "'http://[]/'" do expect do Addressable::URI.parse("http://[]/") end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when parsing IPv6 address" do subject { Addressable::URI.parse("http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/") } its(:host) { should == '[3ffe:1900:4545:3:200:f8ff:fe21:67cf]' } its(:hostname) { should == '3ffe:1900:4545:3:200:f8ff:fe21:67cf' } end describe Addressable::URI, "when assigning IPv6 address" do it "should allow to set bare IPv6 address as hostname" do uri = Addressable::URI.parse("http://[::1]/") uri.hostname = '3ffe:1900:4545:3:200:f8ff:fe21:67cf' expect(uri.to_s).to eq('http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/') end it "should allow to set bare IPv6 address as hostname with IPAddr object" do uri = Addressable::URI.parse("http://[::1]/") uri.hostname = IPAddr.new('3ffe:1900:4545:3:200:f8ff:fe21:67cf') expect(uri.to_s).to eq('http://[3ffe:1900:4545:3:200:f8ff:fe21:67cf]/') end it "should not allow to set bare IPv6 address as host" do uri = Addressable::URI.parse("http://[::1]/") skip "not checked" expect do uri.host = '3ffe:1900:4545:3:200:f8ff:fe21:67cf' end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when parsing IPvFuture addresses" do it "should not raise an error for " + "'http://[v9.3ffe:1900:4545:3:200:f8ff:fe21:67cf]/'" do Addressable::URI.parse("http://[v9.3ffe:1900:4545:3:200:f8ff:fe21:67cf]/") end it "should not raise an error for " + "'http://[vff.fe80:0:0:0:200:f8ff:fe21:67cf]/'" do Addressable::URI.parse("http://[vff.fe80:0:0:0:200:f8ff:fe21:67cf]/") end it "should not raise an error for " + "'http://[v12.fe80::200:f8ff:fe21:67cf]/'" do Addressable::URI.parse("http://[v12.fe80::200:f8ff:fe21:67cf]/") end it "should not raise an error for " + "'http://[va0.::1]/'" do Addressable::URI.parse("http://[va0.::1]/") end it "should not raise an error for " + "'http://[v255.fe80::1]/'" do Addressable::URI.parse("http://[v255.fe80::1]/") end it "should raise an error for " + "'http://[v0.]/'" do expect do Addressable::URI.parse("http://[v0.]/") end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when parsed from " + "'http://example.com/'" do before do @uri = Addressable::URI.parse("http://example.com/") end # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence it "should be equivalent to http://example.com" do expect(@uri).to eq(Addressable::URI.parse("http://example.com")) end # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence it "should be equivalent to HTTP://example.com/" do expect(@uri).to eq(Addressable::URI.parse("HTTP://example.com/")) end # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence it "should be equivalent to http://example.com:/" do expect(@uri).to eq(Addressable::URI.parse("http://example.com:/")) end # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence it "should be equivalent to http://example.com:80/" do expect(@uri).to eq(Addressable::URI.parse("http://example.com:80/")) end # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence it "should be equivalent to http://Example.com/" do expect(@uri).to eq(Addressable::URI.parse("http://Example.com/")) end it "should have the correct username after assignment" do @uri.user = nil expect(@uri.user).to eq(nil) expect(@uri.password).to eq(nil) expect(@uri.to_s).to eq("http://example.com/") end it "should have the correct password after assignment" do @uri.password = nil expect(@uri.password).to eq(nil) expect(@uri.user).to eq(nil) expect(@uri.to_s).to eq("http://example.com/") end it "should have a request URI of '/'" do expect(@uri.request_uri).to eq("/") end it "should correctly convert to a hash" do expect(@uri.to_hash).to eq({ :scheme => "http", :user => nil, :password => nil, :host => "example.com", :port => nil, :path => "/", :query => nil, :fragment => nil }) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end it "should have the same hash as its duplicate" do expect(@uri.hash).to eq(@uri.dup.hash) end it "should have a different hash from its equivalent String value" do expect(@uri.hash).not_to eq(@uri.to_s.hash) end it "should have the same hash as an equal URI" do expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com/").hash) end it "should be equivalent to http://EXAMPLE.com" do expect(@uri).to eq(Addressable::URI.parse("http://EXAMPLE.com")) end it "should be equivalent to http://EXAMPLE.com:80/" do expect(@uri).to eq(Addressable::URI.parse("http://EXAMPLE.com:80/")) end it "should have the same hash as http://example.com/" do expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com/").hash) end it "should have the same hash as http://example.com after assignment" do @uri.path = "" expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com").hash) end it "should have the same hash as http://example.com/? after assignment" do @uri.query = "" expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com/?").hash) end it "should have the same hash as http://example.com/? after assignment" do @uri.query_values = {} expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com/?").hash) end it "should have the same hash as http://example.com/# after assignment" do @uri.fragment = "" expect(@uri.hash).to eq(Addressable::URI.parse("http://example.com/#").hash) end it "should have a different hash from http://example.com" do expect(@uri.hash).not_to eq(Addressable::URI.parse("http://example.com").hash) end it "should have an origin of 'http://example.com'" do expect(@uri.origin).to eq('http://example.com') end end describe Addressable::URI, "when parsed from " + "'http://example.com?#'" do before do @uri = Addressable::URI.parse("http://example.com?#") end it "should correctly convert to a hash" do expect(@uri.to_hash).to eq({ :scheme => "http", :user => nil, :password => nil, :host => "example.com", :port => nil, :path => "", :query => "", :fragment => "" }) end it "should have a request URI of '/?'" do expect(@uri.request_uri).to eq("/?") end it "should normalize to 'http://example.com/'" do expect(@uri.normalize.to_s).to eq("http://example.com/") end it "should have an origin of 'http://example.com'" do expect(@uri.origin).to eq("http://example.com") end end describe Addressable::URI, "when parsed from " + "'http://@example.com/'" do before do @uri = Addressable::URI.parse("http://@example.com/") end it "should be equivalent to http://example.com" do expect(@uri).to eq(Addressable::URI.parse("http://example.com")) end it "should correctly convert to a hash" do expect(@uri.to_hash).to eq({ :scheme => "http", :user => "", :password => nil, :host => "example.com", :port => nil, :path => "/", :query => nil, :fragment => nil }) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end it "should have an origin of 'http://example.com'" do expect(@uri.origin).to eq('http://example.com') end end describe Addressable::URI, "when parsed from " + "'http://example.com./'" do before do @uri = Addressable::URI.parse("http://example.com./") end it "should be equivalent to http://example.com" do expect(@uri).to eq(Addressable::URI.parse("http://example.com")) end it "should not be considered to be in normal form" do expect(@uri.normalize).not_to be_eql(@uri) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end it "should have an origin of 'http://example.com'" do expect(@uri.origin).to eq('http://example.com') end end describe Addressable::URI, "when parsed from " + "'http://:@example.com/'" do before do @uri = Addressable::URI.parse("http://:@example.com/") end it "should be equivalent to http://example.com" do expect(@uri).to eq(Addressable::URI.parse("http://example.com")) end it "should correctly convert to a hash" do expect(@uri.to_hash).to eq({ :scheme => "http", :user => "", :password => "", :host => "example.com", :port => nil, :path => "/", :query => nil, :fragment => nil }) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end it "should have an origin of 'http://example.com'" do expect(@uri.origin).to eq('http://example.com') end end describe Addressable::URI, "when parsed from " + "'HTTP://EXAMPLE.COM/'" do before do @uri = Addressable::URI.parse("HTTP://EXAMPLE.COM/") end it "should be equivalent to http://example.com" do expect(@uri).to eq(Addressable::URI.parse("http://example.com")) end it "should correctly convert to a hash" do expect(@uri.to_hash).to eq({ :scheme => "HTTP", :user => nil, :password => nil, :host => "EXAMPLE.COM", :port => nil, :path => "/", :query => nil, :fragment => nil }) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end it "should have an origin of 'http://example.com'" do expect(@uri.origin).to eq('http://example.com') end it "should have a tld of 'com'" do expect(@uri.tld).to eq('com') end end describe Addressable::URI, "when parsed from " + "'http://www.example.co.uk/'" do before do @uri = Addressable::URI.parse("http://www.example.co.uk/") end it "should have an origin of 'http://www.example.co.uk'" do expect(@uri.origin).to eq('http://www.example.co.uk') end it "should have a tld of 'co.uk'" do expect(@uri.tld).to eq('co.uk') end it "should have a domain of 'example.co.uk'" do expect(@uri.domain).to eq('example.co.uk') end end describe Addressable::URI, "when parsed from " + "'http://sub_domain.blogspot.com/'" do before do @uri = Addressable::URI.parse("http://sub_domain.blogspot.com/") end it "should have an origin of 'http://sub_domain.blogspot.com'" do expect(@uri.origin).to eq('http://sub_domain.blogspot.com') end it "should have a tld of 'com'" do expect(@uri.tld).to eq('com') end it "should have a domain of 'blogspot.com'" do expect(@uri.domain).to eq('blogspot.com') end end describe Addressable::URI, "when parsed from " + "'http://example.com/~smith/'" do before do @uri = Addressable::URI.parse("http://example.com/~smith/") end # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence it "should be equivalent to http://example.com/%7Esmith/" do expect(@uri).to eq(Addressable::URI.parse("http://example.com/%7Esmith/")) end # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence it "should be equivalent to http://example.com/%7esmith/" do expect(@uri).to eq(Addressable::URI.parse("http://example.com/%7esmith/")) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end end describe Addressable::URI, "when parsed from " + "'http://example.com/%E8'" do before do @uri = Addressable::URI.parse("http://example.com/%E8") end it "should not raise an exception when normalized" do expect do @uri.normalize end.not_to raise_error end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should not change if encoded with the normalizing algorithm" do expect(Addressable::URI.normalized_encode(@uri).to_s).to eq( "http://example.com/%E8" ) expect(Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s).to be === "http://example.com/%E8" end end describe Addressable::URI, "when parsed from " + "'http://example.com/path%2Fsegment/'" do before do @uri = Addressable::URI.parse("http://example.com/path%2Fsegment/") end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should be equal to 'http://example.com/path%2Fsegment/'" do expect(@uri.normalize).to be_eql( Addressable::URI.parse("http://example.com/path%2Fsegment/") ) end it "should not be equal to 'http://example.com/path/segment/'" do expect(@uri).not_to eq( Addressable::URI.parse("http://example.com/path/segment/") ) end it "should not be equal to 'http://example.com/path/segment/'" do expect(@uri.normalize).not_to be_eql( Addressable::URI.parse("http://example.com/path/segment/") ) end end describe Addressable::URI, "when parsed from " + "'http://example.com/?%F6'" do before do @uri = Addressable::URI.parse("http://example.com/?%F6") end it "should not raise an exception when normalized" do expect do @uri.normalize end.not_to raise_error end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should not change if encoded with the normalizing algorithm" do expect(Addressable::URI.normalized_encode(@uri).to_s).to eq( "http://example.com/?%F6" ) expect(Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s).to be === "http://example.com/?%F6" end end describe Addressable::URI, "when parsed from " + "'http://example.com/#%F6'" do before do @uri = Addressable::URI.parse("http://example.com/#%F6") end it "should not raise an exception when normalized" do expect do @uri.normalize end.not_to raise_error end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should not change if encoded with the normalizing algorithm" do expect(Addressable::URI.normalized_encode(@uri).to_s).to eq( "http://example.com/#%F6" ) expect(Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s).to be === "http://example.com/#%F6" end end describe Addressable::URI, "when parsed from " + "'http://example.com/%C3%87'" do before do @uri = Addressable::URI.parse("http://example.com/%C3%87") end # Based on http://intertwingly.net/blog/2004/07/31/URI-Equivalence it "should be equivalent to 'http://example.com/C%CC%A7'" do expect(@uri).to eq(Addressable::URI.parse("http://example.com/C%CC%A7")) end it "should not change if encoded with the normalizing algorithm" do expect(Addressable::URI.normalized_encode(@uri).to_s).to eq( "http://example.com/%C3%87" ) expect(Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s).to be === "http://example.com/%C3%87" end it "should raise an error if encoding with an unexpected return type" do expect do Addressable::URI.normalized_encode(@uri, Integer) end.to raise_error(TypeError) end it "if percent encoded should be 'http://example.com/C%25CC%25A7'" do expect(Addressable::URI.encode(@uri).to_s).to eq( "http://example.com/%25C3%2587" ) end it "if percent encoded should be 'http://example.com/C%25CC%25A7'" do expect(Addressable::URI.encode(@uri, Addressable::URI)).to eq( Addressable::URI.parse("http://example.com/%25C3%2587") ) end it "should raise an error if encoding with an unexpected return type" do expect do Addressable::URI.encode(@uri, Integer) end.to raise_error(TypeError) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end end describe Addressable::URI, "when parsed from " + "'http://example.com/?q=string'" do before do @uri = Addressable::URI.parse("http://example.com/?q=string") end it "should use the 'http' scheme" do expect(@uri.scheme).to eq("http") end it "should have an authority segment of 'example.com'" do expect(@uri.authority).to eq("example.com") end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should have no username" do expect(@uri.user).to eq(nil) end it "should have no password" do expect(@uri.password).to eq(nil) end it "should use port 80" do expect(@uri.inferred_port).to eq(80) end it "should have a path of '/'" do expect(@uri.path).to eq("/") end it "should have a query string of 'q=string'" do expect(@uri.query).to eq("q=string") end it "should have no fragment" do expect(@uri.fragment).to eq(nil) end it "should be considered absolute" do expect(@uri).to be_absolute end it "should not be considered relative" do expect(@uri).not_to be_relative end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end end describe Addressable::URI, "when parsed from " + "'http://example.com:80/'" do before do @uri = Addressable::URI.parse("http://example.com:80/") end it "should use the 'http' scheme" do expect(@uri.scheme).to eq("http") end it "should have an authority segment of 'example.com:80'" do expect(@uri.authority).to eq("example.com:80") end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should have no username" do expect(@uri.user).to eq(nil) end it "should have no password" do expect(@uri.password).to eq(nil) end it "should use port 80" do expect(@uri.inferred_port).to eq(80) end it "should have explicit port 80" do expect(@uri.port).to eq(80) end it "should have a path of '/'" do expect(@uri.path).to eq("/") end it "should have no query string" do expect(@uri.query).to eq(nil) end it "should have no fragment" do expect(@uri.fragment).to eq(nil) end it "should be considered absolute" do expect(@uri).to be_absolute end it "should not be considered relative" do expect(@uri).not_to be_relative end it "should be exactly equal to http://example.com:80/" do expect(@uri.eql?(Addressable::URI.parse("http://example.com:80/"))).to eq(true) end it "should be roughly equal to http://example.com/" do expect(@uri === Addressable::URI.parse("http://example.com/")).to eq(true) end it "should be roughly equal to the string 'http://example.com/'" do expect(@uri === "http://example.com/").to eq(true) end it "should not be roughly equal to the string " + "'http://example.com:bogus/'" do expect do expect(@uri === "http://example.com:bogus/").to eq(false) end.not_to raise_error end it "should result in itself when joined with itself" do expect(@uri.join(@uri).to_s).to eq("http://example.com:80/") expect(@uri.join!(@uri).to_s).to eq("http://example.com:80/") end # Section 6.2.3 of RFC 3986 it "should be equal to http://example.com/" do expect(@uri).to eq(Addressable::URI.parse("http://example.com/")) end # Section 6.2.3 of RFC 3986 it "should be equal to http://example.com:/" do expect(@uri).to eq(Addressable::URI.parse("http://example.com:/")) end # Section 6.2.3 of RFC 3986 it "should be equal to http://example.com:80/" do expect(@uri).to eq(Addressable::URI.parse("http://example.com:80/")) end # Section 6.2.2.1 of RFC 3986 it "should be equal to http://EXAMPLE.COM/" do expect(@uri).to eq(Addressable::URI.parse("http://EXAMPLE.COM/")) end it "should correctly convert to a hash" do expect(@uri.to_hash).to eq({ :scheme => "http", :user => nil, :password => nil, :host => "example.com", :port => 80, :path => "/", :query => nil, :fragment => nil }) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end it "should have an origin of 'http://example.com'" do expect(@uri.origin).to eq('http://example.com') end it "should not change if encoded with the normalizing algorithm" do expect(Addressable::URI.normalized_encode(@uri).to_s).to eq( "http://example.com:80/" ) expect(Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s).to be === "http://example.com:80/" end end describe Addressable::URI, "when parsed from " + "'http://example.com:8080/'" do before do @uri = Addressable::URI.parse("http://example.com:8080/") end it "should use the 'http' scheme" do expect(@uri.scheme).to eq("http") end it "should have an authority segment of 'example.com:8080'" do expect(@uri.authority).to eq("example.com:8080") end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should have no username" do expect(@uri.user).to eq(nil) end it "should have no password" do expect(@uri.password).to eq(nil) end it "should use port 8080" do expect(@uri.inferred_port).to eq(8080) end it "should have explicit port 8080" do expect(@uri.port).to eq(8080) end it "should have default port 80" do expect(@uri.default_port).to eq(80) end it "should have a path of '/'" do expect(@uri.path).to eq("/") end it "should have no query string" do expect(@uri.query).to eq(nil) end it "should have no fragment" do expect(@uri.fragment).to eq(nil) end it "should be considered absolute" do expect(@uri).to be_absolute end it "should not be considered relative" do expect(@uri).not_to be_relative end it "should be exactly equal to http://example.com:8080/" do expect(@uri.eql?(Addressable::URI.parse( "http://example.com:8080/"))).to eq(true) end it "should have a route of 'http://example.com:8080/' from " + "'http://example.com/path/to/'" do expect(@uri.route_from("http://example.com/path/to/")).to eq( Addressable::URI.parse("http://example.com:8080/") ) end it "should have a route of 'http://example.com:8080/' from " + "'http://example.com:80/path/to/'" do expect(@uri.route_from("http://example.com:80/path/to/")).to eq( Addressable::URI.parse("http://example.com:8080/") ) end it "should have a route of '../../' from " + "'http://example.com:8080/path/to/'" do expect(@uri.route_from("http://example.com:8080/path/to/")).to eq( Addressable::URI.parse("../../") ) end it "should have a route of 'http://example.com:8080/' from " + "'http://user:pass@example.com/path/to/'" do expect(@uri.route_from("http://user:pass@example.com/path/to/")).to eq( Addressable::URI.parse("http://example.com:8080/") ) end it "should correctly convert to a hash" do expect(@uri.to_hash).to eq({ :scheme => "http", :user => nil, :password => nil, :host => "example.com", :port => 8080, :path => "/", :query => nil, :fragment => nil }) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end it "should have an origin of 'http://example.com:8080'" do expect(@uri.origin).to eq('http://example.com:8080') end it "should not change if encoded with the normalizing algorithm" do expect(Addressable::URI.normalized_encode(@uri).to_s).to eq( "http://example.com:8080/" ) expect(Addressable::URI.normalized_encode(@uri, Addressable::URI).to_s).to be === "http://example.com:8080/" end end describe Addressable::URI, "when parsed from " + "'http://example.com:%38%30/'" do before do @uri = Addressable::URI.parse("http://example.com:%38%30/") end it "should have the correct port" do expect(@uri.port).to eq(80) end it "should not be considered to be in normal form" do expect(@uri.normalize).not_to be_eql(@uri) end it "should normalize to 'http://example.com/'" do expect(@uri.normalize.to_s).to eq("http://example.com/") end it "should have an origin of 'http://example.com'" do expect(@uri.origin).to eq('http://example.com') end end describe Addressable::URI, "when parsed with empty port" do subject(:uri) do Addressable::URI.parse("//example.com:") end it "should not infer a port" do expect(uri.port).to be(nil) end it "should have a site value of '//example.com'" do expect(uri.site).to eq("//example.com") end end describe Addressable::URI, "when parsed from " + "'http://example.com/%2E/'" do before do @uri = Addressable::URI.parse("http://example.com/%2E/") end it "should be considered to be in normal form" do skip( 'path segment normalization should happen before ' + 'percent escaping normalization' ) @uri.normalize.should be_eql(@uri) end it "should normalize to 'http://example.com/%2E/'" do skip( 'path segment normalization should happen before ' + 'percent escaping normalization' ) expect(@uri.normalize).to eq("http://example.com/%2E/") end end describe Addressable::URI, "when parsed from " + "'http://example.com/..'" do before do @uri = Addressable::URI.parse("http://example.com/..") end it "should have the correct port" do expect(@uri.inferred_port).to eq(80) end it "should not be considered to be in normal form" do expect(@uri.normalize).not_to be_eql(@uri) end it "should normalize to 'http://example.com/'" do expect(@uri.normalize.to_s).to eq("http://example.com/") end end describe Addressable::URI, "when parsed from " + "'http://example.com/../..'" do before do @uri = Addressable::URI.parse("http://example.com/../..") end it "should have the correct port" do expect(@uri.inferred_port).to eq(80) end it "should not be considered to be in normal form" do expect(@uri.normalize).not_to be_eql(@uri) end it "should normalize to 'http://example.com/'" do expect(@uri.normalize.to_s).to eq("http://example.com/") end end describe Addressable::URI, "when parsed from " + "'http://example.com/path(/..'" do before do @uri = Addressable::URI.parse("http://example.com/path(/..") end it "should have the correct port" do expect(@uri.inferred_port).to eq(80) end it "should not be considered to be in normal form" do expect(@uri.normalize).not_to be_eql(@uri) end it "should normalize to 'http://example.com/'" do expect(@uri.normalize.to_s).to eq("http://example.com/") end end describe Addressable::URI, "when parsed from " + "'http://example.com/(path)/..'" do before do @uri = Addressable::URI.parse("http://example.com/(path)/..") end it "should have the correct port" do expect(@uri.inferred_port).to eq(80) end it "should not be considered to be in normal form" do expect(@uri.normalize).not_to be_eql(@uri) end it "should normalize to 'http://example.com/'" do expect(@uri.normalize.to_s).to eq("http://example.com/") end end describe Addressable::URI, "when parsed from " + "'http://example.com/path(/../'" do before do @uri = Addressable::URI.parse("http://example.com/path(/../") end it "should have the correct port" do expect(@uri.inferred_port).to eq(80) end it "should not be considered to be in normal form" do expect(@uri.normalize).not_to be_eql(@uri) end it "should normalize to 'http://example.com/'" do expect(@uri.normalize.to_s).to eq("http://example.com/") end end describe Addressable::URI, "when parsed from " + "'http://example.com/(path)/../'" do before do @uri = Addressable::URI.parse("http://example.com/(path)/../") end it "should have the correct port" do expect(@uri.inferred_port).to eq(80) end it "should not be considered to be in normal form" do expect(@uri.normalize).not_to be_eql(@uri) end it "should normalize to 'http://example.com/'" do expect(@uri.normalize.to_s).to eq("http://example.com/") end end describe Addressable::URI, "when parsed from " + "'/..//example.com'" do before do @uri = Addressable::URI.parse("/..//example.com") end it "should become invalid when normalized" do expect do @uri.normalize end.to raise_error(Addressable::URI::InvalidURIError, /authority/) end it "should have a path of '/..//example.com'" do expect(@uri.path).to eq("/..//example.com") end end describe Addressable::URI, "when parsed from '/a/b/c/./../../g'" do before do @uri = Addressable::URI.parse("/a/b/c/./../../g") end it "should not be considered to be in normal form" do expect(@uri.normalize).not_to be_eql(@uri) end # Section 5.2.4 of RFC 3986 it "should normalize to '/a/g'" do expect(@uri.normalize.to_s).to eq("/a/g") end end describe Addressable::URI, "when parsed from 'mid/content=5/../6'" do before do @uri = Addressable::URI.parse("mid/content=5/../6") end it "should not be considered to be in normal form" do expect(@uri.normalize).not_to be_eql(@uri) end # Section 5.2.4 of RFC 3986 it "should normalize to 'mid/6'" do expect(@uri.normalize.to_s).to eq("mid/6") end end describe Addressable::URI, "when parsed from " + "'http://www.example.com///../'" do before do @uri = Addressable::URI.parse('http://www.example.com///../') end it "should not be considered to be in normal form" do expect(@uri.normalize).not_to be_eql(@uri) end it "should normalize to 'http://www.example.com//'" do expect(@uri.normalize.to_s).to eq("http://www.example.com//") end end describe Addressable::URI, "when parsed from " + "'http://example.com/path/to/resource/'" do before do @uri = Addressable::URI.parse("http://example.com/path/to/resource/") end it "should use the 'http' scheme" do expect(@uri.scheme).to eq("http") end it "should have an authority segment of 'example.com'" do expect(@uri.authority).to eq("example.com") end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should have no username" do expect(@uri.user).to eq(nil) end it "should have no password" do expect(@uri.password).to eq(nil) end it "should use port 80" do expect(@uri.inferred_port).to eq(80) end it "should have a path of '/path/to/resource/'" do expect(@uri.path).to eq("/path/to/resource/") end it "should have no query string" do expect(@uri.query).to eq(nil) end it "should have no fragment" do expect(@uri.fragment).to eq(nil) end it "should be considered absolute" do expect(@uri).to be_absolute end it "should not be considered relative" do expect(@uri).not_to be_relative end it "should be exactly equal to http://example.com:8080/" do expect(@uri.eql?(Addressable::URI.parse( "http://example.com/path/to/resource/"))).to eq(true) end it "should have a route of 'resource/' from " + "'http://example.com/path/to/'" do expect(@uri.route_from("http://example.com/path/to/")).to eq( Addressable::URI.parse("resource/") ) end it "should have a route of '../' from " + "'http://example.com/path/to/resource/sub'" do expect(@uri.route_from("http://example.com/path/to/resource/sub")).to eq( Addressable::URI.parse("../") ) end it "should have a route of 'resource/' from " + "'http://example.com/path/to/another'" do expect(@uri.route_from("http://example.com/path/to/another")).to eq( Addressable::URI.parse("resource/") ) end it "should have a route of 'resource/' from " + "'http://example.com/path/to/res'" do expect(@uri.route_from("http://example.com/path/to/res")).to eq( Addressable::URI.parse("resource/") ) end it "should have a route of 'resource/' from " + "'http://example.com:80/path/to/'" do expect(@uri.route_from("http://example.com:80/path/to/")).to eq( Addressable::URI.parse("resource/") ) end it "should have a route of 'http://example.com/path/to/' from " + "'http://example.com:8080/path/to/'" do expect(@uri.route_from("http://example.com:8080/path/to/")).to eq( Addressable::URI.parse("http://example.com/path/to/resource/") ) end it "should have a route of 'http://example.com/path/to/' from " + "'http://user:pass@example.com/path/to/'" do expect(@uri.route_from("http://user:pass@example.com/path/to/")).to eq( Addressable::URI.parse("http://example.com/path/to/resource/") ) end it "should have a route of '../../path/to/resource/' from " + "'http://example.com/to/resource/'" do expect(@uri.route_from("http://example.com/to/resource/")).to eq( Addressable::URI.parse("../../path/to/resource/") ) end it "should correctly convert to a hash" do expect(@uri.to_hash).to eq({ :scheme => "http", :user => nil, :password => nil, :host => "example.com", :port => nil, :path => "/path/to/resource/", :query => nil, :fragment => nil }) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end end describe Addressable::URI, "when parsed from " + "'relative/path/to/resource'" do before do @uri = Addressable::URI.parse("relative/path/to/resource") end it "should not have a scheme" do expect(@uri.scheme).to eq(nil) end it "should not be considered ip-based" do expect(@uri).not_to be_ip_based end it "should not have an authority segment" do expect(@uri.authority).to eq(nil) end it "should not have a host" do expect(@uri.host).to eq(nil) end it "should have no username" do expect(@uri.user).to eq(nil) end it "should have no password" do expect(@uri.password).to eq(nil) end it "should not have a port" do expect(@uri.port).to eq(nil) end it "should have a path of 'relative/path/to/resource'" do expect(@uri.path).to eq("relative/path/to/resource") end it "should have no query string" do expect(@uri.query).to eq(nil) end it "should have no fragment" do expect(@uri.fragment).to eq(nil) end it "should not be considered absolute" do expect(@uri).not_to be_absolute end it "should be considered relative" do expect(@uri).to be_relative end it "should raise an error if routing is attempted" do expect do @uri.route_to("http://example.com/") end.to raise_error(ArgumentError, /relative\/path\/to\/resource/) expect do @uri.route_from("http://example.com/") end.to raise_error(ArgumentError, /relative\/path\/to\/resource/) end it "when joined with 'another/relative/path' should be " + "'relative/path/to/another/relative/path'" do expect(@uri.join('another/relative/path')).to eq( Addressable::URI.parse("relative/path/to/another/relative/path") ) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end end describe Addressable::URI, "when parsed from " + "'relative_path_with_no_slashes'" do before do @uri = Addressable::URI.parse("relative_path_with_no_slashes") end it "should not have a scheme" do expect(@uri.scheme).to eq(nil) end it "should not be considered ip-based" do expect(@uri).not_to be_ip_based end it "should not have an authority segment" do expect(@uri.authority).to eq(nil) end it "should not have a host" do expect(@uri.host).to eq(nil) end it "should have no username" do expect(@uri.user).to eq(nil) end it "should have no password" do expect(@uri.password).to eq(nil) end it "should not have a port" do expect(@uri.port).to eq(nil) end it "should have a path of 'relative_path_with_no_slashes'" do expect(@uri.path).to eq("relative_path_with_no_slashes") end it "should have no query string" do expect(@uri.query).to eq(nil) end it "should have no fragment" do expect(@uri.fragment).to eq(nil) end it "should not be considered absolute" do expect(@uri).not_to be_absolute end it "should be considered relative" do expect(@uri).to be_relative end it "when joined with 'another_relative_path' should be " + "'another_relative_path'" do expect(@uri.join('another_relative_path')).to eq( Addressable::URI.parse("another_relative_path") ) end end describe Addressable::URI, "when parsed from " + "'http://example.com/file.txt'" do before do @uri = Addressable::URI.parse("http://example.com/file.txt") end it "should have a scheme of 'http'" do expect(@uri.scheme).to eq("http") end it "should have an authority segment of 'example.com'" do expect(@uri.authority).to eq("example.com") end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should have no username" do expect(@uri.user).to eq(nil) end it "should have no password" do expect(@uri.password).to eq(nil) end it "should use port 80" do expect(@uri.inferred_port).to eq(80) end it "should have a path of '/file.txt'" do expect(@uri.path).to eq("/file.txt") end it "should have a basename of 'file.txt'" do expect(@uri.basename).to eq("file.txt") end it "should have an extname of '.txt'" do expect(@uri.extname).to eq(".txt") end it "should have no query string" do expect(@uri.query).to eq(nil) end it "should have no fragment" do expect(@uri.fragment).to eq(nil) end end describe Addressable::URI, "when parsed from " + "'http://example.com/file.txt;parameter'" do before do @uri = Addressable::URI.parse("http://example.com/file.txt;parameter") end it "should have a scheme of 'http'" do expect(@uri.scheme).to eq("http") end it "should have an authority segment of 'example.com'" do expect(@uri.authority).to eq("example.com") end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should have no username" do expect(@uri.user).to eq(nil) end it "should have no password" do expect(@uri.password).to eq(nil) end it "should use port 80" do expect(@uri.inferred_port).to eq(80) end it "should have a path of '/file.txt;parameter'" do expect(@uri.path).to eq("/file.txt;parameter") end it "should have a basename of 'file.txt'" do expect(@uri.basename).to eq("file.txt") end it "should have an extname of '.txt'" do expect(@uri.extname).to eq(".txt") end it "should have no query string" do expect(@uri.query).to eq(nil) end it "should have no fragment" do expect(@uri.fragment).to eq(nil) end end describe Addressable::URI, "when parsed from " + "'http://example.com/file.txt;x=y'" do before do @uri = Addressable::URI.parse("http://example.com/file.txt;x=y") end it "should have a scheme of 'http'" do expect(@uri.scheme).to eq("http") end it "should have a scheme of 'http'" do expect(@uri.scheme).to eq("http") end it "should have an authority segment of 'example.com'" do expect(@uri.authority).to eq("example.com") end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should have no username" do expect(@uri.user).to eq(nil) end it "should have no password" do expect(@uri.password).to eq(nil) end it "should use port 80" do expect(@uri.inferred_port).to eq(80) end it "should have a path of '/file.txt;x=y'" do expect(@uri.path).to eq("/file.txt;x=y") end it "should have an extname of '.txt'" do expect(@uri.extname).to eq(".txt") end it "should have no query string" do expect(@uri.query).to eq(nil) end it "should have no fragment" do expect(@uri.fragment).to eq(nil) end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end end describe Addressable::URI, "when parsed from " + "'svn+ssh://developername@rubyforge.org/var/svn/project'" do before do @uri = Addressable::URI.parse( "svn+ssh://developername@rubyforge.org/var/svn/project" ) end it "should have a scheme of 'svn+ssh'" do expect(@uri.scheme).to eq("svn+ssh") end it "should be considered to be ip-based" do expect(@uri).to be_ip_based end it "should have a path of '/var/svn/project'" do expect(@uri.path).to eq("/var/svn/project") end it "should have a username of 'developername'" do expect(@uri.user).to eq("developername") end it "should have no password" do expect(@uri.password).to eq(nil) end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end end describe Addressable::URI, "when parsed from " + "'ssh+svn://developername@RUBYFORGE.ORG/var/svn/project'" do before do @uri = Addressable::URI.parse( "ssh+svn://developername@RUBYFORGE.ORG/var/svn/project" ) end it "should have a scheme of 'ssh+svn'" do expect(@uri.scheme).to eq("ssh+svn") end it "should have a normalized scheme of 'svn+ssh'" do expect(@uri.normalized_scheme).to eq("svn+ssh") end it "should have a normalized site of 'svn+ssh'" do expect(@uri.normalized_site).to eq("svn+ssh://developername@rubyforge.org") end it "should not be considered to be ip-based" do expect(@uri).not_to be_ip_based end it "should have a path of '/var/svn/project'" do expect(@uri.path).to eq("/var/svn/project") end it "should have a username of 'developername'" do expect(@uri.user).to eq("developername") end it "should have no password" do expect(@uri.password).to eq(nil) end it "should not be considered to be in normal form" do expect(@uri.normalize).not_to be_eql(@uri) end end describe Addressable::URI, "when parsed from " + "'mailto:user@example.com'" do before do @uri = Addressable::URI.parse("mailto:user@example.com") end it "should have a scheme of 'mailto'" do expect(@uri.scheme).to eq("mailto") end it "should not be considered to be ip-based" do expect(@uri).not_to be_ip_based end it "should have a path of 'user@example.com'" do expect(@uri.path).to eq("user@example.com") end it "should have no user" do expect(@uri.user).to eq(nil) end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end end describe Addressable::URI, "when parsed from " + "'tag:example.com,2006-08-18:/path/to/something'" do before do @uri = Addressable::URI.parse( "tag:example.com,2006-08-18:/path/to/something") end it "should have a scheme of 'tag'" do expect(@uri.scheme).to eq("tag") end it "should be considered to be ip-based" do expect(@uri).not_to be_ip_based end it "should have a path of " + "'example.com,2006-08-18:/path/to/something'" do expect(@uri.path).to eq("example.com,2006-08-18:/path/to/something") end it "should have no user" do expect(@uri.user).to eq(nil) end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end describe Addressable::URI, "when parsed from " + "'http://example.com/x;y/'" do before do @uri = Addressable::URI.parse("http://example.com/x;y/") end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end end describe Addressable::URI, "when parsed from " + "'http://example.com/?x=1&y=2'" do before do @uri = Addressable::URI.parse("http://example.com/?x=1&y=2") end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end end describe Addressable::URI, "when parsed from " + "'view-source:http://example.com/'" do before do @uri = Addressable::URI.parse("view-source:http://example.com/") end it "should have a scheme of 'view-source'" do expect(@uri.scheme).to eq("view-source") end it "should have a path of 'http://example.com/'" do expect(@uri.path).to eq("http://example.com/") end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end describe Addressable::URI, "when parsed from " + "'http://user:pass@example.com/path/to/resource?query=x#fragment'" do before do @uri = Addressable::URI.parse( "http://user:pass@example.com/path/to/resource?query=x#fragment") end it "should use the 'http' scheme" do expect(@uri.scheme).to eq("http") end it "should have an authority segment of 'user:pass@example.com'" do expect(@uri.authority).to eq("user:pass@example.com") end it "should have a username of 'user'" do expect(@uri.user).to eq("user") end it "should have a password of 'pass'" do expect(@uri.password).to eq("pass") end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should use port 80" do expect(@uri.inferred_port).to eq(80) end it "should have a path of '/path/to/resource'" do expect(@uri.path).to eq("/path/to/resource") end it "should have a query string of 'query=x'" do expect(@uri.query).to eq("query=x") end it "should have a fragment of 'fragment'" do expect(@uri.fragment).to eq("fragment") end it "should be considered to be in normal form" do expect(@uri.normalize).to be_eql(@uri) end it "should have a route of '../../' to " + "'http://user:pass@example.com/path/'" do expect(@uri.route_to("http://user:pass@example.com/path/")).to eq( Addressable::URI.parse("../../") ) end it "should have a route of 'to/resource?query=x#fragment' " + "from 'http://user:pass@example.com/path/'" do expect(@uri.route_from("http://user:pass@example.com/path/")).to eq( Addressable::URI.parse("to/resource?query=x#fragment") ) end it "should have a route of '?query=x#fragment' " + "from 'http://user:pass@example.com/path/to/resource'" do expect(@uri.route_from("http://user:pass@example.com/path/to/resource")).to eq( Addressable::URI.parse("?query=x#fragment") ) end it "should have a route of '#fragment' " + "from 'http://user:pass@example.com/path/to/resource?query=x'" do expect(@uri.route_from( "http://user:pass@example.com/path/to/resource?query=x")).to eq( Addressable::URI.parse("#fragment") ) end it "should have a route of '#fragment' from " + "'http://user:pass@example.com/path/to/resource?query=x#fragment'" do expect(@uri.route_from( "http://user:pass@example.com/path/to/resource?query=x#fragment" )).to eq(Addressable::URI.parse("#fragment")) end it "should have a route of 'http://elsewhere.com/' to " + "'http://elsewhere.com/'" do expect(@uri.route_to("http://elsewhere.com/")).to eq( Addressable::URI.parse("http://elsewhere.com/") ) end it "should have a route of " + "'http://user:pass@example.com/path/to/resource?query=x#fragment' " + "from 'http://example.com/path/to/'" do expect(@uri.route_from("http://elsewhere.com/path/to/")).to eq( Addressable::URI.parse( "http://user:pass@example.com/path/to/resource?query=x#fragment") ) end it "should have the correct scheme after assignment" do @uri.scheme = "ftp" expect(@uri.scheme).to eq("ftp") expect(@uri.to_s).to eq( "ftp://user:pass@example.com/path/to/resource?query=x#fragment" ) expect(@uri.to_str).to eq( "ftp://user:pass@example.com/path/to/resource?query=x#fragment" ) end it "should have the correct site segment after assignment" do @uri.site = "https://newuser:newpass@example.com:443" expect(@uri.scheme).to eq("https") expect(@uri.authority).to eq("newuser:newpass@example.com:443") expect(@uri.user).to eq("newuser") expect(@uri.password).to eq("newpass") expect(@uri.userinfo).to eq("newuser:newpass") expect(@uri.normalized_userinfo).to eq("newuser:newpass") expect(@uri.host).to eq("example.com") expect(@uri.port).to eq(443) expect(@uri.inferred_port).to eq(443) expect(@uri.to_s).to eq( "https://newuser:newpass@example.com:443" + "/path/to/resource?query=x#fragment" ) end it "should have the correct authority segment after assignment" do @uri.authority = "newuser:newpass@example.com:80" expect(@uri.authority).to eq("newuser:newpass@example.com:80") expect(@uri.user).to eq("newuser") expect(@uri.password).to eq("newpass") expect(@uri.userinfo).to eq("newuser:newpass") expect(@uri.normalized_userinfo).to eq("newuser:newpass") expect(@uri.host).to eq("example.com") expect(@uri.port).to eq(80) expect(@uri.inferred_port).to eq(80) expect(@uri.to_s).to eq( "http://newuser:newpass@example.com:80" + "/path/to/resource?query=x#fragment" ) end it "should have the correct userinfo segment after assignment" do @uri.userinfo = "newuser:newpass" expect(@uri.userinfo).to eq("newuser:newpass") expect(@uri.authority).to eq("newuser:newpass@example.com") expect(@uri.user).to eq("newuser") expect(@uri.password).to eq("newpass") expect(@uri.host).to eq("example.com") expect(@uri.port).to eq(nil) expect(@uri.inferred_port).to eq(80) expect(@uri.to_s).to eq( "http://newuser:newpass@example.com" + "/path/to/resource?query=x#fragment" ) end it "should have the correct username after assignment" do @uri.user = "newuser" expect(@uri.user).to eq("newuser") expect(@uri.authority).to eq("newuser:pass@example.com") end it "should have the correct password after assignment" do @uri.password = "newpass" expect(@uri.password).to eq("newpass") expect(@uri.authority).to eq("user:newpass@example.com") end it "should have the correct host after assignment" do @uri.host = "newexample.com" expect(@uri.host).to eq("newexample.com") expect(@uri.authority).to eq("user:pass@newexample.com") end it "should have the correct host after assignment" do @uri.hostname = "newexample.com" expect(@uri.host).to eq("newexample.com") expect(@uri.hostname).to eq("newexample.com") expect(@uri.authority).to eq("user:pass@newexample.com") end it "should raise an error if assigning a bogus object to the hostname" do expect do @uri.hostname = Object.new end.to raise_error(TypeError) end it "should have the correct port after assignment" do @uri.port = 8080 expect(@uri.port).to eq(8080) expect(@uri.authority).to eq("user:pass@example.com:8080") end it "should have the correct origin after assignment" do @uri.origin = "http://newexample.com" expect(@uri.host).to eq("newexample.com") expect(@uri.authority).to eq("newexample.com") end it "should have the correct path after assignment" do @uri.path = "/newpath/to/resource" expect(@uri.path).to eq("/newpath/to/resource") expect(@uri.to_s).to eq( "http://user:pass@example.com/newpath/to/resource?query=x#fragment" ) end it "should have the correct scheme and authority after nil assignment" do @uri.site = nil expect(@uri.scheme).to eq(nil) expect(@uri.authority).to eq(nil) expect(@uri.to_s).to eq("/path/to/resource?query=x#fragment") end it "should have the correct scheme and authority after assignment" do @uri.site = "file://" expect(@uri.scheme).to eq("file") expect(@uri.authority).to eq("") expect(@uri.to_s).to eq("file:///path/to/resource?query=x#fragment") end it "should have the correct path after nil assignment" do @uri.path = nil expect(@uri.path).to eq("") expect(@uri.to_s).to eq( "http://user:pass@example.com?query=x#fragment" ) end it "should have the correct query string after assignment" do @uri.query = "newquery=x" expect(@uri.query).to eq("newquery=x") expect(@uri.to_s).to eq( "http://user:pass@example.com/path/to/resource?newquery=x#fragment" ) @uri.query = nil expect(@uri.query).to eq(nil) expect(@uri.to_s).to eq( "http://user:pass@example.com/path/to/resource#fragment" ) end it "should have the correct query string after hash assignment" do @uri.query_values = {"?uestion mark" => "=sign", "hello" => "g\xC3\xBCnther"} expect(@uri.query.split("&")).to include("%3Fuestion%20mark=%3Dsign") expect(@uri.query.split("&")).to include("hello=g%C3%BCnther") expect(@uri.query_values).to eq({ "?uestion mark" => "=sign", "hello" => "g\xC3\xBCnther" }) end it "should have the correct query string after flag hash assignment" do @uri.query_values = {'flag?1' => nil, 'fl=ag2' => nil, 'flag3' => nil} expect(@uri.query.split("&")).to include("flag%3F1") expect(@uri.query.split("&")).to include("fl%3Dag2") expect(@uri.query.split("&")).to include("flag3") expect(@uri.query_values(Array).sort).to eq([["fl=ag2"], ["flag3"], ["flag?1"]]) expect(@uri.query_values(Hash)).to eq({ 'flag?1' => nil, 'fl=ag2' => nil, 'flag3' => nil }) end it "should raise an error if query values are set to a bogus type" do expect do @uri.query_values = "bogus" end.to raise_error(TypeError) end it "should have the correct fragment after assignment" do @uri.fragment = "newfragment" expect(@uri.fragment).to eq("newfragment") expect(@uri.to_s).to eq( "http://user:pass@example.com/path/to/resource?query=x#newfragment" ) @uri.fragment = nil expect(@uri.fragment).to eq(nil) expect(@uri.to_s).to eq( "http://user:pass@example.com/path/to/resource?query=x" ) end it "should have the correct values after a merge" do expect(@uri.merge(:fragment => "newfragment").to_s).to eq( "http://user:pass@example.com/path/to/resource?query=x#newfragment" ) end it "should have the correct values after a merge" do expect(@uri.merge(:fragment => nil).to_s).to eq( "http://user:pass@example.com/path/to/resource?query=x" ) end it "should have the correct values after a merge" do expect(@uri.merge(:userinfo => "newuser:newpass").to_s).to eq( "http://newuser:newpass@example.com/path/to/resource?query=x#fragment" ) end it "should have the correct values after a merge" do expect(@uri.merge(:userinfo => nil).to_s).to eq( "http://example.com/path/to/resource?query=x#fragment" ) end it "should have the correct values after a merge" do expect(@uri.merge(:path => "newpath").to_s).to eq( "http://user:pass@example.com/newpath?query=x#fragment" ) end it "should have the correct values after a merge" do expect(@uri.merge(:port => "42", :path => "newpath", :query => "").to_s).to eq( "http://user:pass@example.com:42/newpath?#fragment" ) end it "should have the correct values after a merge" do expect(@uri.merge(:authority => "foo:bar@baz:42").to_s).to eq( "http://foo:bar@baz:42/path/to/resource?query=x#fragment" ) # Ensure the operation was not destructive expect(@uri.to_s).to eq( "http://user:pass@example.com/path/to/resource?query=x#fragment" ) end it "should have the correct values after a destructive merge" do @uri.merge!(:authority => "foo:bar@baz:42") # Ensure the operation was destructive expect(@uri.to_s).to eq( "http://foo:bar@baz:42/path/to/resource?query=x#fragment" ) end it "should fail to merge with bogus values" do expect do @uri.merge(:port => "bogus") end.to raise_error(Addressable::URI::InvalidURIError) end it "should fail to merge with bogus values" do expect do @uri.merge(:authority => "bar@baz:bogus") end.to raise_error(Addressable::URI::InvalidURIError) end it "should fail to merge with bogus parameters" do expect do @uri.merge(42) end.to raise_error(TypeError) end it "should fail to merge with bogus parameters" do expect do @uri.merge("http://example.com/") end.to raise_error(TypeError) end it "should fail to merge with both authority and subcomponents" do expect do @uri.merge(:authority => "foo:bar@baz:42", :port => "42") end.to raise_error(ArgumentError) end it "should fail to merge with both userinfo and subcomponents" do expect do @uri.merge(:userinfo => "foo:bar", :user => "foo") end.to raise_error(ArgumentError) end it "should be identical to its duplicate" do expect(@uri).to eq(@uri.dup) end it "should have an origin of 'http://example.com'" do expect(@uri.origin).to eq('http://example.com') end end describe Addressable::URI, "when parsed from " + "'http://example.com/search?q=Q%26A'" do before do @uri = Addressable::URI.parse("http://example.com/search?q=Q%26A") end it "should have a query of 'q=Q%26A'" do expect(@uri.query).to eq("q=Q%26A") end it "should have query_values of {'q' => 'Q&A'}" do expect(@uri.query_values).to eq({ 'q' => 'Q&A' }) end it "should normalize to the original uri " + "(with the ampersand properly percent-encoded)" do expect(@uri.normalize.to_s).to eq("http://example.com/search?q=Q%26A") end end describe Addressable::URI, "when parsed from " + "'http://example.com/?&x=b'" do before do @uri = Addressable::URI.parse("http://example.com/?&x=b") end it "should have a query of '&x=b'" do expect(@uri.query).to eq("&x=b") end it "should have query_values of {'x' => 'b'}" do expect(@uri.query_values).to eq({'x' => 'b'}) end end describe Addressable::URI, "when parsed from " + "'http://example.com/?q='one;two'&x=1'" do before do @uri = Addressable::URI.parse("http://example.com/?q='one;two'&x=1") end it "should have a query of 'q='one;two'&x=1'" do expect(@uri.query).to eq("q='one;two'&x=1") end it "should have query_values of {\"q\" => \"'one;two'\", \"x\" => \"1\"}" do expect(@uri.query_values).to eq({"q" => "'one;two'", "x" => "1"}) end it "should escape the ';' character when normalizing to avoid ambiguity " + "with the W3C HTML 4.01 specification" do # HTML 4.01 Section B.2.2 expect(@uri.normalize.query).to eq("q='one%3Btwo'&x=1") end end describe Addressable::URI, "when parsed from " + "'http://example.com/?&&x=b'" do before do @uri = Addressable::URI.parse("http://example.com/?&&x=b") end it "should have a query of '&&x=b'" do expect(@uri.query).to eq("&&x=b") end it "should have query_values of {'x' => 'b'}" do expect(@uri.query_values).to eq({'x' => 'b'}) end end describe Addressable::URI, "when parsed from " + "'http://example.com/?q=a&&x=b'" do before do @uri = Addressable::URI.parse("http://example.com/?q=a&&x=b") end it "should have a query of 'q=a&&x=b'" do expect(@uri.query).to eq("q=a&&x=b") end it "should have query_values of {'q' => 'a, 'x' => 'b'}" do expect(@uri.query_values).to eq({'q' => 'a', 'x' => 'b'}) end end describe Addressable::URI, "when parsed from " + "'http://example.com/?q&&x=b'" do before do @uri = Addressable::URI.parse("http://example.com/?q&&x=b") end it "should have a query of 'q&&x=b'" do expect(@uri.query).to eq("q&&x=b") end it "should have query_values of {'q' => true, 'x' => 'b'}" do expect(@uri.query_values).to eq({'q' => nil, 'x' => 'b'}) end end describe Addressable::URI, "when parsed from " + "'http://example.com/?q=a+b'" do before do @uri = Addressable::URI.parse("http://example.com/?q=a+b") end it "should have a query of 'q=a+b'" do expect(@uri.query).to eq("q=a+b") end it "should have query_values of {'q' => 'a b'}" do expect(@uri.query_values).to eq({'q' => 'a b'}) end it "should have a normalized query of 'q=a+b'" do expect(@uri.normalized_query).to eq("q=a+b") end end describe Addressable::URI, "when parsed from 'https://example.com/?q=a+b'" do before do @uri = Addressable::URI.parse("https://example.com/?q=a+b") end it "should have query_values of {'q' => 'a b'}" do expect(@uri.query_values).to eq("q" => "a b") end end describe Addressable::URI, "when parsed from 'example.com?q=a+b'" do before do @uri = Addressable::URI.parse("example.com?q=a+b") end it "should have query_values of {'q' => 'a b'}" do expect(@uri.query_values).to eq("q" => "a b") end end describe Addressable::URI, "when parsed from 'mailto:?q=a+b'" do before do @uri = Addressable::URI.parse("mailto:?q=a+b") end it "should have query_values of {'q' => 'a+b'}" do expect(@uri.query_values).to eq("q" => "a+b") end end describe Addressable::URI, "when parsed from " + "'http://example.com/?q=a%2bb'" do before do @uri = Addressable::URI.parse("http://example.com/?q=a%2bb") end it "should have a query of 'q=a+b'" do expect(@uri.query).to eq("q=a%2bb") end it "should have query_values of {'q' => 'a+b'}" do expect(@uri.query_values).to eq({'q' => 'a+b'}) end it "should have a normalized query of 'q=a%2Bb'" do expect(@uri.normalized_query).to eq("q=a%2Bb") end end describe Addressable::URI, "when parsed from " + "'http://example.com/?v=%7E&w=%&x=%25&y=%2B&z=C%CC%A7'" do before do @uri = Addressable::URI.parse("http://example.com/?v=%7E&w=%&x=%25&y=%2B&z=C%CC%A7") end it "should have a normalized query of 'v=~&w=%25&x=%25&y=%2B&z=%C3%87'" do expect(@uri.normalized_query).to eq("v=~&w=%25&x=%25&y=%2B&z=%C3%87") end end describe Addressable::URI, "when parsed from " + "'http://example.com/?v=%7E&w=%&x=%25&y=+&z=C%CC%A7'" do before do @uri = Addressable::URI.parse("http://example.com/?v=%7E&w=%&x=%25&y=+&z=C%CC%A7") end it "should have a normalized query of 'v=~&w=%25&x=%25&y=+&z=%C3%87'" do expect(@uri.normalized_query).to eq("v=~&w=%25&x=%25&y=+&z=%C3%87") end end describe Addressable::URI, "when parsed from 'http://example/?b=1&a=2&c=3'" do before do @uri = Addressable::URI.parse("http://example/?b=1&a=2&c=3") end it "should have a sorted normalized query of 'a=2&b=1&c=3'" do expect(@uri.normalized_query(:sorted)).to eq("a=2&b=1&c=3") end end describe Addressable::URI, "when parsed from 'http://example/?&a&&c&'" do before do @uri = Addressable::URI.parse("http://example/?&a&&c&") end it "should have a compacted normalized query of 'a&c'" do expect(@uri.normalized_query(:compacted)).to eq("a&c") end end describe Addressable::URI, "when parsed from 'http://example.com/?a=1&a=1'" do before do @uri = Addressable::URI.parse("http://example.com/?a=1&a=1") end it "should have a compacted normalized query of 'a=1'" do expect(@uri.normalized_query(:compacted)).to eq("a=1") end end describe Addressable::URI, "when parsed from 'http://example.com/?a=1&a=2'" do before do @uri = Addressable::URI.parse("http://example.com/?a=1&a=2") end it "should have a compacted normalized query of 'a=1&a=2'" do expect(@uri.normalized_query(:compacted)).to eq("a=1&a=2") end end describe Addressable::URI, "when parsed from " + "'http://example.com/sound%2bvision'" do before do @uri = Addressable::URI.parse("http://example.com/sound%2bvision") end it "should have a normalized path of '/sound+vision'" do expect(@uri.normalized_path).to eq('/sound+vision') end end describe Addressable::URI, "when parsed from " + "'http://example.com/?q='" do before do @uri = Addressable::URI.parse("http://example.com/?q=") end it "should have a query of 'q='" do expect(@uri.query).to eq("q=") end it "should have query_values of {'q' => ''}" do expect(@uri.query_values).to eq({'q' => ''}) end end describe Addressable::URI, "when parsed from " + "'http://user@example.com'" do before do @uri = Addressable::URI.parse("http://user@example.com") end it "should use the 'http' scheme" do expect(@uri.scheme).to eq("http") end it "should have a username of 'user'" do expect(@uri.user).to eq("user") end it "should have no password" do expect(@uri.password).to eq(nil) end it "should have a userinfo of 'user'" do expect(@uri.userinfo).to eq("user") end it "should have a normalized userinfo of 'user'" do expect(@uri.normalized_userinfo).to eq("user") end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should have default_port 80" do expect(@uri.default_port).to eq(80) end it "should use port 80" do expect(@uri.inferred_port).to eq(80) end it "should have the correct username after assignment" do @uri.user = "newuser" expect(@uri.user).to eq("newuser") expect(@uri.password).to eq(nil) expect(@uri.to_s).to eq("http://newuser@example.com") end it "should have the correct password after assignment" do @uri.password = "newpass" expect(@uri.password).to eq("newpass") expect(@uri.to_s).to eq("http://user:newpass@example.com") end it "should have the correct userinfo segment after assignment" do @uri.userinfo = "newuser:newpass" expect(@uri.userinfo).to eq("newuser:newpass") expect(@uri.user).to eq("newuser") expect(@uri.password).to eq("newpass") expect(@uri.host).to eq("example.com") expect(@uri.port).to eq(nil) expect(@uri.inferred_port).to eq(80) expect(@uri.to_s).to eq("http://newuser:newpass@example.com") end it "should have the correct userinfo segment after nil assignment" do @uri.userinfo = nil expect(@uri.userinfo).to eq(nil) expect(@uri.user).to eq(nil) expect(@uri.password).to eq(nil) expect(@uri.host).to eq("example.com") expect(@uri.port).to eq(nil) expect(@uri.inferred_port).to eq(80) expect(@uri.to_s).to eq("http://example.com") end it "should have the correct authority segment after assignment" do @uri.authority = "newuser@example.com" expect(@uri.authority).to eq("newuser@example.com") expect(@uri.user).to eq("newuser") expect(@uri.password).to eq(nil) expect(@uri.host).to eq("example.com") expect(@uri.port).to eq(nil) expect(@uri.inferred_port).to eq(80) expect(@uri.to_s).to eq("http://newuser@example.com") end it "should raise an error after nil assignment of authority segment" do expect do # This would create an invalid URI @uri.authority = nil end.to raise_error(Addressable::URI::InvalidURIError) end end describe Addressable::URI, "when parsed from " + "'http://user:@example.com'" do before do @uri = Addressable::URI.parse("http://user:@example.com") end it "should use the 'http' scheme" do expect(@uri.scheme).to eq("http") end it "should have a username of 'user'" do expect(@uri.user).to eq("user") end it "should have a password of ''" do expect(@uri.password).to eq("") end it "should have a normalized userinfo of 'user:'" do expect(@uri.normalized_userinfo).to eq("user:") end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should use port 80" do expect(@uri.inferred_port).to eq(80) end it "should have the correct username after assignment" do @uri.user = "newuser" expect(@uri.user).to eq("newuser") expect(@uri.password).to eq("") expect(@uri.to_s).to eq("http://newuser:@example.com") end it "should have the correct password after assignment" do @uri.password = "newpass" expect(@uri.password).to eq("newpass") expect(@uri.to_s).to eq("http://user:newpass@example.com") end it "should have the correct authority segment after assignment" do @uri.authority = "newuser:@example.com" expect(@uri.authority).to eq("newuser:@example.com") expect(@uri.user).to eq("newuser") expect(@uri.password).to eq("") expect(@uri.host).to eq("example.com") expect(@uri.port).to eq(nil) expect(@uri.inferred_port).to eq(80) expect(@uri.to_s).to eq("http://newuser:@example.com") end end describe Addressable::URI, "when parsed from " + "'http://:pass@example.com'" do before do @uri = Addressable::URI.parse("http://:pass@example.com") end it "should use the 'http' scheme" do expect(@uri.scheme).to eq("http") end it "should have a username of ''" do expect(@uri.user).to eq("") end it "should have a password of 'pass'" do expect(@uri.password).to eq("pass") end it "should have a userinfo of ':pass'" do expect(@uri.userinfo).to eq(":pass") end it "should have a normalized userinfo of ':pass'" do expect(@uri.normalized_userinfo).to eq(":pass") end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should use port 80" do expect(@uri.inferred_port).to eq(80) end it "should have the correct username after assignment" do @uri.user = "newuser" expect(@uri.user).to eq("newuser") expect(@uri.password).to eq("pass") expect(@uri.to_s).to eq("http://newuser:pass@example.com") end it "should have the correct password after assignment" do @uri.password = "newpass" expect(@uri.password).to eq("newpass") expect(@uri.user).to eq("") expect(@uri.to_s).to eq("http://:newpass@example.com") end it "should have the correct authority segment after assignment" do @uri.authority = ":newpass@example.com" expect(@uri.authority).to eq(":newpass@example.com") expect(@uri.user).to eq("") expect(@uri.password).to eq("newpass") expect(@uri.host).to eq("example.com") expect(@uri.port).to eq(nil) expect(@uri.inferred_port).to eq(80) expect(@uri.to_s).to eq("http://:newpass@example.com") end end describe Addressable::URI, "when parsed from " + "'http://:@example.com'" do before do @uri = Addressable::URI.parse("http://:@example.com") end it "should use the 'http' scheme" do expect(@uri.scheme).to eq("http") end it "should have a username of ''" do expect(@uri.user).to eq("") end it "should have a password of ''" do expect(@uri.password).to eq("") end it "should have a normalized userinfo of nil" do expect(@uri.normalized_userinfo).to eq(nil) end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should use port 80" do expect(@uri.inferred_port).to eq(80) end it "should have the correct username after assignment" do @uri.user = "newuser" expect(@uri.user).to eq("newuser") expect(@uri.password).to eq("") expect(@uri.to_s).to eq("http://newuser:@example.com") end it "should have the correct password after assignment" do @uri.password = "newpass" expect(@uri.password).to eq("newpass") expect(@uri.user).to eq("") expect(@uri.to_s).to eq("http://:newpass@example.com") end it "should have the correct authority segment after assignment" do @uri.authority = ":@newexample.com" expect(@uri.authority).to eq(":@newexample.com") expect(@uri.user).to eq("") expect(@uri.password).to eq("") expect(@uri.host).to eq("newexample.com") expect(@uri.port).to eq(nil) expect(@uri.inferred_port).to eq(80) expect(@uri.to_s).to eq("http://:@newexample.com") end end describe Addressable::URI, "when parsed from " + "'#example'" do before do @uri = Addressable::URI.parse("#example") end it "should be considered relative" do expect(@uri).to be_relative end it "should have a host of nil" do expect(@uri.host).to eq(nil) end it "should have a site of nil" do expect(@uri.site).to eq(nil) end it "should have a normalized_site of nil" do expect(@uri.normalized_site).to eq(nil) end it "should have a path of ''" do expect(@uri.path).to eq("") end it "should have a query string of nil" do expect(@uri.query).to eq(nil) end it "should have a fragment of 'example'" do expect(@uri.fragment).to eq("example") end end describe Addressable::URI, "when parsed from " + "the network-path reference '//example.com/'" do before do @uri = Addressable::URI.parse("//example.com/") end it "should be considered relative" do expect(@uri).to be_relative end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should have a path of '/'" do expect(@uri.path).to eq("/") end it "should raise an error if routing is attempted" do expect do @uri.route_to("http://example.com/") end.to raise_error(ArgumentError, /\/\/example.com\//) expect do @uri.route_from("http://example.com/") end.to raise_error(ArgumentError, /\/\/example.com\//) end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end describe Addressable::URI, "when parsed from " + "'feed://http://example.com/'" do before do @uri = Addressable::URI.parse("feed://http://example.com/") end it "should have a host of 'http'" do expect(@uri.host).to eq("http") end it "should have a path of '//example.com/'" do expect(@uri.path).to eq("//example.com/") end end describe Addressable::URI, "when parsed from " + "'feed:http://example.com/'" do before do @uri = Addressable::URI.parse("feed:http://example.com/") end it "should have a path of 'http://example.com/'" do expect(@uri.path).to eq("http://example.com/") end it "should normalize to 'http://example.com/'" do expect(@uri.normalize.to_s).to eq("http://example.com/") expect(@uri.normalize!.to_s).to eq("http://example.com/") end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end describe Addressable::URI, "when parsed from " + "'example://a/b/c/%7Bfoo%7D'" do before do @uri = Addressable::URI.parse("example://a/b/c/%7Bfoo%7D") end # Section 6.2.2 of RFC 3986 it "should be equivalent to eXAMPLE://a/./b/../b/%63/%7bfoo%7d" do expect(@uri).to eq( Addressable::URI.parse("eXAMPLE://a/./b/../b/%63/%7bfoo%7d") ) end it "should have an origin of 'example://a'" do expect(@uri.origin).to eq('example://a') end end describe Addressable::URI, "when parsed from " + "'http://example.com/indirect/path/./to/../resource/'" do before do @uri = Addressable::URI.parse( "http://example.com/indirect/path/./to/../resource/") end it "should use the 'http' scheme" do expect(@uri.scheme).to eq("http") end it "should have a host of 'example.com'" do expect(@uri.host).to eq("example.com") end it "should use port 80" do expect(@uri.inferred_port).to eq(80) end it "should have a path of '/indirect/path/./to/../resource/'" do expect(@uri.path).to eq("/indirect/path/./to/../resource/") end # Section 6.2.2.3 of RFC 3986 it "should have a normalized path of '/indirect/path/resource/'" do expect(@uri.normalize.path).to eq("/indirect/path/resource/") expect(@uri.normalize!.path).to eq("/indirect/path/resource/") end end describe Addressable::URI, "when parsed from " + "'http://under_score.example.com/'" do it "should not cause an error" do expect do Addressable::URI.parse("http://under_score.example.com/") end.not_to raise_error end end describe Addressable::URI, "when parsed from " + "'./this:that'" do before do @uri = Addressable::URI.parse("./this:that") end it "should be considered relative" do expect(@uri).to be_relative end it "should have no scheme" do expect(@uri.scheme).to eq(nil) end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end describe Addressable::URI, "when parsed from " + "'this:that'" do before do @uri = Addressable::URI.parse("this:that") end it "should be considered absolute" do expect(@uri).to be_absolute end it "should have a scheme of 'this'" do expect(@uri.scheme).to eq("this") end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end describe Addressable::URI, "when parsed from '?'" do before do @uri = Addressable::URI.parse("?") end it "should normalize to ''" do expect(@uri.normalize.to_s).to eq("") end it "should have the correct return type" do expect(@uri.query_values).to eq({}) expect(@uri.query_values(Hash)).to eq({}) expect(@uri.query_values(Array)).to eq([]) end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end describe Addressable::URI, "when parsed from '?one=1&two=2&three=3'" do before do @uri = Addressable::URI.parse("?one=1&two=2&three=3") end it "should have the correct query values" do expect(@uri.query_values).to eq({"one" => "1", "two" => "2", "three" => "3"}) end it "should raise an error for invalid return type values" do expect do @uri.query_values(Integer) end.to raise_error(ArgumentError) end it "should have the correct array query values" do expect(@uri.query_values(Array)).to eq([ ["one", "1"], ["two", "2"], ["three", "3"] ]) end it "should have a 'null' origin" do expect(@uri.origin).to eq('null') end end describe Addressable::URI, "when parsed from '?one=1=uno&two=2=dos'" do before do @uri = Addressable::URI.parse("?one=1=uno&two=2=dos") end it "should have the correct query values" do expect(@uri.query_values).to eq({"one" => "1=uno", "two" => "2=dos"}) end it "should have the correct array query values" do expect(@uri.query_values(Array)).to eq([ ["one", "1=uno"], ["two", "2=dos"] ]) end end describe Addressable::URI, "when parsed from '?one[two][three]=four'" do before do @uri = Addressable::URI.parse("?one[two][three]=four") end it "should have the correct query values" do expect(@uri.query_values).to eq({"one[two][three]" => "four"}) end it "should have the correct array query values" do expect(@uri.query_values(Array)).to eq([ ["one[two][three]", "four"] ]) end end describe Addressable::URI, "when parsed from '?one.two.three=four'" do before do @uri = Addressable::URI.parse("?one.two.three=four") end it "should have the correct query values" do expect(@uri.query_values).to eq({ "one.two.three" => "four" }) end it "should have the correct array query values" do expect(@uri.query_values(Array)).to eq([ ["one.two.three", "four"] ]) end end describe Addressable::URI, "when parsed from " + "'?one[two][three]=four&one[two][five]=six'" do before do @uri = Addressable::URI.parse("?one[two][three]=four&one[two][five]=six") end it "should have the correct query values" do expect(@uri.query_values).to eq({ "one[two][three]" => "four", "one[two][five]" => "six" }) end it "should have the correct array query values" do expect(@uri.query_values(Array)).to eq([ ["one[two][three]", "four"], ["one[two][five]", "six"] ]) end end describe Addressable::URI, "when parsed from " + "'?one.two.three=four&one.two.five=six'" do before do @uri = Addressable::URI.parse("?one.two.three=four&one.two.five=six") end it "should have the correct query values" do expect(@uri.query_values).to eq({ "one.two.three" => "four", "one.two.five" => "six" }) end it "should have the correct array query values" do expect(@uri.query_values(Array)).to eq([ ["one.two.three", "four"], ["one.two.five", "six"] ]) end end describe Addressable::URI, "when parsed from " + "'?one=two&one=three'" do before do @uri = Addressable::URI.parse( "?one=two&one=three&one=four" ) end it "should have correct array query values" do expect(@uri.query_values(Array)).to eq( [['one', 'two'], ['one', 'three'], ['one', 'four']] ) end it "should have correct hash query values" do skip("This is probably more desirable behavior.") expect(@uri.query_values(Hash)).to eq( {'one' => ['two', 'three', 'four']} ) end it "should handle assignment with keys of mixed type" do @uri.query_values = @uri.query_values(Hash).merge({:one => 'three'}) expect(@uri.query_values(Hash)).to eq({'one' => 'three'}) end end describe Addressable::URI, "when parsed from " + "'?one[two][three][]=four&one[two][three][]=five'" do before do @uri = Addressable::URI.parse( "?one[two][three][]=four&one[two][three][]=five" ) end it "should have correct query values" do expect(@uri.query_values(Hash)).to eq({"one[two][three][]" => "five"}) end it "should have correct array query values" do expect(@uri.query_values(Array)).to eq([ ["one[two][three][]", "four"], ["one[two][three][]", "five"] ]) end end describe Addressable::URI, "when parsed from " + "'?one[two][three][0]=four&one[two][three][1]=five'" do before do @uri = Addressable::URI.parse( "?one[two][three][0]=four&one[two][three][1]=five" ) end it "should have the correct query values" do expect(@uri.query_values).to eq({ "one[two][three][0]" => "four", "one[two][three][1]" => "five" }) end end describe Addressable::URI, "when parsed from " + "'?one[two][three][1]=four&one[two][three][0]=five'" do before do @uri = Addressable::URI.parse( "?one[two][three][1]=four&one[two][three][0]=five" ) end it "should have the correct query values" do expect(@uri.query_values).to eq({ "one[two][three][1]" => "four", "one[two][three][0]" => "five" }) end end describe Addressable::URI, "when parsed from " + "'?one[two][three][2]=four&one[two][three][1]=five'" do before do @uri = Addressable::URI.parse( "?one[two][three][2]=four&one[two][three][1]=five" ) end it "should have the correct query values" do expect(@uri.query_values).to eq({ "one[two][three][2]" => "four", "one[two][three][1]" => "five" }) end end describe Addressable::URI, "when parsed from " + "'http://www.詹姆斯.com/'" do before do @uri = Addressable::URI.parse("http://www.詹姆斯.com/") end it "should be equivalent to 'http://www.xn--8ws00zhy3a.com/'" do expect(@uri).to eq( Addressable::URI.parse("http://www.xn--8ws00zhy3a.com/") ) end it "should not have domain name encoded during normalization" do expect(Addressable::URI.normalized_encode(@uri.to_s)).to eq( "http://www.詹姆斯.com/" ) end it "should have an origin of 'http://www.xn--8ws00zhy3a.com'" do expect(@uri.origin).to eq('http://www.xn--8ws00zhy3a.com') end end describe Addressable::URI, "when parsed from " + "'http://www.詹姆斯.com/ some spaces /'" do before do @uri = Addressable::URI.parse("http://www.詹姆斯.com/ some spaces /") end it "should be equivalent to " + "'http://www.xn--8ws00zhy3a.com/%20some%20spaces%20/'" do expect(@uri).to eq( Addressable::URI.parse( "http://www.xn--8ws00zhy3a.com/%20some%20spaces%20/") ) end it "should not have domain name encoded during normalization" do expect(Addressable::URI.normalized_encode(@uri.to_s)).to eq( "http://www.詹姆斯.com/%20some%20spaces%20/" ) end it "should have an origin of 'http://www.xn--8ws00zhy3a.com'" do expect(@uri.origin).to eq('http://www.xn--8ws00zhy3a.com') end end describe Addressable::URI, "when parsed from " + "'http://www.xn--8ws00zhy3a.com/'" do before do @uri = Addressable::URI.parse("http://www.xn--8ws00zhy3a.com/") end it "should be displayed as http://www.詹姆斯.com/" do expect(@uri.display_uri.to_s).to eq("http://www.詹姆斯.com/") end it "should properly force the encoding" do display_string = @uri.display_uri.to_str expect(display_string).to eq("http://www.詹姆斯.com/") if display_string.respond_to?(:encoding) expect(display_string.encoding.to_s).to eq(Encoding::UTF_8.to_s) end end it "should have an origin of 'http://www.xn--8ws00zhy3a.com'" do expect(@uri.origin).to eq('http://www.xn--8ws00zhy3a.com') end end describe Addressable::URI, "when parsed from " + "'http://www.詹姆斯.com/atomtests/iri/詹.html'" do before do @uri = Addressable::URI.parse("http://www.詹姆斯.com/atomtests/iri/詹.html") end it "should normalize to " + "http://www.xn--8ws00zhy3a.com/atomtests/iri/%E8%A9%B9.html" do expect(@uri.normalize.to_s).to eq( "http://www.xn--8ws00zhy3a.com/atomtests/iri/%E8%A9%B9.html" ) expect(@uri.normalize!.to_s).to eq( "http://www.xn--8ws00zhy3a.com/atomtests/iri/%E8%A9%B9.html" ) end end describe Addressable::URI, "when parsed from a percent-encoded IRI" do before do @uri = Addressable::URI.parse( "http://www.%E3%81%BB%E3%82%93%E3%81%A8%E3%81%86%E3%81%AB%E3%81%AA" + "%E3%81%8C%E3%81%84%E3%82%8F%E3%81%91%E3%81%AE%E3%82%8F%E3%81%8B%E3" + "%82%89%E3%81%AA%E3%81%84%E3%81%A9%E3%82%81%E3%81%84%E3%82%93%E3%82" + "%81%E3%81%84%E3%81%AE%E3%82%89%E3%81%B9%E3%82%8B%E3%81%BE%E3%81%A0" + "%E3%81%AA%E3%81%8C%E3%81%8F%E3%81%97%E3%81%AA%E3%81%84%E3%81%A8%E3" + "%81%9F%E3%82%8A%E3%81%AA%E3%81%84.w3.mag.keio.ac.jp" ) end it "should normalize to something sane" do expect(@uri.normalize.to_s).to eq( "http://www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3f" + "g11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp/" ) expect(@uri.normalize!.to_s).to eq( "http://www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3f" + "g11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp/" ) end it "should have the correct origin" do expect(@uri.origin).to eq( "http://www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3f" + "g11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp" ) end end describe Addressable::URI, "with a base uri of 'http://a/b/c/d;p?q'" do before do @uri = Addressable::URI.parse("http://a/b/c/d;p?q") end # Section 5.4.1 of RFC 3986 it "when joined with 'g:h' should resolve to g:h" do expect((@uri + "g:h").to_s).to eq("g:h") expect(Addressable::URI.join(@uri, "g:h").to_s).to eq("g:h") end # Section 5.4.1 of RFC 3986 it "when joined with 'g' should resolve to http://a/b/c/g" do expect((@uri + "g").to_s).to eq("http://a/b/c/g") expect(Addressable::URI.join(@uri.to_s, "g").to_s).to eq("http://a/b/c/g") end # Section 5.4.1 of RFC 3986 it "when joined with './g' should resolve to http://a/b/c/g" do expect((@uri + "./g").to_s).to eq("http://a/b/c/g") expect(Addressable::URI.join(@uri.to_s, "./g").to_s).to eq("http://a/b/c/g") end # Section 5.4.1 of RFC 3986 it "when joined with 'g/' should resolve to http://a/b/c/g/" do expect((@uri + "g/").to_s).to eq("http://a/b/c/g/") expect(Addressable::URI.join(@uri.to_s, "g/").to_s).to eq("http://a/b/c/g/") end # Section 5.4.1 of RFC 3986 it "when joined with '/g' should resolve to http://a/g" do expect((@uri + "/g").to_s).to eq("http://a/g") expect(Addressable::URI.join(@uri.to_s, "/g").to_s).to eq("http://a/g") end # Section 5.4.1 of RFC 3986 it "when joined with '//g' should resolve to http://g" do expect((@uri + "//g").to_s).to eq("http://g") expect(Addressable::URI.join(@uri.to_s, "//g").to_s).to eq("http://g") end # Section 5.4.1 of RFC 3986 it "when joined with '?y' should resolve to http://a/b/c/d;p?y" do expect((@uri + "?y").to_s).to eq("http://a/b/c/d;p?y") expect(Addressable::URI.join(@uri.to_s, "?y").to_s).to eq("http://a/b/c/d;p?y") end # Section 5.4.1 of RFC 3986 it "when joined with 'g?y' should resolve to http://a/b/c/g?y" do expect((@uri + "g?y").to_s).to eq("http://a/b/c/g?y") expect(Addressable::URI.join(@uri.to_s, "g?y").to_s).to eq("http://a/b/c/g?y") end # Section 5.4.1 of RFC 3986 it "when joined with '#s' should resolve to http://a/b/c/d;p?q#s" do expect((@uri + "#s").to_s).to eq("http://a/b/c/d;p?q#s") expect(Addressable::URI.join(@uri.to_s, "#s").to_s).to eq( "http://a/b/c/d;p?q#s" ) end # Section 5.4.1 of RFC 3986 it "when joined with 'g#s' should resolve to http://a/b/c/g#s" do expect((@uri + "g#s").to_s).to eq("http://a/b/c/g#s") expect(Addressable::URI.join(@uri.to_s, "g#s").to_s).to eq("http://a/b/c/g#s") end # Section 5.4.1 of RFC 3986 it "when joined with 'g?y#s' should resolve to http://a/b/c/g?y#s" do expect((@uri + "g?y#s").to_s).to eq("http://a/b/c/g?y#s") expect(Addressable::URI.join( @uri.to_s, "g?y#s").to_s).to eq("http://a/b/c/g?y#s") end # Section 5.4.1 of RFC 3986 it "when joined with ';x' should resolve to http://a/b/c/;x" do expect((@uri + ";x").to_s).to eq("http://a/b/c/;x") expect(Addressable::URI.join(@uri.to_s, ";x").to_s).to eq("http://a/b/c/;x") end # Section 5.4.1 of RFC 3986 it "when joined with 'g;x' should resolve to http://a/b/c/g;x" do expect((@uri + "g;x").to_s).to eq("http://a/b/c/g;x") expect(Addressable::URI.join(@uri.to_s, "g;x").to_s).to eq("http://a/b/c/g;x") end # Section 5.4.1 of RFC 3986 it "when joined with 'g;x?y#s' should resolve to http://a/b/c/g;x?y#s" do expect((@uri + "g;x?y#s").to_s).to eq("http://a/b/c/g;x?y#s") expect(Addressable::URI.join( @uri.to_s, "g;x?y#s").to_s).to eq("http://a/b/c/g;x?y#s") end # Section 5.4.1 of RFC 3986 it "when joined with '' should resolve to http://a/b/c/d;p?q" do expect((@uri + "").to_s).to eq("http://a/b/c/d;p?q") expect(Addressable::URI.join(@uri.to_s, "").to_s).to eq("http://a/b/c/d;p?q") end # Section 5.4.1 of RFC 3986 it "when joined with '.' should resolve to http://a/b/c/" do expect((@uri + ".").to_s).to eq("http://a/b/c/") expect(Addressable::URI.join(@uri.to_s, ".").to_s).to eq("http://a/b/c/") end # Section 5.4.1 of RFC 3986 it "when joined with './' should resolve to http://a/b/c/" do expect((@uri + "./").to_s).to eq("http://a/b/c/") expect(Addressable::URI.join(@uri.to_s, "./").to_s).to eq("http://a/b/c/") end # Section 5.4.1 of RFC 3986 it "when joined with '..' should resolve to http://a/b/" do expect((@uri + "..").to_s).to eq("http://a/b/") expect(Addressable::URI.join(@uri.to_s, "..").to_s).to eq("http://a/b/") end # Section 5.4.1 of RFC 3986 it "when joined with '../' should resolve to http://a/b/" do expect((@uri + "../").to_s).to eq("http://a/b/") expect(Addressable::URI.join(@uri.to_s, "../").to_s).to eq("http://a/b/") end # Section 5.4.1 of RFC 3986 it "when joined with '../g' should resolve to http://a/b/g" do expect((@uri + "../g").to_s).to eq("http://a/b/g") expect(Addressable::URI.join(@uri.to_s, "../g").to_s).to eq("http://a/b/g") end # Section 5.4.1 of RFC 3986 it "when joined with '../..' should resolve to http://a/" do expect((@uri + "../..").to_s).to eq("http://a/") expect(Addressable::URI.join(@uri.to_s, "../..").to_s).to eq("http://a/") end # Section 5.4.1 of RFC 3986 it "when joined with '../../' should resolve to http://a/" do expect((@uri + "../../").to_s).to eq("http://a/") expect(Addressable::URI.join(@uri.to_s, "../../").to_s).to eq("http://a/") end # Section 5.4.1 of RFC 3986 it "when joined with '../../g' should resolve to http://a/g" do expect((@uri + "../../g").to_s).to eq("http://a/g") expect(Addressable::URI.join(@uri.to_s, "../../g").to_s).to eq("http://a/g") end # Section 5.4.2 of RFC 3986 it "when joined with '../../../g' should resolve to http://a/g" do expect((@uri + "../../../g").to_s).to eq("http://a/g") expect(Addressable::URI.join(@uri.to_s, "../../../g").to_s).to eq("http://a/g") end it "when joined with '../.././../g' should resolve to http://a/g" do expect((@uri + "../.././../g").to_s).to eq("http://a/g") expect(Addressable::URI.join(@uri.to_s, "../.././../g").to_s).to eq( "http://a/g" ) end # Section 5.4.2 of RFC 3986 it "when joined with '../../../../g' should resolve to http://a/g" do expect((@uri + "../../../../g").to_s).to eq("http://a/g") expect(Addressable::URI.join( @uri.to_s, "../../../../g").to_s).to eq("http://a/g") end # Section 5.4.2 of RFC 3986 it "when joined with '/./g' should resolve to http://a/g" do expect((@uri + "/./g").to_s).to eq("http://a/g") expect(Addressable::URI.join(@uri.to_s, "/./g").to_s).to eq("http://a/g") end # Section 5.4.2 of RFC 3986 it "when joined with '/../g' should resolve to http://a/g" do expect((@uri + "/../g").to_s).to eq("http://a/g") expect(Addressable::URI.join(@uri.to_s, "/../g").to_s).to eq("http://a/g") end # Section 5.4.2 of RFC 3986 it "when joined with 'g.' should resolve to http://a/b/c/g." do expect((@uri + "g.").to_s).to eq("http://a/b/c/g.") expect(Addressable::URI.join(@uri.to_s, "g.").to_s).to eq("http://a/b/c/g.") end # Section 5.4.2 of RFC 3986 it "when joined with '.g' should resolve to http://a/b/c/.g" do expect((@uri + ".g").to_s).to eq("http://a/b/c/.g") expect(Addressable::URI.join(@uri.to_s, ".g").to_s).to eq("http://a/b/c/.g") end # Section 5.4.2 of RFC 3986 it "when joined with 'g..' should resolve to http://a/b/c/g.." do expect((@uri + "g..").to_s).to eq("http://a/b/c/g..") expect(Addressable::URI.join(@uri.to_s, "g..").to_s).to eq("http://a/b/c/g..") end # Section 5.4.2 of RFC 3986 it "when joined with '..g' should resolve to http://a/b/c/..g" do expect((@uri + "..g").to_s).to eq("http://a/b/c/..g") expect(Addressable::URI.join(@uri.to_s, "..g").to_s).to eq("http://a/b/c/..g") end # Section 5.4.2 of RFC 3986 it "when joined with './../g' should resolve to http://a/b/g" do expect((@uri + "./../g").to_s).to eq("http://a/b/g") expect(Addressable::URI.join(@uri.to_s, "./../g").to_s).to eq("http://a/b/g") end # Section 5.4.2 of RFC 3986 it "when joined with './g/.' should resolve to http://a/b/c/g/" do expect((@uri + "./g/.").to_s).to eq("http://a/b/c/g/") expect(Addressable::URI.join(@uri.to_s, "./g/.").to_s).to eq("http://a/b/c/g/") end # Section 5.4.2 of RFC 3986 it "when joined with 'g/./h' should resolve to http://a/b/c/g/h" do expect((@uri + "g/./h").to_s).to eq("http://a/b/c/g/h") expect(Addressable::URI.join(@uri.to_s, "g/./h").to_s).to eq("http://a/b/c/g/h") end # Section 5.4.2 of RFC 3986 it "when joined with 'g/../h' should resolve to http://a/b/c/h" do expect((@uri + "g/../h").to_s).to eq("http://a/b/c/h") expect(Addressable::URI.join(@uri.to_s, "g/../h").to_s).to eq("http://a/b/c/h") end # Section 5.4.2 of RFC 3986 it "when joined with 'g;x=1/./y' " + "should resolve to http://a/b/c/g;x=1/y" do expect((@uri + "g;x=1/./y").to_s).to eq("http://a/b/c/g;x=1/y") expect(Addressable::URI.join( @uri.to_s, "g;x=1/./y").to_s).to eq("http://a/b/c/g;x=1/y") end # Section 5.4.2 of RFC 3986 it "when joined with 'g;x=1/../y' should resolve to http://a/b/c/y" do expect((@uri + "g;x=1/../y").to_s).to eq("http://a/b/c/y") expect(Addressable::URI.join( @uri.to_s, "g;x=1/../y").to_s).to eq("http://a/b/c/y") end # Section 5.4.2 of RFC 3986 it "when joined with 'g?y/./x' " + "should resolve to http://a/b/c/g?y/./x" do expect((@uri + "g?y/./x").to_s).to eq("http://a/b/c/g?y/./x") expect(Addressable::URI.join( @uri.to_s, "g?y/./x").to_s).to eq("http://a/b/c/g?y/./x") end # Section 5.4.2 of RFC 3986 it "when joined with 'g?y/../x' " + "should resolve to http://a/b/c/g?y/../x" do expect((@uri + "g?y/../x").to_s).to eq("http://a/b/c/g?y/../x") expect(Addressable::URI.join( @uri.to_s, "g?y/../x").to_s).to eq("http://a/b/c/g?y/../x") end # Section 5.4.2 of RFC 3986 it "when joined with 'g#s/./x' " + "should resolve to http://a/b/c/g#s/./x" do expect((@uri + "g#s/./x").to_s).to eq("http://a/b/c/g#s/./x") expect(Addressable::URI.join( @uri.to_s, "g#s/./x").to_s).to eq("http://a/b/c/g#s/./x") end # Section 5.4.2 of RFC 3986 it "when joined with 'g#s/../x' " + "should resolve to http://a/b/c/g#s/../x" do expect((@uri + "g#s/../x").to_s).to eq("http://a/b/c/g#s/../x") expect(Addressable::URI.join( @uri.to_s, "g#s/../x").to_s).to eq("http://a/b/c/g#s/../x") end # Section 5.4.2 of RFC 3986 it "when joined with 'http:g' should resolve to http:g" do expect((@uri + "http:g").to_s).to eq("http:g") expect(Addressable::URI.join(@uri.to_s, "http:g").to_s).to eq("http:g") end # Edge case to be sure it "when joined with '//example.com/' should " + "resolve to http://example.com/" do expect((@uri + "//example.com/").to_s).to eq("http://example.com/") expect(Addressable::URI.join( @uri.to_s, "//example.com/").to_s).to eq("http://example.com/") end it "when joined with a bogus object a TypeError should be raised" do expect do Addressable::URI.join(@uri, 42) end.to raise_error(TypeError) end end describe Addressable::URI, "when converting the path " + "'relative/path/to/something'" do before do @path = 'relative/path/to/something' end it "should convert to " + "\'relative/path/to/something\'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.to_str).to eq("relative/path/to/something") end it "should join with an absolute file path correctly" do @base = Addressable::URI.convert_path("/absolute/path/") @uri = Addressable::URI.convert_path(@path) expect((@base + @uri).to_str).to eq( "file:///absolute/path/relative/path/to/something" ) end end describe Addressable::URI, "when converting a bogus path" do it "should raise a TypeError" do expect do Addressable::URI.convert_path(42) end.to raise_error(TypeError) end end describe Addressable::URI, "when given a UNIX root directory" do before do @path = "/" end it "should convert to \'file:///\'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.to_str).to eq("file:///") end it "should have an origin of 'file://'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.origin).to eq('file://') end end describe Addressable::URI, "when given a Windows root directory" do before do @path = "C:\\" end it "should convert to \'file:///c:/\'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.to_str).to eq("file:///c:/") end it "should have an origin of 'file://'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.origin).to eq('file://') end end describe Addressable::URI, "when given the path '/one/two/'" do before do @path = '/one/two/' end it "should convert to " + "\'file:///one/two/\'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.to_str).to eq("file:///one/two/") end it "should have an origin of 'file://'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.origin).to eq('file://') end end describe Addressable::URI, "when given the tld " do it "'uk' should have a tld of 'uk'" do uri = Addressable::URI.parse("http://example.com") uri.tld = "uk" expect(uri.tld).to eq("uk") end context "which " do let (:uri) { Addressable::URI.parse("http://www.comrade.net/path/to/source/") } it "contains a subdomain" do uri.tld = "co.uk" expect(uri.to_s).to eq("http://www.comrade.co.uk/path/to/source/") end it "is part of the domain" do uri.tld = "com" expect(uri.to_s).to eq("http://www.comrade.com/path/to/source/") end end end describe Addressable::URI, "when given the path " + "'c:\\windows\\My Documents 100%20\\foo.txt'" do before do @path = "c:\\windows\\My Documents 100%20\\foo.txt" end it "should convert to " + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.to_str).to eq("file:///c:/windows/My%20Documents%20100%20/foo.txt") end it "should have an origin of 'file://'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.origin).to eq('file://') end end describe Addressable::URI, "when given the path " + "'file://c:\\windows\\My Documents 100%20\\foo.txt'" do before do @path = "file://c:\\windows\\My Documents 100%20\\foo.txt" end it "should convert to " + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.to_str).to eq("file:///c:/windows/My%20Documents%20100%20/foo.txt") end it "should have an origin of 'file://'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.origin).to eq('file://') end end describe Addressable::URI, "when given the path " + "'file:c:\\windows\\My Documents 100%20\\foo.txt'" do before do @path = "file:c:\\windows\\My Documents 100%20\\foo.txt" end it "should convert to " + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.to_str).to eq("file:///c:/windows/My%20Documents%20100%20/foo.txt") end it "should have an origin of 'file://'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.origin).to eq('file://') end end describe Addressable::URI, "when given the path " + "'file:/c:\\windows\\My Documents 100%20\\foo.txt'" do before do @path = "file:/c:\\windows\\My Documents 100%20\\foo.txt" end it "should convert to " + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.to_str).to eq("file:///c:/windows/My%20Documents%20100%20/foo.txt") end it "should have an origin of 'file://'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.origin).to eq('file://') end end describe Addressable::URI, "when given the path " + "'file:///c|/windows/My%20Documents%20100%20/foo.txt'" do before do @path = "file:///c|/windows/My%20Documents%20100%20/foo.txt" end it "should convert to " + "\'file:///c:/windows/My%20Documents%20100%20/foo.txt\'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.to_str).to eq("file:///c:/windows/My%20Documents%20100%20/foo.txt") end it "should have an origin of 'file://'" do @uri = Addressable::URI.convert_path(@path) expect(@uri.origin).to eq('file://') end end describe Addressable::URI, "when given an http protocol URI" do before do @path = "http://example.com/" end it "should not do any conversion at all" do @uri = Addressable::URI.convert_path(@path) expect(@uri.to_str).to eq("http://example.com/") end end class SuperString def initialize(string) @string = string.to_s end def to_str return @string end end describe Addressable::URI, "when parsing a non-String object" do it "should correctly parse anything with a 'to_str' method" do Addressable::URI.parse(SuperString.new(42)) end it "should raise a TypeError for objects than cannot be converted" do expect do Addressable::URI.parse(42) end.to raise_error(TypeError) end it "should correctly parse heuristically anything with a 'to_str' method" do Addressable::URI.heuristic_parse(SuperString.new(42)) end it "should raise a TypeError for objects than cannot be converted" do expect do Addressable::URI.heuristic_parse(42) end.to raise_error(TypeError) end end describe Addressable::URI, "when form encoding a hash" do it "should result in correct percent encoded sequence" do expect(Addressable::URI.form_encode( [["&one", "/1"], ["=two", "?2"], [":three", "#3"]] )).to eq("%26one=%2F1&%3Dtwo=%3F2&%3Athree=%233") end it "should result in correct percent encoded sequence" do expect(Addressable::URI.form_encode( {"q" => "one two three"} )).to eq("q=one+two+three") end it "should result in correct percent encoded sequence" do expect(Addressable::URI.form_encode( {"key" => nil} )).to eq("key=") end it "should result in correct percent encoded sequence" do expect(Addressable::URI.form_encode( {"q" => ["one", "two", "three"]} )).to eq("q=one&q=two&q=three") end it "should result in correctly encoded newlines" do expect(Addressable::URI.form_encode( {"text" => "one\ntwo\rthree\r\nfour\n\r"} )).to eq("text=one%0D%0Atwo%0D%0Athree%0D%0Afour%0D%0A%0D%0A") end it "should result in a sorted percent encoded sequence" do expect(Addressable::URI.form_encode( [["a", "1"], ["dup", "3"], ["dup", "2"]], true )).to eq("a=1&dup=2&dup=3") end end describe Addressable::URI, "when form encoding a non-Array object" do it "should raise a TypeError for objects than cannot be converted" do expect do Addressable::URI.form_encode(42) end.to raise_error(TypeError) end end # See https://tools.ietf.org/html/rfc6749#appendix-B describe Addressable::URI, "when form encoding the example value from OAuth 2" do it "should result in correct values" do expect(Addressable::URI.form_encode( {"value" => " %&+£€"} )).to eq("value=+%25%26%2B%C2%A3%E2%82%AC") end end # See https://tools.ietf.org/html/rfc6749#appendix-B describe Addressable::URI, "when form unencoding the example value from OAuth 2" do it "should result in correct values" do expect(Addressable::URI.form_unencode( "value=+%25%26%2B%C2%A3%E2%82%AC" )).to eq([["value", " %&+£€"]]) end end describe Addressable::URI, "when form unencoding a string" do it "should result in correct values" do expect(Addressable::URI.form_unencode( "%26one=%2F1&%3Dtwo=%3F2&%3Athree=%233" )).to eq([["&one", "/1"], ["=two", "?2"], [":three", "#3"]]) end it "should result in correct values" do expect(Addressable::URI.form_unencode( "q=one+two+three" )).to eq([["q", "one two three"]]) end it "should result in correct values" do expect(Addressable::URI.form_unencode( "text=one%0D%0Atwo%0D%0Athree%0D%0Afour%0D%0A%0D%0A" )).to eq([["text", "one\ntwo\nthree\nfour\n\n"]]) end it "should result in correct values" do expect(Addressable::URI.form_unencode( "a=1&dup=2&dup=3" )).to eq([["a", "1"], ["dup", "2"], ["dup", "3"]]) end it "should result in correct values" do expect(Addressable::URI.form_unencode( "key" )).to eq([["key", nil]]) end it "should result in correct values" do expect(Addressable::URI.form_unencode("GivenName=Ren%C3%A9")).to eq( [["GivenName", "René"]] ) end end describe Addressable::URI, "when form unencoding a non-String object" do it "should correctly parse anything with a 'to_str' method" do Addressable::URI.form_unencode(SuperString.new(42)) end it "should raise a TypeError for objects than cannot be converted" do expect do Addressable::URI.form_unencode(42) end.to raise_error(TypeError) end end describe Addressable::URI, "when normalizing a non-String object" do it "should correctly parse anything with a 'to_str' method" do Addressable::URI.normalize_component(SuperString.new(42)) end it "should raise a TypeError for objects than cannot be converted" do expect do Addressable::URI.normalize_component(42) end.to raise_error(TypeError) end it "should raise a TypeError for objects than cannot be converted" do expect do Addressable::URI.normalize_component("component", 42) end.to raise_error(TypeError) end end describe Addressable::URI, "when normalizing a path with an encoded slash" do it "should result in correct percent encoded sequence" do expect(Addressable::URI.parse("/path%2Fsegment/").normalize.path).to eq( "/path%2Fsegment/" ) end end describe Addressable::URI, "when normalizing a path with special unicode" do it "does not stop at or ignore null bytes" do expect(Addressable::URI.parse("/path%00segment/").normalize.path).to eq( "/path%00segment/" ) end it "does apply NFC unicode normalization" do expect(Addressable::URI.parse("/%E2%84%A6").normalize.path).to eq( "/%CE%A9" ) end it "does not apply NFKC unicode normalization" do expect(Addressable::URI.parse("/%C2%AF%C2%A0").normalize.path).to eq( "/%C2%AF%C2%A0" ) end end describe Addressable::URI, "when normalizing a partially encoded string" do it "should result in correct percent encoded sequence" do expect(Addressable::URI.normalize_component( "partially % encoded%21" )).to eq("partially%20%25%20encoded!") end it "should result in correct percent encoded sequence" do expect(Addressable::URI.normalize_component( "partially %25 encoded!" )).to eq("partially%20%25%20encoded!") end end describe Addressable::URI, "when normalizing a unicode sequence" do it "should result in correct percent encoded sequence" do expect(Addressable::URI.normalize_component( "/C%CC%A7" )).to eq("/%C3%87") end it "should result in correct percent encoded sequence" do expect(Addressable::URI.normalize_component( "/%C3%87" )).to eq("/%C3%87") end end describe Addressable::URI, "when normalizing a multibyte string" do it "should result in correct percent encoded sequence" do expect(Addressable::URI.normalize_component("günther")).to eq( "g%C3%BCnther" ) end it "should result in correct percent encoded sequence" do expect(Addressable::URI.normalize_component("g%C3%BCnther")).to eq( "g%C3%BCnther" ) end end describe Addressable::URI, "when normalizing a string but leaving some characters encoded" do it "should result in correct percent encoded sequence" do expect(Addressable::URI.normalize_component("%58X%59Y%5AZ", "0-9a-zXY", "Y")).to eq( "XX%59Y%5A%5A" ) end it "should not modify the character class" do character_class = "0-9a-zXY" character_class_copy = character_class.dup Addressable::URI.normalize_component("%58X%59Y%5AZ", character_class, "Y") expect(character_class).to eq(character_class_copy) end end describe Addressable::URI, "when encoding IP literals" do it "should work for IPv4" do input = "http://127.0.0.1/" expect(Addressable::URI.encode(input)).to eq(input) end it "should work for IPv6" do input = "http://[fe80::200:f8ff:fe21:67cf]/" expect(Addressable::URI.encode(input)).to eq(input) end end describe Addressable::URI, "when encoding a string with existing encodings to upcase" do it "should result in correct percent encoded sequence" do expect(Addressable::URI.encode_component("JK%4c", "0-9A-IKM-Za-z%", "L")).to eq("%4AK%4C") end end describe Addressable::URI, "when encoding a multibyte string" do it "should result in correct percent encoded sequence" do expect(Addressable::URI.encode_component("günther")).to eq("g%C3%BCnther") end it "should result in correct percent encoded sequence" do expect(Addressable::URI.encode_component( "günther", /[^a-zA-Z0-9\:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\-\.\_\~]/ )).to eq("g%C3%BCnther") end end describe Addressable::URI, "when form encoding a multibyte string" do it "should result in correct percent encoded sequence" do expect(Addressable::URI.form_encode({"GivenName" => "René"})).to eq( "GivenName=Ren%C3%A9" ) end end describe Addressable::URI, "when encoding a string with ASCII chars 0-15" do it "should result in correct percent encoded sequence" do expect(Addressable::URI.encode_component("one\ntwo")).to eq("one%0Atwo") end it "should result in correct percent encoded sequence" do expect(Addressable::URI.encode_component( "one\ntwo", /[^a-zA-Z0-9\:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\-\.\_\~]/ )).to eq("one%0Atwo") end end describe Addressable::URI, "when unencoding a multibyte string" do it "should result in correct percent encoded sequence" do expect(Addressable::URI.unencode_component("g%C3%BCnther")).to eq("günther") end it "should consistently use UTF-8 internally" do expect(Addressable::URI.unencode_component("ski=%BA%DAɫ")).to eq("ski=\xBA\xDAɫ") end it "should not fail with UTF-8 incompatible string" do url = "/M%E9/\xE9?p=\xFC".b expect(Addressable::URI.unencode_component(url)).to eq("/M\xE9/\xE9?p=\xFC") end it "should result in correct percent encoded sequence as a URI" do expect(Addressable::URI.unencode( "/path?g%C3%BCnther", ::Addressable::URI )).to eq(Addressable::URI.new( :path => "/path", :query => "günther" )) end end describe Addressable::URI, "when partially unencoding a string" do it "should unencode all characters by default" do expect(Addressable::URI.unencode('%%25~%7e+%2b', String)).to eq('%%~~++') end it "should unencode characters not in leave_encoded" do expect(Addressable::URI.unencode('%%25~%7e+%2b', String, '~')).to eq('%%~%7e++') end it "should leave characters in leave_encoded alone" do expect(Addressable::URI.unencode('%%25~%7e+%2b', String, '%~+')).to eq('%%25~%7e+%2b') end end describe Addressable::URI, "when unencoding a bogus object" do it "should raise a TypeError" do expect do Addressable::URI.unencode_component(42) end.to raise_error(TypeError) end it "should raise a TypeError" do expect do Addressable::URI.unencode("/path?g%C3%BCnther", Integer) end.to raise_error(TypeError) end end describe Addressable::URI, "when encoding a bogus object" do it "should raise a TypeError" do expect do Addressable::URI.encode(Object.new) end.to raise_error(TypeError) end it "should raise a TypeError" do expect do Addressable::URI.normalized_encode(Object.new) end.to raise_error(TypeError) end it "should raise a TypeError" do expect do Addressable::URI.encode_component("günther", Object.new) end.to raise_error(TypeError) end it "should raise a TypeError" do expect do Addressable::URI.encode_component(Object.new) end.to raise_error(TypeError) end end describe Addressable::URI, "when given the input " + "'http://example.com/'" do before do @input = "http://example.com/" end it "should heuristically parse to 'http://example.com/'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("http://example.com/") end it "should not raise error when frozen" do expect do Addressable::URI.heuristic_parse(@input).freeze.to_s end.not_to raise_error end end describe Addressable::URI, "when given the input " + "'https://example.com/'" do before do @input = "https://example.com/" end it "should heuristically parse to 'https://example.com/'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("https://example.com/") end end describe Addressable::URI, "when given the input " + "'http:example.com/'" do before do @input = "http:example.com/" end it "should heuristically parse to 'http://example.com/'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("http://example.com/") end it "should heuristically parse to 'http://example.com/' " + "even with a scheme hint of 'ftp'" do @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) expect(@uri.to_s).to eq("http://example.com/") end end describe Addressable::URI, "when given the input " + "'https:example.com/'" do before do @input = "https:example.com/" end it "should heuristically parse to 'https://example.com/'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("https://example.com/") end it "should heuristically parse to 'https://example.com/' " + "even with a scheme hint of 'ftp'" do @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) expect(@uri.to_s).to eq("https://example.com/") end end describe Addressable::URI, "when given the input " + "'http://example.com/example.com/'" do before do @input = "http://example.com/example.com/" end it "should heuristically parse to 'http://example.com/example.com/'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("http://example.com/example.com/") end end describe Addressable::URI, "when given the input " + "'http://prefix\\.example.com/'" do before do @input = "http://prefix\\.example.com/" end it "should heuristically parse to 'http://prefix/.example.com/'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.authority).to eq("prefix") expect(@uri.to_s).to eq("http://prefix/.example.com/") end it "should heuristically parse to 'http://prefix/.example.com/' " + "even with a scheme hint of 'ftp'" do @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) expect(@uri.to_s).to eq("http://prefix/.example.com/") end end describe Addressable::URI, "when given the input " + "'http://p:\\/'" do before do @input = "http://p:\\/" end it "should heuristically parse to 'http://p//'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.authority).to eq("p") expect(@uri.to_s).to eq("http://p//") end it "should heuristically parse to 'http://p//' " + "even with a scheme hint of 'ftp'" do @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) expect(@uri.to_s).to eq("http://p//") end end describe Addressable::URI, "when given the input " + "'http://p://'" do before do @input = "http://p://" end it "should heuristically parse to 'http://p//'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.authority).to eq("p") expect(@uri.to_s).to eq("http://p//") end it "should heuristically parse to 'http://p//' " + "even with a scheme hint of 'ftp'" do @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) expect(@uri.to_s).to eq("http://p//") end end describe Addressable::URI, "when given the input " + "'http://p://p'" do before do @input = "http://p://p" end it "should heuristically parse to 'http://p//p'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.authority).to eq("p") expect(@uri.to_s).to eq("http://p//p") end it "should heuristically parse to 'http://p//p' " + "even with a scheme hint of 'ftp'" do @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) expect(@uri.to_s).to eq("http://p//p") end end describe Addressable::URI, "when given the input " + "'http://prefix .example.com/'" do before do @input = "http://prefix .example.com/" end # Justification here being that no browser actually tries to resolve this. # They all treat this as a web search. it "should heuristically parse to 'http://prefix%20.example.com/'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.authority).to eq("prefix%20.example.com") expect(@uri.to_s).to eq("http://prefix%20.example.com/") end it "should heuristically parse to 'http://prefix%20.example.com/' " + "even with a scheme hint of 'ftp'" do @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) expect(@uri.to_s).to eq("http://prefix%20.example.com/") end end describe Addressable::URI, "when given the input " + "' http://www.example.com/ '" do before do @input = " http://www.example.com/ " end it "should heuristically parse to 'http://prefix%20.example.com/'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.scheme).to eq("http") expect(@uri.path).to eq("/") expect(@uri.to_s).to eq("http://www.example.com/") end end describe Addressable::URI, "when given the input " + "'http://prefix%2F.example.com/'" do before do @input = "http://prefix%2F.example.com/" end it "should heuristically parse to 'http://prefix%2F.example.com/'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.authority).to eq("prefix%2F.example.com") expect(@uri.to_s).to eq("http://prefix%2F.example.com/") end it "should heuristically parse to 'http://prefix%2F.example.com/' " + "even with a scheme hint of 'ftp'" do @uri = Addressable::URI.heuristic_parse(@input, {:scheme => 'ftp'}) expect(@uri.to_s).to eq("http://prefix%2F.example.com/") end end describe Addressable::URI, "when given the input " + "'/path/to/resource'" do before do @input = "/path/to/resource" end it "should heuristically parse to '/path/to/resource'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("/path/to/resource") end end describe Addressable::URI, "when given the input " + "'relative/path/to/resource'" do before do @input = "relative/path/to/resource" end it "should heuristically parse to 'relative/path/to/resource'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("relative/path/to/resource") end end describe Addressable::URI, "when given the input " + "'example.com'" do before do @input = "example.com" end it "should heuristically parse to 'http://example.com'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("http://example.com") end end describe Addressable::URI, "when given the input " + "'example.com' and a scheme hint of 'ftp'" do before do @input = "example.com" @hints = {:scheme => 'ftp'} end it "should heuristically parse to 'http://example.com'" do @uri = Addressable::URI.heuristic_parse(@input, @hints) expect(@uri.to_s).to eq("ftp://example.com") end end describe Addressable::URI, "when given the input " + "'example.com:21' and a scheme hint of 'ftp'" do before do @input = "example.com:21" @hints = {:scheme => 'ftp'} end it "should heuristically parse to 'http://example.com:21'" do @uri = Addressable::URI.heuristic_parse(@input, @hints) expect(@uri.to_s).to eq("ftp://example.com:21") end end describe Addressable::URI, "when given the input " + "'example.com/path/to/resource'" do before do @input = "example.com/path/to/resource" end it "should heuristically parse to 'http://example.com/path/to/resource'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("http://example.com/path/to/resource") end end describe Addressable::URI, "when given the input " + "'http:///example.com'" do before do @input = "http:///example.com" end it "should heuristically parse to 'http://example.com'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("http://example.com") end end describe Addressable::URI, "when given the input which "\ "start with digits and has specified port" do before do @input = "7777.example.org:8089" end it "should heuristically parse to 'http://7777.example.org:8089'" do uri = Addressable::URI.heuristic_parse(@input) expect(uri.to_s).to eq("http://7777.example.org:8089") end end describe Addressable::URI, "when given the input " + "'feed:///example.com'" do before do @input = "feed:///example.com" end it "should heuristically parse to 'feed://example.com'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("feed://example.com") end end describe Addressable::URI, "when given the input " + "'file://localhost/path/to/resource/'" do before do @input = "file://localhost/path/to/resource/" end it "should heuristically parse to 'file:///path/to/resource/'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("file:///path/to/resource/") end end describe Addressable::URI, "when given the input " + "'file://path/to/resource/'" do before do @input = "file://path/to/resource/" end it "should heuristically parse to 'file:///path/to/resource/'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("file:///path/to/resource/") end end describe Addressable::URI, "when given the input " + "'file://///path/to/resource/'" do before do @input = "file:///////path/to/resource/" end it "should heuristically parse to 'file:////path/to/resource/'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("file:////path/to/resource/") end end describe Addressable::URI, "when given the input " + "'feed://http://example.com'" do before do @input = "feed://http://example.com" end it "should heuristically parse to 'feed:http://example.com'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("feed:http://example.com") end end describe Addressable::URI, "when given the input " + "::URI.parse('http://example.com')" do before do @input = ::URI.parse('http://example.com') end it "should heuristically parse to 'http://example.com'" do @uri = Addressable::URI.heuristic_parse(@input) expect(@uri.to_s).to eq("http://example.com") end end describe Addressable::URI, "when given the input: 'user@domain.com'" do before do @input = "user@domain.com" end context "for heuristic parse" do it "should remain 'mailto:user@domain.com'" do uri = Addressable::URI.heuristic_parse("mailto:#{@input}") expect(uri.to_s).to eq("mailto:user@domain.com") end it "should have a scheme of 'mailto'" do uri = Addressable::URI.heuristic_parse(@input) expect(uri.to_s).to eq("mailto:user@domain.com") expect(uri.scheme).to eq("mailto") end it "should remain 'acct:user@domain.com'" do uri = Addressable::URI.heuristic_parse("acct:#{@input}") expect(uri.to_s).to eq("acct:user@domain.com") end context "HTTP" do before do @uri = Addressable::URI.heuristic_parse("http://#{@input}/") end it "should remain 'http://user@domain.com/'" do expect(@uri.to_s).to eq("http://user@domain.com/") end it "should have the username 'user' for HTTP basic authentication" do expect(@uri.user).to eq("user") end end end end describe Addressable::URI, "when assigning query values" do before do @uri = Addressable::URI.new end it "should correctly assign {:a => 'a', :b => ['c', 'd', 'e']}" do @uri.query_values = {:a => "a", :b => ["c", "d", "e"]} expect(@uri.query).to eq("a=a&b=c&b=d&b=e") end it "should raise an error attempting to assign {'a' => {'b' => ['c']}}" do expect do @uri.query_values = { 'a' => {'b' => ['c'] } } end.to raise_error(TypeError) end it "should raise an error attempting to assign " + "{:b => '2', :a => {:c => '1'}}" do expect do @uri.query_values = {:b => '2', :a => {:c => '1'}} end.to raise_error(TypeError) end it "should raise an error attempting to assign " + "{:a => 'a', :b => [{:c => 'c', :d => 'd'}, " + "{:e => 'e', :f => 'f'}]}" do expect do @uri.query_values = { :a => "a", :b => [{:c => "c", :d => "d"}, {:e => "e", :f => "f"}] } end.to raise_error(TypeError) end it "should raise an error attempting to assign " + "{:a => 'a', :b => [{:c => true, :d => 'd'}, " + "{:e => 'e', :f => 'f'}]}" do expect do @uri.query_values = { :a => 'a', :b => [{:c => true, :d => 'd'}, {:e => 'e', :f => 'f'}] } end.to raise_error(TypeError) end it "should raise an error attempting to assign " + "{:a => 'a', :b => {:c => true, :d => 'd'}}" do expect do @uri.query_values = { :a => 'a', :b => {:c => true, :d => 'd'} } end.to raise_error(TypeError) end it "should raise an error attempting to assign " + "{:a => 'a', :b => {:c => true, :d => 'd'}}" do expect do @uri.query_values = { :a => 'a', :b => {:c => true, :d => 'd'} } end.to raise_error(TypeError) end it "should correctly assign {:a => 1, :b => 1.5}" do @uri.query_values = { :a => 1, :b => 1.5 } expect(@uri.query).to eq("a=1&b=1.5") end it "should raise an error attempting to assign " + "{:z => 1, :f => [2, {999.1 => [3,'4']}, ['h', 'i']], " + ":a => {:b => ['c', 'd'], :e => true, :y => 0.5}}" do expect do @uri.query_values = { :z => 1, :f => [ 2, {999.1 => [3,'4']}, ['h', 'i'] ], :a => { :b => ['c', 'd'], :e => true, :y => 0.5 } } end.to raise_error(TypeError) end it "should correctly assign {}" do @uri.query_values = {} expect(@uri.query).to eq('') end it "should correctly assign nil" do @uri.query_values = nil expect(@uri.query).to eq(nil) end it "should correctly sort {'ab' => 'c', :ab => 'a', :a => 'x'}" do @uri.query_values = {'ab' => 'c', :ab => 'a', :a => 'x'} expect(@uri.query).to eq("a=x&ab=a&ab=c") end it "should correctly assign " + "[['b', 'c'], ['b', 'a'], ['a', 'a']]" do # Order can be guaranteed in this format, so preserve it. @uri.query_values = [['b', 'c'], ['b', 'a'], ['a', 'a']] expect(@uri.query).to eq("b=c&b=a&a=a") end it "should preserve query string order" do query_string = (('a'..'z').to_a.reverse.map { |e| "#{e}=#{e}" }).join("&") @uri.query = query_string original_uri = @uri.to_s @uri.query_values = @uri.query_values(Array) expect(@uri.to_s).to eq(original_uri) end describe 'when a hash with mixed types is assigned to query_values' do it 'should not raise an error' do skip 'Issue #94' expect { subject.query_values = { "page" => "1", :page => 2 } }.to_not raise_error end end end describe Addressable::URI, "when assigning path values" do before do @uri = Addressable::URI.new end it "should correctly assign paths containing colons" do @uri.path = "acct:bob@sporkmonger.com" expect(@uri.path).to eq("acct:bob@sporkmonger.com") expect(@uri.normalize.to_str).to eq("acct%2Fbob@sporkmonger.com") expect { @uri.to_s }.to raise_error( Addressable::URI::InvalidURIError ) end it "should correctly assign paths containing colons" do @uri.path = "/acct:bob@sporkmonger.com" @uri.authority = "example.com" expect(@uri.normalize.to_str).to eq("//example.com/acct:bob@sporkmonger.com") end it "should correctly assign paths containing colons" do @uri.path = "acct:bob@sporkmonger.com" @uri.scheme = "something" expect(@uri.normalize.to_str).to eq("something:acct:bob@sporkmonger.com") end it "should not allow relative paths to be assigned on absolute URIs" do expect do @uri.scheme = "http" @uri.host = "example.com" @uri.path = "acct:bob@sporkmonger.com" end.to raise_error(Addressable::URI::InvalidURIError) end it "should not allow relative paths to be assigned on absolute URIs" do expect do @uri.path = "acct:bob@sporkmonger.com" @uri.scheme = "http" @uri.host = "example.com" end.to raise_error(Addressable::URI::InvalidURIError) end it "should not allow relative paths to be assigned on absolute URIs" do expect do @uri.path = "uuid:0b3ecf60-3f93-11df-a9c3-001f5bfffe12" @uri.scheme = "urn" end.not_to raise_error end end describe Addressable::URI, "when initializing a subclass of Addressable::URI" do before do @uri = Class.new(Addressable::URI).new end it "should have the same class after being parsed" do expect(@uri.class).to eq(Addressable::URI.parse(@uri).class) end it "should have the same class as its duplicate" do expect(@uri.class).to eq(@uri.dup.class) end it "should have the same class after being normalized" do expect(@uri.class).to eq(@uri.normalize.class) end it "should have the same class after being merged" do expect(@uri.class).to eq(@uri.merge(:path => 'path').class) end it "should have the same class after being joined" do expect(@uri.class).to eq(@uri.join('path').class) end end describe Addressable::URI, "support serialization roundtrip" do before do @uri = Addressable::URI.new( :scheme => "http", :user => "user", :password => "password", :host => "example.com", :port => 80, :path => "/path", :query => "query=value", :fragment => "fragment" ) end it "is in a working state after being serialized with Marshal" do @uri = Addressable::URI.parse("http://example.com") cloned_uri = Marshal.load(Marshal.dump(@uri)) expect(cloned_uri.normalized_scheme).to be == @uri.normalized_scheme end it "is in a working state after being serialized with YAML" do @uri = Addressable::URI.parse("http://example.com") cloned_uri = if YAML.respond_to?(:unsafe_load) YAML.unsafe_load(YAML.dump(@uri)) else YAML.load(YAML.dump(@uri)) end expect(cloned_uri.normalized_scheme).to be == @uri.normalized_scheme end end describe Addressable::URI, "when initialized in a non-main `Ractor`" do it "should have the same value as if used in the main `Ractor`" do pending("Ruby 3.0+ for `Ractor` support") unless defined?(Ractor) main = Addressable::URI.parse("http://example.com") expect( Ractor.new { Addressable::URI.parse("http://example.com") }.take ).to eq(main) end end describe Addressable::URI, "when deferring validation" do subject(:deferred) { uri.instance_variable_get(:@validation_deferred) } let(:uri) { Addressable::URI.parse("http://example.com") } it "defers validation within the block" do uri.defer_validation do expect(deferred).to be true end end it "always resets deferral afterward" do expect { uri.defer_validation { raise "boom" } }.to raise_error("boom") expect(deferred).to be false end it "returns nil" do res = uri.defer_validation {} expect(res).to be nil end end describe Addressable::URI, "YAML safe loading" do it "doesn't serialize anonymous objects" do url = Addressable::URI.parse("http://example.com/") expect(YAML.dump(url)).to_not include("!ruby/object {}") end end addressable-2.8.7/spec/addressable/security_spec.rb0000644000004100000410000000424214636033505022451 0ustar www-datawww-data# frozen_string_literal: true # Copyright (C) Bob Aman # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "spec_helper" require "addressable/uri" describe Addressable::URI, "when created with a URI known to cause crashes " + "in certain browsers" do it "should parse correctly" do uri = Addressable::URI.parse('%%30%30') expect(uri.path).to eq('%%30%30') expect(uri.normalize.path).to eq('%2500') end it "should parse correctly as a full URI" do uri = Addressable::URI.parse('http://www.example.com/%%30%30') expect(uri.path).to eq('/%%30%30') expect(uri.normalize.path).to eq('/%2500') end end describe Addressable::URI, "when created with a URI known to cause crashes " + "in certain browsers" do it "should parse correctly" do uri = Addressable::URI.parse('لُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ 冗') expect(uri.path).to eq('لُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ 冗') expect(uri.normalize.path).to eq( '%D9%84%D9%8F%D8%B5%D9%91%D8%A8%D9%8F%D9%84%D9%8F%D9%84%D8%B5%D9%91' + '%D8%A8%D9%8F%D8%B1%D8%B1%D9%8B%20%E0%A5%A3%20%E0%A5%A3h%20%E0%A5' + '%A3%20%E0%A5%A3%20%E5%86%97' ) end it "should parse correctly as a full URI" do uri = Addressable::URI.parse('http://www.example.com/لُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ 冗') expect(uri.path).to eq('/لُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ 冗') expect(uri.normalize.path).to eq( '/%D9%84%D9%8F%D8%B5%D9%91%D8%A8%D9%8F%D9%84%D9%8F%D9%84%D8%B5%D9%91' + '%D8%A8%D9%8F%D8%B1%D8%B1%D9%8B%20%E0%A5%A3%20%E0%A5%A3h%20%E0%A5' + '%A3%20%E0%A5%A3%20%E5%86%97' ) end end addressable-2.8.7/spec/addressable/idna_spec.rb0000644000004100000410000002432214636033505021516 0ustar www-datawww-data# frozen_string_literal: true # Copyright (C) Bob Aman # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "spec_helper" # Have to use RubyGems to load the idn gem. require "rubygems" require "addressable/idna" shared_examples_for "converting from unicode to ASCII" do it "should convert 'www.google.com' correctly" do expect(Addressable::IDNA.to_ascii("www.google.com")).to eq("www.google.com") end long = 'AcinusFallumTrompetumNullunCreditumVisumEstAtCuadLongumEtCefallum.com' it "should convert '#{long}' correctly" do expect(Addressable::IDNA.to_ascii(long)).to eq(long) end it "should convert 'www.詹姆斯.com' correctly" do expect(Addressable::IDNA.to_ascii( "www.詹姆斯.com" )).to eq("www.xn--8ws00zhy3a.com") end it "also accepts unicode strings encoded as ascii-8bit" do expect(Addressable::IDNA.to_ascii( "www.詹姆斯.com".b )).to eq("www.xn--8ws00zhy3a.com") end it "should convert 'www.Iñtërnâtiônàlizætiøn.com' correctly" do "www.Iñtërnâtiônàlizætiøn.com" expect(Addressable::IDNA.to_ascii( "www.I\xC3\xB1t\xC3\xABrn\xC3\xA2ti\xC3\xB4" + "n\xC3\xA0liz\xC3\xA6ti\xC3\xB8n.com" )).to eq("www.xn--itrntinliztin-vdb0a5exd8ewcye.com") end it "should convert 'www.Iñtërnâtiônàlizætiøn.com' correctly" do expect(Addressable::IDNA.to_ascii( "www.In\xCC\x83te\xCC\x88rna\xCC\x82tio\xCC\x82n" + "a\xCC\x80liz\xC3\xA6ti\xC3\xB8n.com" )).to eq("www.xn--itrntinliztin-vdb0a5exd8ewcye.com") end it "should convert " + "'www.ほんとうにながいわけのわからないどめいんめいのらべるまだながくしないとたりない.w3.mag.keio.ac.jp' " + "correctly" do expect(Addressable::IDNA.to_ascii( "www.\343\201\273\343\202\223\343\201\250\343\201\206\343\201\253\343" + "\201\252\343\201\214\343\201\204\343\202\217\343\201\221\343\201\256" + "\343\202\217\343\201\213\343\202\211\343\201\252\343\201\204\343\201" + "\251\343\202\201\343\201\204\343\202\223\343\202\201\343\201\204\343" + "\201\256\343\202\211\343\201\271\343\202\213\343\201\276\343\201\240" + "\343\201\252\343\201\214\343\201\217\343\201\227\343\201\252\343\201" + "\204\343\201\250\343\201\237\343\202\212\343\201\252\343\201\204." + "w3.mag.keio.ac.jp" )).to eq( "www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3" + "fg11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp" ) end it "should convert " + "'www.ほんとうにながいわけのわからないどめいんめいのらべるまだながくしないとたりない.w3.mag.keio.ac.jp' " + "correctly" do expect(Addressable::IDNA.to_ascii( "www.\343\201\273\343\202\223\343\201\250\343\201\206\343\201\253\343" + "\201\252\343\201\213\343\202\231\343\201\204\343\202\217\343\201\221" + "\343\201\256\343\202\217\343\201\213\343\202\211\343\201\252\343\201" + "\204\343\201\250\343\202\231\343\202\201\343\201\204\343\202\223\343" + "\202\201\343\201\204\343\201\256\343\202\211\343\201\270\343\202\231" + "\343\202\213\343\201\276\343\201\237\343\202\231\343\201\252\343\201" + "\213\343\202\231\343\201\217\343\201\227\343\201\252\343\201\204\343" + "\201\250\343\201\237\343\202\212\343\201\252\343\201\204." + "w3.mag.keio.ac.jp" )).to eq( "www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3" + "fg11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp" ) end it "should convert '点心和烤鸭.w3.mag.keio.ac.jp' correctly" do expect(Addressable::IDNA.to_ascii( "点心和烤鸭.w3.mag.keio.ac.jp" )).to eq("xn--0trv4xfvn8el34t.w3.mag.keio.ac.jp") end it "should convert '가각갂갃간갅갆갇갈갉힢힣.com' correctly" do expect(Addressable::IDNA.to_ascii( "가각갂갃간갅갆갇갈갉힢힣.com" )).to eq("xn--o39acdefghijk5883jma.com") end it "should convert " + "'\347\242\274\346\250\231\346\272\226\350" + "\220\254\345\234\213\347\242\274.com' correctly" do expect(Addressable::IDNA.to_ascii( "\347\242\274\346\250\231\346\272\226\350" + "\220\254\345\234\213\347\242\274.com" )).to eq("xn--9cs565brid46mda086o.com") end it "should convert 'リ宠퐱〹.com' correctly" do expect(Addressable::IDNA.to_ascii( "\357\276\230\345\256\240\355\220\261\343\200\271.com" )).to eq("xn--eek174hoxfpr4k.com") end it "should convert 'リ宠퐱卄.com' correctly" do expect(Addressable::IDNA.to_ascii( "\343\203\252\345\256\240\355\220\261\345\215\204.com" )).to eq("xn--eek174hoxfpr4k.com") end it "should convert 'ᆵ' correctly" do expect(Addressable::IDNA.to_ascii( "\341\206\265" )).to eq("xn--4ud") end it "should convert 'ᆵ' correctly" do expect(Addressable::IDNA.to_ascii( "\357\276\257" )).to eq("xn--4ud") end it "should convert '🌹🌹🌹.ws' correctly" do expect(Addressable::IDNA.to_ascii( "\360\237\214\271\360\237\214\271\360\237\214\271.ws" )).to eq("xn--2h8haa.ws") end it "should handle two adjacent '.'s correctly" do expect(Addressable::IDNA.to_ascii( "example..host" )).to eq("example..host") end end shared_examples_for "converting from ASCII to unicode" do long = 'AcinusFallumTrompetumNullunCreditumVisumEstAtCuadLongumEtCefallum.com' it "should convert '#{long}' correctly" do expect(Addressable::IDNA.to_unicode(long)).to eq(long) end it "should return the identity conversion when punycode decode fails" do expect(Addressable::IDNA.to_unicode("xn--zckp1cyg1.sblo.jp")).to eq( "xn--zckp1cyg1.sblo.jp") end it "should return the identity conversion when the ACE prefix has no suffix" do expect(Addressable::IDNA.to_unicode("xn--...-")).to eq("xn--...-") end it "should convert 'www.google.com' correctly" do expect(Addressable::IDNA.to_unicode("www.google.com")).to eq( "www.google.com") end it "should convert 'www.詹姆斯.com' correctly" do expect(Addressable::IDNA.to_unicode( "www.xn--8ws00zhy3a.com" )).to eq("www.詹姆斯.com") end it "should convert '詹姆斯.com' correctly" do expect(Addressable::IDNA.to_unicode( "xn--8ws00zhy3a.com" )).to eq("詹姆斯.com") end it "should convert 'www.iñtërnâtiônàlizætiøn.com' correctly" do expect(Addressable::IDNA.to_unicode( "www.xn--itrntinliztin-vdb0a5exd8ewcye.com" )).to eq("www.iñtërnâtiônàlizætiøn.com") end it "should convert 'iñtërnâtiônàlizætiøn.com' correctly" do expect(Addressable::IDNA.to_unicode( "xn--itrntinliztin-vdb0a5exd8ewcye.com" )).to eq("iñtërnâtiônàlizætiøn.com") end it "should convert " + "'www.ほんとうにながいわけのわからないどめいんめいのらべるまだながくしないとたりない.w3.mag.keio.ac.jp' " + "correctly" do expect(Addressable::IDNA.to_unicode( "www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3" + "fg11amb5gzdb4wi9bya3kc6lra.w3.mag.keio.ac.jp" )).to eq( "www.ほんとうにながいわけのわからないどめいんめいのらべるまだながくしないとたりない.w3.mag.keio.ac.jp" ) end it "should convert '点心和烤鸭.w3.mag.keio.ac.jp' correctly" do expect(Addressable::IDNA.to_unicode( "xn--0trv4xfvn8el34t.w3.mag.keio.ac.jp" )).to eq("点心和烤鸭.w3.mag.keio.ac.jp") end it "should convert '가각갂갃간갅갆갇갈갉힢힣.com' correctly" do expect(Addressable::IDNA.to_unicode( "xn--o39acdefghijk5883jma.com" )).to eq("가각갂갃간갅갆갇갈갉힢힣.com") end it "should convert " + "'\347\242\274\346\250\231\346\272\226\350" + "\220\254\345\234\213\347\242\274.com' correctly" do expect(Addressable::IDNA.to_unicode( "xn--9cs565brid46mda086o.com" )).to eq( "\347\242\274\346\250\231\346\272\226\350" + "\220\254\345\234\213\347\242\274.com" ) end it "should convert 'リ宠퐱卄.com' correctly" do expect(Addressable::IDNA.to_unicode( "xn--eek174hoxfpr4k.com" )).to eq("\343\203\252\345\256\240\355\220\261\345\215\204.com") end it "should convert 'ᆵ' correctly" do expect(Addressable::IDNA.to_unicode( "xn--4ud" )).to eq("\341\206\265") end it "should convert '🌹🌹🌹.ws' correctly" do expect(Addressable::IDNA.to_unicode( "xn--2h8haa.ws" )).to eq("\360\237\214\271\360\237\214\271\360\237\214\271.ws") end it "should handle two adjacent '.'s correctly" do expect(Addressable::IDNA.to_unicode( "example..host" )).to eq("example..host") end end describe Addressable::IDNA, "when using the pure-Ruby implementation" do before do Addressable.send(:remove_const, :IDNA) load "addressable/idna/pure.rb" end it_should_behave_like "converting from unicode to ASCII" it_should_behave_like "converting from ASCII to unicode" begin require "fiber" it "should not blow up inside fibers" do f = Fiber.new do Addressable.send(:remove_const, :IDNA) load "addressable/idna/pure.rb" end f.resume end rescue LoadError # Fibers aren't supported in this version of Ruby, skip this test. warn('Fibers unsupported.') end end begin require "idn" describe Addressable::IDNA, "when using the native-code implementation" do before do Addressable.send(:remove_const, :IDNA) load "addressable/idna/native.rb" end it_should_behave_like "converting from unicode to ASCII" it_should_behave_like "converting from ASCII to unicode" end rescue LoadError => error raise error if ENV["CI"] && TestHelper.native_supported? # Cannot test the native implementation without libidn support. warn('Could not load native IDN implementation.') end addressable-2.8.7/spec/addressable/net_http_compat_spec.rb0000644000004100000410000000161614636033505023774 0ustar www-datawww-data# frozen_string_literal: true # Copyright (C) Bob Aman # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "spec_helper" require "addressable/uri" require "net/http" describe Net::HTTP do it "should be compatible with Addressable" do response_body = Net::HTTP.get(Addressable::URI.parse('http://www.google.com/')) expect(response_body).not_to be_nil end end addressable-2.8.7/spec/addressable/template_spec.rb0000644000004100000410000012017414636033505022420 0ustar www-datawww-data# frozen_string_literal: true # Copyright (C) Bob Aman # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require "spec_helper" require "bigdecimal" require "timeout" require "addressable/template" shared_examples_for 'expands' do |tests| tests.each do |template, expansion| exp = expansion.is_a?(Array) ? expansion.first : expansion it "#{template} to #{exp}" do tmpl = Addressable::Template.new(template).expand(subject) expect(tmpl.to_str).to eq(expansion) end end end describe "eql?" do let(:template) { Addressable::Template.new('https://www.example.com/{foo}') } it 'is equal when the pattern matches' do other_template = Addressable::Template.new('https://www.example.com/{foo}') expect(template).to be_eql(other_template) expect(other_template).to be_eql(template) end it 'is not equal when the pattern differs' do other_template = Addressable::Template.new('https://www.example.com/{bar}') expect(template).to_not be_eql(other_template) expect(other_template).to_not be_eql(template) end it 'is not equal to non-templates' do uri = 'https://www.example.com/foo/bar' addressable_template = Addressable::Template.new uri addressable_uri = Addressable::URI.parse uri expect(addressable_template).to_not be_eql(addressable_uri) expect(addressable_uri).to_not be_eql(addressable_template) end end describe "==" do let(:template) { Addressable::Template.new('https://www.example.com/{foo}') } it 'is equal when the pattern matches' do other_template = Addressable::Template.new('https://www.example.com/{foo}') expect(template).to eq other_template expect(other_template).to eq template end it 'is not equal when the pattern differs' do other_template = Addressable::Template.new('https://www.example.com/{bar}') expect(template).not_to eq other_template expect(other_template).not_to eq template end it 'is not equal to non-templates' do uri = 'https://www.example.com/foo/bar' addressable_template = Addressable::Template.new uri addressable_uri = Addressable::URI.parse uri expect(addressable_template).not_to eq addressable_uri expect(addressable_uri).not_to eq addressable_template end end describe "#to_regexp" do it "does not match the first line of multiline strings" do uri = "https://www.example.com/bar" template = Addressable::Template.new(uri) expect(template.match(uri)).not_to be_nil expect(template.match("#{uri}\ngarbage")).to be_nil end end describe "Type conversion" do subject { { :var => true, :hello => 1234, :nothing => nil, :sym => :symbolic, :decimal => BigDecimal('1') } } it_behaves_like 'expands', { '{var}' => 'true', '{hello}' => '1234', '{nothing}' => '', '{sym}' => 'symbolic', '{decimal}' => RUBY_VERSION < '2.4.0' ? '0.1E1' : '0.1e1' } end describe "Level 1:" do subject { {:var => "value", :hello => "Hello World!"} } it_behaves_like 'expands', { '{var}' => 'value', '{hello}' => 'Hello%20World%21' } end describe "Level 2" do subject { { :var => "value", :hello => "Hello World!", :path => "/foo/bar" } } context "Operator +:" do it_behaves_like 'expands', { '{+var}' => 'value', '{+hello}' => 'Hello%20World!', '{+path}/here' => '/foo/bar/here', 'here?ref={+path}' => 'here?ref=/foo/bar' } end context "Operator #:" do it_behaves_like 'expands', { 'X{#var}' => 'X#value', 'X{#hello}' => 'X#Hello%20World!' } end end describe "Level 3" do subject { { :var => "value", :hello => "Hello World!", :empty => "", :path => "/foo/bar", :x => "1024", :y => "768" } } context "Operator nil (multiple vars):" do it_behaves_like 'expands', { 'map?{x,y}' => 'map?1024,768', '{x,hello,y}' => '1024,Hello%20World%21,768' } end context "Operator + (multiple vars):" do it_behaves_like 'expands', { '{+x,hello,y}' => '1024,Hello%20World!,768', '{+path,x}/here' => '/foo/bar,1024/here' } end context "Operator # (multiple vars):" do it_behaves_like 'expands', { '{#x,hello,y}' => '#1024,Hello%20World!,768', '{#path,x}/here' => '#/foo/bar,1024/here' } end context "Operator ." do it_behaves_like 'expands', { 'X{.var}' => 'X.value', 'X{.x,y}' => 'X.1024.768' } end context "Operator /" do it_behaves_like 'expands', { '{/var}' => '/value', '{/var,x}/here' => '/value/1024/here' } end context "Operator ;" do it_behaves_like 'expands', { '{;x,y}' => ';x=1024;y=768', '{;x,y,empty}' => ';x=1024;y=768;empty' } end context "Operator ?" do it_behaves_like 'expands', { '{?x,y}' => '?x=1024&y=768', '{?x,y,empty}' => '?x=1024&y=768&empty=' } end context "Operator &" do it_behaves_like 'expands', { '?fixed=yes{&x}' => '?fixed=yes&x=1024', '{&x,y,empty}' => '&x=1024&y=768&empty=' } end end describe "Level 4" do subject { { :var => "value", :hello => "Hello World!", :path => "/foo/bar", :semi => ";", :list => %w(red green blue), :keys => {"semi" => ';', "dot" => '.', :comma => ','} } } context "Expansion with value modifiers" do it_behaves_like 'expands', { '{var:3}' => 'val', '{var:30}' => 'value', '{list}' => 'red,green,blue', '{list*}' => 'red,green,blue', '{keys}' => 'semi,%3B,dot,.,comma,%2C', '{keys*}' => 'semi=%3B,dot=.,comma=%2C', } end context "Operator + with value modifiers" do it_behaves_like 'expands', { '{+path:6}/here' => '/foo/b/here', '{+list}' => 'red,green,blue', '{+list*}' => 'red,green,blue', '{+keys}' => 'semi,;,dot,.,comma,,', '{+keys*}' => 'semi=;,dot=.,comma=,', } end context "Operator # with value modifiers" do it_behaves_like 'expands', { '{#path:6}/here' => '#/foo/b/here', '{#list}' => '#red,green,blue', '{#list*}' => '#red,green,blue', '{#keys}' => '#semi,;,dot,.,comma,,', '{#keys*}' => '#semi=;,dot=.,comma=,', } end context "Operator . with value modifiers" do it_behaves_like 'expands', { 'X{.var:3}' => 'X.val', 'X{.list}' => 'X.red,green,blue', 'X{.list*}' => 'X.red.green.blue', 'X{.keys}' => 'X.semi,%3B,dot,.,comma,%2C', 'X{.keys*}' => 'X.semi=%3B.dot=..comma=%2C', } end context "Operator / with value modifiers" do it_behaves_like 'expands', { '{/var:1,var}' => '/v/value', '{/list}' => '/red,green,blue', '{/list*}' => '/red/green/blue', '{/list*,path:4}' => '/red/green/blue/%2Ffoo', '{/keys}' => '/semi,%3B,dot,.,comma,%2C', '{/keys*}' => '/semi=%3B/dot=./comma=%2C', } end context "Operator ; with value modifiers" do it_behaves_like 'expands', { '{;hello:5}' => ';hello=Hello', '{;list}' => ';list=red,green,blue', '{;list*}' => ';list=red;list=green;list=blue', '{;keys}' => ';keys=semi,%3B,dot,.,comma,%2C', '{;keys*}' => ';semi=%3B;dot=.;comma=%2C', } end context "Operator ? with value modifiers" do it_behaves_like 'expands', { '{?var:3}' => '?var=val', '{?list}' => '?list=red,green,blue', '{?list*}' => '?list=red&list=green&list=blue', '{?keys}' => '?keys=semi,%3B,dot,.,comma,%2C', '{?keys*}' => '?semi=%3B&dot=.&comma=%2C', } end context "Operator & with value modifiers" do it_behaves_like 'expands', { '{&var:3}' => '&var=val', '{&list}' => '&list=red,green,blue', '{&list*}' => '&list=red&list=green&list=blue', '{&keys}' => '&keys=semi,%3B,dot,.,comma,%2C', '{&keys*}' => '&semi=%3B&dot=.&comma=%2C', } end end describe "Modifiers" do subject { { :var => "value", :semi => ";", :year => [1965, 2000, 2012], :dom => %w(example com) } } context "length" do it_behaves_like 'expands', { '{var:3}' => 'val', '{var:30}' => 'value', '{var}' => 'value', '{semi}' => '%3B', '{semi:2}' => '%3B' } end context "explode" do it_behaves_like 'expands', { 'find{?year*}' => 'find?year=1965&year=2000&year=2012', 'www{.dom*}' => 'www.example.com', } end end describe "Expansion" do subject { { :count => ["one", "two", "three"], :dom => ["example", "com"], :dub => "me/too", :hello => "Hello World!", :half => "50%", :var => "value", :who => "fred", :base => "http://example.com/home/", :path => "/foo/bar", :list => ["red", "green", "blue"], :keys => {"semi" => ";","dot" => ".",:comma => ","}, :v => "6", :x => "1024", :y => "768", :empty => "", :empty_keys => {}, :undef => nil } } context "concatenation" do it_behaves_like 'expands', { '{count}' => 'one,two,three', '{count*}' => 'one,two,three', '{/count}' => '/one,two,three', '{/count*}' => '/one/two/three', '{;count}' => ';count=one,two,three', '{;count*}' => ';count=one;count=two;count=three', '{?count}' => '?count=one,two,three', '{?count*}' => '?count=one&count=two&count=three', '{&count*}' => '&count=one&count=two&count=three' } end context "simple expansion" do it_behaves_like 'expands', { '{var}' => 'value', '{hello}' => 'Hello%20World%21', '{half}' => '50%25', 'O{empty}X' => 'OX', 'O{undef}X' => 'OX', '{x,y}' => '1024,768', '{x,hello,y}' => '1024,Hello%20World%21,768', '?{x,empty}' => '?1024,', '?{x,undef}' => '?1024', '?{undef,y}' => '?768', '{var:3}' => 'val', '{var:30}' => 'value', '{list}' => 'red,green,blue', '{list*}' => 'red,green,blue', '{keys}' => 'semi,%3B,dot,.,comma,%2C', '{keys*}' => 'semi=%3B,dot=.,comma=%2C', } end context "reserved expansion (+)" do it_behaves_like 'expands', { '{+var}' => 'value', '{+hello}' => 'Hello%20World!', '{+half}' => '50%25', '{base}index' => 'http%3A%2F%2Fexample.com%2Fhome%2Findex', '{+base}index' => 'http://example.com/home/index', 'O{+empty}X' => 'OX', 'O{+undef}X' => 'OX', '{+path}/here' => '/foo/bar/here', 'here?ref={+path}' => 'here?ref=/foo/bar', 'up{+path}{var}/here' => 'up/foo/barvalue/here', '{+x,hello,y}' => '1024,Hello%20World!,768', '{+path,x}/here' => '/foo/bar,1024/here', '{+path:6}/here' => '/foo/b/here', '{+list}' => 'red,green,blue', '{+list*}' => 'red,green,blue', '{+keys}' => 'semi,;,dot,.,comma,,', '{+keys*}' => 'semi=;,dot=.,comma=,', } end context "fragment expansion (#)" do it_behaves_like 'expands', { '{#var}' => '#value', '{#hello}' => '#Hello%20World!', '{#half}' => '#50%25', 'foo{#empty}' => 'foo#', 'foo{#undef}' => 'foo', '{#x,hello,y}' => '#1024,Hello%20World!,768', '{#path,x}/here' => '#/foo/bar,1024/here', '{#path:6}/here' => '#/foo/b/here', '{#list}' => '#red,green,blue', '{#list*}' => '#red,green,blue', '{#keys}' => '#semi,;,dot,.,comma,,', '{#keys*}' => '#semi=;,dot=.,comma=,', } end context "label expansion (.)" do it_behaves_like 'expands', { '{.who}' => '.fred', '{.who,who}' => '.fred.fred', '{.half,who}' => '.50%25.fred', 'www{.dom*}' => 'www.example.com', 'X{.var}' => 'X.value', 'X{.empty}' => 'X.', 'X{.undef}' => 'X', 'X{.var:3}' => 'X.val', 'X{.list}' => 'X.red,green,blue', 'X{.list*}' => 'X.red.green.blue', 'X{.keys}' => 'X.semi,%3B,dot,.,comma,%2C', 'X{.keys*}' => 'X.semi=%3B.dot=..comma=%2C', 'X{.empty_keys}' => 'X', 'X{.empty_keys*}' => 'X' } end context "path expansion (/)" do it_behaves_like 'expands', { '{/who}' => '/fred', '{/who,who}' => '/fred/fred', '{/half,who}' => '/50%25/fred', '{/who,dub}' => '/fred/me%2Ftoo', '{/var}' => '/value', '{/var,empty}' => '/value/', '{/var,undef}' => '/value', '{/var,x}/here' => '/value/1024/here', '{/var:1,var}' => '/v/value', '{/list}' => '/red,green,blue', '{/list*}' => '/red/green/blue', '{/list*,path:4}' => '/red/green/blue/%2Ffoo', '{/keys}' => '/semi,%3B,dot,.,comma,%2C', '{/keys*}' => '/semi=%3B/dot=./comma=%2C', } end context "path-style expansion (;)" do it_behaves_like 'expands', { '{;who}' => ';who=fred', '{;half}' => ';half=50%25', '{;empty}' => ';empty', '{;v,empty,who}' => ';v=6;empty;who=fred', '{;v,bar,who}' => ';v=6;who=fred', '{;x,y}' => ';x=1024;y=768', '{;x,y,empty}' => ';x=1024;y=768;empty', '{;x,y,undef}' => ';x=1024;y=768', '{;hello:5}' => ';hello=Hello', '{;list}' => ';list=red,green,blue', '{;list*}' => ';list=red;list=green;list=blue', '{;keys}' => ';keys=semi,%3B,dot,.,comma,%2C', '{;keys*}' => ';semi=%3B;dot=.;comma=%2C', } end context "form query expansion (?)" do it_behaves_like 'expands', { '{?who}' => '?who=fred', '{?half}' => '?half=50%25', '{?x,y}' => '?x=1024&y=768', '{?x,y,empty}' => '?x=1024&y=768&empty=', '{?x,y,undef}' => '?x=1024&y=768', '{?var:3}' => '?var=val', '{?list}' => '?list=red,green,blue', '{?list*}' => '?list=red&list=green&list=blue', '{?keys}' => '?keys=semi,%3B,dot,.,comma,%2C', '{?keys*}' => '?semi=%3B&dot=.&comma=%2C', } end context "form query expansion (&)" do it_behaves_like 'expands', { '{&who}' => '&who=fred', '{&half}' => '&half=50%25', '?fixed=yes{&x}' => '?fixed=yes&x=1024', '{&x,y,empty}' => '&x=1024&y=768&empty=', '{&x,y,undef}' => '&x=1024&y=768', '{&var:3}' => '&var=val', '{&list}' => '&list=red,green,blue', '{&list*}' => '&list=red&list=green&list=blue', '{&keys}' => '&keys=semi,%3B,dot,.,comma,%2C', '{&keys*}' => '&semi=%3B&dot=.&comma=%2C', } end context "non-string key in match data" do subject {Addressable::Template.new("http://example.com/{one}")} it "raises TypeError" do expect { subject.expand(Object.new => "1") }.to raise_error TypeError end end end class ExampleTwoProcessor def self.restore(name, value) return value.gsub(/-/, " ") if name == "query" return value end def self.match(name) return ".*?" if name == "first" return ".*" end def self.validate(name, value) return !!(value =~ /^[\w ]+$/) if name == "query" return true end def self.transform(name, value) return value.gsub(/ /, "+") if name == "query" return value end end class DumbProcessor def self.match(name) return ".*?" if name == "first" end end describe Addressable::Template do describe 'initialize' do context 'with a non-string' do it 'raises a TypeError' do expect { Addressable::Template.new(nil) }.to raise_error(TypeError) end end end describe 'freeze' do subject { Addressable::Template.new("http://example.com/{first}/{+second}/") } it 'freezes the template' do expect(subject.freeze).to be_frozen end end describe "Matching" do let(:uri){ Addressable::URI.parse( "http://example.com/search/an-example-search-query/" ) } let(:uri2){ Addressable::URI.parse("http://example.com/a/b/c/") } let(:uri3){ Addressable::URI.parse("http://example.com/;a=1;b=2;c=3;first=foo") } let(:uri4){ Addressable::URI.parse("http://example.com/?a=1&b=2&c=3&first=foo") } let(:uri5){ "http://example.com/foo" } context "first uri with ExampleTwoProcessor" do subject { Addressable::Template.new( "http://example.com/search/{query}/" ).match(uri, ExampleTwoProcessor) } its(:variables){ should == ["query"] } its(:captures){ should == ["an example search query"] } end context "second uri with ExampleTwoProcessor" do subject { Addressable::Template.new( "http://example.com/{first}/{+second}/" ).match(uri2, ExampleTwoProcessor) } its(:variables){ should == ["first", "second"] } its(:captures){ should == ["a", "b/c"] } end context "second uri with DumbProcessor" do subject { Addressable::Template.new( "http://example.com/{first}/{+second}/" ).match(uri2, DumbProcessor) } its(:variables){ should == ["first", "second"] } its(:captures){ should == ["a", "b/c"] } end context "second uri" do subject { Addressable::Template.new( "http://example.com/{first}{/second*}/" ).match(uri2) } its(:variables){ should == ["first", "second"] } its(:captures){ should == ["a", ["b","c"]] } end context "third uri" do subject { Addressable::Template.new( "http://example.com/{;hash*,first}" ).match(uri3) } its(:variables){ should == ["hash", "first"] } its(:captures){ should == [ {"a" => "1", "b" => "2", "c" => "3", "first" => "foo"}, nil] } end # Note that this expansion is impossible to revert deterministically - the # * operator means first could have been a key of hash or a separate key. # Semantically, a separate key is more likely, but both are possible. context "fourth uri" do subject { Addressable::Template.new( "http://example.com/{?hash*,first}" ).match(uri4) } its(:variables){ should == ["hash", "first"] } its(:captures){ should == [ {"a" => "1", "b" => "2", "c" => "3", "first"=> "foo"}, nil] } end context "fifth uri" do subject { Addressable::Template.new( "http://example.com/{path}{?hash*,first}" ).match(uri5) } its(:variables){ should == ["path", "hash", "first"] } its(:captures){ should == ["foo", nil, nil] } end end describe 'match' do subject { Addressable::Template.new('http://example.com/first/second/') } context 'when the URI is the same as the template' do it 'returns the match data itself with an empty mapping' do uri = Addressable::URI.parse('http://example.com/first/second/') match_data = subject.match(uri) expect(match_data).to be_an Addressable::Template::MatchData expect(match_data.uri).to eq(uri) expect(match_data.template).to eq(subject) expect(match_data.mapping).to be_empty expect(match_data.inspect).to be_an String end end end describe "extract" do let(:template) { Addressable::Template.new( "http://{host}{/segments*}/{?one,two,bogus}{#fragment}" ) } let(:uri){ "http://example.com/a/b/c/?one=1&two=2#foo" } let(:uri2){ "http://example.com/a/b/c/#foo" } it "should be able to extract with queries" do expect(template.extract(uri)).to eq({ "host" => "example.com", "segments" => %w(a b c), "one" => "1", "bogus" => nil, "two" => "2", "fragment" => "foo" }) end it "should be able to extract without queries" do expect(template.extract(uri2)).to eq({ "host" => "example.com", "segments" => %w(a b c), "one" => nil, "bogus" => nil, "two" => nil, "fragment" => "foo" }) end context "issue #137" do subject { Addressable::Template.new('/path{?page,per_page}') } it "can match empty" do data = subject.extract("/path") expect(data["page"]).to eq(nil) expect(data["per_page"]).to eq(nil) expect(data.keys.sort).to eq(['page', 'per_page']) end it "can match first var" do data = subject.extract("/path?page=1") expect(data["page"]).to eq("1") expect(data["per_page"]).to eq(nil) expect(data.keys.sort).to eq(['page', 'per_page']) end it "can match second var" do data = subject.extract("/path?per_page=1") expect(data["page"]).to eq(nil) expect(data["per_page"]).to eq("1") expect(data.keys.sort).to eq(['page', 'per_page']) end it "can match both vars" do data = subject.extract("/path?page=2&per_page=1") expect(data["page"]).to eq("2") expect(data["per_page"]).to eq("1") expect(data.keys.sort).to eq(['page', 'per_page']) end end end describe "Partial expand with symbols" do context "partial_expand with two simple values" do subject { Addressable::Template.new("http://example.com/{one}/{two}/") } it "builds a new pattern" do expect(subject.partial_expand(:one => "1").pattern).to eq( "http://example.com/1/{two}/" ) end end context "partial_expand query with missing param in middle" do subject { Addressable::Template.new("http://example.com/{?one,two,three}/") } it "builds a new pattern" do expect(subject.partial_expand(:one => "1", :three => "3").pattern).to eq( "http://example.com/?one=1{&two}&three=3/" ) end end context "partial_expand form style query with missing param at beginning" do subject { Addressable::Template.new("http://example.com/{?one,two}/") } it "builds a new pattern" do expect(subject.partial_expand(:two => "2").pattern).to eq( "http://example.com/?two=2{&one}/" ) end end context "issue #307 - partial_expand form query with nil params" do subject do Addressable::Template.new("http://example.com/{?one,two,three}/") end it "builds a new pattern with two=nil" do expect(subject.partial_expand(two: nil).pattern).to eq( "http://example.com/{?one}{&three}/" ) end it "builds a new pattern with one=nil and two=nil" do expect(subject.partial_expand(one: nil, two: nil).pattern).to eq( "http://example.com/{?three}/" ) end it "builds a new pattern with one=1 and two=nil" do expect(subject.partial_expand(one: 1, two: nil).pattern).to eq( "http://example.com/?one=1{&three}/" ) end it "builds a new pattern with one=nil and two=2" do expect(subject.partial_expand(one: nil, two: 2).pattern).to eq( "http://example.com/?two=2{&three}/" ) end it "builds a new pattern with one=nil" do expect(subject.partial_expand(one: nil).pattern).to eq( "http://example.com/{?two}{&three}/" ) end end context "partial_expand with query string" do subject { Addressable::Template.new("http://example.com/{?two,one}/") } it "builds a new pattern" do expect(subject.partial_expand(:one => "1").pattern).to eq( "http://example.com/?one=1{&two}/" ) end end context "partial_expand with path operator" do subject { Addressable::Template.new("http://example.com{/one,two}/") } it "builds a new pattern" do expect(subject.partial_expand(:one => "1").pattern).to eq( "http://example.com/1{/two}/" ) end end context "partial expand with unicode values" do subject do Addressable::Template.new("http://example.com/{resource}/{query}/") end it "normalizes unicode by default" do template = subject.partial_expand("query" => "Cafe\u0301") expect(template.pattern).to eq( "http://example.com/{resource}/Caf%C3%A9/" ) end it "normalizes as unicode even with wrong encoding specified" do template = subject.partial_expand("query" => "Cafe\u0301".b) expect(template.pattern).to eq( "http://example.com/{resource}/Caf%C3%A9/" ) end it "raises on invalid unicode input" do expect { subject.partial_expand("query" => "M\xE9thode".b) }.to raise_error(ArgumentError, "invalid byte sequence in UTF-8") end it "does not normalize unicode when byte semantics requested" do template = subject.partial_expand({"query" => "Cafe\u0301"}, nil, false) expect(template.pattern).to eq( "http://example.com/{resource}/Cafe%CC%81/" ) end end end describe "Partial expand with strings" do context "partial_expand with two simple values" do subject { Addressable::Template.new("http://example.com/{one}/{two}/") } it "builds a new pattern" do expect(subject.partial_expand("one" => "1").pattern).to eq( "http://example.com/1/{two}/" ) end end context "partial_expand query with missing param in middle" do subject { Addressable::Template.new("http://example.com/{?one,two,three}/") } it "builds a new pattern" do expect(subject.partial_expand("one" => "1", "three" => "3").pattern).to eq( "http://example.com/?one=1{&two}&three=3/" ) end end context "partial_expand with query string" do subject { Addressable::Template.new("http://example.com/{?two,one}/") } it "builds a new pattern" do expect(subject.partial_expand("one" => "1").pattern).to eq( "http://example.com/?one=1{&two}/" ) end end context "partial_expand with path operator" do subject { Addressable::Template.new("http://example.com{/one,two}/") } it "builds a new pattern" do expect(subject.partial_expand("one" => "1").pattern).to eq( "http://example.com/1{/two}/" ) end end end describe "Expand" do context "expand with unicode values" do subject do Addressable::Template.new("http://example.com/search/{query}/") end it "normalizes unicode by default" do uri = subject.expand("query" => "Cafe\u0301").to_str expect(uri).to eq("http://example.com/search/Caf%C3%A9/") end it "normalizes as unicode even with wrong encoding specified" do uri = subject.expand("query" => "Cafe\u0301".b).to_str expect(uri).to eq("http://example.com/search/Caf%C3%A9/") end it "raises on invalid unicode input" do expect { subject.expand("query" => "M\xE9thode".b).to_str }.to raise_error(ArgumentError, "invalid byte sequence in UTF-8") end it "does not normalize unicode when byte semantics requested" do uri = subject.expand({ "query" => "Cafe\u0301" }, nil, false).to_str expect(uri).to eq("http://example.com/search/Cafe%CC%81/") end end context "expand with a processor" do subject { Addressable::Template.new("http://example.com/search/{query}/") } it "processes spaces" do expect(subject.expand({"query" => "an example search query"}, ExampleTwoProcessor).to_str).to eq( "http://example.com/search/an+example+search+query/" ) end it "validates" do expect{ subject.expand({"query" => "Bogus!"}, ExampleTwoProcessor).to_str }.to raise_error(Addressable::Template::InvalidTemplateValueError) end end context "partial_expand query with missing param in middle" do subject { Addressable::Template.new("http://example.com/{?one,two,three}/") } it "builds a new pattern" do expect(subject.partial_expand("one" => "1", "three" => "3").pattern).to eq( "http://example.com/?one=1{&two}&three=3/" ) end end context "partial_expand with query string" do subject { Addressable::Template.new("http://example.com/{?two,one}/") } it "builds a new pattern" do expect(subject.partial_expand("one" => "1").pattern).to eq( "http://example.com/?one=1{&two}/" ) end end context "partial_expand with path operator" do subject { Addressable::Template.new("http://example.com{/one,two}/") } it "builds a new pattern" do expect(subject.partial_expand("one" => "1").pattern).to eq( "http://example.com/1{/two}/" ) end end end context "Matching with operators" do describe "Level 1:" do subject { Addressable::Template.new("foo{foo}/{bar}baz") } it "can match" do data = subject.match("foofoo/bananabaz") expect(data.mapping["foo"]).to eq("foo") expect(data.mapping["bar"]).to eq("banana") end it "can fail" do expect(subject.match("bar/foo")).to be_nil expect(subject.match("foobaz")).to be_nil end it "can match empty" do data = subject.match("foo/baz") expect(data.mapping["foo"]).to eq(nil) expect(data.mapping["bar"]).to eq(nil) end it "lists vars" do expect(subject.variables).to eq(["foo", "bar"]) end end describe "Level 2:" do subject { Addressable::Template.new("foo{+foo}{#bar}baz") } it "can match" do data = subject.match("foo/test/banana#bazbaz") expect(data.mapping["foo"]).to eq("/test/banana") expect(data.mapping["bar"]).to eq("baz") end it "can match empty level 2 #" do data = subject.match("foo/test/bananabaz") expect(data.mapping["foo"]).to eq("/test/banana") expect(data.mapping["bar"]).to eq(nil) data = subject.match("foo/test/banana#baz") expect(data.mapping["foo"]).to eq("/test/banana") expect(data.mapping["bar"]).to eq("") end it "can match empty level 2 +" do data = subject.match("foobaz") expect(data.mapping["foo"]).to eq(nil) expect(data.mapping["bar"]).to eq(nil) data = subject.match("foo#barbaz") expect(data.mapping["foo"]).to eq(nil) expect(data.mapping["bar"]).to eq("bar") end it "lists vars" do expect(subject.variables).to eq(["foo", "bar"]) end end describe "Level 3:" do context "no operator" do subject { Addressable::Template.new("foo{foo,bar}baz") } it "can match" do data = subject.match("foofoo,barbaz") expect(data.mapping["foo"]).to eq("foo") expect(data.mapping["bar"]).to eq("bar") end it "lists vars" do expect(subject.variables).to eq(["foo", "bar"]) end end context "+ operator" do subject { Addressable::Template.new("foo{+foo,bar}baz") } it "can match" do data = subject.match("foofoo/bar,barbaz") expect(data.mapping["bar"]).to eq("foo/bar,bar") expect(data.mapping["foo"]).to eq("") end it "lists vars" do expect(subject.variables).to eq(["foo", "bar"]) end end context ". operator" do subject { Addressable::Template.new("foo{.foo,bar}baz") } it "can match" do data = subject.match("foo.foo.barbaz") expect(data.mapping["foo"]).to eq("foo") expect(data.mapping["bar"]).to eq("bar") end it "lists vars" do expect(subject.variables).to eq(["foo", "bar"]) end end context "/ operator" do subject { Addressable::Template.new("foo{/foo,bar}baz") } it "can match" do data = subject.match("foo/foo/barbaz") expect(data.mapping["foo"]).to eq("foo") expect(data.mapping["bar"]).to eq("bar") end it "lists vars" do expect(subject.variables).to eq(["foo", "bar"]) end end context "; operator" do subject { Addressable::Template.new("foo{;foo,bar,baz}baz") } it "can match" do data = subject.match("foo;foo=bar%20baz;bar=foo;bazbaz") expect(data.mapping["foo"]).to eq("bar baz") expect(data.mapping["bar"]).to eq("foo") expect(data.mapping["baz"]).to eq("") end it "lists vars" do expect(subject.variables).to eq(%w(foo bar baz)) end end context "? operator" do context "test" do subject { Addressable::Template.new("foo{?foo,bar}baz") } it "can match" do data = subject.match("foo?foo=bar%20baz&bar=foobaz") expect(data.mapping["foo"]).to eq("bar baz") expect(data.mapping["bar"]).to eq("foo") end it "lists vars" do expect(subject.variables).to eq(%w(foo bar)) end end context "issue #137" do subject { Addressable::Template.new('/path{?page,per_page}') } it "can match empty" do data = subject.match("/path") expect(data.mapping["page"]).to eq(nil) expect(data.mapping["per_page"]).to eq(nil) expect(data.mapping.keys.sort).to eq(['page', 'per_page']) end it "can match first var" do data = subject.match("/path?page=1") expect(data.mapping["page"]).to eq("1") expect(data.mapping["per_page"]).to eq(nil) expect(data.mapping.keys.sort).to eq(['page', 'per_page']) end it "can match second var" do data = subject.match("/path?per_page=1") expect(data.mapping["page"]).to eq(nil) expect(data.mapping["per_page"]).to eq("1") expect(data.mapping.keys.sort).to eq(['page', 'per_page']) end it "can match both vars" do data = subject.match("/path?page=2&per_page=1") expect(data.mapping["page"]).to eq("2") expect(data.mapping["per_page"]).to eq("1") expect(data.mapping.keys.sort).to eq(['page', 'per_page']) end end context "issue #71" do subject { Addressable::Template.new("http://cyberscore.dev/api/users{?username}") } it "can match" do data = subject.match("http://cyberscore.dev/api/users?username=foobaz") expect(data.mapping["username"]).to eq("foobaz") end it "lists vars" do expect(subject.variables).to eq(%w(username)) expect(subject.keys).to eq(%w(username)) end end end context "& operator" do subject { Addressable::Template.new("foo{&foo,bar}baz") } it "can match" do data = subject.match("foo&foo=bar%20baz&bar=foobaz") expect(data.mapping["foo"]).to eq("bar baz") expect(data.mapping["bar"]).to eq("foo") end it "lists vars" do expect(subject.variables).to eq(%w(foo bar)) end end end end context "support regexes:" do context "EXPRESSION" do subject { Addressable::Template::EXPRESSION } it "should be able to match an expression" do expect(subject).to match("{foo}") expect(subject).to match("{foo,9}") expect(subject).to match("{foo.bar,baz}") expect(subject).to match("{+foo.bar,baz}") expect(subject).to match("{foo,foo%20bar}") expect(subject).to match("{#foo:20,baz*}") expect(subject).to match("stuff{#foo:20,baz*}things") end it "should fail on non vars" do expect(subject).not_to match("!{foo") expect(subject).not_to match("{foo.bar.}") expect(subject).not_to match("!{}") end end context "VARNAME" do subject { Addressable::Template::VARNAME } it "should be able to match a variable" do expect(subject).to match("foo") expect(subject).to match("9") expect(subject).to match("foo.bar") expect(subject).to match("foo_bar") expect(subject).to match("foo_bar.baz") expect(subject).to match("foo%20bar") expect(subject).to match("foo%20bar.baz") end it "should fail on non vars" do expect(subject).not_to match("!foo") expect(subject).not_to match("foo.bar.") expect(subject).not_to match("foo%2%00bar") expect(subject).not_to match("foo_ba%r") expect(subject).not_to match("foo_bar*") expect(subject).not_to match("foo_bar:20") end it 'should parse in a reasonable time' do expect do Timeout.timeout(0.1) do expect(subject).not_to match("0"*25 + "!") end end.not_to raise_error end end context "VARIABLE_LIST" do subject { Addressable::Template::VARIABLE_LIST } it "should be able to match a variable list" do expect(subject).to match("foo,bar") expect(subject).to match("foo") expect(subject).to match("foo,bar*,baz") expect(subject).to match("foo.bar,bar_baz*,baz:12") end it "should fail on non vars" do expect(subject).not_to match(",foo,bar*,baz") expect(subject).not_to match("foo,*bar,baz") expect(subject).not_to match("foo,,bar*,baz") end end context "VARSPEC" do subject { Addressable::Template::VARSPEC } it "should be able to match a variable with modifier" do expect(subject).to match("9:8") expect(subject).to match("foo.bar*") expect(subject).to match("foo_bar:12") expect(subject).to match("foo_bar.baz*") expect(subject).to match("foo%20bar:12") expect(subject).to match("foo%20bar.baz*") end it "should fail on non vars" do expect(subject).not_to match("!foo") expect(subject).not_to match("*foo") expect(subject).not_to match("fo*o") expect(subject).not_to match("fo:o") expect(subject).not_to match("foo:") end end end end describe Addressable::Template::MatchData do let(:template) { Addressable::Template.new('{foo}/{bar}') } subject(:its) { template.match('ab/cd') } its(:uri) { should == Addressable::URI.parse('ab/cd') } its(:template) { should == template } its(:mapping) { should == { 'foo' => 'ab', 'bar' => 'cd' } } its(:variables) { should == ['foo', 'bar'] } its(:keys) { should == ['foo', 'bar'] } its(:names) { should == ['foo', 'bar'] } its(:values) { should == ['ab', 'cd'] } its(:captures) { should == ['ab', 'cd'] } its(:to_a) { should == ['ab/cd', 'ab', 'cd'] } its(:to_s) { should == 'ab/cd' } its(:string) { should == its.to_s } its(:pre_match) { should == "" } its(:post_match) { should == "" } describe 'values_at' do it 'returns an array with the values' do expect(its.values_at(0, 2)).to eq(['ab/cd', 'cd']) end it 'allows mixing integer an string keys' do expect(its.values_at('foo', 1)).to eq(['ab', 'ab']) end it 'accepts unknown keys' do expect(its.values_at('baz', 'foo')).to eq([nil, 'ab']) end end describe '[]' do context 'string key' do it 'returns the corresponding capture' do expect(its['foo']).to eq('ab') expect(its['bar']).to eq('cd') end it 'returns nil for unknown keys' do expect(its['baz']).to be_nil end end context 'symbol key' do it 'returns the corresponding capture' do expect(its[:foo]).to eq('ab') expect(its[:bar]).to eq('cd') end it 'returns nil for unknown keys' do expect(its[:baz]).to be_nil end end context 'integer key' do it 'returns the full URI for index 0' do expect(its[0]).to eq('ab/cd') end it 'returns the corresponding capture' do expect(its[1]).to eq('ab') expect(its[2]).to eq('cd') end it 'returns nil for unknown keys' do expect(its[3]).to be_nil end end context 'other key' do it 'raises an exception' do expect { its[Object.new] }.to raise_error(TypeError) end end context 'with length' do it 'returns an array starting at index with given length' do expect(its[0, 2]).to eq(['ab/cd', 'ab']) expect(its[2, 1]).to eq(['cd']) end end end end addressable-2.8.7/Rakefile0000644000004100000410000000170314636033505015504 0ustar www-datawww-data# frozen_string_literal: true require 'rubygems' require 'rake' require File.join(File.dirname(__FILE__), 'lib', 'addressable', 'version') PKG_DISPLAY_NAME = 'Addressable' PKG_NAME = PKG_DISPLAY_NAME.downcase PKG_VERSION = Addressable::VERSION::STRING PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}" RELEASE_NAME = "REL #{PKG_VERSION}" PKG_SUMMARY = "URI Implementation" PKG_DESCRIPTION = <<-TEXT Addressable is an alternative implementation to the URI implementation that is part of Ruby's standard library. It is flexible, offers heuristic parsing, and additionally provides extensive support for IRIs and URI templates. TEXT PKG_FILES = FileList[ "data/**/*", "lib/**/*.rb", "spec/**/*.rb", "tasks/**/*.rake", "addressable.gemspec", "CHANGELOG.md", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", ] task :default => "spec" Dir['tasks/**/*.rake'].each { |rake| load rake } addressable-2.8.7/Gemfile0000644000004100000410000000110114636033505015322 0ustar www-datawww-data# frozen_string_literal: true source 'https://rubygems.org' gemspec group :test do gem 'bigdecimal' if RUBY_VERSION > '2.4' gem 'rspec', '~> 3.8' gem 'rspec-its', '~> 1.3' end group :coverage do gem "coveralls", "> 0.7", require: false, platforms: :mri gem "simplecov", require: false end group :development do gem 'launchy', '~> 2.4', '>= 2.4.3' gem 'redcarpet', :platform => :mri_19 gem 'yard' end group :test, :development do gem 'memory_profiler' gem "rake", ">= 12.3.3" end unless ENV["IDNA_MODE"] == "pure" gem "idn-ruby", platform: :mri end addressable-2.8.7/README.md0000644000004100000410000000626614636033505015327 0ustar www-datawww-data# Addressable
Homepage
github.com/sporkmonger/addressable
Author
Bob Aman
Copyright
Copyright © Bob Aman
License
Apache 2.0
[![Gem Version](https://img.shields.io/gem/dt/addressable.svg)][gem] [![Build Status](https://github.com/sporkmonger/addressable/workflows/CI/badge.svg)][actions] [![Test Coverage Status](https://img.shields.io/coveralls/sporkmonger/addressable.svg)][coveralls] [![Documentation Coverage Status](https://inch-ci.org/github/sporkmonger/addressable.svg?branch=master)][inch] [gem]: https://rubygems.org/gems/addressable [actions]: https://github.com/sporkmonger/addressable/actions [coveralls]: https://coveralls.io/r/sporkmonger/addressable [inch]: https://inch-ci.org/github/sporkmonger/addressable # Description Addressable is an alternative implementation to the URI implementation that is part of Ruby's standard library. It is flexible, offers heuristic parsing, and additionally provides extensive support for IRIs and URI templates. Addressable closely conforms to RFC 3986, RFC 3987, and RFC 6570 (level 4). # Reference - {Addressable::URI} - {Addressable::Template} # Example usage ```ruby require "addressable/uri" uri = Addressable::URI.parse("http://example.com/path/to/resource/") uri.scheme #=> "http" uri.host #=> "example.com" uri.path #=> "/path/to/resource/" uri = Addressable::URI.parse("http://www.詹姆斯.com/") uri.normalize #=> # ``` # URI Templates For more details, see [RFC 6570](https://www.rfc-editor.org/rfc/rfc6570.txt). ```ruby require "addressable/template" template = Addressable::Template.new("http://example.com/{?query*}") template.expand({ "query" => { 'foo' => 'bar', 'color' => 'red' } }) #=> # template = Addressable::Template.new("http://example.com/{?one,two,three}") template.partial_expand({"one" => "1", "three" => 3}).pattern #=> "http://example.com/?one=1{&two}&three=3" template = Addressable::Template.new( "http://{host}{/segments*}/{?one,two,bogus}{#fragment}" ) uri = Addressable::URI.parse( "http://example.com/a/b/c/?one=1&two=2#foo" ) template.extract(uri) #=> # { # "host" => "example.com", # "segments" => ["a", "b", "c"], # "one" => "1", # "two" => "2", # "fragment" => "foo" # } ``` # Install ```console $ gem install addressable ``` You may optionally turn on native IDN support by installing libidn and the idn gem: ```console $ sudo apt-get install libidn11-dev # Debian/Ubuntu $ brew install libidn # OS X $ gem install idn-ruby ``` # Semantic Versioning This project uses [Semantic Versioning](https://semver.org/). You can (and should) specify your dependency using a pessimistic version constraint covering the major and minor values: ```ruby spec.add_dependency 'addressable', '~> 2.7' ``` If you need a specific bug fix, you can also specify minimum tiny versions without preventing updates to the latest minor release: ```ruby spec.add_dependency 'addressable', '~> 2.3', '>= 2.3.7' ``` addressable-2.8.7/CHANGELOG.md0000644000004100000410000003110114636033505015643 0ustar www-datawww-data# Addressable 2.8.7 - Allow `public_suffix` 6 ([#535]) [#535]: https://github.com/sporkmonger/addressable/pull/535 # Addressable 2.8.6 - Memoize regexps for common character classes ([#524]) [#524]: https://github.com/sporkmonger/addressable/pull/524 # Addressable 2.8.5 - Fix thread safety issue with encoding tables ([#515]) - Define URI::NONE as a module to avoid serialization issues ([#509]) - Fix YAML serialization ([#508]) [#508]: https://github.com/sporkmonger/addressable/pull/508 [#509]: https://github.com/sporkmonger/addressable/pull/509 [#515]: https://github.com/sporkmonger/addressable/pull/515 # Addressable 2.8.4 - Restore `Addressable::IDNA.unicode_normalize_kc` as a deprecated method ([#504]) [#504]: https://github.com/sporkmonger/addressable/pull/504 # Addressable 2.8.3 - Fix template expand level 2 hash support for non-string objects ([#499], [#498]) [#499]: https://github.com/sporkmonger/addressable/pull/499 [#498]: https://github.com/sporkmonger/addressable/pull/498 # Addressable 2.8.2 - Improve cache hits and JIT friendliness ([#486](https://github.com/sporkmonger/addressable/pull/486)) - Improve code style and test coverage ([#482](https://github.com/sporkmonger/addressable/pull/482)) - Ensure reset of deferred validation ([#481](https://github.com/sporkmonger/addressable/pull/481)) - Resolve normalization differences between `IDNA::Native` and `IDNA::Pure` ([#408](https://github.com/sporkmonger/addressable/issues/408), [#492]) - Remove redundant colon in `Addressable::URI::CharacterClasses::AUTHORITY` regex ([#438](https://github.com/sporkmonger/addressable/pull/438)) (accidentally reverted by [#449] merge but [added back](https://github.com/sporkmonger/addressable/pull/492#discussion_r1105125280) in [#492]) [#492]: https://github.com/sporkmonger/addressable/pull/492 # Addressable 2.8.1 - refactor `Addressable::URI.normalize_path` to address linter offenses ([#430](https://github.com/sporkmonger/addressable/pull/430)) - update gemspec to reflect supported Ruby versions ([#466], [#464], [#463]) - compatibility w/ public_suffix 5.x ([#466], [#465], [#460]) - fixes "invalid byte sequence in UTF-8" exception when unencoding URLs containing non UTF-8 characters ([#459](https://github.com/sporkmonger/addressable/pull/459)) - `Ractor` compatibility ([#449]) - use the whole string instead of a single line for template match ([#431](https://github.com/sporkmonger/addressable/pull/431)) - force UTF-8 encoding only if needed ([#341](https://github.com/sporkmonger/addressable/pull/341)) [#449]: https://github.com/sporkmonger/addressable/pull/449 [#460]: https://github.com/sporkmonger/addressable/pull/460 [#463]: https://github.com/sporkmonger/addressable/pull/463 [#464]: https://github.com/sporkmonger/addressable/pull/464 [#465]: https://github.com/sporkmonger/addressable/pull/465 [#466]: https://github.com/sporkmonger/addressable/pull/466 # Addressable 2.8.0 - fixes ReDoS vulnerability in Addressable::Template#match - no longer replaces `+` with spaces in queries for non-http(s) schemes - fixed encoding ipv6 literals - the `:compacted` flag for `normalized_query` now dedupes parameters - fix broken `escape_component` alias - dropping support for Ruby 2.0 and 2.1 - adding Ruby 3.0 compatibility for development tasks - drop support for `rack-mount` and remove Addressable::Template#generate - performance improvements - switch CI/CD to GitHub Actions # Addressable 2.7.0 - added `:compacted` flag to `normalized_query` - `heuristic_parse` handles `mailto:` more intuitively - dropped explicit support for JRuby 9.0.5.0 - compatibility w/ public_suffix 4.x - performance improvements # Addressable 2.6.0 - added `tld=` method to allow assignment to the public suffix - most `heuristic_parse` patterns are now case-insensitive - `heuristic_parse` handles more `file://` URI variations - fixes bug in `heuristic_parse` when uri starts with digit - fixes bug in `request_uri=` with query strings - fixes template issues with `nil` and `?` operator - `frozen_string_literal` pragmas added - minor performance improvements in regexps - fixes to eliminate warnings # Addressable 2.5.2 - better support for frozen string literals - fixed bug w/ uppercase characters in scheme - IDNA errors w/ emoji URLs - compatibility w/ public_suffix 3.x # Addressable 2.5.1 - allow unicode normalization to be disabled for URI Template expansion - removed duplicate test # Addressable 2.5.0 - dropping support for Ruby 1.9 - adding support for Ruby 2.4 preview - add support for public suffixes and tld; first runtime dependency - hostname escaping should match RFC; underscores in hostnames no longer escaped - paths beginning with // and missing an authority are now considered invalid - validation now also takes place after setting a path - handle backslashes in authority more like a browser for `heuristic_parse` - unescaped backslashes in host now raise an `InvalidURIError` - `merge!`, `join!`, `omit!` and `normalize!` don't disable deferred validation - `heuristic_parse` now trims whitespace before parsing - host parts longer than 63 bytes will be ignored and not passed to libidn - normalized values always encoded as UTF-8 # Addressable 2.4.0 - support for 1.8.x dropped - double quotes in a host now raises an error - newlines in host will no longer get unescaped during normalization - stricter handling of bogus scheme values - stricter handling of encoded port values - calling `require 'addressable'` will now load both the URI and Template files - assigning to the `hostname` component with an `IPAddr` object is now supported - assigning to the `origin` component is now supported - fixed minor bug where an exception would be thrown for a missing ACE suffix - better partial expansion of URI templates # Addressable 2.3.8 - fix warnings - update dependency gems - support for 1.8.x officially deprecated # Addressable 2.3.7 - fix scenario in which invalid URIs don't get an exception until inspected - handle hostnames with two adjacent periods correctly - upgrade of RSpec # Addressable 2.3.6 - normalization drops empty query string - better handling in template extract for missing values - template modifier for `'?'` now treated as optional - fixed issue where character class parameters were modified - templates can now be tested for equality - added `:sorted` option to normalization of query strings - fixed issue with normalization of hosts given in `'example.com.'` form # Addressable 2.3.5 - added Addressable::URI#empty? method - Addressable::URI#hostname methods now strip square brackets from IPv6 hosts - compatibility with Net::HTTP in Ruby 2.0.0 - Addressable::URI#route_from should always give relative URIs # Addressable 2.3.4 - fixed issue with encoding altering its inputs - query string normalization now leaves ';' characters alone - FakeFS is detected before attempting to load unicode tables - additional testing to ensure frozen objects don't cause problems # Addressable 2.3.3 - fixed issue with converting common primitives during template expansion - fixed port encoding issue - removed a few warnings - normalize should now ignore %2B in query strings - the IDNA logic should now be handled by libidn in Ruby 1.9 - no template match should now result in nil instead of an empty MatchData - added license information to gemspec # Addressable 2.3.2 - added Addressable::URI#default_port method - fixed issue with Marshalling Unicode data on Windows - improved heuristic parsing to better handle IPv4 addresses # Addressable 2.3.1 - fixed missing unicode data file # Addressable 2.3.0 - updated Addressable::Template to use RFC 6570, level 4 - fixed compatibility problems with some versions of Ruby - moved unicode tables into a data file for performance reasons - removing support for multiple query value notations # Addressable 2.2.8 - fixed issues with dot segment removal code - form encoding can now handle multiple values per key - updated development environment # Addressable 2.2.7 - fixed issues related to Addressable::URI#query_values= - the Addressable::URI.parse method is now polymorphic # Addressable 2.2.6 - changed the way ambiguous paths are handled - fixed bug with frozen URIs - https supported in heuristic parsing # Addressable 2.2.5 - 'parsing' a pre-parsed URI object is now a dup operation - introduced conditional support for libidn - fixed normalization issue on ampersands in query strings - added additional tests around handling of query strings # Addressable 2.2.4 - added origin support from draft-ietf-websec-origin-00 - resolved issue with attempting to navigate below root - fixed bug with string splitting in query strings # Addressable 2.2.3 - added :flat_array notation for query strings # Addressable 2.2.2 - fixed issue with percent escaping of '+' character in query strings # Addressable 2.2.1 - added support for application/x-www-form-urlencoded. # Addressable 2.2.0 - added site methods - improved documentation # Addressable 2.1.2 - added HTTP request URI methods - better handling of Windows file paths - validation_deferred boolean replaced with defer_validation block - normalization of percent-encoded paths should now be correct - fixed issue with constructing URIs with relative paths - fixed warnings # Addressable 2.1.1 - more type checking changes - fixed issue with unicode normalization - added method to find template defaults - symbolic keys are now allowed in template mappings - numeric values and symbolic values are now allowed in template mappings # Addressable 2.1.0 - refactored URI template support out into its own class - removed extract method due to being useless and unreliable - removed Addressable::URI.expand_template - removed Addressable::URI#extract_mapping - added partial template expansion - fixed minor bugs in the parse and heuristic_parse methods - fixed incompatibility with Ruby 1.9.1 - fixed bottleneck in Addressable::URI#hash and Addressable::URI#to_s - fixed unicode normalization exception - updated query_values methods to better handle subscript notation - worked around issue with freezing URIs - improved specs # Addressable 2.0.2 - fixed issue with URI template expansion - fixed issue with percent escaping characters 0-15 # Addressable 2.0.1 - fixed issue with query string assignment - fixed issue with improperly encoded components # Addressable 2.0.0 - the initialize method now takes an options hash as its only parameter - added query_values method to URI class - completely replaced IDNA implementation with pure Ruby - renamed Addressable::ADDRESSABLE_VERSION to Addressable::VERSION - completely reworked the Rakefile - changed the behavior of the port method significantly - Addressable::URI.encode_segment, Addressable::URI.unencode_segment renamed - documentation is now in YARD format - more rigorous type checking - to_str method implemented, implicit conversion to Strings now allowed - Addressable::URI#omit method added, Addressable::URI#merge method replaced - updated URI Template code to match v 03 of the draft spec - added a bunch of new specifications # Addressable 1.0.4 - switched to using RSpec's pending system for specs that rely on IDN - fixed issue with creating URIs with paths that are not prefixed with '/' # Addressable 1.0.3 - implemented a hash method # Addressable 1.0.2 - fixed minor bug with the extract_mapping method # Addressable 1.0.1 - fixed minor bug with the extract_mapping method # Addressable 1.0.0 - heuristic parse method added - parsing is slightly more strict - replaced to_h with to_hash - fixed routing methods - improved specifications - improved heckle rake task - no surviving heckle mutations # Addressable 0.1.2 - improved normalization - fixed bug in joining algorithm - updated specifications # Addressable 0.1.1 - updated documentation - added URI Template variable extraction # Addressable 0.1.0 - initial release - implementation based on RFC 3986, 3987 - support for IRIs via libidn - support for the URI Template draft spec addressable-2.8.7/addressable.gemspec0000644000004100000410000000426114636033505017657 0ustar www-datawww-data# -*- encoding: utf-8 -*- # stub: addressable 2.8.7 ruby lib Gem::Specification.new do |s| s.name = "addressable".freeze s.version = "2.8.7".freeze s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "changelog_uri" => "https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md#v2.8.7" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Bob Aman".freeze] s.date = "2024-06-21" s.description = "Addressable is an alternative implementation to the URI implementation that is\npart of Ruby's standard library. It is flexible, offers heuristic parsing, and\nadditionally provides extensive support for IRIs and URI templates.\n".freeze s.email = "bob@sporkmonger.com".freeze s.extra_rdoc_files = ["README.md".freeze] s.files = ["CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE.txt".freeze, "README.md".freeze, "Rakefile".freeze, "addressable.gemspec".freeze, "data/unicode.data".freeze, "lib/addressable.rb".freeze, "lib/addressable/idna.rb".freeze, "lib/addressable/idna/native.rb".freeze, "lib/addressable/idna/pure.rb".freeze, "lib/addressable/template.rb".freeze, "lib/addressable/uri.rb".freeze, "lib/addressable/version.rb".freeze, "spec/addressable/idna_spec.rb".freeze, "spec/addressable/net_http_compat_spec.rb".freeze, "spec/addressable/security_spec.rb".freeze, "spec/addressable/template_spec.rb".freeze, "spec/addressable/uri_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tasks/clobber.rake".freeze, "tasks/gem.rake".freeze, "tasks/git.rake".freeze, "tasks/metrics.rake".freeze, "tasks/profile.rake".freeze, "tasks/rspec.rake".freeze, "tasks/yard.rake".freeze] s.homepage = "https://github.com/sporkmonger/addressable".freeze s.licenses = ["Apache-2.0".freeze] s.rdoc_options = ["--main".freeze, "README.md".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.2".freeze) s.rubygems_version = "3.5.11".freeze s.summary = "URI Implementation".freeze s.specification_version = 4 s.add_runtime_dependency(%q.freeze, [">= 2.0.2".freeze, "< 7.0".freeze]) s.add_development_dependency(%q.freeze, [">= 1.0".freeze, "< 3.0".freeze]) end