pax_global_header00006660000000000000000000000064147323133410014513gustar00rootroot0000000000000052 comment=86a755578f7bfb82fddc1f712c96db2f0bf36076 xq-1.3.0/000077500000000000000000000000001473231334100121445ustar00rootroot00000000000000xq-1.3.0/.github/000077500000000000000000000000001473231334100135045ustar00rootroot00000000000000xq-1.3.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001473231334100156675ustar00rootroot00000000000000xq-1.3.0/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000003211473231334100203550ustar00rootroot00000000000000--- name: Bug report about: Something works wrong title: '' labels: bug assignees: sibprogrammer --- **Problem Statement** TBD **Steps to Reproduce** TBD **Actual Result** TBD **Expected Result** TBD xq-1.3.0/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000002641473231334100214160ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: '' labels: enhancement assignees: sibprogrammer --- **Problem Statement** TBD **Expected Result** TBD xq-1.3.0/.github/dependabot.yml000066400000000000000000000002271473231334100163350ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: "gomod" directory: "/" schedule: interval: "weekly" commit-message: prefix: "TECH " xq-1.3.0/.github/workflows/000077500000000000000000000000001473231334100155415ustar00rootroot00000000000000xq-1.3.0/.github/workflows/build.yml000066400000000000000000000011761473231334100173700ustar00rootroot00000000000000name: build on: push: paths: - '**.go' - 'go.mod' - 'build.yml' pull_request: paths: - '**.go' - 'go.mod' - 'build.yml' jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: ^1.23 - name: Build run: go build - name: Test run: go test -coverprofile=coverage.txt -covermode=atomic -v ./... - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} xq-1.3.0/.github/workflows/release.yml000066400000000000000000000010411473231334100177000ustar00rootroot00000000000000name: release on: push: tags: - '*' jobs: release: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go uses: actions/setup-go@v5 with: go-version: ^1.23 - name: Release uses: goreleaser/goreleaser-action@v5 with: distribution: goreleaser version: latest args: release --rm-dist env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} xq-1.3.0/.gitignore000066400000000000000000000000371473231334100141340ustar00rootroot00000000000000/xq /.env /dist/ /coverage.txt xq-1.3.0/.goreleaser.yml000066400000000000000000000012061473231334100150740ustar00rootroot00000000000000project_name: xq builds: - env: - CGO_ENABLED=0 goos: - linux - darwin - aix - windows goarch: - 386 - amd64 - arm64 - arm - ppc64 goamd64: - '' goarm: - '6' - '7' ignore: - goos: linux goarch: ppc64 - goos: windows goarch: 386 - goos: windows goarch: arm - goos: windows goarch: arm64 archives: - format_overrides: - goos: windows format: zip checksum: name_template: 'checksums.txt' snapshot: name_template: "{{ .Tag }}" changelog: filters: exclude: - '^TECH' xq-1.3.0/Dockerfile000066400000000000000000000003251473231334100141360ustar00rootroot00000000000000FROM golang:1.23 as builder ARG CGO_ENABLED=0 WORKDIR /opt COPY go.mod go.sum ./ RUN go mod download COPY . . RUN go build FROM ubuntu:22.04 COPY --from=builder /opt/xq /usr/local/bin/xq ENTRYPOINT ["bash"] xq-1.3.0/LICENSE000066400000000000000000000020651473231334100131540ustar00rootroot00000000000000MIT License Copyright (c) 2021-2024 Alexey Yuzhakov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. xq-1.3.0/README.md000066400000000000000000000070201473231334100134220ustar00rootroot00000000000000# xq [![build](https://github.com/sibprogrammer/xq/workflows/build/badge.svg)](https://github.com/sibprogrammer/xq/actions) [![Go Report Card](https://goreportcard.com/badge/github.com/sibprogrammer/xq)](https://goreportcard.com/report/github.com/sibprogrammer/xq) [![Codecov](https://codecov.io/gh/sibprogrammer/xq/branch/master/graph/badge.svg?token=G6QX77SQOH)](https://codecov.io/gh/sibprogrammer/xq) [![Scc Count](https://sloc.xyz/github/sibprogrammer/xq/)](https://github.com/sibprogrammer/xq/) [![Homebrew](https://img.shields.io/badge/dynamic/json.svg?url=https://formulae.brew.sh/api/formula/xq.json&query=$.versions.stable&label=homebrew)](https://formulae.brew.sh/formula/xq) [![Macports](https://repology.org/badge/version-for-repo/macports/xq-sibprogrammer.svg)](https://repology.org/project/xq-sibprogrammer/versions) Command-line XML and HTML beautifier and content extractor. ![xq](./assets/images/screenshot.png?raw=true) # Features * Syntax highlighting * Automatic indentation and formatting * Automatic pagination * Node content extraction # Usage Format an XML file and highlight the syntax: ``` xq test/data/xml/unformatted.xml ``` `xq` also accepts input through `stdin`: ``` curl -s https://www.w3schools.com/xml/note.xml | xq ``` HTML content can be formatted and highlighted as well (using `-m` flag): ``` xq -m test/data/html/formatted.html ``` It is possible to extract the content using XPath query language. `-x` parameter accepts XPath expression. Extract the text content of all nodes with `city` name: ``` cat test/data/xml/unformatted.xml | xq -x //city ``` Extract the value of attribute named `status` and belonging to `user`: ``` cat test/data/xml/unformatted.xml | xq -x /user/@status ``` See https://en.wikipedia.org/wiki/XPath for details. It is possible to use CSS selector to extract the content as well: ``` cat test/data/html/unformatted.html | xq -q "body > p" ``` Extract an attribute value instead of node content additional option `--attr` (`-a`) can be used: ``` cat test/data/html/unformatted.html | xq -q "head > script" -a "src" ``` Extract part of HTML with tags (not only text content) using CSS selector: ``` cat test/data/html/unformatted.html | xq -n -q "head" ``` Output the result as JSON: ``` cat test/data/xml/unformatted.xml | xq -j ``` This will output the result in JSON format, preserving the XML structure. The JSON output will be an object where: - XML elements become object keys - Attributes are prefixed with "@" - Text content is stored under "#text" if the element has attributes or child elements - Repeated elements are automatically converted to arrays - Elements with only text content are represented as strings # Installation The preferable ways to install the utility are described below. For macOS, via [Homebrew](https://brew.sh): ``` brew install xq ``` For macOS, via [MacPorts](https://www.macports.org): ``` sudo port install xq ``` For Linux using custom installer: ``` curl -sSL https://bit.ly/install-xq | sudo bash ``` For Ubuntu 22.10 or higher via package manager: ``` apt-get install xq ``` For Fedora via package manager: ``` dnf install xq ``` A more detailed list of Linux distros that package the `xq` utility can be found here: https://repology.org/project/xq-sibprogrammer/versions If you have Go toolchain installed, you can use the following command to install `xq`: ``` go install github.com/sibprogrammer/xq@latest ``` You can play with the `xq` utility using the Dockerized environment: ``` docker-compose run --rm xq xq /opt/examples/xml/unformatted.xml ``` xq-1.3.0/assets/000077500000000000000000000000001473231334100134465ustar00rootroot00000000000000xq-1.3.0/assets/images/000077500000000000000000000000001473231334100147135ustar00rootroot00000000000000xq-1.3.0/assets/images/screenshot.png000066400000000000000000004314751473231334100176140ustar00rootroot00000000000000PNG  IHDRy}n ?iCCPICC ProfileHWXS[EJMEJ-t*ZP ]Qp-Ql`e],ؕ7)̹s@8O"C5J‚X)i,c@t@Z/cc,kZEK ,B!(C|/@S %r +Б!^$YJ\%JWaǁ5*'yV? j v Db4XO@-@,N'oC<^VEQԂE<޴3}XJ͖ v#wRS!gD@ {@a1Jɖ'*Q#~ 0!v#!68T32E\ A CHX,6dJ9l'U'Md_e *}^ 1b"QR4t r#U69у6RY<~K >V) Sٗ ۜ-Fpe~V>O? !u)QsCsǞ ʼn* 8X"ɋU¼09o[AQj,TRϔ&(ċsxx p@0``^x < Y@UdE^A1"!("bWG-R! Cޒ#Ȉ+ƛ7 (#$Pnx{ރfOxL$< \%tnN͓hCU>5tǃp?q&nq7臍@gfPّ(YHq$ݞ>"Qƚ1oPϏ9e_-E~ ;cÚ 9Z]k["\#'+dssge_p|IiRQVv! BWwrqvq@}Qn_!BBh1@L+qA$BT$BĈ Gʐrd=A~E!'H'r (RQFG^(Dh:-FKѵh5m@Oѫh1138X ebRlVU`X e >DpGDOgKNo/>+F0"8|\B !0PB l'$R7-Hdm]L%7ljć~d@r bH^Io_ kXi5&hkTh׸ѫIִh4giVjҼٯDkY$mkm'20331N1u:6:\2=::}ںnISu+uv115c.cc^c~3c ]{?L?P___U `A]CpÍ { V:l߰[FQtFMÌ%O0MMrLV51eLW3}eYyVVYlY'sDyw-(^,Z,,M-G[ΰeEʶZcf:zuS}MM[mdj+vD;/\ v}}EAs8apl"ZNL(yNN/FXHbDۈyۜo1r摯\]..W\i]\_9 6pgv_CQiYyK+kowl|<| }(QQF=3mgo 0 T<n|¶cw_9Ipfrca!!!CfֆM;N _~ksk}3#Z##DGIG#F}'*Zb1+cNm qL1F͈kgO6!(aYDDYbKFҸw])#RfO5L6ҒҶ zl8q%㮍?u &17q:!=9}Wg^ ןͨskU\$/WOFJ  u'"ʢS쟪5U<4i=)-e:>?eٌ3d2 1e927w{3?y~s<)zB߅D.^k\sYE%%~ڟf.m_lrrk+V,*/.rʆUUެl[Ŧ555]k6\|VUWU-zAu7mYƖ- [[>ޖ_jn/exGθ555v-Eke=αnK=l/+_ײkUKi }ٍ]MM"46W=(肣NJ=uaĖ'SN^i~*ԙӡOێ;sC58p?pbSwGsΣ.|Wv^Kv]77̻VѭO!)yѽ?:r?n??|i+>ypOhOdzϺK-SϪ/ׅҗ6xۛ{o~zW^>&|ig_4zg `@“hf&v@K!(c?EAgV +ψ@lzԆ>!Cu8W 6͕]?@~l<|eXIfMM*>F(iNx֠ASCIIScreenshotG% pHYs%%IR$iTXtXML:com.adobe.xmp 712 1238 Screenshot kbiDOTd(ddT0]i@IDATx]`>=$@h! *bAw>{޻ر QQ ^͝ܝ&xdgέٽ)A䣜r)#p]( QP<_,     sWɜUsVՔj YRR̙3k E]]\\<;1J*jVs_yDA@A@A@A@}@1`LQp0P вࠠz;**_|ӾzDvZTdd5Uה/)-RcFOUUUyڞA@A@A@A@9֘/"""/,<<3$8񒒢YN6HuYGTTVTRRVXXHTVVPr^A@A@A@A@h1S\\0)4$7|sN}pKykׯV&ӂfVrNA@A@A@Ae#M$l'sI$3<,<򵢢3lD    5j۶-DG[VVz1CASm5oL9*    .:t@qqo,Zb3θ+/7օFA@A@A@A@S|{3;kSNk9d_A@A@A@A@!R&>ȷ~{=v@;s"srVn۶-M     8ҥ6}_Xڔ)ݺ3c@     P4Hr̙?X(Q[vݮnIA@A@A@A@ Ю]q1%Xk'O>{WUU B     `%> E?ٻt_A@A@A@A@AmgAӦMYacvYYY#    6YHgjZRJe/1eh:yL uMv}?|1]CpmU?irh~!}kmvRxUϚ-3a=/ɯ)'A@ւ &(SdΜ9\38&H7|:n-;X ^tE.ɺukC,,l~&==\7OWAp_Eܹsi۶m0p- T& LAA`+2 Zprѐ)(^=W^ʬر.JOJ3;yК0믿(&& 6|iȑ1v`vסCXXe#F.afH 9c[:S21_`* _|RX,#*oȦv6zY(" 3aeJ ' j#C jzcNcȝ# hb4ǽfm׹5'|rJA 'GqA{nSaW-X?&pԷo_/(_kMځ&ḫg6\5KtZKhhtAJC&G%\Bڵg1ZeqA@GnV0_kvE,tSUDH0b`~z{Xԩ{I^,Xƒ%AG\ϵw'%)W9+0UO3a5f &ת酭\;5.OJZY+wbM)α=E^5ڎN' T[ jd>NZϑUL4G4B!@E^xC;L=5QL ~kaB+--M'+r%>Hv@L\Is!㎳w}gˎ4&k%5 FkQFYp5IV.:/oF-hAh` ?:qg j7d/ `%a.$6XV}>ծցF']yW ic"c3s >n܆Rۅ2WV۾j54T2x6?`l[3ٔ㜀\ OkKlEh-gzR=F#Xki\9QlDA@4)xۆlv;w*1{2ShGX,(up'F$_G0 ƍǿ+k6m8DƗPG5s7, "oܸ ,LGvZݼ)%,MJaAtQW [N8E3CT+h y\;vD B{aMwsO,H!&Q/~Ub͇yE3Lqm)ЮuOHHP >P?\7W>,D CvAP7NfO`0pҌsAyYDxaY8{F7#^k,0vUMZaoQ CA_yk>`#0N*A@^Au>fG`xٲeN `fMXXĴ% 񧑫RhBr")S j*f75ZkV5L \/r\wb<0*I1 e1P5v P$:Dt^gOF@No)Iv GH;zUg$2_s]YP@g.Aߎ?x›1wo)sKre9O/ETA_yE<+ .@4 H E;V!?"<(O4I*dzKFGu&SC8|A] ȉɓ'CELX:uY/YDc|NR~1>3; @$1 `@ L@矄ȕZkF= C_hyꩧ@_`v |"ty_3 6'NCKn3gT9Z@bNo9lݍA8]=[ o6[3P;Tf~ >DZ/v/q/ >9#> q^6)ʺ.+[A@^wZk E^K5xZ~6lDyR~%'y'Z1g@lb^](.4Dz&ypGl-zHiIb lFa>G }6ZY.S(5ݾCK͡RkǾ"j)bW}e+W9BŖr;%"(d51Ku~nh _ѓʒ*|&m.3ReWA+]?дN8-y|`&)RMCy`h! A 3<4L2wQa'U?,r%Xx -{C/"SZE1s" IଳrKunw,D{'Ěq[oQ~3&O<*kX4rwq~ƌ&*s5CX;cB OZSy͹c; λ'8io"ʀE>?к!`^!ίz⪾k s M; +xnjd;6:k  Ł"/]Y x3r^^oI=/Q#Bk/!K]pƺ[q)z1_dr?@kYNu%)N 2 OvݭuLJmXCTURH3nˢ d0ul,]t4T/A"֐s|RKmkJ9msزu>=)g9`A yQT^meXMWMbReg|CYK '@)SX9 iiiNx`&6V%AW;UŢoV$ꄶAFxgU`x-3h_kvRE׃YLN[Aއ/hjXZzzb~Wbk0+8󕹞zN`簐Y6ŮqL-k kanxN>]tyzgZub bnX]` i'\k ~@kM,4(?s+{}f9+ANT |x_yySJq3'I諯F)_h_pu@ hZ- 0v~2k 2i /LGmU8\C7n2ֳ#Z=)A@Z8x!3bw k( 2-3|"^N>\v3xXߘ,ԏv]llXDv.gT<''7`ePPj arJEAjyt׺f^=--2IM@ }ue~@yQȃ RLQu C5n>LT}7wPz5wќctytjp3Khk 3EA@Acj,t?W|@QxY/6} %L(5L:"$C>YfnB3y g}67QRZTĀbؤYLA])0CU$;9UL/ZlzJioA [,45UP|˙cƌQt&qj` e]G4s s݂ FAЂ`^]wy7PoAz꩔K,Ӗ;b ܵ^D69S04sy xrR_siPC}G|W;2|>Ch0cmzD}UҴiӬ:-W&qz1 4p3a}Nuk@AD֋֩x pИ^JCS.B&^ԝ s kvD?,6gcNeAb1!ӒS#yQ, bMmEet HYfܐL*@;yڑ6o!9+GU1#dѴG#zґ"ڇ9bTg4UwSe`'OGj#Ҭ ZsGvA@SK=:Bd)1#` wO56f34L Q:n8Yh"}pDс0dk/?,0!94j X`k sUQio64-O9 pmD;yMA횥ꪫ<:>NIk LXM2h}kxh ]hAkצzkH;餓>B`zf! >2-XCBť4Oxy $w^f~ٌ5İbV4u>wmTúƮKX|>L1`뾷#7 BiDZd>PxZk_>bZ}羽;"ē"C3tjVRurQ5U;S+P 4D_5~5jj6[NUcxT]VEnަKVAC`Oh5V`v᧟~_\sSՅ3qU ҜzTZ4l_vRԖu@ - ḺtŬ>b4OEY ]0h15h{_}"t^lD@b/InZ[SB "#_{{ \-u~s A?68yɥI,Tz!<kvRBAA3"AgSڡcb-!@YjQ0|{֗TVYQU4-(48<t[,*B.k'Ifb-<&TyGc1n_eT0T=<"8PS7Ph?'Ty_@&a1_Y^Moڪɇ eω'4 0k?.haX~ 7M1eŁ] Ą6 LOOW6u=X3MSV;bj:ĚFpm9Bċ]D(s0^ZB .ߴSc vHk`*+ބxƽEoؓo>6vEH!R|O@cnmZ#sv c[, suEk  zQeFƚZ L2Rی Y;R /&^ЃFS^hfFAt:pݒ;R(yjZSԵ]HMܔiR5$)}da"Ki~g5\s[wWдGjWysK' oh_&kspkV^uq (8K2tA@ @ 7nM섃_w*04XЖN.h7?I$>/ 7.0 Mz3WL_:?4'|RaṿMϮ -#Shم̇8|ל4r}Mf0mD `>NL y|U~ޕ %2Cʙs>2}|nhųWXCGSLS~o{>5Du9O{^څ *1LBݞϮhVkisCuG웙@eqN5!A"$y%^x w@zzk=cx9ML5Xgú!60ݑ uASMD07c ! ^̚7A9xAH!=~MPB|"sռm6Ȃ/RSpTFj辡0TUT*|9[Eh޲綣6ؠj_3~_>4>SxYgs?2A_0{?8A )Uh-43xU"H!Tq >X`h(K~/k-^z)\~7JTC4[77vjǶt~d(X~rR./Pg| ;6?3qJ 䖢P We;k|LK~bTr!3Π< ӱQ 5jn|ůuT#)eBc_5hө}nVE#垪^oOkr2?),/6y\AZM ';Arp #*wgԩ6(>}:DfC; xiń@[<ؚ ql'U\EFm~]C$ZrrrTee=XC0wIsM9~{$K@9ӕI@MͰsw%?b7Mt?$hA&uC` 7ZqqBt^/B`fP7Dѩմ67"MԆ\f;E o!'Hi xuA@t:pI3nhڳsw6-q {0AIy'Р1?e -A,nE ކ#se„ K EDy֯3`S TU85ݓkz ! @ ]Np#k@ADv5WL0MZ&sP*̋};qj5 `T"VbxôwpFRTҗғwrIm脑Sc5[i X#5]BI`:DIphfU}9><^V= 8j=I' 1cƌQf>&ڧp 5xw coD5oВ |ğF /4`Ia͋5y`m 籆ß)7#ǛۇaKXCE5R(5* )N9G%( 0[RCX<(oΠeu/U܋|urJMUM:o"QF6wA8nO[QL2 bӰE`>G[s2EҬ ^6nm5("!>o4L/;fC{}Y*Ғ hdOJSk' &M ~CS tX;:ekH[Thj3QxJZsO`NF-sw& TL>b ux-Ok֍|?0 k 5$tXc%B' R['A@ zkz05unfI @Cw/ 4w!^]b 9.9.I@Yc'`pVqDb53/lɤ/c~|LMOlC!K bw/P gf'ћEG'%Ppv~rC8pv~CtA@ Gě3f8e+  !M6S+ iqdb f .LRy]i 2u|Q-ڂ8vN6 qN"鼾nO>d'# hX53n85,! _pm:~Id&A!+rhjfK/ڲ^-ƚNC݈@j'000YcǾi)8v% \y|_Ѿ1y6Pޠ4Yеk.\if0 hE]Zs e}foBid+ "0b U1uNfr AH ħOc| 6_pM5{QCb)"9W>w)a 8nR\YF (Tc*ǂ 4%kaJf:wU?f@@{ *YsUWYU(vXW -0dE}Y+z_cl~K k>ƵC(68D?ULsV^(~ڛG?ds$TkâhHD':$& JǿK%PbGP1fX4G ƍ 5g0WQ\Ey(gQ!wP;r^A ؉|Oyh@s0sG/2h4gq"J!LDFn }g@anCS.=={z-{B56R @k@Q5 L($[HAƌPfim)-ՅɴźHn0&v Ծ ;`c~-36U[iɆ2Z%0A \tIQ])c(%(b,Y6~6V_<վR~!1  " Z-'    xkC%A@A@A@A@ZXBA@A@A@A@bc$     PkXȞ     1By dA@A@A@A@jb A@A@A@A@&EA@A@A@A@!d    > 16b" `">0PFAkzRA@A@A@gXsCFE@FW*A@5   4 B5 Ҋ bM&BS ZS,m   ETP1" r7QUEȄ0jnNC@wMeD   <y]W}A}qb*Uj!4nֱ>Xk}TF$  !֚u^R:N]h ֤p7Ɩ'"   иָJ@;̤ݞX B5ͻ3w67NJA@A@A@h/te"<ڦMZg5OUԶolcuC>>4)  G@} Rb1VըxBciYi9]?Ry"먺qYJZA@A@A Z3f77&Ui(ǘd!07"I `?.4.ֱ|CZKU墺f($$֮]K-o-Ѵ~iΝu[KBdd$uܙbb%5++ _3=o5T*@xb-8k ťDmzm`-'PuE) w4et{ٚ{d_ԡR((Gm&xTt~W0>m+@ cQ.ͻ}5UZ+dGqu֍,YB}3g"=;J~atO믿:(SO?4Nirhu5+'=A@-X+/Ȣf]Ew*js'֖>>5_Y3)C&Ǽ5^e?Zp<kggwk]r Rei|woj*ZO?߲ +Cwڇ_D!45@`DDDM7D6m XYY@| A;3$hAy*y:{>p1>تfԩNki|jvnv0aТEh˖-̼yԱ=rĴ1'Owu5-IA@h~hbmwҎ6}Ss?m~أ?<ȖaZ;6_)kMͭG>7RHXXzI*ea͔C[zx6GVj1(bm (W5޻޴Js+Z'5B#C蛋Rκ3?H>֬Y@/s9,Xmc>0j|ތ.f=Oȑ#"֚BCC駟~`ꪫh…ar1'OO i[OA`#b|VYC.Mk{X[w%گ{XfJ{$rE S]WPTp:ჺ>z2҃ ˗]so\AŻϷ_SO!\#f42.Re 5שuép 9k׮PEET?ZIi__d?=v$ @@k;~|u ŦͭfY~URhL[6 2#(<.N3|SvP޺\Gj7"Y/ݳ wYY^J)8,:o߁icUY] ln^dS8s5s-,}|*Jrx?`sِhL8e(ɣʢVӇ(pұЅ8郢T{-$ OL.m}׽0J g\IeY!U8H+,do)2;S"\ qhNJwEdަ&JQEYE%SR^Q@IcMürB_RXJr7)'4*l\HƾaE}WL%{˕^LJ>윯uyajm}uʹ!45:9Ny}qʋ*)gC2?nN=c(21fH@IDATLv-f*0 v/Żh\5ƶb)}γ%+0HbBج6S}m)u4HfQ"ǵ,ʺABP]}cҮM]69e"_Ē{Oӆ ~ 333ux(##C9߻Uovޝ@&mۖrssUY+~~J+.<-޽{ SQhUVVRC:tP&۷"Uf}(k@ϛႹSvvYڇY-L-! D5P&%% mܸQիo `_1<< 9 hE^^YgyӿJMM%sժU..C=])ʢh!R.)+{Bɶ5S 4Z$VUQFKGLt% 8˟= F'=äR Ny:x)u[Rg G*".mғpZ銼*a('$w=ͳҰK'?CmLqJkfJ{mC öoK;yd9?x|5u=n&\?P2&M=20ħ(hGi׷nmS⬵BǩPbc'[L~tp] 6J톝53l5oNiG}6|tXB=B;CnmHX\ wMM0\=9|5SsuT7[cusJl}/L CHd06Ҏo<&>j?<.M\{Rs+ۡڲٙ~L:ܕU+[iL|QS:Q媟ïIwq"?ܟظEYeR^ S Ԇ]ڍ[ chގ#hE.֊JZFE,К{G>2?}|-/Mo-fWAy "̅oƏ.}iе\jib-m*^OIOخ+ͬ݋f 2j㔗\^ M{?e-zب4"|hͧ#ϧcUu1~{YLɊLYʓ:!xЕusZng?WDH+-vMv=q3eҖK`k٥4wxf,kmg %8S^B}UcAWU_[dYJj;:q]CJ[ԁT"Q|X#n(U1+n=Y g4mujkտϥ6Vm[gE;~z+vK-hM4*pyFXCCsϵu|X}2ڳ*0X  ^R4_(aAJkDŽTDoq]"i›~]U)o,<4j]TTK)(&%:U(n=iZ a;~˱YNU#8C{Z m6wM!k_2~T;mGT2@ת|m;Km?oH*.S[=&̺/)W> G>ÚWVPAkPZ¡t@ ]k:N4Txbo+{(G4Ni V'RޓY×7}u:ئ44o@>fH<\~7g+;Ҥщvҷo_ƒW_}E[n;H6m/B7x.R m;vP~m=z(G 5>S?*1v&NHv9 / H"sٲej,111Dxp@6BC 0A~h O%K{]\0GZu:,uu=^x/=\KKktC$Ohr|ϩs4j(SOUCy2>MtJ801A"}J $/S?xi Ə4gΜifS-^JV B "@{P&֞|Iu˗ ͵C{~O___|@HK|A@ط4C1E%H XG_5KU&O~OsY&p2ǩ苭|9kկ1QhuSTr/L#|۬O+b8sťҶ|uy:ENЖ2MM}wm^5ULԚY;D(")}}KYjYvZp&rיQډ־sY:D9 7\JwS9}ܵ?ЪW&0KBCnXV\&{]n=()KbrԷT}y~/MA!4_HoÊt& ZQ0]@8BOyl* )PB#jWoXxҟLV0Nǿ5M : օ)T(51|6ez)n c RhD"T}^w;Lg3Z3@bȘ 3RlZTQ[$O"*v|6m)lZ`_7tzS&,Drs)_ M&S1@!ZEk;oIݘ V15mc q"5J& 4i4UiY''4gkpm۶) -m6q@ 魷Rd4]ˈ#ЈCΝ;)!u:a; Ц֭Ҏ!J4[n4@~K@D?Is \{A?N8A!.ތ/}OqA^Cz҈;~iEӔXc "*d:O"<Z_WbKwyV"5̋c9Jꫯ*$l}iӦ)" DIhBNr"uXC {D7KZĚ//ӛA[o}綷f?oc &!2xUC~93= M,{YnϲOi[Sx.4nM5J 쾴4qд㧛M}}^BLGՙ3 N桨]q0?՚`uIhX/%V[qH6ʘcc/- utV!v"mjƯkKmuGCQTw2NdeO1kO~ڏ8Ǫ;>Fl>y>=˿3&hPp1uu;EY/O"kk%:h`OvOk&54邂?\27Q85w}Zεe_OlR~&1eJXIyT1֏: Պm,~n3fAq4 gy4"X/4riע<Ⱦ??HFeur}) o]Dșu5Wb (Rf&W^I h9͛N^my`W Bvɓ'[!x/SQu5ר$;fsɣnϟ*W DOCvOpқoEsΝ;f̘H1~:j$YmsWék_b >h 1g=}˙y)*h\56%,,L]좉50ANymx2?}=-Yc~Oq2[g_A@ZNl@{VxM+7PbQ>/ v~.5=}0nR''䬷^w]WօaO&$j;4yk:-ZCK}3TWVw$(}A~Qt<ޚZH);vzu2 }>VkcK)7cmI&I?Ac. U'fKۢ4Fԝ*l?x?sNo癧Ě֎i!LQ0FY]T!L;d`n|q䴈c໹f"0q7D֛ԁ*]s߈thAs 4nC_[nQlMg]Is%ִ4p` N9?aZ?Tp>kD><}`vU&t@h̞S>5)tIhCz}zZi;m9_k{' sB $h&X[M\uU'G&m>hAYrk_b >`iM Sb$t\>De *fMAg}~𴜯g{wZn. мhtbm+;Cea7)4Sc؟Ni]~dŴ!7.__0˃aYS)&ֺ_|x݅EWf){짝ii8#ͳ L[Nρ]y~C1l:% e-Edj\Wi-wܥ{C!`gaSJUXlK c+,畻f;=I[Y%AcNUsa~{6Wfa4+Ytow5_[om՛RLH ]MV]ߕLO3a6AUp?Jag_FBNT¦ٻ 66BVQ#|y eQ6} ]<%ִvcmekN뤜>L\k|>)ws5Du' o2]n\&~Z 9@"@iZmc *f[1gQ&rМsg#GO|Cڼs?饧ۋZb`N=؇!"4+L51ſ[IA d.X@By3>/w ^⮜Sb >?|YMEAkdMAi9_uR?_'A@=Neٗbv]k48Bc5%?~|Hg@$HoG_ib_Mڻ+9ɻhqwNXf)l.Zdq0 \@ []fAѠ]"4Y sNcon2$"N_34@ʾYF]"-T o5TSYV~*țZâinzueߴ~b];ϡa?qb[.{af2"LͥUiqeY砥4ʁu¶)-ND15 &(6A48Bh=fCsg/zH[Z. eg2w0 VQ6{EbS;)sYԉ]Is%[ &0I`CM&hiADy䑔R;WJJJ?V~ݛz[ % ~ LWAk Ěv֎+daRz!O\U<[9(|ѹM`g'd+Ks=4n8'-6uXf|kh $]I!40Jt̵kתlϣG}T7~̟ __[ Gщ5 ѝ4 }{*U1%iIh}nOf",ZX&ֺyuwkY͠ 3/bi454좉IOR.v:֦6X3L[u-_ 6}]n"26~rGMe=g6.+47Ϻu46#8ĚYsu#ȥE; 0yf6k sX1w$q8>Jc-4W itt b.3%ּ_CƇȷ?սXӦX;C,3k3sȵ_Ue5V{B϶Q  {XoE((c%=_06ɳwq$9%L֪*imfMEj󳢤|Q ץS'=mWbm10&-yuH`ܫnX3 k-wv,_{ue&׍G=?zPȥ?^mH.N4'b GJӈkSb=g>*7/SNj$G XkB^e\&!+f3sX!𷅀0'tn 'A@ZXt+^ a9kuk&Bc~gYNe ~RM|!֪*hѽUQ PYZYk<рkXC%a %fK(bS\F+%RO)Mx} L^8NUrQQxb2 lCKs'^+;ocERei˨{QAOUX ZǤڍcӟoYmiũ~}Xu&ebyܻV>z+SP~yõ+; )35.d֙!ϷQL ߺJusJ&BA{׫4aǞ)z˃յ)*~t2@j)kǡiIRWuNሮ4b۞4_XXL{/B],ҴXܜ2e wn[_Ƈ:/$l}IC >{D Ed֘)5A[O}fagRr9z+ -Am #Jhb ` P-9:z ͡72QXXCGK5hA+ M(ۆ5_@a8;:ʩbڽ~ Ci{VrT1nStp 9VdЊ\h*ڱDeo b-"fus3]kΕhvEv@A_= hT`&@Ӧ,؉5wY#MIHMG4XWYg;͌$:L&Pp;iӛ)]7a+(-߳&+ $TyAv@:DaF)F% @ J chߟo[E;~%q/ #}/u',{UccւV h mIz+-_)kDD:L Q!pN?;֭ M?Q榛n"] ?2 V{TOZ߾}--'w0MA{Eg8H}Ě=_p2dN:>tm.8G -$0?0Op=0GMu{z&NHv ߐ8vx_kE@;AA`uV/|`DA R4}~֛r~=ZKqʾ @DkeW9tBNҚX_ &nzRMxe}k=p]4b D"ex!} aDO5D\IB|աWIBpJ&:rpԣ6gMleJ@PJw{? nfm+u?Ҫnaq)lV6y @۾I{)< 2n.nSdHs>u//bmQ*zgh7.mYv>?*P1Yw?Oe31!w,$QA#S޷29x0:ǎ+Wf$N?vYWb o7 +j;~۫ȫrPNVZvE h\HEZKEYltjhep^D&:`~9^N`:*)0,^Eo1e,PmN稟:̏}MZ_P:|zJMU$5%(<6zF+3EOobrVP8"Ai-b-ø*Z,@yn}aw 1o+)-{m 驧R޽lB$Pfp@?zhE矴qFE|2 @Diu( vpn >9III* /3MO$#z>J+}D hxl$Pv AuM@8Gy3>_u=A3֦Me !H 53Ё&hi8hiԗn\>L!''ϟ"⚬YFEzԩ>XC?1^u#//ORIСC}tW_}u)544;k9_|XkIlA@Z6Hh7q=Q>ȩ[8N}SZIRYLk08|QFyK"kвGj+wv?Ej0'>ev @`ILbկ&d<k9HnhЭyE(::]Dߚ7Nf"7 p ^S^!DYm j+_~0q<XGfΏP5v#hv=M$zr#mfBCY5FSiXe-'oܦH7SCy 8E0w.̡U`a%T̚'|E?{g?Ek 6`b+ 6bwwN usqvvfw~w|~'oo͜=K ޻jDY|Iu9R͆gRV⃭zmͿ٬n {f(c3pxTar=\vGU(7'U7 ~$Xwq*d’j5K[>rFd !*G7h$uY*Ek~a)r-NEyZp9Ydwꩧױ$^,-X^!\b+)ik`ͷ}F? u3`{  &Ԃ59}>Zpuv ֺYIפO0j+mi2L2S4Q3x`wUͳElIiv^H:v@S/|7:c( ,{,?~&.\E<oP!N;".[WZO>E|ʂ0eݖzւ5$`TK$ g?7Xa;2_\;K_g~!_:8ԉY?{/ Cݧ/" Kk_vX[O_RqBs-c9|nȑ6ҐsN^@#A#Pk lĚgyT KlM'K,'SD` uKPY7`smС<}6C޳gȳ8 eeHHH @S FFԈ%ˉ7ǧ{=*X} /BhΖ9{MՄo{rVOZǙv3<[?h9Yyޕmo:[rvDB!^?gh7LI`SSX )nw.|l$@$@$@$M-Xė6%4d9ek_Žed9q}.Kͳy^%X۝\P^9wiqܘk %^s0g M1fi44.Ydi\{45 ZUk^,TK73Y 8ɤb#AɶG!Xa]9GvkX`tMCq#     (@]<sKl5/|fo;bk5sXYeTS捙"     @ C C/` e';_\\黥p-ʧ)Xdޯ)ɛ~>wL{/jC/HHH(}-**C$@$(XkJ`&3l"fmԨQn*}W\1Hemu={tHrP6$LV]uU;X >,8/`Yfq\rm* ܠA* ZWHHHHHHH  f}vO>#e^` ܔSN3p@QCZ6TSi{b+oeYr!nonꩧznf׭[7+n]vtO9UoZ'$@$@$@$@$@$@$?sΥ^;6#8/^|Œ\biDm6k|ߎEo,kT]V=!d/BV[mUyY\|4ݬ"z衒M+{rKu[VY92'sfjuXn\ǎS_zE]$\xUXNM^opbON:4p4߰rÆ 7VO5ؘ{_2`oQ6lt~wυ/CiPRK-{=W_s=s9F?i<>?+zG}=PIN\O>[hT3 >TiVd"ႯFӴ Cڭުl?OHծm;RHk "9HX>ɍHHHHHHZ@Ⴕ[mᆮ*,;k}u9G뭷^|Gyġ @3(D6 3u]WmAk :{'<!1 2=,UspnSm@/;` ֠ OX ^w}66>rKKb_O[bL묳NWTvqG@(blAثW/ n#Fp:p .B}<q@smWO&d^Zq >S" ̂wnipyWM-ěnAZxhG_^Bze`B#Y Blv^kOOABj :E".mx}u HHHHHHHY TU&KJ" +=s}(1^O%6,;,=L|^ ҲEm!,M v)c5| EEmNYƚA8 /W_>]~{k׮eD+$7~R"0"HQ;Z"+v]tE`U> 4sχ=-‰>hR`+,W .``MZkUvOJzO4JL3Mpx>&lmrE_5fq[TH0;h|U>Yл$چ%U)"U+ӍDNlllllllllllŵk ’DxAԅs?{43̈́tuש48 ]8sAXX)]&%]/4ְlg[(wKa kHo}um y oдꪫ4ͮlA3L$NPc1f]{W75,Rґ#GV<wvjj>XMkZIkƃ2tsh塮6X7vitV{1{ ɴic \=5vжP,7'˵m7޲w6nV&6h=[zHHHHHHH iHfϡI%h'4dX Z-ݻ4h EȤiCCʹdil8X}kz0vYg5hs}5֠(iYŇ{w\YL{L %Cs86HrXڀ^ج&Xpqjiu=HKu@*i%i@`>}…hzjPTY=SZf]ezMz (4ReUA(˻pNVd66666666666 d{gQ;믿*x|7Zm<<{t 78U_< F79YDxA"ll]4=eFOuư7\ѣG;o>z<3Ra_u?z9QҞkXBo &e6Zܿ 91JC@IDAT4 En%]2dHE֭-Mwx8ճgO=l9lq#      f "yvώ<l7&J{GU"S-jbM A /1Aigk"dв!tys.F5q Qr=h X>]4wj[!Ճ8(_DmFy1Ȉmmmmmmmmmmm6?B,5k&G1QaPЮC']H횥U`lOEmyYZE<%8l0?&(Ygub V`}fio-g`-oCO( G&Znݺ'` Cm 47hUO6666666666016VM>좍;y^+91Nd9n'pv gv`(kHP<%:iڰk6n8=}oEmW\1j-p#F"rQoaÆ98 1Z9>R~]vY8g&B>nʽ/Zz饝h{iDȽ+ei졅79Jso[|I= k։J}FBs/իw)8 ohWYm7mWI 6ؖ?w"d`/k E(dYvpw`v`o/~"^]ȑ#3&.hki; >s`eСC&g-nt\#7       (XΌ!HHHHHHHHHQF@$@$@$@$@$@$@$@$@(X $@$@$@$@$@$@$@$@$@ x` kl$@$@$@$@$@$@$@$@$A5h B$@$@$@$@$@$@$@$@  <1 P6@$@$@$@$@$@$@$@$@(X $@$@$@$@$@$@$@$@$@ x` kl$@$@$@$@$@$@$@$@$A5h B$@$@$@$@$@$@$@$@  <1 P6@$@$@$@$@$@$@$@$@(X L3䦘b c~]/tR)=zpM69rߛ8c=426>3j(_犵g\Z%qyE`iuK.dE F]qHHHH!@Z1K݂ .vo6lk{~裏dvs|ASUawzrcƌq<@SD޽ݲ.)qܠA4̹?|w뭷f'p3hq*;/;* u9;:/ Cb8i,xja⋺ս@@+ tC3 Z>?pF{huIcrp@h ֚C@ ~8Tpv&-+evm]Ϟ=k @]PV駟vSO=qݧ~Z^ $ @'o=@S Yh2@ӪVpk/5hӧ)NT^n_ꢱ֌\h|K\$@$@$@$Qka!SzK?C5}@Gxe e)^_(׈|UK<ִ?i6RdOj6l5}n-\l4uǥ4ngD6cޙ/ꦱ6tӹ;sDa)t?߄{63!uذ?o9眮K.~p0&G;y=#gn;wE~ ՗Zj)5p%__}UlXߋiˇmoͣ> :.yӭ[7]"ҵkW-l >_eq'TWS* ϸlAm_uS 'd\CD|Yf~ml|ap|I\ Ϣh\k:|.|B -k.7l0Ƕ5}Zlv}O̧f~=|\$dY^e|-_5r~ᙧN˾f{ar @ [l1.y睚W4s0t/|>se!L;#b]Av':,Qnk[o&t6<;r-K/Mý%Xy_wz~dX$yg{.yﳖwT魻eB[NB 93w^ڢyO{#A>| m[l;  oW]uUqa#4G>Ce#4V_}u+tg[YkjXk} s>pfyf駟ܳ>^IѶkyW<_6tS  iI5ѾYg7~ -A/?z뮻_#OІŘs}[63ӌg)X@?E.0^CePh[>g4ݬ筐Ozԩ馛4{ݍn6D=y],Lq5`ͷ? EϛD$@$@Y xYzK'tRI4ԎP|%DU_wMJ+[fe|D(VvO ZsQq]mko$"(GD+Ch/ª|W-Ң.H-_8,6m$Kb +hN#|%FֻG;L&e_"n)Z!Oukh_1Ҵ}z0^81 hh}ʖ|A%BDb,jm9#xc)X0ΣZemB4LSv/igg\Y5c>mZ쳏֑K"\+]wUaNexe¼KḒIqw,|f,ɦ^-3E͛m]ONllllMU^~V&xJ(Aa}_6xcMG%GaCpxAǹb 4zq8}/N2&H)Jz?CT!GJec^}y LKAagI4Wt kpXp@*G7ye[#wl'Z K8ahK=aS $6,-8&H{ .<ؚSh^CFa]e82r^ٸzk#e) u6;j"fzK@:i)( 7ܠK,vl;h*~Xm2"ŕgc%hذSNqڍϢ}.y уj'\t<%0yx,n"Хg0TҴ"jyHsinz޽#lQۜПPqy\qJ23,Ey׬KA}m<_Rfj͛*?%  V'IcO{l&Fb`jGذ8/v6رc×Զh4P/c|K˂0GFQpb[g7z5zr>uGze9K=%F pm|TvFA, ljD/Z Ϣj ~h.n-:w/߯NS|{-`/vM/i>43.,ך16fe]Vpۥq,չBQG㶼R\q|ݸx\3 ~l^w,|*Xyy_vQijoZyN7k}  X d}Ѫ݅ ^oz ċtX%g!.m5X2,A0TpnNl1cƸ믿.'ak^jihg-_4,2faNB6l &Ykdf}yvinUV{Ygy2K=%F p;찃{,Rp_ڭ"ɻA5h!6htm.x cyǝ9>Y4ϐW M?yV8_w3B s&0Цĸ^wd=^g,|*X6O,ga}%ּIHHn@HױcG#ت[]`+vb<'ޏ:/ u]/eʋCiL-ax.Mȇu篚W8meGxp~-,w_#3`/_ԸzjybZv/K=X^j K/ǚn4QÊ]E|f9 |M}0W>*;eS{x 2q^44Zg8q3ָWNvD#\DIKI<^;Y־mpY"d6XO'Lm e/0^.‹{Qapw.x3j}0RaqB.K?gy _ĵE6 ,@sG eeyF @1mzFҒXqliƛwkY!.,/\ʲdM10[Do5]WR|싆WPW]uU Mqgϒ^`-?s_| ‰ 9b#Lq).K=ą"0A >._[<ƶ"_\~=AENq8ӌg'V?_~V=#XjeO<}!GkyZq׺w,|(X ͵Zeݗg\Y/hbʡ.իW9t+1~!F{>Zh6D߿m[ԃ #:ñxSR,%p }M94Q0ugKϢ%V?oVZg޺IӏO.ɅF969眳c^=qQYڵ#_y]t.{8XdĎF<,lwWQVyӸq_y'@sL 2So 7m"R#tPK/f͉-$'tnGNhhW^y% }gx 7l0o>*'B=unpeʼn@;$PCIF+y\-_8)袋_ƏvVݻwWN0.:깰,5\q'%\DJ7tCv)N;/~ze^N#!-'Z*r?cpORRs;@eJv^M㶼/.ΤkhܢY4-B&Bi_Fis+_-g."Tѱ$YbZ%6 g@"T1Ai`NJJĖe\JƍO> $Ac%Js=שS'A$<%!Xwq4Ŵ!w+[yyBxq7 믿?<ix7Dԉ}%=^m՜?AQkm&xB(X |gQg*!%ڲ<jmiǥZ$;&[{AqA>81 p 7Z叻{Vok5c= @1*XC!HgyT+RktAEE2_^vܹVRW_#G`/mz?|Y'Ʃ]=姟~he'mUi"xB h}y4᛽5 (fċ@OLJV' LhBִ}^pEWRYV)_[Yy& @^ 0Ó @3`jy        h9\1$@$@$@$@$@$@$@$@@fHHHHHHHHPrU 4 ֚        #@ZU3L$@$@$@$@$@$@$@$ (XkZ`HHHHHHHHZk-We0 @3`jy        h9\1$@$@$@$@$@$@$@$@@fHHHHHHHHPrU 4 ֚        #@ZU3L$@$@$@$@$@$@$@$ (XkZ`HHHHHHHHZk-We0 @3`jy        h9m.Xz:tFƎ[d=dMF~& ԓOFz&Tq6UuLviݒK.YQ!C8%HU#fkO /~|g_M7\ @h3|[s5\|n*=yGUn> z$V\qE7ǒ{7|{/s=ם[oi_}];||&6 0n"s9qy@uY5\nfr}8kWlQҼ~~x Ue]G}(R'IHڔ@ ֎9z~ͽ[n jTbZ-ݴ7TS;}i Xrvr|IܭךC&s$@Nwv9h$mƕ67۶ۺ={fq~j6|s7fs[o{Y_f+E$V|dڪLHH ;i蟼Ж^|/\Zfe2-j}ݷԭ[aQ֧~Z&SMF0h4c$&u6 V/!n喅hv{AU~q=wh[lͪ,+燶G[mtYg6xh{r-om'KLQy}D[tYp3Z~660Ws܊fW*(ˋp+=OQVMI4(/^/ߖklIm>u믿~X7$f_콤x}=Dֲ+~~[~Td2pEq ԯ m)tM:vquyToܙg~;kpT?Ν;)҅MZs_}UY;{\.]?K#!^,mmРAZVؐ:t]=Ҋ/{ raYB -6c >lDOLuUyc`lYfq,r@:Pj U`,amhTF(A9lDޤc[V}%=%OX~{T+wܵZԚW9۳N am󃵌l;}z1]O?qCdUm:J4<ѼH@Ⴕ[mzE;Sj/| 07|scry^Xb SOUg^´#8"l'x{饗aJ]wXaR0q'%l_Fm0BQGUri^!nntg8؀ owC8 b 7餓N;ףQ"Ɠ6Oմ:8hyÏ-s2?*s 6ؠbnDGy˗%R^ʳ!+o'?,oF={xӶcǺ}]{5pH{%k=XYc>oyH@!fA`U0APrǻ'|Rq^AZk;g /~m;<6tڀSLIvjg}v$:b&DbB4QQF9+G1A/o*|dз~\~1^^ Yve!,^{muBmwԗ!h} 606Ji5(Gr/8M w| 3OW6턹ŷ|Ƴ<-벴O.hFL֔d)w0>FE} g/O= -y'\=Iɐ  o"aWA ^!h% l!2Aw,/i>g/`F֙ Q={V܏>>7hie!,6$ZnsP`O=^ N8;oe]{qbkP&>2&X_|B(iyhG TCڲo=+\KG4/^q{lceCz+|mQ:z]qO7΋~06yǏ6vky2Z<׾o8+cQIɐ  o#|L*/j R1m.K"SQl2fT,m)X;ce/ b;>ʂINd g Ɵ,򇵘V/X `uYz̈́h4p_ch4,T-*?n/FVK=f,5W\8\&X %i/ȲfMSl+e/Y'\Qiy8?Jc >bchn#|Z3 턹wv_uUuLó6[0fk,^M{%<.\F;>oqp ɐm6ƚHtm><[{6/js vnb6ϲ8/=j& 13| !:FmYG[!y o]3Y5b&Dm7\E~VWԃ<.\|4 @$Xs0$ 8GsQi|0J*W,!}s~)=" ^ #$sE*0֤Ab[}z^ĞZ L0 FϽDr!N4n̘1gmn[o=m0\ K>&X8E#3Om}a۾6a"W\qEPZ췵վS=ۢ58@q~hULEGr8F}[1~8 X-,X kiW_cqh\<' f",ޱc C&--`+-RaqɀaHslpuŲjayˋ4+Rp.- v 5sMPsc=!P.bI&Q# z8c3/ŷ>gz@?ؿC~Fʗf~?&agok+ھ9/ii1)c| ,^kFK}g|Ay_yN[|w}l?88^ .4w~z|1y7Iɐ  obR9#h Dc=: hpM, H _8çg}}^doͿyccxb}5%f"/ƁxMVx:#z `k#|/v/c{v x+S7{g׿UVpIc1kk8Nl߾<-=Ei~xiT4uTgtU}g|ϧW>턹ŧ|3v6mbz`< 8@EgC8X4lRzGywS2$C@vЇ=7b%vV@ M.So׉>׋|?~Ûj5RH^+h#ň yi5.8_)$nذaN4k< ^(R 'Y8;L(iWļbu*wٳwpաCׯ_?wzkv^Rf^yFZO8F7{ h&X-=[->wW:e:QaGPD۬,.#/e7bNIB.]qzocBdݩS' Iwz@kZU/&ƍӴ TӳIڣ/!x ox9miC&N\=x5So=@ſD@UPG!1?[oV^ye'O-`</8hH>ъ󊕑_3iVg跖އQ6(+iU@A>#{p{Zo8'$@$ `b҄1MK 駟u.~ #G?d! mTCqIy%nС&ٖC@9k/ev6m}6'cΪsۨv&ؙtFqD-%>Wo<\VHp9v|1pJçIHPzu@&Мrj,r&n$@$@$<HHH`j?WʰC{e~F,iIzobÑԏJ췕LxHH&QMæv1T8haH`Ό!`;Ό!H ߶u 0}  h;{q2셅=zE@$@^o1PFlgqhMP   <%       hmv1$@$@$@$@$@$@$@$@mD6dIHHHHHHHZk]= @`3Y        &@ZksO$@$@$@$@$@$@$@$F(Xk#LHHHHHHHH Pܓ  <%       hmv1$@$@$@$@$@$@$@$@mD6dIHHHu2@IDATHHHHZk]= @`3Y        &@ZksO$@$@$@$@$@$@$@$F(Xk#Lz&l27rHGo<^X~g_@19N;n%`Ȑ!no8 _>M7\j8C;Oku^? @s`Yve^0=,[qsfyf_Çz f}vpxuY]N7|£~}.n6niqK}}%p?>2+aw^RK~=#q~zn>(sŁvjcǎՏ׏>oe'p:tp첋C뽭{wqofc-H/'_aÆ/~ oᆊ(9wwT\ ,|4OpE81~"Ԋq5\|ipy@K3 ($](^j*wa^\QdIܪva 94z~  –n]tEZߝqT 7xc{W^9.L7\@`VOLCunm4>l/{'fou_}K7 wzjv9h5j(2Yj3Y{rOZb/;܈#bg #m{j |Y:EԻo>}QiLS,y,Qγ<.6h/ M$@h)O?uO?-F؈-2Cqs5G`Ke/?j38` +=\wݨQܫZN}ݻRI']qꫯ .]A)BE ߔSN{o2L@;y'SM5!3fea_SҵkW?h bKcG,1 7{=t;{饗|1Na|F'koV.aڃ>h!cmGhB~M .ӧ`-ohNJE g}$/ 3T}>NcX:ҋ/XcYk:tMeDeFۈֽ8K"H?|ImME^5 .`] N"ִ_|Ոq-n{//f613-آ~ys imY}1O|˓`d -ܡM6NlE5Mgw7j4~{beY|ͧ}\Z|x"q@ yѮ6 [_Ǖ=#|$m1VTF…ZM,# 8g\l8 /4'7n85 3 #pHEc% 6,|0>Kc8٘w\8 Km[zp}=Ny!G\a\}yw~11܇v~\pyi&^+>0{-IOx +-pgYK#!Z& 4/I$kmS;UW[wyg7ixۉ'˧,vZu L ! yםh>GEg^{K;Rr.}^`η|BQc'`-, yU&?]uUh0)9x>Xc W/0 ^X ޢW֖[n9m nІ8,KD%yםz-k[t=}ϲBzhy:bp㵥Wm_t{ F8}%ڬ\,_dAX0p@׫W/XAgaO Q^xz [K>j>7x`N}6aBD^(N!] (fqM4! P7|H\l'X?S)j[0Z`+ ahnip eGh6芶~^[Ӂ kdN8[* ʲY'(=!>} ra f6.dtEW_+ҖҢ.+ƕy0%/t-p>3x+ɒ [ne e [XkA%XyƁ,(͒|DXU7䑥6eJ힉&W^5J\KJ3u&3ia ǰ{bkAyqanԉBnvy ?'Z ?ml'sE|tPP>R7y"\(Z}ٽ]wUÁs4^_qPM!;+#!y ʑTWx>xf6e#3s`.:~ֻ ,ˠ+ۀ5MgOϊ}-ۼ(/Oa'0>"maE=al|1o".t{UϕVZěw<^0Wȇ| d |$2O2cD+Qo>O_ Y>,,  !Ы%Q.8X,]vYp7\8^iSI#AT Ѵ<`&0Z Pb{$l{{6Vok?6sqiI5㘴>4E;N ={}yXaY+aI C逑ؤ+KK~- }t xv=h[1T^EkYLJ4n{8VQF}]4A&Z4Y,Yxr4/iZEӑ,JXf,Ǐܴty)jDI 0[ 2kYSX>^zzK9O-@Zo8+_a^5`͇Kxfi/l"&n+RK$<(W$|lCV&CAմg06@Ҹy_G c?۟,{ ^M(h{YXŸg ?ƐKH,{Z޽mp^b$J<$K.M.$+R-2W4X>~>oQp0В,,Oi9i1YfL}ըq! lqkky3KBD<3= 4l q<~i9ꬳΊf=y0+_1/1FA wּF'Ab>A勚7i=OƚȀ9LI㾅gwQC~ed|kzh<;X#,=7kZu[,矿s2@j_;6qvi➷k,}"(iq,f.ŲM[x)DR3 +_ޖ` ۋ2Uۧ_fqGQv,$pT`φ*M.jK|UyJ{^ ^p"\N=SDzq[. k6Ps7|`,{y1 Fx)(;a,BD߅pi9V9}Pp~=pUh_ḣYRPѸpmc&(jD"xiIjLY \p/k#z/O=#udkd=4z3[;kw5\7 Z`* 2-<㙥XC8,͟DN-+ &0TL {GMGa0rB@=6qʣy PQNXop8N[>ρ1LVwN|@EmD gu!pz0؄hpYx؀ǽ?!_v?фWmG&ZuKBG8@ݴGl RhF }_ 8p>gRMC5vr A_3a,|ض;LyfW3΅^4aHV:YaKz@i?ҿ׫=O17;\> woj/c+|K,\,K{)>O?֑Y5Y(B/yM7 Q,_A,%àˀ:񩧞j,$1shF}@NT.F\pAPby;Rw1&I1R(vJL i$X;[E;} xz]))jQV>t= Lx1~u0@]b|xiB3CYX3܃Qk {8>gZ|`8}whgiOhv۳اc[h1|ybl1 a~p7ؽ<`lt,=!yzG\Yi WT=XOӏ]EC[yF}>|kEck׮x%4:pAzydz,Px/GVd6yd,&`4QGd=[z饝"FEʽ+iYy1_>|x`G0}<nذa޿#݉d1 Җ@}7xH@ApqؐxXaOl0_mAo3/p9aP?N`X[hT'p:ݓ ^A->y^Fnw#ɋhY.X8 '/u[oGR Bq]ʲ1EyA4T2zpF */MFFe!eGV6똃$dׯX q:we:2dH&8?~5j tw<+:ނ1/@]۷,wD߃ -p#s OҨ\yoy9[o=ڍ7N&e w YD[Lp!tPD[tY%\`~;~"N0lEC{|wpuST{AJ_R^4d< Bx3Wt2@ÊLZ&/: Z> e/t"^ U {a&TQVS4,Qw}7z+kA OC)q9x 46Qꪫ:.Ң'|Ƌh7Pln8/Oăxv ?c'Ϝ,|U/]#A AExm,EEW񏢯*% J l6`lĺ~g{۞\^Ǐ\!6vmܭ*S' {P>u?xlYB0½$,G mؑ?ϻrITsL!ÑE/E`}Ŋ%ún |y$BEH!_PQǭBINNb0QM[;N5k9:~[TmHط:4ſXlz]}kz9(!=T*N>֮]+㏽\l}zh&,FaX/ע"/*z_@%!##CxmP-8OOE " ,ZKWbgQV'"%}7s $WSNJV{PhK.}I4OSRY~I m֔éow^nk=scv>G/ {X{,.Nuf|sY[ f4{.Ax|-kk |Ǐ?@۸bMX\`-T9"ł7;p{ [p#K4&Д9?m:4Z\I`$š3rL 0&J"EFFʞeڴiTVV#@#_ۻJ{72b8phOǎ3ZvxyyQN׷暝ZfMuЁ';v'h.Zvo8;c΢s WSAT]QJ}|;Z5]w-)rq-qOX;,Y+$څ\ImܚKC%l .gLΣhھ};mٲ1\Rr ޽z-D[8z~qqq`fx oM[xC\`phܹ_O'Yz>lzWiݺu裏ZZcL 0hZyA6m{J('2AX.xk|)7,$^5^wO]1rq+t8Ϻk댿.#-mUVzP`ïCsh0{W>}< +p:% {:9* sAő9jAAA?:ř_5?Kb|=\۲wBȑ#fZ%{4?mbsoo6 :.a͍~wrqq6m -M[[93m9/š5\& Xa4_ZUP;VP@_i[hJa_wwC0y#kݜ6h6{]@ޡ4='ҍ" 5$S kۄ5`?|o: #g~ ﵗK=w_tB| UTT\UKKKJjw1WI^QY1Oڹy:C?¤~GmQ_*;Jyֈ6M}dorq֎= Rzn N*CbLfr%T|\|u]=|ȫCOQ%yTYtZ2\'~xu] $*9󏓛OyG_u]“TUZ `gTREAhae\JNQmUs !Šqny^gCmlaTUUw/×ck+O+$ÏwD܃ERqv Q׿`߰\NZ+7ܓBzv׺Jk ?ct4.NyQ%(>aK^e`T)yOR|o˕slǏ|Ü{+L}!uunM"[boSnޡ♫kYBՕI7O7U}_ZW.\]e"]"%U+ O)ʢ*≉LjxٵkWо}{͕u̸GSW_-vIwq:zA+\EaWYYI }a.aaaTTT$­u#gM{c-//'Oip% `y_NDD%$$ȸtiiix ٳAw\{7? s𠂂) iE^^iGM޽)**0ϔ^CC`0sLY.S`;Qא(">y AIay5F{5σGD;־l}O>-YϒyqowoW,Ssr!> gFzJ%5?N|>(K>&Z )UU\]ݯB\l}ůE Y.ELjUsN9)Kf2*W%pe\,PRXz *C7ZX%RE)1d:E_'uPNJ%=tGd_}K\ ZK_1A} [jhnš.SZ҅$+W:%v.T^pф5 -G\ݧKw 5vb/Evj0¯;{j%}qDU}($OvB{cgRQRI+o' UH.c)xO ]\+T: 58Cʲ `m$:Z(/~Ak:<[#*D^ׯ(a J}/1N^T|Ln&Y,۶vnq K]aWVPANkP$5D=T#;t~E)3Jn>5&TZ n "cz5[Z+X4CZY/gyV \.[N:ʼy% k,/K,t$p#<%#@uѣGe)X[n2P=DQg8Ft+&L'|RZ\s#E"s׮]r.Exp8+(Al'0({~ǒ=?կ.GM& 7 jo"z[6glͅs:,5k&M$߸X3?G-s! /,~iOsΕb]KUQVX!3/b՗bf0{*.`h"O>b%D &z)A +@X^vejS k87f;4a͖ӚAKk>S 8]oϟsT;[XC?gi ëO҆ʮ;1sPey5"3VaN3ͪIQr^2,>Øw0&9FֲDYtE=o^$b~%>}S~_Mu:*a#( fR\Bc&w!q) >c2 P$\(RrW)TYt5j_ۗS@Q&M1\B_CAJ{<qbv| ~݅ڮ-xh; Ӈ+p>zߧ!7ibg\qqF㧒~ }-v.)j0.K7nBhG,myJXӋJ"N.Cɔ-©8tQֹwQ&my6DjhDWoȎ k"U?D{h:mC(a B81^X5u座y6%XһY}'vįH Or/ݰ(nzK5{w` 8$PK/JjifǏɓ5LD7- 7b ,xXXӟgn]G?0_)V f?n լ}gR\;5khRKO?NK%>EVXœrY k^a 1aŨ/R=% [N-`]R<Yp]^`E k g܇%ϻl}9=aI?YW-K; Å%_-Bo"}؆߳ӁS/qUdwP%"QQqcGR;W% {_L=n0C!H-trۗa͒U֔X;7O),ΤUit{E|7_\8sth2B65z[#=wl>j,rٿ-MS %jx]mYJ;/>uXVS'TWVOIצ8ڕQxܳQ ^XsqJ1Qm|&FĐ@:^MK%33" nѶJS"ɘ7{, ,X! Ap@aGRױaZf[xw#sZ{Y*)8|`%>rkT!E\07nC95gjZ' 1j\\M"k̀_Nf+>XN"(F{_u\iš:\=a?Z8Tub.:eiK0kJ :hxf|ѣe)XMzʸtQh5|aGv)6B,lapyLf &2 b?NіJ/ #`k,sb-*Y:?{5` qQm|Xn[*sس>+]Pѯ)+a ֤<+~ޟ>ֳ}D}:Ҟ0x/⭉02t>1P7iIԏ?\YVS+aXXSTx@K%ta-]?z&uy4Ι"1(uPD0.5[x,^WR%uY4Љ*cq͸(ȳ^4>l\K gKyڗIEc" @H_L֐Lյ#),P Q`+յa %\)k?LX T]1Ϛoغ9tr,d\53ǹ{W w Mԝgl}_JXsq7Z齹1ֵO kY"XJ-ԹȖkrW0#L)JXf?BΡsfgS寝© @P8!@!Cw$xiݻd3Q {Q̹"fQ}[jRaMYǩz -雁"m&Z k,l]%-Dja Be*L{aC @Dc.W k b.w+F.\'kOOX%}.b}Rf18P cz˥4>) k2&-8BD2&S:@Ke/t,8_ kB6͡ iEz͆ysݩ˨oqVZCkqX "K+;JwY͕*!\$N ,` %]ϧ{{+?n[K0bD ıB \W!+  k*X;_%CU"* \~̙?k*aYx⣭Eg(a bv $s=e_s=MEXf~ k "qqdH}5sEeܻwQo!Josq[Z= =_[[gP1>~t;}p!-P?y((և5spx`-Ӆ5Ш+n~q-U E(M _!0oJjBĪ(aOSs095{:?qQZ%s(|Ƈ k& }QX\[Չd +`%ϸ""T!i|d[ ku4;k9Bd4.kŠ2}"+[E\ #兄kCf2+48#L>L N$ة;bꦧ }YOm[Hj%jp&b*Q,uM]A ~T_Kk vsQu}bUUӦpkmL5wRTs8Q3P;VTҎO)x`M`,E_{[ !!Ęo&q{AaM_YY9xg"❵kϴ,mW W >e2=&sw]tܹukNR Z-.!ӺR^z1-SEt٭;L Kl.u~xG%\[7pI9ZcIoɀ@<-|1G5䈂x[H(w1c٤7fpBR_{,4$߿_} ",4,#~>JHBoVVVVwaVaFߟZ7NR<b b4c5oXEqi a'm`S='#TyfKu5 XxQÂefн?f{E80A ?*>G-1,|`͛@ k)p%>%>$̢570~?͠b!WYQ aa$Jl*Tj,kHXC"@u#0:׵H|{ C$>e5ؿ}fo*z# ^[K!+x qR0hʖ%n!(vH+_#+_N,OT>P [_|YCO%-YA7Oj{6N{V`dM3[5=%e~l kfR_0`}(\AcЯgGMKvB" LmbK}h4sUVPA[W^XIæw ;ujE\Ҝw:lc?'JNPرhأݨPW- Ŀ{mc5J$55UUa۟\ďC /X,bP~2$YSő)Sb>e~h~Ȧ/ľ a|Zqd EfV__:?{KuZZZ 5>,]K5fm a".Q+\߉nBGJHynf8qEL T-BXK[d#9JX1%T";~.TFXC "]v/ U'NeC*!vݡ&"?jA[Utb7 x•u_XNEmP~ Od^BqWfP:gNZ#b,D_Cr]Ӛ'BfI"J.۪1{vi1o}Q%UZfЊ\X*:]šo2Nn!ڵ_O$ն+-Re贫qʶ kЊ쒭!:,T8m*ɂC\aAOUK$!p_?dFBGq~%^6ƹ kgOCd /#̢ `UHuEO<%%%)c (N⎩ s9u`'<!S>  }za->>^rBr+h Rf.iSH:k.G?'Tq Q=c՟Z2 &ГO>)c"8=oͶO>r)5 "` pLOO{pFbXCԸ4flWKk>=ƇZKzuZi?IBc$̮n.ZۻP;$s7z _ kaLhZY~ΊID>52b5&2Q%ATMv܃B:[#I%п Bz+C: 1g)5A7;N8Ar CPn@?b)m޼Ҥ $7 nM e `7,@ !+d}s8qȄp4-)"| 0F$"gA`>za @\tt 8'Y3?[KPP1w-00PFbőڃh߾5`5`1P[懶qM-Z$琓CׯlqMRSSe׎;6Ɖh2F^^Dy9z饗hɒ%8ݤ4Nm?y3[jk-SwLa3qX*~=i;iaO}Ȼ7?P$ղ]4d@ % ;ޘɰWp"1QYC롥E kGeyGEfҙ‚&P;WaȨHY+!k:;A #{g+Kq`DXS AWQhߘuX.WLdOcqc(j+۱n랜ԕt7PW ejLDm:$*8evA(!˸X{a%UBdːѓS{b8L29۔C)_1JTvNV1tUF]$29/]V"c)鍭pNS k`+>ĪsV5{H#e`c[ri8թR;w>5ZY7yc@Wu!y",Q Ў.C o^Cu:U{~/Nޚ 2B\@iݺuf- 9vhRRRd0xF0ݻkk/T8 <RXz4dȪ RqX$Κ5K //>\ EPQTev~y$$$/,_K2^B(}є X!rשXš-}g PTXkiϟK kQi.~pu^Aey/NuqGQ/5ikH7iϪL 0&of^h a BWK^wJҢ†,RiEp=4ei7L2`>B<2̠vmsaTSvr)|^w !:MR?vpO JiEV_츢LO?^P׮-Dedd# c(եK)^@ wd#P:u*!0-Xݺunp9 NϒcMb8#8f氺0͵@hijkmܟa־0f[ay N8i|VpDq ,947@hQa)B8\ds\m caͪMx2,RM#bs׽Gϡp3ݖeGXXSk: II9HզoMk K%&`"0bG5%ݻ7]}Մl_|Cvfc.d8jL6`N'šsL@hayFXca 7.6p`L 0&hXXk| [>u'eiMhۼ|5fcψ 0&`L 0& / h aE~&`L 0&c X k"š@r3L 0&`L 0X,5fL 0&`L 0&`m kmrd`L 0&`L 0&E5Gv`L 0&`L 0&2&`L 0&`L 8 k"0&`L 0&`L ),͓eL 0&`L 0&pEaL 0&`L 0&hSXXkS'`L 0&`L 0&(,9$`L 0&`L 0&Цft}||hF{Oǎ3;'CA7Ќjxw'Ww<]Mns>u1xL 0&`L 0&4ַO=*:w!t\;vяRyyӫqqq` oз~kwXO`@v%%%Y@3q})Ѳ[wh#KES:'mJ혹-ZyJs+̝f>`w22BW;Lʧ-#lί?f';`L 0&`L XHф7z}f_JhvhGԻS2k'#Gj]{K,iH^aa_2*z_Ӊj\ݾriێZ ѳ{_I;H{4oRw &`L 0&`Vh4aSG/a'5~9v䓏^8!<<\ͧiV?Vi4tPHjlUx H.5Vj%*' aM &`L 0&` p/\?D@4xPVyޥoL{nH&P^^N'OxyyQPPܝY,-P'""hݔ&޽;={Ȥm귝)oߞ)//vPN:Eee`pH {ӧOa"=  AQEEܹLEP4ԵkWҥ aO2/"Q cz~@ \ǺkQ޽)**JKIIOֱVTYVMfQ-ŋ({qv>AUK>=h0peMŽwS)q[5`fg?aZ۷ 0&`L 0&@"pa@i}6ftzG-7E ᨌOS;W^Rv;dV\\\ޣҥKiƌoIÇL"ÁW^y:t c^xY3{&MD 溧nݺ.ŮK!LhԩtWks1/lm4sLڴiRRmC\{iѢEj0fsYS! g!]iնZ64^}UZrjJ[Ξ=FAo8qz)'hPxT7tLa3ȍ.~'S9&YM_k5?ARfH:^De+Saaâ]^gL 0&`L 0&"Ѹ4QsD9TVVӳ3vӪ c6Op`zcf^N%K cnA6m=znePko[nLW^y֦35[0.HZo?y0 :K,tqQ``IXQڜ9s hk?P1ϟ/p- ƥJ+2H1 u Op=p-ݱ&Đ!C", vE%y4T, z]w_/>pU~e*a >sTu xBfqqXp\f -X@bpa駟 )aM/*}ԧOwޡK0X5+ ]wu,͛'#Xb`Mmۦh{wmZQ26$]z裏ҡC誫RشlHX5޲e Q!Cõoq(a 1`ͨ/p]z5a 6*ޠc4L~]WkELa-PXU +o<hӅv||wEH9hm5bj]e5;1?/&˲*Z غԝՖqq&`L 0&`e/]n?ם]QoP},e;g%Tj "SpHg}l=!J;.>F5k'ߴ}1b]k/sX-1/!c<~ c5օ8(ǺK.J(B2hu={ZT&BvD2c,B<58.5/D:y|СfV}ouӡc.۽!׈'d_}o,_о;kwUˮ>ݵE#;o7ZstX}zffČ{{{"blR"9|A\DR"QB*aMUƨOO>(yB4A\1W " WN)WliD*S2C')ćC}|EG﷥k3gΤ~&:w,J_=z!= Ր& D ²Lƍtj|A-EAkk ճk~:qY)u p$mЏ18t6?d-{h{{a6Nr EE2#b2NaA 0&`L 0&=/ ]c%Ld["2f)џC ̬(1[zwuwО={ j8RX4rH裏HBȍ>*!9/"Gp~dLNN6 Q!!ѣ Ol+雄ɓe1c]oHXhpBYwĉm / ,Γ *>b͞_{ kGPܤp;iק3"% "?7ACV+`z٢&a}SذyiP!E!oVyh1uUUv 2&`L 0&q|]/Y!~ n[̢믗qUWlS$}B\/5yLj WPOXj# q Tj9m4yq,/uQKuS3g9KXic#V.9ͭkqk!Ƌh"f5c msx,H V٧&_y&Ўk><},M2X19Bg=ߣ1 +?x"cB`vs59n,.=iqqjwK8.|=|=|=@#ޣ_#v^꺂"E D1)W;՚Q@͑9#@γ:ˠ} WW9G*aVgW\q<Y.e0aBu]›xNO?59f|.hfnoYx.]#cHy:X"7պx?M4f>Oxߑ,}ޑwg}1q[}3O|=|=mT@L&L1Vlq5h7~@1>Z.>VUBߪ)9hԝjS[ 5xwN$x^Wu$bW>/ȡANm{CTejظbś[`L 0&`L&7rKhC @6l0ht}%I 2w- >\nۛVQt]wڄPQ Em6A{Tj*Hdy bW_}EIIIǰavgȌ\]kF/ WPK[t1͛7O q IM' Ғ5$M ksvBZvc5NHwæN. 3Ry[hKw;L 0&`L 0&@kM6VqHHuU~*Ƞ XĸVdV >asCfMf[c1N'S ؂ω 0&`L 0&XX WgL 0&`L 0&hXXkםg`L 0&`L 0&`'ՙ`L 0&`L 0&&uY3&`L 0&`L I5;ru&`L 0&`L 0IyyL 0&`L 0&`v`aN\ 0&`L 0&`Lm`am^w5`L 0&`L 0&XX WgL 0&`L 0&hXXkםg`L 0&`L 0&`'ՙ`L 0&`L 0&&uY3&`L 0&`L I5;ru&`L 0&`L 0IyyL 0&`L 0&`v`aN\ 0&`L 0&`Lm`am^w5`L 0&`L 0&XX WgL 0&`L 0&hXXkםg`L 0&`L 0&`'[BUUT|\+DڡM\ ReiUO[< 0&`L 0&l"šMظRk#p})Ѳ[whKES:'mJXK_l`w_E'w4, `L 0&`L&,لyUZ`yzzң>Jt?OHt% {:[5q&`L 0&`XX327V^M^^^t7Rjj'9}B(]dyҲ;vPξ"13z3(Ψ38pL 0&`L 0&22Sllw:{5sh3-:87`L 0&`-ӄ5ύ+@Ķ)(@A"xk;/2P.>ԾSff Nɧ* .+RLe{'.Ǜ[AE5qBEQEy5Lʣ,ށk׮b~]ڋeݻ 'CZ_}t}衇~deep0***Ç4=aTPP {ͽU ݕu7o5e)զ-K{0 !Pw(KlHB{? H ҦͧP8[ Kٺ14mƌau]Gw}]ʸq)Çu}j^{5Z|%7{l1b[_ 싊ӧڵk [Š:"rh#J G]VAvӛith C6´}j%@m~H⯌;z?LB aAt+&J^0X6!Җg_7tѼ2ꏗoZE< v+"EQocG&£-aʑt8H>VBSqy'`L 0&`L 0; 8DX tqc#h`iorVaSg@GiӖJg՗F*ź.v{(]AKbqS`;$=.9>?JX3w:>ʄXƺS+"Sgpw_C}&8V\19Rl*1v}abe%-AZ%1orphpNtӴ=Z.wP&C'$OyAe[ KJ+;gOh<`L 0&`Li HX=*܅JZZ!4Ȣ'k]lֆ 9obS[s-UD ӌ#n7Ew+cA6XsI:S"%pg}d!?{2̙#WAȎ3 $PS6YZlTZZ*E5:,5ktٜ4it4>gf + lnh iU%+uȰ %JeoB9R 9?GѨ*ZAL""h {ZKu~t|\~0kpDvmBaCChuV{w"!-]] TUe7*SI|2LԊquN#i,U394ebE$|" C|#虽8{x P fAQJkw)_ ayLG k=Zg [ CB{F<9@r&#a>:r&bKL{VZl>Wd{G|\F`F`F`kOZ*N5H sezYikip ubT܃/ՖA3R4ԓAb)( Zj4G&~uZ7faaabXmm-Bqq ٴ1"0w\ j&hug?KE{]y0"UPc񗾃[I@ _ʭtH0c6ۻX#E o,F9~88RܗDՠi>D`8g{kZSEMb{{+x*-Hԁ_VU1fF`F`F`0X{fy{;kF)TO^]Jۗ٠)^>ن}OVV%P:|<w8ީwAi2"*~YT3a0i$m-.۷oWO4 (ѣ#֭o@j/رcRbwF*O O"jK !%J+> 8zn1A7Yrt CQA[; ^ 71I'%u$OC M|XI(T2SCI>!ߒR%x#0#0#0퉀YA)D  r#) yFk߲!7%*gҷ@N_j8{,4ϟ5{*\ߑ+(`sW(~N:tR\zQS]^^^Jڲe*[nEq\zSpI|jѐu.FN%FHs{7oU􅺸ԷXѐ{̈Xsލ ~IML >Xu^=Ё"͓>}Rozc]N^{S Hv j]}F`F`F`n'&ִ wۤ B("+#ٴ:>ۄq^qSlRmF>=۬tLhYx̜nɭ$Q0WLꗷ`ܤ|{x4h`.ۙc˜={x=+AazҾc)mT_wl#mz BNX;S)a02Gv]F(U=Ϊ~;[+dx.bmرaj֭Ԗ-[T}2t:fbڵk%kkkcCCC|j vڥE''' ϽhuvvPAOu.D$&FB5M +'zq4Kl鯑lP ^ZM㌝!PT $ry}-(W!ڶ%u*&aDﵱvw(c˜={x={c{CуC]0ULV$˗!00: ʮA **j4T %RRRt-,$`C f%~E08ԃUk*tMw.X.\W-wވK4>HKK#G(7W^yE@ee%466+WCk]_~F% CLL # f*9 ;;?wW/C~~>P)(++ʤF t9P&)N]~5X 5x;jњ/Gx /u`dnż~u|tԣZf/|+j4v08S*_GWZ?*BA&P+͑O/>{3=Q(l l׉o~dxwM hֿG{R#0#0#0#tfA"5Hى&Ib+R YoF K_  H44Y$.:lx; !.TӁ)cӵ(xQZ-:w>Ν˰)/AUbՅ.^̤3锝]n~~~I&c5SQttVBBeeeSժUs瞞&qFqT)|B=(eO*d߶yQ`q'fPFR>($T&ڇ\\(Mq6r+G @ P\($9@ @ /ZF8 @ @f  @ @ ΀ @ @kf$H @ @@o3 @ @ `&  @ @ k @ @  fF@ @ /ZF8 @ @f  @ @ ΀ @ @kf$H @ @@o3 @ @ `&  @ @ k @ @  fF@ @ /ZF8 @ @f!˻,\;Ii t\(8eg\RY(9<<Bd[\'k@ @pn;&U^ h@7RTԮ\T)3eݼN{wL>*WL׎};'lGϟA?Em#gZRY* CқVDw}m@ @pn;&ITt_TԮneqV0?z,*V@`yOhRyEPҕEs+Ecӎk 4l@ @(QE${Eu0u͓=.nt<+FXk rwE7']әvJJ=./].t{ @ JSOH@/k6T 8kPXsg@ @pD<|_e,N^ZZzȎ\]=(|#*SxNR[quu'O2f23YcxrКT6|QFr.!VPOo0229@)$tA־y|o1Q~biM0rY {-ϹʹrI_݀B*]C S/(S6uRFˣnpd!tJ a-OIgA_u3ϛ"@at|#M_7J×єva#cK!adL ?OG1;VЄ.iêZO*z흮&ɠf6P&*Z(b׆7uEX3lgz<Hz~7}o9HlzaG}y*] wtlM)m @@(5oV1Qq*/DN-Z :vdA`-E}N<[{)00+ ntptx18j0TK^gZ``{hfSʵt:|aeVKNeHqiZ( t9xRw_weT{%銯"j:N Ǻim^y fmߡKvcw^jȠUHX]ci rj`f˺1_NSJdk2@5ѐnfБD]Q@_yӿǖ򅽌UX笁5G[G=U\{4~?a޲8 |̟vqO @(%*V]TCN.:~!:z@`-F ޚ_jf5=&SNHc.U;gdZ`bT{dS )/Mv\t94k;4{IH4-_ƭ^ g_ 9T;hQsqP_OTծt_NJaI8fxqJI}i?6C#9'6-zW%<ҹG.ŏ҉Kz9k`QO+{22/^?<Ŗp'94;  @%Ik<CLo:Tk< 4DHpFs?/'Ryܟyo Ӟg cgx1 |T.P˟=1Xʆt@ @:Ɠ7ꅼR_ [fyjy8[irx.r t%_C̑|ze:fo`mhf6ɶx8S~PxD#=y:'~]3=8l/kƾ3S *9{x*gѷVھ'LE7W`e W a:'rjt2,U[Q0Ykdw{TTw_jsѣ1yWhq2A @w$2wub?,WxV$΋K [CH["s~.s51l-X3^Faָ\بūr(S@`z)1I~-:NLMK/ [k|⬧X9CMK豦%'?4;Xz5l>J]E uܒu1Xtlu Q lZ~\) V,yE/Ulmu5?#z+gmK."PT pSM/k^z)ՍY)݁5uI~N'm>8ixQ5f3Wڷ}ʋ!ޏ?<~ꙙtTiW.K= @(%2f BQM1LWHk['og:t=a1%~YkQU [E M\T{@4F"{֊a1ԴdosPX PI"f}[n.>]ZLC\(z9VXc̿\eZY!uC ϿL5@R)gD 19)m7[ ňY<_Yih؈=@9ΙހR}+H[BSoXs}pSV࿿X{.%iż ,y9@ XS}DO`Ucx{7X[;FKU?yٙS(3vB߸ԸreW>9X "*E'J2ضlsk9fFK-="l-WU3i94Z{ &+E v8's3YNa,$ѭR(/8O:D@\ӟ{\ Y3WU]\D}?]Niy=[G*4ew^ KێŁO܇#.7sŨd@lH 6{먧z$8nK @ &.kBtx%ȍY߾y,@JOCm kۦwĤ鿪I.)t903y8W\)\ϻV?8T57 @ wL`͹C鯝gĒv=_ĿNw% ǽCk9ג.]vϠx@勻)GלWE/.1Q<*yAksrJ]8I >mu @ ' @ @ k0 @ @XSA @ @@`-  @ @kz*H @ @@> @ @@`MOi @ @G|p @ @z  @ @ C @ @@O5=A @ @ a@ @  4@ @ #Z>@8 @ @ =T@ @ |X!@ @ ' @ @ k0 @ @+UC~nܹ tKn.x&23stl@)00Ξ=K/_.߶ώm0 @ Xck qtOp#SѬىFi;+2o:paCڴiCժUӕXx1]rE~)hт&NHsε7Ӝ߱CEU{i, E @ 'ckoO[!t߸ {>k3kD^^4td4; ouM DG=fobiyТˍ AǎZd{k @ @  _Kw$E?dp\gL~oMn4pNJ8z8.kp8-lٲԫW/"7Ah+ `` @REF?5y3e,]!|υ6{lY1򞏯-ZL~r(hQ-؃ @ (5ww'^?ep3/Pbi)-=6pLSJIɖ>r70Lq#n2L1 OOWJIIQvBE ުRd/󓓳 :t:} {UOՋ{լ@E}OLG[)E11~)]xǽuK1FٲىWܤoS+P:ok\/WޠcǍװ0Ċs|L:*z%]2֌t@ @&XW <>&}y,:+oӏkS!"p/^вE0}2Y^[/25D'$!%ja M(-YzNM435l)YbU5aTmt̃IS='~X&z#K=wkW͛PlUT;] .jiل:H(rPX ͻ( ZWO U?|칉4Fۈ _|&+V]TZ߶BBBwߥ J}^(w k*({nz37h>` ?,zѨWohQۙi>[S}ﭾR!@ TDʔq]"qo$pϧ=Dk^qΝQVV~6mBv'&Q*~ЃFM/&|J)t:1BC=~ Z gSRt=Nw^x\6C/6qU`~$z `tSKizsGqej$-Yчt.'{qJؿ rqKuqoeN?IӾW˧yv5kpn!_SŊԬi0:FBLi@D, Y^|Q&C}䘼kF|?R:ٻ_`-((f͚EgyZf 5hЀZj%/ ۸q#5k֌6mD "8I]t,Y"suv4a-z7G/z֥R; ixos)ޞVk؀ @ `+7 R{amevO3+{Q=@zE+X3j_+~mLRQ0S Қ4o\\b(*aZW1ǚ,ZV95y v):=D/Xe1d(MK!2ߺխvQE`MPYK[LddAs&ji8oNS%()'ct|qڵ 7SFu3ummVkxo nK|mmmmmmmmmm 8/ R6hpagsFoޯeS\bZ==]Wս/5@ִIY| (͚U왍bRkM5 ar{ѩA4Êpz[EeV,&!q-i=jaQ-Z`-**J8p&-뭷ޒ3 {a2_ӦM;?or>RѨ^jf5ֶV"0D@@@@@@@(mXIy2^ͷ:@O'7 rb!EzIμ]>wz2L:u:rW^|CV>+.Wwtuz^|bڽ'*ȲL!__7P(*A!nXĉTΫ֪H4S7'MWfrǎD`7o.f8}\ӓ֭Ke˖%>|جT___IDJ!1dT.fP~}^{l2"@&Wg.|Fc{ŸfKcS?%bxoM@ @0JM`=?s:$M_uW~Xk"X%̨,F| ڸQN&eIL/V"sjYzlWzymIszPp2U;W5 D:*v!2CE0RӲE*9[(N˖-f͚hhΝF;\3f }yi.\@cǎ;vhiꆣ2G׵14_eڲ ۛWle"sAyJV-mc  @@Z??7#zyQZ-:w>Ν( B=):ڗnQG~,'z^g);p *Qbb9iܓڝ$V=.vV:ƽ,hNݴgoJ_m{[45G @&ڝq(b9éK.⫡x@ @@`]i'ikE;S FLs 3t<3Uk! @ @`ouʜҚkt" eA" @ @`iEVf.(V)MI)] p ཽn @pz֜ @ @(3>  @ @XsG B @ 8kTP'@ @ @`*@ @ 9SA @ @^5D  @ @3 Ou @ @pz֜ @ @(3>  @ @XsG B @ 8kTP'@ @ @`*@ @ 9SA @ @^|}ݨa px*;anhrssD,pفtY|r]-LM@ @E-PjkUh>(_x, `@{Tre $ڶmܹ^+W!CЁ xO?-Zĉiܹ.tFQ}id586 @ @Z`;i=?r+z<#0|pz]'O>}+D{k3gŋF%IUpZP-ߌܨߠtXVw6 @ @֡M:F滑7LoE(裏҈#(;;Oڲe ڵ¨jժԣGp[Q}ϟO.\2֭śH Vw!4h`mz^jZA@ @pEԡ?Е)*k`([nU~]{aÆn:WV-z+Ҿ3dxosiZl"8@ @ Zea4c`@o,=CU"6nB\uQEFИtW#MNɢw߮jyת[}HuWxA~hذay6vjt5^7ސH2vMQo[?.炟QxqkEcxosTp @ "P"keʸS.]Ը8ֻhK@ؿ pϭtxP\?u.SiktԆbUI?d:myMΓƓWGmZ`bQ? Q>UI7tޘ6_s(с͗sn+ C]:#77c9qQkYY94C*8sfB-rL] 5#>Ο[-,ݗKLmkֲh^zٖ.]*"5kL)0 ˹z!-#[T EVZis0{X^ /--o 5qFYM6y"##K.⹻ђ%K裏>ʷe5^5^KvX*(m.[f@ @N%F YŅ9g*ax={o/[oi> ڀh΍,RX888380{^^45$zz>lg`mz 8&׮sQk_7w?ib].rrê<_M{|7<5mwWC=Ɣ~I8=ٔmY5֮];ԩSeގ;ji&Mi-2PӧkR]E7Edu1:^X_9,L"Cmj` sJ # mmmmmmmmmt *z99 m۞D.;/f,os?:5C?(_?iiOIW<<*r{ex#~y 51 S#pZ!es%b4⥽[bCAHEM.5jX^6oGuzݴkw2g(33x'QƟoQ 4Zg 0tI#O&!v||i1%ОZsuATLiرC(Տ:t}{0ɓ'SFW^͛7S?cjݺ5=쳴k.5ٷ ,ͱfAX 8P4=n;w.M8a4bڶmL+o7  Ĝ{g̮o)m [O Zj;H @ PNXy2^ͷ;W50{~+䪠' 3/ MCQ=@f0w)"v36y15;j"Vѯ 'E ==lR_#m?x&+x5T^HH4nK;[:89?Q]IUCKgO?M{쑗TX>ڷoOz-[&ӊ#ƁYfՁnBѣiÆ xa<_#^g?)==oR$Q[]@ @E.ԁSǎarJĽ~[~֭d׏sVb'cd/%Xҵ,oɾ}")$-[Sp(;>gdܢ3Nٜ) :wy!K5G\gwiA jB{h߹5AbѠQtB͘uZ0qX MjnbI8zƋ^n)^R%D .$5&S{ʴ &{9ڹsLn ΰ<`WqָL?zz&~RG.P1i'M/mum.X{k{ka  @ By#qb?M`ewx7_W54b$B%@IDAT+Rt˲tNX{s'`9,*(<]F(7q<jXSիiWĢ2յkW28h/nZS= =ʵz%N>÷޴>Z\5 m'xo]Ua6666666666p;ۀS/^ `lꡁVWTV, J TN΋%ݗB$STejl'! t|QFATN,dU/ӟ]xO|˗3tʭכoBM^X#]̫Bv;B'N7X^V@ p?9!r4;vŋ_2GFF}]v$+39Jt51c񊠙jԨAӧOʲ1uT6m)M6~QTTh/!u&K^k{fh Wl"ʦ{x`4! @ @=a+n Go@<.E]h"w\FKT? x1ϤSvmĞk)S"""(,,L<4:{yn S֝z.\9vӞFh{[4ۢ=J @ k @q9*b(uێ8 @ PX+Yϋi'ikE&##zzӅV<̒~.ےQ@ @8mX5ԡAZCy (ۂ!7 @ g@`Yzլ`DJiJJ*Q@(ʃ @ 9s@- @ @Jk%쁡 @ @!s< @ @ V @ @ 9s@- @ @Jk%쁡 @ @!s< @ @ V @ @ 9s@- @ @Jk%쁡 @ @!s< @ @ V @ @ 9s@- @ @Jk%쁡 @ @!ϡVrssܠs; D@ @ b@`N+Z; ~o:t͹gp" @ @@ f'2GY=@ @ PL h|vVC @ kvB; s4 @ @$PjkNeѕ ? [tX*:Nn)FPjT%ڏOEd  OOWJIΖxRFAо)tbi5徯Qt/IGޠkY&VH_ IN΢3q9`kxw$% @ @J@ի[z_nFEezj/]ΤgCOmhqGELG xQ;胱(.6 M(-YzN~*D(s?칉4H35lfѾSݱi֫Zaoۈ fU(5UD& @ @DDʔq]"q/-p=Dk^WAGCtb:q쉃U;N?IӾWUfr՗^b6_47s{ h>j`Ǩb:p0E;4ԓ K`to4"`MV\疏zȺ_rhtھwEUMP?ZyP͗|K~U*_>7PSh>j`dY_AaՂRTOPt6|00qFc,1?6^V/CM#HmF8h &1RH>W5 n]#mgDؖ@))yZ%@ @JxnNTG^W_5gɂ._{e>ڼ%wcTe3,n;pEzaxbngMv'B}{3ю|x`Orq[&\̏0-[~A+>x]/z~*Tsd WklLcDO9k㡞<5CIiG--uI#Ow~yr{9/-^{u|&|䴘h^ a^NlA @ pO~s{jo}Pi+߽Q"媠8AO\UyY5mea`|Pk3gQ3o§G'1@ @ NX{}L Oʟljxp{4h@]A3f6f(Vf\Sp9q?lJm ?MǎR; <dF=|II7kf*Gܟr70 9x)UOwڨ͟fX#ۯK=XQ.gEXCgۊ9vMʒ77В5yhs%p" @ @(fXSm|jt ={H.VC%{]j~5a5^`dh賻tSrF=5ŷh^sћϝ=˖ba|Ԁ]vvﴉxR[>EܸM+nPX-@ @ %2f(yh{oNwSFO O>Ca^a`{u=vF/O;;Vjr}mKZAJ q{UFK&:9n9 o[xٖ?P4uIw  H>^|X*zY{2o\Py|C @ (Pk9训~9:Ԭi\`(K>ԢyBqo7ZL/}=>xi$u-T\4h>x8q(C5wD*\ٗj w)pTQ4dp\iW=N5b!T!jzjZ6mzhԛXW堢:癚qS^? @ @M)d+P&AYYyuѪU蘘f|w^pU#WW-L9(REibU^ܹ gTv @ @@)(Rp  @ @N(>T  @ @XsgB @ 8kNPP%@ @ @`j@ @ 9CA @ @_5F! @ @ U @ @p~֜ @ @N(>T  @ @XsgB @ 8kNPP%@ @ @`j@ @ 9CA @ @_5F! @ @ U @ @p~֜ @ @N(>T  @ @XsgBTDGG%&&Rfff'gZjIۣGRzzT  @ PX+ξf͚trJvN:ԦMT˗ԩSl2PŊq`|DW\˗?Rb߾}LJ~t 4jժOԨQ#L+V0;0?00 B(" T:.]sѡC(##踳^hE]ώ(/ޓL;Nu=P> @ -"*J3kD^^4tdZc)sqqӀ(>>^s}cA,}8?ӤIϟ?__hܸq(f={QFɢn޼Iڵ+֮^z~aF=z0رcl5裏,Vի4c my~ *X E󛑷K-;,' vV @ R!=u&oo78x'%D5+5i҄^y\48ۖk܋>7n evaSlٲԽ{wjݺ駟Ҽy0~':{,_SRRծ][iذ!ҷ~KӧO7gBs!\qy3ݻs8EXj|opV۵aXTwww Ϗ{ gʔ)4sUM[Ci(ڲ ⸿#F([nUDO1GUD5ibȣ豦Oow>e]V(sĜaF}Yo͚5Eg.z)T%Ɨ"#})$ē :th|%__71画8Ǧr(ˣë.^4=DO#WJIΦ[PqF(;K}R}ďd(_:!S AIײN5J5_͟$8cOdϣ_dϵs98#/d<ډ'v~f%ȽRRR=j֬)ܛR^ `cZ~VJ?L=z4mذAqqqr8vz8#|AvUJ GA{YLQѧw%\Uڷ?z&96̕ @@ fqea4c`YH35l)YbU5aTmt̃^S&գhھ#>[b M(-YzN+݅~*FHvu&yfM)_?ֹ3|m4Y.Pjq xHhAk\w̯diӦz3gΘ͞=[GC:u qp>|8m߾]xG7f͛ӰaD6֬$h>-[O>쐵 xm-;𨪭 BH @Hz* bED~DQV.`džr)*i *4EJHZ $99ӒaB wZ Gy!9gU&$X"TN2Eٴ~I M.RxJ -v<>̥}i}hw/ߑGјq;hZ߃ߟ{l     VY7EXP.DxzinZKzhCqqAluEm:e[zAԽ[?y?}cD%\՗--R+LzдqhUf_%ԇ֬=MǚNr[#xW~L۶Wia[n!Xm={T"#cE2T̖|͢lرJ۷o kӦM#?qߧOJ&l kw=CJLܵk%%%)lb%,Ăjƌh"_ԓdnCa_Dt]f XNիܒ%K :wXCIZZhѢEW^y,ZDcl1'*OvUqPuSΊ7vءHPY'b9ԑ3m{QܸFlAl4f,߃@@@@@Tna /71KwSHov;=wGڷ SeVzfMѲcͲ]|ՙjc„ v}&>i馛L,V)o?7śz,(g,,>؊LO3gg=k& 'Kx㍪_Kk,X8믿1{cd6U^mLɘ8Ά@>W)ϮOj>F_U+^y-A1Z_6tP%ZpP[O56G@-4ib]&-maMk_+N_|Eշ=aMhcjl^Yg5j[ǩ1 cfo_{Faw&fb C[ا0btf}eIY8Dl_J$;ʷ,o|366V%I0cyy;|Ka3>*B}Yؑ=8=hir|Z=8 ʻIB@,(0цwN/S+g_:{/OM+~쵆/~ijwWՕ8CzP${i4cQR6k֌>cuQޮׯ*+G9::qFzܹsfU#gV}hr\|j⨟hԨQn:baQPm\rt_?rSQXs5jXY|I#lQgل::IݰaU3 ƣ!mB͛7O gK/wlQ=z |I xdHu)g}̘֚&y}j=h{Pwf`*NGD|]Nc;4cZj8Dxt.%سr`V҄9_Y:Z߭)55\gف+lC=iOzwY I.W5T1g5k*E*iV҈6֤I&)?`yS+uIDU jN.g>H0lO7YtZֱn־{A.*,-̚o" 7j뒀L?]A1@@@@@} X>7;$?/h~Kb} bLjM3lh,]߳:E(t/y#tBV.MX{#.\\ԪqN@ ˂A6"V 3+zf+3!eГJKWQw`,?"EFF*Q-**Kȅ bEd?YJ|P

]ٳX,Ă?T%"&4H9}ת-{8#pe_--a*+>CUXtȐ!tQRQ4 khS2|UU6[D/(]4igidw|Ѿ?-A]A1@@@@@|p6-8tۭLs>md/<ԶM>4v&qv^zq\abi}]6WnX؇mȳ+ QA#4w+Wt3B[`aM?Hh/UW_}$ ,;[}QO?T*ed^9[>X`T֮]k@jXo㌏5f=x8h3_+c2ȀgE믿nWğMX<ߑ#G2AKs߮ڒ@Z[ƻʗ1YX3.ϝ|v%_G=h=ZZ ````````8ӸgR+1PͧW?NE3[>KѨQk@#b,8su~E}ioW1˸g_(S@b3ZPPI$ 8˷Z{"piu'Nh;w?y==%Vk|Q 62V[ȖRLEM"b#dE3f*O2iš+gY>{O=ooc%={;yw~6w`V6؀b#20t [{#Sʏ^7V7+gMZkwkl[H]-);w]ŚXCWCk8܇,y8:v4(&9<^cFѡ85???'|X`wc;< O(%R5x1RYISš2e#CWӵ0_UU0´f՞}Z?ڝPw(a["GE]߃߃=========P*{TWQOFq˻ϳ[jn]AkOLPB -Xh`ڄ}؆3šԻڪ%;E-y4e\glE'SZzclgG5JȞDf2:h_9JNMbd_Nv 0eUƲ'aqƺ`cyAKFּ$M6mj(C9ҫ>n҅qΣGVy}@{)<5 8}֟oaM+w{g7?nl߃?.<[7L{{{{{{{{R0=W.ꭢfJ/SE%h,b`Ԯm@&5fIoOʡ#IY촾0 /@ ^֤dmkoқͨsjjL7C2H6BLL 5Mo=}Z3*O*ZiRR $GK.t)lei^,}hN(l|4+Acx(=ĶKpqTk%?JM?Dל.Jԡ}Ubg"W5洶_GgXGtVXӺ4bxU%{Ffghd+ҦNVϙ?!K{W1 kՑ<$DdhJ`+BԩSi֭Yv˛hԨQ>fP*Bҋ/HNE u^Ӆ(у^{55CE\;v,]{*)))~hƍWyJl"E={ mÆ ݻwtuiZ?m߃j{P w%a|Nt[QfV>%Ȧl72^ HPvGeQ^^V[һ7ӒXծ]j,zhU~FH_̤{%ZW~-W&;x [8K)u"U`, zђEx/{C#i4%{dF(     P1@XY[ȇѶi4DF@@@@@@VQWԍ cޔr2[!B3     J̘$ @Xs7Q        P)@XˌI5wE{        J̘$ @Xs7Q        P)@XˌI5wE{        J̘$ @Xs7Q        P)@XˌI5wE{        J̘$ @Xs7Q        P)@XˌI5wE{        rqqAGeQNNA9aR`` ijdt-zZ}wˋ=cIWj=U@@@@@@ Z i jϪL:q:tKI9sX5;… ҵWiq_biΝ6tuֳ9˘H ĭiiRIE 4       `Fš9%??ON2$xb%rbdz~zz())rf0ս{w=Cu֥5WaqZ r[aa>ŽEn2ֶ3      CZpVe̋.:F)'m 4vOߋK7f]gxVZԣG RСCI,}}ԡC5~]gَ3b,RRR8]РJЈq4XZ4z!(RA@@@@@ W0LW_mj \# k&HSW_}ZnqVؗ, >n6w;LzΌ͝eLlIyUZKwV[gkHܻ`;ʕ+$ě!~AA^TnRVv>>I>myYGV|ҋ}qyvPGAGNq- C$hU%p!22Q`{pFcҪU1k_}ĐXM8QK6K;#Lo}ٳg{a,֪UƜ|ZEEE9srssJ`]{HOOu>Z9󥬃e[{I#wFcOwу'jvE 7$̖-Pkҵ=")hZ?ZnS,]^H&cqY^[^ȇYл:.GKC7Gf8e}:Zؓ[鯍跟ӑLZ46-KDIYfZ=}L&/iԩ% P)iCի)kUٺGY}uNO>@CzA4ZzZQl iWXk:v q[H3g,Y)3)::|فD?[5q%kT3_=g9/6m7U? kb5l0'U&;VחMF7f!/-[|լYzMUT5kѣ =Z?GY'馛B8 %26p@x߾}\yܵ2IG?G:ܸFE6 h@(Wxf<چ&/ݕo'cLmVRUnL5k[hjbA*rΚ/ !%x2kZb&M'X&>j-tj_|iʔ)ꏭL˗/Wy'O6hª>3P ,0U^,?224U-mF,rcmɒ%ŎcѢE*gϞfs0Q{ԴijuJ{~Xg?GAy_W{M5_4!.ybWx>7ZEPYk짟O?]/ύӧ3ڪl)њKhぅ5 kfY5x}uz&fiZ{jybF4?IY^[թo(j(DeoNbۼ^h'kҥ* EGjCCCo!#Ж-[ }Q4h%&&?l%Ś1rH'/WK[)g+WT"pmذA=`&XΝ)--x ڳgo߾=%䨧]˃͗v3(ъ2Zv/maM*̙3t@IDATլ,k5;3~?~n kå|,̘֚&y [g      CUeg'ْELrlә?x4JX_|X}A͡5fhL4\#UWPK7wd#|筷ު֯_]c|.җsp 8X4}*cǎzql(p)##%ﻘFx<Zcvbwv=7I~^jKb:oUytՑ;lq44-d ,U>鿞u*4VA4GI>6[U*A$^ڹ낙ŚD\jUZ?Xr-|/FAK=Ϟ=۪ekSk^kǐ!CqTcmG}DgΜo ?NyXsu.s$wS44}?Z;>֟?      vZpo*?8Ls>m[`c7eնM]*;Ƕ-֤_>bۯo!QEpІ b&+Wt3BY]G,LLkٲ߿xb*.,,XiݺuիWBB O:c|v^hh: vZk"'"9;Nms:hjwG>G/`\Ck co``````````@&IޔW)[R|`x6m>GePH75ƍB:|F>\On]'mrΟ2VkچчTNБ,տ$np!O+jvOhB3Fep ~ KLզezI,ʕ+UlW,ǎx'<==iҤIԹsgƍt!⣡C,1ZөYf*599222Գ)w9[WRJJJߍ4rHcl޼?DÃԪ:Rϝk[~}hNǏޡµ2ֱϟ=2H(-Lۃ ;o樘^z&x>r( $^ÌYOо*qP j|-T>qd"qβsQ\\-_BLc}IFaPVV%,V*amѷt@ozDڒfz)QLDGR^mK=֊iKu`ozhd"mvi17( u,u@-bq,ewo,c@ K9m{x$QKw|*bb     JƩwjNaa>hl<@HAAޔr2wa : (ryWGd5հ$@“Oo\ ` @4 Wt6=ke( b8> G,cB PYWYV, UnWwd̏ƌAל*۩c8|.bI{iŏ'$yPzTz*yt+}6֓N~ؒZ x\m."|!14⁺tX|l1Hnύ}v'Z}Jڷ $c>!|1󣸮!zUjfkVEA@@@@@@@ʐ@ćX Ӣk(4XJP2G.x)d;7%ZSӄP4o1l"DIp_7O= 2zqM6)bj7%U?-J6 k3 k~?EcRK<9)>wjGIO={2:^ۮE+Z(zbjM$'}^ںZ$,'p?r-{%Q-_xy~Y l$eekнQQA{ubZQ7[UfV^ҍšhڜ/~Ԍ[ԢO50&ZxVgΘֆ4Qum"YOn8{v4QW70O='&ؠŵ<p@֞ۈz$?/e]%Gşگ(NskgiYVXsΞHAAwס:;{o ?<. r>66%a*xQXsMX{#.\l?"@ "، #jZÆƪQ5 }I^vv>-8}61]z툨ׇ4䣡dA. QwrHexW kaM&쥎IЂx)W=JU6m.VJҬ(|3_"{Z^A"֢hDmB",Swn\g@D\zyDNc9y߯&c'v=Ů9h csPW&)gEp^lAػW ݂P={b#@@@@@@@{a8+'":ؒ2"Ox w/Ivכс4VXdfšV\oU: 5W;pFXS?l~?؞+O?OokoXp٫ط^^Qԡ}UmJM<-YL?<ŢBAp%i 䨖7\_]Y`5nTK^EZ1_-q҉9z>kآKsܯk^k`J+_pRh\GkbNlMٲ$qi]^^~ IRG.{_ڙ«&h9pAm GE(Wf$#7T2sb?4-%̼2#fF錶5늎6wnN~*(If=v>zZ A>(]J=5aM~[mzx:C>7[]>٧Qxֵe8M^@\i(+$hXG=WJ9j@@@@@@@.#+^XIPo=ex-߉mzнC7ZZ ^myJܚF1ԹS5S` p!fGAqVCII_g)(Лt Sr)vpj)ZOšgf35mduel@jJ!!4{%Tj4|X*@f?k6jp ikԘǟg*J=#$e(o*f Vni%X{ Q3"/?Ћ&5֭T$J`"ZS Sӂ/;PP7 {`}WI' k$qT#ZzFf_?jfօHDP5gZI7m!ZOsVw(*&VeK{hd"mݖ4_I"PݗN/:7L: j^s}[IJ^ PhGe#-(ȋpDЈj~Y%xDrr\g^@@@@@@@@Auh(gx$P@@@@@@@@* )29vr2[VQ (*V>b        @Vjh0@E&a".        Pj Z4         P @Xȫk Td*bn        FZE        @Vjh0@E&a".        Pj Z4         P @Xȫk Td*bn        FZE        @z^I156m>Wcn        @|ϋHdT@E&P.h}ni5fGE捹T]X uz?(haiT`&xSp7%'g;ԧ;ʆr;GVUprsMVPn թHժRZE:q"v@͙/>>bDJۗNg]4+c{>-2Uv۶m]4ިa07ݲ \.lQ\IN9@>n-ߑGјq;hVe}uTޟZp*/S =xju M0zi/{<C%<=Qe2˯OQ~mo-u0zk^kYzmbSj5Ayy&>Z4~;ITLB!N/rK-Z*ԻWcAMi/v'߷w=7:AlYUaϓ>ц,k9gbW^uĺoX2^4mjkj(zQաCbhu9=F>U?)dalvgwҪէƬ kr8}]f}3OFֱC8an.a)t|UHćX Ӣk\G?|R jv_phV"ƽjSJIɦwn{Uam-5įtH&u_)4ԛY؉ط#&Җ4zGAqV&G>JonN}D)k9I-V"6o9g*A@@@@@@@.$> L᯳ݲ4cZkjJ|ͷsUX1ޛ\5ݴ-J4+uS|%uծOϰ߶|k [D+@S4z3lAzP}U${i6kϙQ@@@@@@@@=پ./e_`L`$ee骰&,gLkCM(Rr,5Es 8{:j8L߭)5&pc6 {Q :ɞbAhI        D)agHbK-:*)~-Xqr\a>lwW5iDaCc˨z#$Xkq4tH::$-}962 kpυGD(g؇%䣡,A. Fwr쨭@@@@@@@@JSš"8KQj`Y,.*U شx_` ڒ[ZZZek% kZdgA>m @];s(1ȵ2qzIcgl?tg4aMDG-jlV RE帩k@P+@@@@@@@@ 8-^]u_Dj[YFܔ /7\~c%K]#;}_7OӬ¿/O?OoVvt k"[UaiH|~4`1kt+:J^^Dv%K駕',fXp3Kִr,7*i&yL"[Qq:('r&>uG4}A&Y9MDg5^^hkH"x%x_/woϖl?@匰^08Azz-go"?l(        P",,7T2s?4-% 2s_ܸF* 'HozԴib)uZu歾>1:R-o&oMO=O'SswZ4T>M67g5  z%rr-j62'nִIPo=jfx-߉C7сYedq'RŇΝHkן&O>ڮ]ݛNuV+/SBDM:EǬ]0 L4j3ڐ]NzuTM> HMB7{%Ug:t$)˲ \JMX#Ґ117 &$PD&G7E{]4!e *r4U])޴h$qTߣZ݌e" oJ9\|1cDL s!a @@@@@@@@\ ah        ְ@@@@@@@@@\*         a {@@@@@@@@\ ah         k-K$PCKlAdBn,~zZܹKP @@@@@ ke%0JAZX>Ik} 0JBZ%YhL|V>֡ZE_a@@@@@V^V.O&ta>᫿V3( u*(!}{Hщ6&~$VC#a)f     P> @X+QUPa>џ )rَϏՅeE7ۊ`<@hT-vjZ.W ||LaL0rHZ9\ ŽKEJk֎ kS5 {.zQ)o3kaq%@ a\,Q VPwDXwQ!::4^ckb阮AXf     +^X;u>enT%(Z#S^5{O բ| "&y. k oj_S[{Ž89V?7gt Z Khabz*my!P XK[.m{=[dQ! (F2W/xE5KniOX;c*ZY6c:RG~^8A9T)|2]8.^H!pCŭŌTǗٺs3(/P*>}2o!z|ϓX+B ~ULQM"ni3[@ᾔCwSx Rx$ )#R/L%xxR K;w((EeTÏ;󵾘G9ݷU9Fgy -|:w0γXXݗU-=3#P ,dʥ-ij՚SPgݔq"I -HHa /jBYjp| oz՚ڃҏAuo¢6JY?ͬL.Sl߷:][&sPkiw+Joţ?דD}\o&Tote;Υګ~/)xp8%J^2qkv1qޟ b`RHlgt|;Zv6cu|5+uZ<Ҋ4P96v%uOOH>VHxh%4䓬k:G]h=Hk,s.~~/ZwP5.z2'R;fRDAZvݽ|RoK59fxbc5E{8lT]dhc:>S,mJ;i^ɺw}Qy-OYL띃1Y=xxթ{q՗P- ۰j.r_,3hςd}ZnI-G=!p;8=QjBk_K{<35-v#ּ8r%Ha_ӡEQ@64aͯZ}9}[Nu*ˬS S~.ELons]5a-딺y.qHYWgk8~[K;O1_Ul{m)/#UYUk>#tnrU&[TۣVnC);k>F-Dc[UD{?"rMs\UتI;J\V|˿ UmڏUY^DǨnQUs{~Л9#VZ뻭,{>[I|aNRh|kEygxλo)IʟށGĚwU_y~ڕx:lא=-hɝؚ oڟ塇]LO)3aM}N\ گM#ڏ3{sT<=-Q|ڙV~~<[o!gv_SbU8$_tS}$+/;~|hFP'-|鎮=CmG7 Ubvsz3{%c{FXYIeTkIgf%7D?+R;"E0zMX_w|zrUkOYsVouj5Ȯ w=g|_$965g<@E!Pfm o`֤/պ)`h*(mRG _lw64aM2O5:˝=rB-J 4aES{٘DmT(բcܱz*nM4R"J0slYZY~1Jo=W1Xzӊkyvrpeaxq9GiG)x7ئXpVb+ ){GMX`"v}٘sx-Ċ,Y1tܜaj     P&gژY7k Q@czWQ[V,]%eޙоwohj9fݣC"fY҄39]cYWo ?2MkL>BPi /VOqrT߄5%FC_VPh:X:~tztwrFXK73,ms+.)u*[Bzz yb,غ?͹C&zxfQS@fr$aM|m}wOj.~ Ѧmӄ5Yu~>bP~Nn9ODĸ6ڝu[r6}" 8訰&"һ~)`Q hUd57lB}`.JMX!7W,.O_R6wz(֜F     @kr]rZ8~Ʀ*/oʃT5/[T}yK|q屣}bӲkG)F&V k;=Huoad7,nwJE.)_\jp||c8+:<xj%E?A]% k;ogLG(!Gٿ[{ĺҧTPOl7bӝҿ?E'Ylgf:Z[IѮ|]CZEw}Y{i;-{jZS~mx!LšG.Ո QXc?eQwԮ~J?^?^WkletׄkjLQ_<"Zy2 b?Gż2Ԫ/K %~|DYruSl[wW8QaMWG5WPvn|y2%uavת}QN.9*ތGd5G( @$&Nmo*%s㿾E7B{Q-veVTp\lTZae&X8o=voGI5a-cUNm%mfVQsDlwh8_=ovAB9Bߛշ|)IX@ ,y²V[j),W{٭S\3š 9*>JYhm\BvU"X )yeOgFtgTX)j6[U1Qgj=_/}WlNHj>:UL!&>}Q%55]֮}٪{(y9&Z^: !kcx$Dٴw Fi&iLHT!T-!cil먰YjVZZ3s?,b]僅Gc \3etj֜…     @kbR9*X;ٗv]ttKYqFËl74FY'v{; "ԺvչE|c&YWʜݽ#@d.O8%wMXcQ|\+!?$dlrI_ͩlK4RֺiݻD+մw]t W"ڭTL3š4k::r9vyX3ՑqTRqBbE16?K`,p95/!tÆPQT5(XQw<՜X`Jr/) kMn[5?QI|tMꌙιlQeT*JLq|Cm̆&Gw9F9A\=Oՠk"lzֶ8Bw\ Mg\ID15>8jkS. !A8!#t NkWxٺ*I1}_C,hWx[)~\+cl֙jj>,bwiZ/P략*i\ ;VlayiZ-F,޵⏭DX3m Y,7x4[%ۼ$s&?}4- lFƐD k҇.Q$g5c٧Y0z#f&\w2ӟ]wqXcDVa.hM/Ś %7ϥݟAL/[IzM^ZkV볠C5l& d@{T c|A ljp $kp1UѸ=RN(}8LOG^g^\;]9x\fzczuwuŜmeX +UZph!Vgv:[eT~eo?0^0$2&=Em}ک/j(vh8/oÿ V5}_r? w6g3;c7`s_XJȉ2w:&Υ;9¿%ϐMg3'|IXQTVG5G>?'YAk/.as|+( 0geZMւǿY}KǛJ!ʜd={vڷ]%ٍҜBW[⬩&%Κ&VH殡0ҁf.-d`=GlROaM^ ʸW\F]Y$M.)#yɞA7?G,gBwJ(w'Xu9gU٭vAe8 L8laU}Pvh)%S+H϶qt3f3t jdvOg/r-38jrҜ9&lr75a%Y|ҫUšHb?" o"g?D:bu63[^XKλ6FRzhumN0Y'gExd:ҏ%*lI+)tv\2ZEҹ0QJUJ({d1m}gRR)&8 JJ F|)֖(MFS1­ZdNJ@\KW2̧>K4*>;Ґ9f-HTJ-g;ԽHߙ9"\CI ("9q^nkKw/-Vqrmk@@@@@hi35a.!UpFTٖp*9/z@2ű~ }- ˙ݹ'[۝ZTJzş,GˑfӯJ{FmtكC@9\\Ik 9η4aMLivxCXk*Tj NRɇS=OFLc̞Wdu{ww k1)SBƫ,+rRz9i4L=+l]AXsY      ROf)[Vv.,Rzq)`@ =ٮUqCXM'% Y75kn86vp8wkA@@@@|r ka|P,4~'e5_FcWT6WRQ$J4EWCAja->u#,!yO>5tdCcvx8ɡ*!5|=Oif|MXW iN%AN,{fnxš~1%fu X!y3     }8ܮb"<kh[k lAqY+(:SpNk@[v(Ra3X k_Å}p@VtntOPsua4!ع;cG_ šGqa     !?7<7'Px5 8okG;57x㺋go@- kr:[h5N$@nk6aE      `T{<]ܟ]9T;-\J;"<8\b %ln k:s;O16b% >6x6i+y<')6I 8 { return "", errors.New("indent should be between 0-8 spaces") } indent := strings.Repeat(" ", indentWidth) if tabIndent, err = flags.GetBool("tab"); err != nil { return "", err } if tabIndent { indent = "\t" } return indent, nil } func getXpathQuery(flags *pflag.FlagSet) (query string, single bool) { if query, _ = flags.GetString("xpath"); query != "" { return query, false } query, _ = flags.GetString("extract") return query, true } func getColorMode(flags *pflag.FlagSet) int { colors := utils.ColorsDefault disableColors, _ := flags.GetBool("no-color") if disableColors { colors = utils.ColorsDisabled } forcedColors, _ := flags.GetBool("color") if forcedColors { colors = utils.ColorsForced } return colors } func detectFormat(flags *pflag.FlagSet, origReader io.Reader) (utils.ContentType, io.Reader) { isHtmlFormatter, _ := flags.GetBool("html") if isHtmlFormatter { return utils.ContentHtml, origReader } buf := make([]byte, 10) length, err := origReader.Read(buf) if err != nil { return utils.ContentText, origReader } reader := io.MultiReader(bytes.NewReader(buf[:length]), origReader) if utils.IsJSON(string(buf)) { return utils.ContentJson, reader } if utils.IsHTML(string(buf)) { return utils.ContentHtml, reader } return utils.ContentXml, reader } func processAsJSON(flags *pflag.FlagSet, reader io.Reader, w io.Writer, contentType utils.ContentType) error { var ( jsonCompact bool jsonDepth int result interface{} ) jsonCompact, _ = flags.GetBool("compact") if flags.Changed("depth") { jsonDepth, _ = flags.GetInt("depth") } else { jsonDepth = -1 } switch contentType { case utils.ContentXml, utils.ContentHtml: doc, err := xmlquery.Parse(reader) if err != nil { return fmt.Errorf("error while parsing XML: %w", err) } result = utils.NodeToJSON(doc, jsonDepth) case utils.ContentJson: decoder := json.NewDecoder(reader) if err := decoder.Decode(&result); err != nil { return fmt.Errorf("error while parsing JSON: %w", err) } default: // Treat as plain text content, err := io.ReadAll(reader) if err != nil { return fmt.Errorf("error while reading content: %w", err) } result = map[string]interface{}{ "text": string(content), } } jsonData, err := json.Marshal(result) if err != nil { return fmt.Errorf("error while marshaling JSON: %w", err) } indent := "" if !jsonCompact { indent = " " } colors := getColorMode(flags) return utils.FormatJson(bytes.NewReader(jsonData), w, indent, colors) } xq-1.3.0/cmd/root_test.go000066400000000000000000000110331473231334100152560ustar00rootroot00000000000000package cmd import ( "bytes" "encoding/json" "fmt" "path" "strings" "testing" "github.com/sibprogrammer/xq/internal/utils" "github.com/spf13/cobra" "github.com/spf13/pflag" "github.com/stretchr/testify/assert" ) func execute(cmd *cobra.Command, args ...string) (string, error) { buf := new(bytes.Buffer) cmd.SetOut(buf) cmd.SetErr(buf) if len(args) > 0 { cmd.SetArgs(args) } else { cmd.SetArgs([]string{}) } err := cmd.Execute() return strings.TrimSpace(buf.String()), err } func TestRootCmd(t *testing.T) { command := NewRootCmd() InitFlags(command) var output string var err error xmlFilePath := path.Join("..", "test", "data", "xml", "unformatted.xml") htmlFilePath := path.Join("..", "test", "data", "html", "unformatted.html") jsonFilePath := path.Join("..", "test", "data", "json", "unformatted.json") output, err = execute(command) assert.Nil(t, err) assert.Contains(t, output, "Usage:") output, err = execute(command, xmlFilePath) assert.Nil(t, err) assert.Contains(t, output, "This is not a real user") output, err = execute(command, "--no-color", xmlFilePath) assert.Nil(t, err) assert.Contains(t, output, "first_name") output, err = execute(command, "--indent", "0", xmlFilePath) assert.Nil(t, err) assert.NotContains(t, output, "\n") output, err = execute(command, jsonFilePath) assert.Nil(t, err) assert.Contains(t, output, "{") output, err = execute(command, "--tab", xmlFilePath) assert.Nil(t, err) assert.Contains(t, output, "\t") output, err = execute(command, "-m", htmlFilePath) assert.Nil(t, err) assert.Contains(t, output, "") output, err = execute(command, "-q", "body > p", htmlFilePath) assert.Nil(t, err) assert.Contains(t, output, "text") output, err = execute(command, "-x", "/user/@status", xmlFilePath) assert.Nil(t, err) assert.Contains(t, output, "active") output, err = execute(command, "--no-color", "-x", "/user/@status", xmlFilePath) assert.Nil(t, err) assert.Contains(t, output, "active") output, err = execute(command, "--color", "-x", "/user/@status", xmlFilePath) assert.Nil(t, err) assert.Contains(t, output, "active") _, err = execute(command, "nonexistent.xml") assert.ErrorContains(t, err, "no such file or directory") _, err = execute(command, "--indent", "-1", xmlFilePath) assert.ErrorContains(t, err, "indent should be") _, err = execute(command, "--indent", "incorrect", xmlFilePath) assert.ErrorContains(t, err, "invalid argument") } func TestProcessAsJSON(t *testing.T) { tests := []struct { name string input string contentType utils.ContentType flags map[string]interface{} expected map[string]interface{} wantErr bool }{ { name: "Simple XML", input: "value", contentType: utils.ContentXml, expected: map[string]interface{}{ "root": map[string]interface{}{ "child": "value", }, }, }, {name: "Simple JSON", input: `{"root": {"child": "value"}}`, contentType: utils.ContentJson, expected: map[string]interface{}{ "root": map[string]interface{}{ "child": "value", }, }, }, { name: "Simple HTML", input: "

text

", contentType: utils.ContentHtml, expected: map[string]interface{}{ "html": map[string]interface{}{ "body": map[string]interface{}{ "p": "text", }, }, }, }, { name: "Plain text", input: "text", contentType: utils.ContentText, expected: map[string]interface{}{ "text": "text", }, }, { name: "invalid input", input: "thinking>\nI'll analyze each command and its output:\n", wantErr: true, }, { name: "combined", expected: map[string]interface{}{ "#text": "Thank you\nBye.", "thinking": "1. woop", }, input: `Thank you 1. woop Bye.`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Set up flags flags := pflag.NewFlagSet("test", pflag.ContinueOnError) flags.Bool("compact", false, "") flags.Int("depth", -1, "") for name, v := range tt.flags { _ = flags.Set(name, fmt.Sprint(v)) } reader := strings.NewReader(tt.input) var output bytes.Buffer err := processAsJSON(flags, reader, &output, tt.contentType) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) var resultMap map[string]interface{} err = json.Unmarshal(output.Bytes(), &resultMap) assert.NoError(t, err) assert.Equal(t, tt.expected, resultMap) } }) } } xq-1.3.0/codecov.yml000066400000000000000000000002211473231334100143040ustar00rootroot00000000000000coverage: status: project: default: target: 80% threshold: 10% patch: default: informational: true xq-1.3.0/docker-compose.yml000066400000000000000000000001571473231334100156040ustar00rootroot00000000000000services: xq: build: . volumes: - ./test/data:/opt/examples stdin_open: true tty: true xq-1.3.0/docs/000077500000000000000000000000001473231334100130745ustar00rootroot00000000000000xq-1.3.0/docs/xq.man000066400000000000000000000040261473231334100142230ustar00rootroot00000000000000.\" Manpage for xq utility .TH XQ 1 "06 Nov 2022" "" "xq man page" .SH NAME xq - command-line XML and HTML beautifier and content extractor .SH SYNOPSIS xq [\fIoptions...\fR] [\fIfile\fR] .SH DESCRIPTION Formats the provided \fIfile\fR and outputs it in the colorful mode. The file can be provided as an argument or via stdin. .SH OPTIONS .PP \fB--version\fR | \fB-v\fR .RS 4 Prints versions information and exits. .RE .PP \fB--help\fR | \fB-h\fR .RS 4 Prints the synopsis and a list of options and exits. .RE .PP \fB--indent\fR \fIint\fR .RS 4 Uses the given number of spaces for indentation (default 2). .RE .PP \fB--color\fR | \fB-c\fR .RS 4 Forces colorful output. .RE .PP \fB--no-color\fR .RS 4 Disables colorful output (only formatting). .RE .PP \fB--tab\fR .RS 4 Uses tabs instead of spaces for indentation. .RE .PP \fB--xpath\fR | \fB-x\fR \fIstring\fR .RS 4 Extracts the node(s) from XML using provided XPath query. .RE .PP \fB--extract\fR | \fB-e\fR \fIstring\fR .RS 4 Extracts a single node from XML using provided XPath query. .RE .PP \fB--query\fR | \fB-q\fR \fIstring\fR .RS 4 Extracts the node(s) using CSS selector. .RE .PP \fB--attr\fR | \fB-a\fR \fIstring\fR .RS 4 Extracts an attribute value instead of node content for provided CSS query. .RE .PP \fB--html\fR | \fB-m\fR .RS 4 Uses HTML formatter instead of XML. .RE .PP \fB--node\fR | \fB-n\fR .RS 4 Returns the node content instead of text. .RE .SH EXAMPLES .PP Format an XML file and highlight the syntax: .RS 4 $ xq test/data/xml/unformatted.xml .RE .PP Utility also accepts input through stdin: .RS 4 $ curl -s https://www.w3schools.com/xml/note.xml | xq .RE .PP HTML content can be formatted and highlighted using -m flag: .RS 4 $ xq -m test/data/html/formatted.html .RE .PP Extract the text content of all nodes with city name: .RS 4 $ cat test/data/xml/unformatted.xml | xq -x //city .RE .PP Extract the XML content of all nodes with city name: .RS 4 $ cat test/data/xml/unformatted.xml | xq -n -x //city .RE .SH SEE ALSO .PP \fBhttps://github.com/sibprogrammer/xq\fR - official website xq-1.3.0/go.mod000066400000000000000000000017331473231334100132560ustar00rootroot00000000000000module github.com/sibprogrammer/xq go 1.23 require ( github.com/PuerkitoBio/goquery v1.10.0 github.com/antchfx/xmlquery v1.4.3 github.com/antchfx/xpath v1.3.3 github.com/fatih/color v1.18.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.10.0 golang.org/x/net v0.33.0 golang.org/x/text v0.21.0 ) require ( github.com/andybalholm/cascadia v1.3.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect golang.org/x/sys v0.28.0 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) xq-1.3.0/go.sum000066400000000000000000000244111473231334100133010ustar00rootroot00000000000000github.com/PuerkitoBio/goquery v1.10.0 h1:6fiXdLuUvYs2OJSvNRqlNPoBm6YABE226xrbavY5Wv4= github.com/PuerkitoBio/goquery v1.10.0/go.mod h1:TjZZl68Q3eGHNBA8CWaxAN7rOU1EbDz3CWuolcO5Yu4= github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= github.com/antchfx/xmlquery v1.4.3 h1:f6jhxCzANrWfa93O+NmRWvieVyLs+R2Szfpy+YrZaww= github.com/antchfx/xmlquery v1.4.3/go.mod h1:AEPEEPYE9GnA2mj5Ur2L5Q5/2PycJ0N9Fusrx9b12fc= github.com/antchfx/xpath v1.3.3 h1:tmuPQa1Uye0Ym1Zn65vxPgfltWb/Lxu2jeqIGteJSRs= github.com/antchfx/xpath v1.3.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= xq-1.3.0/internal/000077500000000000000000000000001473231334100137605ustar00rootroot00000000000000xq-1.3.0/internal/utils/000077500000000000000000000000001473231334100151205ustar00rootroot00000000000000xq-1.3.0/internal/utils/config.go000066400000000000000000000023271473231334100167200ustar00rootroot00000000000000package utils import ( "bufio" "os" "strconv" "strings" ) type ConfigOptions struct { Indent int Tab bool NoColor bool Color bool Html bool Node bool } var config ConfigOptions func LoadConfig(fileName string) error { config.Indent = 2 config.Tab = false config.NoColor = false config.Color = false config.Html = false config.Node = false file, err := os.Open(fileName) if os.IsNotExist(err) { return nil } else if err != nil { return err } defer func() { _ = file.Close() }() scanner := bufio.NewScanner(file) for scanner.Scan() { var text = scanner.Text() text = strings.TrimSpace(text) if strings.HasPrefix(text, "#") || len(text) == 0 { continue } var parts = strings.Split(text, "=") if len(parts) != 2 { continue } option, value := parts[0], parts[1] option = strings.TrimSpace(option) value = strings.TrimSpace(value) switch option { case "indent": config.Indent, _ = strconv.Atoi(value) case "tab": config.Tab, _ = strconv.ParseBool(value) case "no-color": config.NoColor, _ = strconv.ParseBool(value) case "color": config.Color, _ = strconv.ParseBool(value) } } return nil } func GetConfig() ConfigOptions { return config } xq-1.3.0/internal/utils/config_test.go000066400000000000000000000010021473231334100177440ustar00rootroot00000000000000package utils import ( "github.com/stretchr/testify/assert" "path" "testing" ) func TestLoadConfig(t *testing.T) { var err error var config ConfigOptions err = LoadConfig(path.Join("..", "..", "test", "data", "config", "config1")) assert.Nil(t, err) config = GetConfig() assert.Equal(t, config.Indent, 8) assert.Equal(t, config.NoColor, true) err = LoadConfig(path.Join("..", "..", "test", "data", "config", "config2")) assert.Nil(t, err) config = GetConfig() assert.Equal(t, config.Indent, 2) } xq-1.3.0/internal/utils/jsonutil.go000066400000000000000000000060251473231334100173210ustar00rootroot00000000000000package utils import ( "strings" "github.com/antchfx/xmlquery" ) // NodeToJSON converts an xmlquery.Node to a JSON object. The depth parameter // specifies how many levels of children to include in the result. A depth of 0 means // only the text content of the node is included. A depth of 1 means the node's children // are included, but not their children, and so on. func NodeToJSON(node *xmlquery.Node, depth int) interface{} { if node == nil { return nil } switch node.Type { case xmlquery.DocumentNode: result := make(map[string]interface{}) var textParts []string // Process the next sibling of the document node first (if any) if node.NextSibling != nil && node.NextSibling.Type == xmlquery.TextNode { text := strings.TrimSpace(node.NextSibling.Data) if text != "" { textParts = append(textParts, text) } } // Process all children, including siblings of the first child for child := node.FirstChild; child != nil; child = child.NextSibling { switch child.Type { case xmlquery.ElementNode: childResult := nodeToJSONInternal(child, depth) result[child.Data] = childResult case xmlquery.TextNode: text := strings.TrimSpace(child.Data) if text != "" { textParts = append(textParts, text) } } } if len(textParts) > 0 { result["#text"] = strings.Join(textParts, "\n") } return result case xmlquery.ElementNode: return nodeToJSONInternal(node, depth) case xmlquery.TextNode: return strings.TrimSpace(node.Data) default: return nil } } func nodeToJSONInternal(node *xmlquery.Node, depth int) interface{} { if depth == 0 { return getTextContent(node) } result := make(map[string]interface{}) for _, attr := range node.Attr { result["@"+attr.Name.Local] = attr.Value } var textParts []string for child := node.FirstChild; child != nil; child = child.NextSibling { switch child.Type { case xmlquery.TextNode: text := strings.TrimSpace(child.Data) if text != "" { textParts = append(textParts, text) } case xmlquery.ElementNode: childResult := nodeToJSONInternal(child, depth-1) addToResult(result, child.Data, childResult) } } if len(textParts) > 0 { if len(result) == 0 { return strings.Join(textParts, "\n") } result["#text"] = strings.Join(textParts, "\n") } return result } func getTextContent(node *xmlquery.Node) string { var parts []string for child := node.FirstChild; child != nil; child = child.NextSibling { switch child.Type { case xmlquery.TextNode: text := strings.TrimSpace(child.Data) if text != "" { parts = append(parts, text) } case xmlquery.ElementNode: parts = append(parts, getTextContent(child)) } } return strings.Join(parts, "\n") } func addToResult(result map[string]interface{}, key string, value interface{}) { if key == "" { return } if existing, ok := result[key]; ok { switch existing := existing.(type) { case []interface{}: result[key] = append(existing, value) default: result[key] = []interface{}{existing, value} } } else { result[key] = value } } xq-1.3.0/internal/utils/jsonutil_test.go000066400000000000000000000023771473231334100203660ustar00rootroot00000000000000package utils import ( "bytes" "encoding/json" "os" "path" "strings" "testing" "github.com/antchfx/xmlquery" "github.com/stretchr/testify/assert" ) func TestXmlToJSON(t *testing.T) { tests := []struct { unformattedFile string expectedFile string depth int }{ {"unformatted.xml", "formatted.json", -1}, {"unformatted2.xml", "formatted2.json", -1}, {"unformatted3.xml", "formatted3.json", -1}, {"unformatted4.xml", "formatted4.json", 1}, } for _, testCase := range tests { inputFileName := path.Join("..", "..", "test", "data", "xml2json", testCase.unformattedFile) unformattedXmlReader := getFileReader(inputFileName) outputFileName := path.Join("..", "..", "test", "data", "xml2json", testCase.expectedFile) data, jsonReadErr := os.ReadFile(outputFileName) assert.Nil(t, jsonReadErr) expectedJson := string(data) node, parseErr := xmlquery.Parse(unformattedXmlReader) assert.Nil(t, parseErr) result := NodeToJSON(node, testCase.depth) jsonData, jsonMarshalErr := json.Marshal(result) assert.Nil(t, jsonMarshalErr) output := new(strings.Builder) formatErr := FormatJson(bytes.NewReader(jsonData), output, " ", ColorsDisabled) assert.Nil(t, formatErr) assert.Equal(t, expectedJson, output.String()) } } xq-1.3.0/internal/utils/utils.go000066400000000000000000000352011473231334100166100ustar00rootroot00000000000000package utils import ( "bytes" "encoding/json" "encoding/xml" "errors" "fmt" "github.com/PuerkitoBio/goquery" "github.com/antchfx/xmlquery" "github.com/antchfx/xpath" "github.com/fatih/color" "golang.org/x/net/html" "golang.org/x/text/encoding/ianaindex" "golang.org/x/text/transform" "io" "os" "os/exec" "reflect" "regexp" "strconv" "strings" ) const ( ColorsDefault = iota ColorsForced ColorsDisabled ) type ContentType int const ( ContentXml ContentType = iota ContentHtml ContentJson ContentText ) type QueryOptions struct { WithTags bool Indent string Colors int } const ( jsonTokenTopValue = iota jsonTokenArrayStart jsonTokenArrayValue jsonTokenArrayComma jsonTokenObjectStart jsonTokenObjectKey jsonTokenObjectColon jsonTokenObjectValue jsonTokenObjectComma ) func FormatXml(reader io.Reader, writer io.Writer, indent string, colors int) error { decoder := xml.NewDecoder(reader) decoder.Strict = false decoder.CharsetReader = getCharsetReader level := 0 hasContent := false nsAliases := map[string]string{"http://www.w3.org/XML/1998/namespace": "xml"} lastTagName := "" startTagClosed := true newline := "\n" if indent == "" { newline = "" } if ColorsDefault != colors { color.NoColor = colors == ColorsDisabled } tagColor := color.New(color.FgYellow).SprintFunc() attrColor := color.New(color.FgGreen).SprintFunc() commentColor := color.New(color.FgHiBlue).SprintFunc() for { token, err := decoder.Token() if err == io.EOF { break } if err != nil { return err } switch typedToken := token.(type) { case xml.ProcInst: _, _ = fmt.Fprintf(writer, "%s%s", tagColor(""), newline) case xml.StartElement: if !startTagClosed { _, _ = fmt.Fprint(writer, tagColor(">")) startTagClosed = true } if level > 0 { _, _ = fmt.Fprint(writer, newline, strings.Repeat(indent, level)) } var attrs []string for _, attr := range typedToken.Attr { if attr.Name.Space == "xmlns" { nsAliases[attr.Value] = attr.Name.Local } if attr.Name.Local == "xmlns" { nsAliases[attr.Value] = "" } escapedValue, _ := escapeText(attr.Value) attrElement := getTokenFullName(attr.Name, nsAliases) + attrColor("=\""+escapedValue+"\"") attrs = append(attrs, attrElement) } attrsStr := strings.Join(attrs, " ") if attrsStr != "" { attrsStr = " " + attrsStr } currentTagName := getTokenFullName(typedToken.Name, nsAliases) _, _ = fmt.Fprint(writer, tagColor("<"+currentTagName)+attrsStr) lastTagName = currentTagName startTagClosed = false level++ hasContent = false case xml.CharData: str := normalizeSpaces(string(typedToken), indent, level) hasContent = str != "" if hasContent && !startTagClosed { _, _ = fmt.Fprint(writer, tagColor(">")) startTagClosed = true } if hasContent && (strings.Contains(str, "&") || strings.Contains(str, "<")) { str = "" } _, _ = fmt.Fprint(writer, str) case xml.Comment: if !startTagClosed { _, _ = fmt.Fprint(writer, tagColor(">")) startTagClosed = true } for index, commentLine := range strings.Split(string(typedToken), "\n") { if !hasContent && level > 0 { _, _ = fmt.Fprint(writer, newline, strings.Repeat(indent, level)) } if index == 0 { _, _ = fmt.Fprint(writer, commentColor("")) if level == 0 { _, _ = fmt.Fprint(writer, newline) } case xml.EndElement: if level > 0 { level-- } currentTagName := getTokenFullName(typedToken.Name, nsAliases) if !hasContent { if lastTagName != currentTagName { if !startTagClosed { _, _ = fmt.Fprint(writer, tagColor(">")) startTagClosed = true } _, _ = fmt.Fprint(writer, newline, strings.Repeat(indent, level), tagColor("")) } else { _, _ = fmt.Fprint(writer, tagColor("/>")) startTagClosed = true } } else { _, _ = fmt.Fprint(writer, tagColor("")) } hasContent = false lastTagName = currentTagName if startTagClosed { lastTagName = "" } case xml.Directive: _, _ = fmt.Fprint(writer, tagColor("")) _, _ = fmt.Fprint(writer, newline, strings.Repeat(indent, level)) default: } } _, _ = fmt.Fprint(writer, "\n") return nil } func XPathQuery(reader io.Reader, writer io.Writer, query string, singleNode bool, options QueryOptions) (errRes error) { defer func() { if err := recover(); err != nil { errRes = fmt.Errorf("XPath error: %v", err) } }() doc, err := xmlquery.ParseWithOptions(reader, xmlquery.ParserOptions{ Decoder: &xmlquery.DecoderOptions{ Strict: false, CharsetReader: getCharsetReader, }, }) if err != nil { return err } if singleNode { if n := xmlquery.FindOne(doc, query); n != nil { return printNodeContent(writer, n, options) } } else if options.WithTags { for _, n := range xmlquery.Find(doc, query) { err := printNodeContent(writer, n, options) if err != nil { return err } } } else { expr, _ := xpath.Compile(query) if expr == nil { return errors.New("unable to parse the XPath query") } val := expr.Evaluate(xmlquery.CreateXPathNavigator(doc)) switch typedVal := val.(type) { case float64: _, err = fmt.Fprintf(writer, "%.0f\n", typedVal) case string: _, err = fmt.Fprintf(writer, "%s\n", strings.TrimSpace(typedVal)) case *xpath.NodeIterator: for typedVal.MoveNext() { typedVal.Current() _, err = fmt.Fprintf(writer, "%s\n", strings.TrimSpace(typedVal.Current().Value())) if err != nil { break } } default: return fmt.Errorf("unknown type error: %v", val) } if err != nil { return err } } return nil } func printNodeContent(writer io.Writer, node *xmlquery.Node, options QueryOptions) error { if options.WithTags { reader := strings.NewReader(node.OutputXML(true)) return FormatXml(reader, writer, options.Indent, options.Colors) } _, err := fmt.Fprintf(writer, "%s\n", strings.TrimSpace(node.InnerText())) return err } func CSSQuery(reader io.Reader, writer io.Writer, query string, attr string, options QueryOptions) error { doc, err := goquery.NewDocumentFromReader(reader) if err != nil { return err } doc.Find(query).Each(func(index int, item *goquery.Selection) { if attr != "" { _, _ = fmt.Fprintf(writer, "%s\n", strings.TrimSpace(item.AttrOr(attr, ""))) } else { if options.WithTags { node := item.Nodes[0] tagName := node.Data var attrs []string attrsStr := "" for _, tagAttr := range node.Attr { escapedValue, _ := escapeText(tagAttr.Val) attrs = append(attrs, tagAttr.Key+"=\""+escapedValue+"\"") } if len(attrs) > 0 { attrsStr = " " + strings.Join(attrs, " ") } html, _ := item.Html() reader := strings.NewReader(fmt.Sprintf("<%s%s>%s", tagName, attrsStr, html, tagName)) FormatHtml(reader, writer, options.Indent, options.Colors) } else { _, _ = fmt.Fprintf(writer, "%s\n", strings.TrimSpace(item.Text())) } } }) return nil } func FormatHtml(reader io.Reader, writer io.Writer, indent string, colors int) error { tokenizer := html.NewTokenizer(reader) if ColorsDefault != colors { color.NoColor = colors == ColorsDisabled } tagColor := color.New(color.FgYellow).SprintFunc() attrColor := color.New(color.FgGreen).SprintFunc() commentColor := color.New(color.FgHiBlue).SprintFunc() level := 0 hasContent := false forceNewLine := false selfClosingTags := getSelfClosingTags() newline := "\n" if indent == "" { newline = "" } for { token := tokenizer.Next() if token == html.ErrorToken { err := tokenizer.Err() if err == io.EOF { break } return err } switch token { case html.TextToken: str := normalizeSpaces(string(tokenizer.Text()), indent, level) hasContent = str != "" _, _ = fmt.Fprint(writer, str) case html.StartTagToken, html.SelfClosingTagToken: if level > 0 { _, _ = fmt.Fprint(writer, newline, strings.Repeat(indent, level)) } tagName, hasAttr := tokenizer.TagName() selfClosingTag := token == html.SelfClosingTagToken if !selfClosingTag && selfClosingTags[string(tagName)] { selfClosingTag = true } var attrs []string attrsStr := "" if hasAttr { for { attrKey, attrValue, moreAttr := tokenizer.TagAttr() escapedValue, _ := escapeText(string(attrValue)) attrs = append(attrs, string(attrKey)+attrColor("=\""+escapedValue+"\"")) if !moreAttr { break } } attrsStr = " " + strings.Join(attrs, " ") } _, _ = fmt.Fprint(writer, tagColor("<"+string(tagName))+attrsStr) if selfClosingTag { _, _ = fmt.Fprint(writer, tagColor("/>")) } else { level++ _, _ = fmt.Fprint(writer, tagColor(">")) forceNewLine = false } case html.EndTagToken: if level > 0 { level-- } tagName, _ := tokenizer.TagName() if forceNewLine { _, _ = fmt.Fprint(writer, newline, strings.Repeat(indent, level)) } _, _ = fmt.Fprint(writer, tagColor("")) hasContent = false forceNewLine = true case html.DoctypeToken: docType := tokenizer.Text() _, _ = fmt.Fprint(writer, tagColor(""), newline) case html.CommentToken: for _, commentLine := range strings.Split(string(tokenizer.Raw()), "\n") { if !hasContent && level > 0 { _, _ = fmt.Fprint(writer, newline, strings.Repeat(indent, level)) } _, _ = fmt.Fprint(writer, commentColor(commentLine)) } if level == 0 { _, _ = fmt.Fprint(writer, newline) } } } _, _ = fmt.Fprint(writer, "\n") return nil } func FormatJson(reader io.Reader, writer io.Writer, indent string, colors int) error { decoder := json.NewDecoder(reader) decoder.UseNumber() if ColorsDefault != colors { color.NoColor = colors == ColorsDisabled } tagColor := color.New(color.FgYellow).SprintFunc() attrColor := color.New(color.FgHiBlue).SprintFunc() valueColor := color.New(color.FgGreen).SprintFunc() level := 0 suffix := "" prefix := "" newline := "\n" if indent == "" { newline = "" } for { token, err := decoder.Token() if err == io.EOF { break } if err != nil { return err } v := reflect.ValueOf(*decoder) tokenState := v.FieldByName("tokenState").Int() switch tokenType := token.(type) { case json.Delim: switch rune(tokenType) { case '{': _, _ = fmt.Fprint(writer, prefix, tagColor("{"), newline) level++ suffix = strings.Repeat(indent, level) case '}': if level > 0 { level-- } _, _ = fmt.Fprint(writer, newline, strings.Repeat(indent, level), tagColor("}")) if tokenState == jsonTokenArrayComma { suffix = "," + newline + strings.Repeat(indent, level) } case '[': _, _ = fmt.Fprint(writer, prefix, tagColor("["), newline) level++ suffix = strings.Repeat(indent, level) case ']': if level > 0 { level-- } _, _ = fmt.Fprint(writer, newline, strings.Repeat(indent, level), tagColor("]")) } case string: escapedToken := strconv.Quote(token.(string)) value := valueColor(escapedToken) if tokenState == jsonTokenObjectColon { value = attrColor(escapedToken) } _, _ = fmt.Fprintf(writer, "%s%s", prefix, value) case float64: _, _ = fmt.Fprintf(writer, "%s%v", prefix, valueColor(token)) case json.Number: _, _ = fmt.Fprintf(writer, "%s%v", prefix, valueColor(token)) case bool: _, _ = fmt.Fprintf(writer, "%s%v", prefix, valueColor(token)) case nil: _, _ = fmt.Fprintf(writer, "%s%s", prefix, valueColor("null")) } switch tokenState { case jsonTokenObjectColon: suffix = ": " case jsonTokenObjectComma: suffix = "," + newline + strings.Repeat(indent, level) case jsonTokenArrayComma: suffix = "," + newline + strings.Repeat(indent, level) } prefix = suffix } _, _ = fmt.Fprint(writer, "\n") return nil } func IsHTML(input string) bool { input = strings.ToLower(input) htmlMarkers := []string{"html", "Some Title"}, {input: "unformatted8.xml", node: false, single: false, query: "count(//link)", result: "2"}, } for _, testCase := range tests { fileReader := getFileReader(path.Join("..", "..", "test", "data", "xml", testCase.input)) output := new(strings.Builder) options := QueryOptions{WithTags: testCase.node, Indent: " "} err := XPathQuery(fileReader, output, testCase.query, testCase.single, options) assert.Nil(t, err) assert.Equal(t, testCase.result, strings.Trim(output.String(), "\n")) } } func TestCSSQuery(t *testing.T) { type test struct { input string node bool query string attr string result string } tests := []test{ {input: "formatted.html", node: false, query: "body > p", attr: "", result: "text"}, {input: "formatted.html", node: false, query: "script", attr: "src", result: "foo.js\nbar.js\nbaz.js"}, {input: "formatted.html", node: true, query: "p", attr: "", result: "

text

"}, {input: "formatted.html", node: true, query: "a", attr: "", result: "
link"}, } for _, testCase := range tests { fileReader := getFileReader(path.Join("..", "..", "test", "data", "html", testCase.input)) output := new(strings.Builder) options := QueryOptions{WithTags: testCase.node, Indent: " "} err := CSSQuery(fileReader, output, testCase.query, testCase.attr, options) assert.Nil(t, err) assert.Equal(t, testCase.result, strings.Trim(output.String(), "\n")) } } func TestIsHTML(t *testing.T) { assert.True(t, IsHTML("")) assert.True(t, IsHTML("")) assert.True(t, IsHTML(" ...")) assert.False(t, IsHTML("")) assert.False(t, IsHTML("")) } func TestIsJSON(t *testing.T) { assert.True(t, IsJSON(`{"key": "value"}`)) assert.True(t, IsJSON(`{"key": "value", "key2": "value2"}`)) assert.True(t, IsJSON(`[1, 2, 3]`)) assert.True(t, IsJSON(` {}`)) assert.False(t, IsJSON(``)) } func TestPagerPrint(t *testing.T) { var output bytes.Buffer fileReader := getFileReader(path.Join("..", "..", "test", "data", "html", "formatted.html")) err := PagerPrint(fileReader, &output) assert.Nil(t, err) assert.Contains(t, output.String(), "") } func TestEscapeText(t *testing.T) { result, err := escapeText("\"value\"") assert.Nil(t, err) assert.Equal(t, ""value"", result) } xq-1.3.0/main.go000066400000000000000000000005331473231334100134200ustar00rootroot00000000000000package main import ( _ "embed" "fmt" "github.com/sibprogrammer/xq/cmd" "strings" ) var ( commit = "000000" date = "" ) //go:embed version var version string func main() { fullVersion := strings.TrimSpace(version) if date != "" { fullVersion += fmt.Sprintf(" (%s, %s)", date, commit) } cmd.Version = fullVersion cmd.Execute() } xq-1.3.0/scripts/000077500000000000000000000000001473231334100136335ustar00rootroot00000000000000xq-1.3.0/scripts/install.sh000077500000000000000000000014071473231334100156420ustar00rootroot00000000000000#!/bin/bash set -e URL_PREFIX="https://github.com/sibprogrammer/xq" INSTALL_DIR=/usr/local/bin/ BINARY=xq LATEST_VERSION=$(curl -L -s -H 'Accept: application/json' $URL_PREFIX/releases/latest | sed -e 's/.*"tag_name":"v\([^"]*\)".*/\1/') PLATFORM=$(uname -s | tr A-Z a-z) case "$(uname -m)" in arm64) ARCH=arm64 ;; aarch64) ARCH=arm64 ;; armv6l) ARCH=armv6 ;; armv7l) ARCH=armv7 ;; *) ARCH=amd64 ;; esac ARCHIVE="${BINARY}_${LATEST_VERSION}_${PLATFORM}_${ARCH}.tar.gz" URL="$URL_PREFIX/releases/download/v${LATEST_VERSION}/$ARCHIVE" echo "Installation of $BINARY" rm -f $INSTALL_DIR$BINARY curl -sSL "$URL" | tar xz -C $INSTALL_DIR $BINARY chmod +x $INSTALL_DIR$BINARY echo "Successfully installed at $INSTALL_DIR$BINARY" xq-1.3.0/test/000077500000000000000000000000001473231334100131235ustar00rootroot00000000000000xq-1.3.0/test/data/000077500000000000000000000000001473231334100140345ustar00rootroot00000000000000xq-1.3.0/test/data/config/000077500000000000000000000000001473231334100153015ustar00rootroot00000000000000xq-1.3.0/test/data/config/config1000066400000000000000000000000371473231334100165520ustar00rootroot00000000000000# config indent = 8 no-color=1 xq-1.3.0/test/data/config/config2000066400000000000000000000000171473231334100165510ustar00rootroot00000000000000# empty config xq-1.3.0/test/data/html/000077500000000000000000000000001473231334100150005ustar00rootroot00000000000000xq-1.3.0/test/data/html/formatted.html000066400000000000000000000004131473231334100176510ustar00rootroot00000000000000 Test

text

link xq-1.3.0/test/data/html/formatted.xml000066400000000000000000000003601473231334100175060ustar00rootroot00000000000000 John Smith
1234 Main Road Bellville
xq-1.3.0/test/data/html/formatted2.html000066400000000000000000000005651473231334100177430ustar00rootroot00000000000000 HTML 5 Boilerplate link here xq-1.3.0/test/data/html/formatted3.html000066400000000000000000000002501473231334100177330ustar00rootroot00000000000000

blah (blah)

xq-1.3.0/test/data/html/formatted4.html000066400000000000000000000001271473231334100177370ustar00rootroot00000000000000

world

xq-1.3.0/test/data/html/formatted5.html000066400000000000000000000001271473231334100177400ustar00rootroot00000000000000 xq-1.3.0/test/data/html/formatted6.html000066400000000000000000000001241473231334100177360ustar00rootroot00000000000000

Welcome

Here is no content, yet.

xq-1.3.0/test/data/html/unformatted.html000066400000000000000000000004031473231334100202130ustar00rootroot00000000000000 Test

text

link xq-1.3.0/test/data/html/unformatted.xml000066400000000000000000000003301473231334100200460ustar00rootroot00000000000000 JohnSmith
1234 Main RoadBellville
xq-1.3.0/test/data/html/unformatted2.html000066400000000000000000000005451473231334100203040ustar00rootroot00000000000000 HTML 5 Boilerplate link here xq-1.3.0/test/data/html/unformatted3.html000066400000000000000000000002201473231334100202730ustar00rootroot00000000000000

blah (blah)

xq-1.3.0/test/data/html/unformatted4.html000066400000000000000000000001031473231334100202740ustar00rootroot00000000000000

world

xq-1.3.0/test/data/html/unformatted5.html000066400000000000000000000001301473231334100202750ustar00rootroot00000000000000 xq-1.3.0/test/data/html/unformatted6.html000066400000000000000000000001441473231334100203030ustar00rootroot00000000000000

Welcome

Here is no content, yet.

xq-1.3.0/test/data/json/000077500000000000000000000000001473231334100150055ustar00rootroot00000000000000xq-1.3.0/test/data/json/formatted.json000066400000000000000000000006441473231334100176710ustar00rootroot00000000000000{ "menu": { "id": "file", "value": 17, "price": 100.32, "popup": { "menuitem": [ { "value": "New", "onclick": "CreateNewDoc()" }, { "value": "Open", "onclick": "OpenDoc()", "new": true }, { "value": "Close", "onclick": "CloseDoc()", "link": null } ] } } } xq-1.3.0/test/data/json/formatted2.json000066400000000000000000000001751473231334100177520ustar00rootroot00000000000000{ "fields": { "fixVersions": [ "1.0.0" ], "customfield_10473": null, "customfield_10474": null } } xq-1.3.0/test/data/json/formatted3.json000066400000000000000000000000461473231334100177500ustar00rootroot00000000000000{ "key": "string \"with\" quotes" } xq-1.3.0/test/data/json/unformatted.json000066400000000000000000000004441473231334100202320ustar00rootroot00000000000000{"menu": { "id": "file" , "value": 17, "price": 100.32, "popup": { "menuitem": [ {"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()", "new": true}, {"value": "Close", "onclick": "CloseDoc()", "link": null } ] } }} xq-1.3.0/test/data/json/unformatted2.json000066400000000000000000000001751473231334100203150ustar00rootroot00000000000000{ "fields": { "fixVersions": [ "1.0.0" ], "customfield_10473": null, "customfield_10474": null } } xq-1.3.0/test/data/json/unformatted3.json000066400000000000000000000000441473231334100203110ustar00rootroot00000000000000{ "key": "string \"with\" quotes" } xq-1.3.0/test/data/xml/000077500000000000000000000000001473231334100146345ustar00rootroot00000000000000xq-1.3.0/test/data/xml/formatted.xml000066400000000000000000000003601473231334100173420ustar00rootroot00000000000000 John Smith
1234 Main Road Bellville
xq-1.3.0/test/data/xml/formatted10.xml000066400000000000000000000001611473231334100175020ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/formatted11.xml000066400000000000000000000001521473231334100175030ustar00rootroot00000000000000

Welcome

Here is no content, yet.

xq-1.3.0/test/data/xml/formatted12.xml000066400000000000000000000001001473231334100174750ustar00rootroot00000000000000 value xq-1.3.0/test/data/xml/formatted13.xml000066400000000000000000000002211473231334100175020ustar00rootroot00000000000000 event seen: xq-1.3.0/test/data/xml/formatted14.xml000066400000000000000000000002421473231334100175060ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/formatted15.xml000066400000000000000000000001111473231334100175020ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/formatted2.xml000066400000000000000000000003741473231334100174310ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/formatted3.xml000066400000000000000000000010701473231334100174240ustar00rootroot00000000000000 http://site1.ru/page1.html 1.1.1.1 site2.ru 2.2.2.2 3.3.3.3 xq-1.3.0/test/data/xml/formatted4.xml000066400000000000000000000002511473231334100174250ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/formatted5.xml000066400000000000000000000000101473231334100174170ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/formatted6.xml000066400000000000000000000002671473231334100174360ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/formatted7.xml000066400000000000000000000000741473231334100174330ustar00rootroot00000000000000

world

xq-1.3.0/test/data/xml/formatted8.xml000066400000000000000000000006741473231334100174420ustar00rootroot00000000000000 Some Title Public posts from ... https://mastodon.social/@some-user https://files... User Name https://mastodon... xq-1.3.0/test/data/xml/formatted9.xml000066400000000000000000000002011473231334100174250ustar00rootroot00000000000000 Good Will Hunting xq-1.3.0/test/data/xml/unformatted.xml000066400000000000000000000003301473231334100177020ustar00rootroot00000000000000 JohnSmith
1234 Main RoadBellville
xq-1.3.0/test/data/xml/unformatted10.xml000066400000000000000000000001611473231334100200450ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/unformatted11.xml000066400000000000000000000001721473231334100200500ustar00rootroot00000000000000

Welcome

Here is no content, yet.

xq-1.3.0/test/data/xml/unformatted12.xml000066400000000000000000000001001473231334100200400ustar00rootroot00000000000000 value xq-1.3.0/test/data/xml/unformatted13.xml000066400000000000000000000002161473231334100200510ustar00rootroot00000000000000 event seen: xq-1.3.0/test/data/xml/unformatted14.xml000066400000000000000000000002661473231334100200570ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/unformatted15.xml000066400000000000000000000001101473231334100200440ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/unformatted2.xml000066400000000000000000000003731473231334100177730ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/unformatted3.xml000066400000000000000000000012251473231334100177710ustar00rootroot00000000000000 1.1.1.1 2.2.2.2 3.3.3.3 xq-1.3.0/test/data/xml/unformatted4.xml000066400000000000000000000002721473231334100177730ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/unformatted5.xml000066400000000000000000000000161473231334100177700ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/unformatted6.xml000066400000000000000000000002701473231334100177730ustar00rootroot00000000000000 xq-1.3.0/test/data/xml/unformatted7.xml000066400000000000000000000000641473231334100177750ustar00rootroot00000000000000

world

xq-1.3.0/test/data/xml/unformatted8.xml000066400000000000000000000007461473231334100200050ustar00rootroot00000000000000 Some Title Public posts from ... https://mastodon.social/@some-user https://files... User Name https://mastodon... xq-1.3.0/test/data/xml/unformatted9.xml000066400000000000000000000002031473231334100177720ustar00rootroot00000000000000 Good Will Hunting xq-1.3.0/test/data/xml2json/000077500000000000000000000000001473231334100156105ustar00rootroot00000000000000xq-1.3.0/test/data/xml2json/formatted.json000066400000000000000000000000511473231334100204640ustar00rootroot00000000000000{ "root": { "child": "value" } } xq-1.3.0/test/data/xml2json/formatted2.json000066400000000000000000000000761473231334100205550ustar00rootroot00000000000000{ "root": { "@attr": "value", "child": "text" } } xq-1.3.0/test/data/xml2json/formatted3.json000066400000000000000000000001111473231334100205440ustar00rootroot00000000000000{ "root": { "#text": "text\nmore text", "child": "value" } } xq-1.3.0/test/data/xml2json/formatted4.json000066400000000000000000000001001473231334100205430ustar00rootroot00000000000000{ "root": { "child1": "value", "child2": "text" } } xq-1.3.0/test/data/xml2json/unformatted.xml000066400000000000000000000000501473231334100206550ustar00rootroot00000000000000 value xq-1.3.0/test/data/xml2json/unformatted2.xml000066400000000000000000000000641473231334100207440ustar00rootroot00000000000000 text xq-1.3.0/test/data/xml2json/unformatted3.xml000066400000000000000000000000741473231334100207460ustar00rootroot00000000000000 text value more text xq-1.3.0/test/data/xml2json/unformatted4.xml000066400000000000000000000001531473231334100207450ustar00rootroot00000000000000 value text xq-1.3.0/test/pipe-test.sh000077500000000000000000000001251473231334100153720ustar00rootroot00000000000000#!/bin/bash FILE=$1 while read -r LINE; do echo $LINE sleep 1 done < $FILE xq-1.3.0/version000066400000000000000000000000061473231334100135500ustar00rootroot000000000000001.3.0