JSON का उपयोग करके JSON स्ट्रिंग को तालिका के रूप में कैसे प्रारूपित करें?


83

बस बैश स्क्रिप्टिंग के साथ शुरुआत की और JSON के साथ काम करने के लिए jq पर ठोकर खाई।

मुझे टर्मिनल में आउटपुट के लिए एक JSON स्ट्रिंग को नीचे तालिका में बदलने की आवश्यकता है।

[{
    "name": "George",
    "id": 12,
    "email": "george@domain.com"
}, {
    "name": "Jack",
    "id": 18,
    "email": "jack@domain.com"
}, {
    "name": "Joe",
    "id": 19,
    "email": "joe@domain.com"
}]

मैं टर्मिनल में क्या प्रदर्शित करना चाहता हूँ:

ID        Name
=================
12        George
18        Jack
19        Joe

ध्यान दें कि मैं प्रत्येक पंक्ति के लिए ईमेल संपत्ति कैसे प्रदर्शित नहीं करना चाहता, इसलिए jq कमांड में कुछ फ़िल्टरिंग शामिल होनी चाहिए। निम्नलिखित मुझे नाम और आईडी की एक सादी सूची देता है:

list=$(echo "$data" | jq -r '.[] | .name, .id')
printf "$list"

इस समस्या के साथ, मैं इसे एक तालिका की तरह प्रदर्शित नहीं कर सकता। मुझे पता है कि jq के पास कुछ प्रारूपण विकल्प हैं, लेकिन लगभग उतने अच्छे नहीं हैं जितने उपयोग करते समय मेरे पास मौजूद विकल्प हैं printf। मुझे लगता है कि मैं इन मूल्यों को एक सरणी में प्राप्त करना चाहता हूं जिसे मैं प्रारूपण करने के लिए खुद के माध्यम से लूप कर सकता हूं ...? जिन चीजों की मैंने कोशिश की, उन्होंने मुझे अलग-अलग परिणाम दिए, लेकिन कभी भी मैं वास्तव में ऐसा नहीं चाहता।

क्या कोई मुझे सही दिशा दिखा सकता है?


क्या आप अपने jq -r ...आदेश के कुछ नमूना आउटपुट जोड़ सकते हैं ?
माइक्रा विडेनमैन

आपके उपयोग से echoबचा जा सकता है jq -r '...' <<<$dataया jr -r '...' < input-file.json
मीका विडेनमैन

क्या आपका प्रश्न है: मेरे पास एक स्ट्रिंग है "name1 value1 name2 value2 name3 value3"मैं इसे तालिका के रूप में कैसे प्रिंट कर सकता हूं?
मीका विडेनमैन

जवाबों:


74

ऐसा कुछ क्यों नहीं:

echo '[{
    "name": "George",
    "id": 12,
    "email": "george@domain.com"
}, {
    "name": "Jack",
    "id": 18,
    "email": "jack@domain.com"
}, {
    "name": "Joe",
    "id": 19,
    "email": "joe@domain.com"
}]' | jq -r '.[] | "\(.id)\t\(.name)"'

उत्पादन

12  George
18  Jack
19  Joe

संपादित 1: ठीक दानेदार स्वरूपण के लिए जैसे उपकरण का उपयोग करेंawk

 echo '[{
    "name": "George",
    "id": 12,
    "email": "george@domain.com"
}, {
    "name": "Jack",
    "id": 18,
    "email": "jack@domain.com"
}, {
    "name": "Joe",
    "id": 19,
    "email": "joe@domain.com"
}]' | jq -r '.[] | [.id, .name] | @csv' | awk -v FS="," 'BEGIN{print "ID\tName";print "============"}{printf "%s\t%s%s",$1,$2,ORS}'
ID  Name
============
12  "George"
18  "Jack"
19  "Joe"

2 संपादित करें: उत्तर में

वहाँ कोई रास्ता नहीं है मैं एक चर सीधे jq से एक सरणी युक्त प्राप्त कर सकते हैं?

क्यों नहीं?

एक बिट शामिल उदाहरण (वास्तव में आप से संशोधित) जहां ईमेल को एक सरणी में बदल दिया जाता है यह प्रदर्शित करता है

echo '[{
    "name": "George",
    "id": 20,
    "email": [ "george@domain1.com" , "george@domain2.com" ]
}, {
    "name": "Jack",
    "id": 18,
    "email": [ "jack@domain3.com" , "jack@domain5.com" ]
}, {
    "name": "Joe",
    "id": 19,
    "email": [ "joe@domain.com" ]
}]' | jq -r '.[] | .email'

उत्पादन

[
  "george@domain1.com",
  "george@domain2.com"
]
[
  "jack@domain3.com",
  "jack@domain5.com"
]
[
  "joe@domain.com"
]

आपके उत्तर के लिए धन्यवाद। यह इस विशेष मामले में बहुत अच्छा काम करता है, आईडी की सभी लंबाई समान है। कल्पना कीजिए कि मैं उस क्षेत्र को चालू कर दूंगा, जो मुझे कुछ ऐसा देगा जो बिल्कुल भी एक उपयोगी तालिका की तरह नहीं दिखता है। मैं वास्तव में एक समाधान की तलाश में हूं जिसे मैं और अधिक डेटासेट पर उपयोग कर सकता हूं। आपके उत्तर के लिए धन्यवाद, हालांकि!
रिन

ठीक मिल गया। वहाँ कोई रास्ता नहीं है मैं एक चर जोड़ jq से सीधे एक सरणी प्राप्त कर सकते हैं? मुझे हमेशा एक तार से जाना पड़ता है?
रेइन करें

आपकी मदद के लिए धन्यवाद, आउटपुट बिल्कुल वैसा ही है जैसा मैं चाहता था (नामों के आसपास के उद्धरणों को छोड़कर)। उदाहरण के लिए हम पाइथन की तरह सरणी का उपयोग करने के लिए तैयार होने के बजाय एक स्ट्रिंग से जाना अजीब लगा। मेरे लिए यह अनाड़ी और गंदगी महसूस करता है, लेकिन मुझे लगता है कि यह सिर्फ मुझे ही है, जो मुझे बकवास के विचारों की आदत है? मैं इसे एक फंक्शन में बनाने की कोशिश करूँगा जिसका मैं पुनः उपयोग कर सकता हूँ, इसलिए मैं इसे अलग हेडर के साथ JSON स्ट्रिंग्स के लिए उपयोग कर सकता हूँ।
रेइन करें

@ संकेत: ठीक-ठीक स्वरूपण के लिए आपको सीएसवी प्रारूप में आउटपुट प्रिंट करना होगा और फिर उपयोग करना होगा awk, लेकिन यह ध्यान रखें कि जटिल मामले विफल हो सकते हैं। अपनी दूसरी टिप्पणी के लिए अंतिम संपादन देखें और इसे [इस] उत्तर के साथ पढ़ें ।
sjsam

1
उस लिंक और स्पष्टीकरण के लिए धन्यवाद, सुपर उपयोगी!
रीन

96

@tsvफ़िल्टर का उपयोग करने के लिए इसकी सिफारिश करने के लिए बहुत कुछ है, मुख्यतः क्योंकि यह मानक तरीके से कई "एज मामलों" को संभालता है:

.[] | [.id, .name] | @tsv

हेडर जोड़ना इस तरह किया जा सकता है:

jq -r '["ID","NAME"], ["--","------"], (.[] | [.id, .name]) | @tsv'

परिणाम:

ID  NAME
--  ------
12  George
18  Jack
19  Joe

length*"-"

डैश की रेखा के उत्पादन को स्वचालित करने के लिए:

jq -r '(["ID","NAME"] | (., map(length*"-"))), (.[] | [.id, .name]) | @tsv'

@Tsv फिल्टर jq, hmm के लिए मूल फिल्टर मैनुअल पेज पर भी है ... मुझे आश्चर्य है कि और क्या याद किया जा सकता है :)
рослав Рахматуллин

17

हाथ से हेडर को परिभाषित करना उप-समरूप है! सिर झुकाना भी उप-अपनाने योग्य है।

टी एल; डॉ

डेटा

[{ "name": "George", "id": 12, "email": "george@domain.com" },
{ "name": "Jack", "id": 18, "email": "jack@domain.com" }, 
{ "name": "Joe", "id": 19, "email": "joe@domain.com" }]

लिपि

  [.[]| with_entries( .key |= ascii_downcase ) ]
      |    (.[0] |keys_unsorted | @tsv)
         , (.[]|.|map(.) |@tsv)

कैसे चलाना है

$ < data jq -rf script  | column -t
name    id  email
George  12  george@domain.com
Jack    18  jack@domain.com
Joe     19  joe@domain.com

अमेजन वेब सेवाओं के कुछ आंकड़ों को सारांशित करते हुए मुझे यह प्रश्न मिला। जिस समस्या के लिए आप एक और उदाहरण चाहते हैं, उस पर मैं काम कर रहा था:

$ aws ec2 describe-spot-instance-requests | tee /tmp/ins |
    jq  --raw-output '
                                     # extract instances as a flat list.
    [.SpotInstanceRequests | .[] 
                                     # remove unwanted data
    | { 
        State, 
        statusCode: .Status.Code, 
        type: .LaunchSpecification.InstanceType, 
        blockPrice: .ActualBlockHourlyPrice, 
        created: .CreateTime, 
        SpotInstanceRequestId}
    ] 
                                        # lowercase keys
                                        # (for predictable sorting, optional)
    |  [.[]| with_entries( .key |= ascii_downcase ) ]
        |    (.[0] |keys_unsorted | @tsv)               # print headers
           , (.[]|.|map(.) |@tsv)                       # print table
    ' | column -t

आउटपुट:

state      statuscode                   type     blockprice  created                   spotinstancerequestid
closed     instance-terminated-by-user  t3.nano  0.002000    2019-02-24T15:21:36.000Z  sir-r5bh7skq
cancelled  bad-parameters               t3.nano  0.002000    2019-02-24T14:51:47.000Z  sir-1k9s5h3m
closed     instance-terminated-by-user  t3.nano  0.002000    2019-02-24T14:55:26.000Z  sir-43x16b6n
cancelled  bad-parameters               t3.nano  0.002000    2019-02-24T14:29:23.000Z  sir-2jsh5brn
active     fulfilled                    t3.nano  0.002000    2019-02-24T15:37:26.000Z  sir-z1e9591m
cancelled  bad-parameters               t3.nano  0.002000    2019-02-24T14:33:42.000Z  sir-n7c15y5p

इनपुट:

$ cat /tmp/ins
{
    "SpotInstanceRequests": [
        {
            "Status": {
                "Message": "2019-02-24T15:29:38+0000 : 2019-02-24T15:29:38+0000 : Spot Instance terminated due to user-initiated termination.", 
                "Code": "instance-terminated-by-user", 
                "UpdateTime": "2019-02-24T15:31:03.000Z"
            }, 
            "ActualBlockHourlyPrice": "0.002000", 
            "ValidUntil": "2019-03-03T15:21:36.000Z", 
            "InstanceInterruptionBehavior": "terminate", 
            "Tags": [], 
            "InstanceId": "i-0414083bef5e91d94", 
            "BlockDurationMinutes": 60, 
            "SpotInstanceRequestId": "sir-r5bh7skq", 
            "State": "closed", 
            "ProductDescription": "Linux/UNIX", 
            "LaunchedAvailabilityZone": "eu-north-1a", 
            "LaunchSpecification": {
                "Placement": {
                    "Tenancy": "default", 
                    "AvailabilityZone": "eu-north-1a"
                }, 
                "ImageId": "ami-6d27a913", 
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda1", 
                        "VirtualName": "root", 
                        "NoDevice": "", 
                        "Ebs": {
                            "Encrypted": false, 
                            "DeleteOnTermination": true, 
                            "VolumeType": "gp2", 
                            "VolumeSize": 8
                        }
                    }
                ], 
                "EbsOptimized": false, 
                "SecurityGroups": [
                    {
                        "GroupName": "default"
                    }
                ], 
                "Monitoring": {
                    "Enabled": false
                }, 
                "InstanceType": "t3.nano", 
                "AddressingType": "public", 
                "NetworkInterfaces": [
                    {
                        "DeviceIndex": 0, 
                        "Description": "eth-zero", 
                        "NetworkInterfaceId": "", 
                        "DeleteOnTermination": true, 
                        "SubnetId": "subnet-420ffc2b", 
                        "AssociatePublicIpAddress": true
                    }
                ]
            }, 
            "Type": "one-time", 
            "CreateTime": "2019-02-24T15:21:36.000Z", 
            "SpotPrice": "0.008000"
        }, 
        {
            "Status": {
                "Message": "Your Spot request failed due to bad parameters.", 
                "Code": "bad-parameters", 
                "UpdateTime": "2019-02-24T14:51:48.000Z"
            }, 
            "ActualBlockHourlyPrice": "0.002000", 
            "ValidUntil": "2019-03-03T14:51:47.000Z", 
            "InstanceInterruptionBehavior": "terminate", 
            "Tags": [], 
            "Fault": {
                "Message": "Invalid device name /dev/sda", 
                "Code": "InvalidBlockDeviceMapping"
            }, 
            "BlockDurationMinutes": 60, 
            "SpotInstanceRequestId": "sir-1k9s5h3m", 
            "State": "cancelled", 
            "ProductDescription": "Linux/UNIX", 
            "LaunchedAvailabilityZone": "eu-north-1a", 
            "LaunchSpecification": {
                "Placement": {
                    "Tenancy": "default", 
                    "AvailabilityZone": "eu-north-1a"
                }, 
                "ImageId": "ami-6d27a913", 
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda", 
                        "VirtualName": "root", 
                        "NoDevice": "", 
                        "Ebs": {
                            "Encrypted": false, 
                            "DeleteOnTermination": true, 
                            "VolumeType": "gp2", 
                            "VolumeSize": 8
                        }
                    }
                ], 
                "EbsOptimized": false, 
                "SecurityGroups": [
                    {
                        "GroupName": "default"
                    }
                ], 
                "Monitoring": {
                    "Enabled": false
                }, 
                "InstanceType": "t3.nano", 
                "AddressingType": "public", 
                "NetworkInterfaces": [
                    {
                        "DeviceIndex": 0, 
                        "Description": "eth-zero", 
                        "NetworkInterfaceId": "", 
                        "DeleteOnTermination": true, 
                        "SubnetId": "subnet-420ffc2b", 
                        "AssociatePublicIpAddress": true
                    }
                ]
            }, 
            "Type": "one-time", 
            "CreateTime": "2019-02-24T14:51:47.000Z", 
            "SpotPrice": "0.011600"
        }, 
        {
            "Status": {
                "Message": "2019-02-24T15:02:17+0000 : 2019-02-24T15:02:17+0000 : Spot Instance terminated due to user-initiated termination.", 
                "Code": "instance-terminated-by-user", 
                "UpdateTime": "2019-02-24T15:03:34.000Z"
            }, 
            "ActualBlockHourlyPrice": "0.002000", 
            "ValidUntil": "2019-03-03T14:55:26.000Z", 
            "InstanceInterruptionBehavior": "terminate", 
            "Tags": [], 
            "InstanceId": "i-010442ac3cc85ec08", 
            "BlockDurationMinutes": 60, 
            "SpotInstanceRequestId": "sir-43x16b6n", 
            "State": "closed", 
            "ProductDescription": "Linux/UNIX", 
            "LaunchedAvailabilityZone": "eu-north-1a", 
            "LaunchSpecification": {
                "Placement": {
                    "Tenancy": "default", 
                    "AvailabilityZone": "eu-north-1a"
                }, 
                "ImageId": "ami-6d27a913", 
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda1", 
                        "VirtualName": "root", 
                        "NoDevice": "", 
                        "Ebs": {
                            "Encrypted": false, 
                            "DeleteOnTermination": true, 
                            "VolumeType": "gp2", 
                            "VolumeSize": 8
                        }
                    }
                ], 
                "EbsOptimized": false, 
                "SecurityGroups": [
                    {
                        "GroupName": "default"
                    }
                ], 
                "Monitoring": {
                    "Enabled": false
                }, 
                "InstanceType": "t3.nano", 
                "AddressingType": "public", 
                "NetworkInterfaces": [
                    {
                        "DeviceIndex": 0, 
                        "Description": "eth-zero", 
                        "NetworkInterfaceId": "", 
                        "DeleteOnTermination": true, 
                        "SubnetId": "subnet-420ffc2b", 
                        "AssociatePublicIpAddress": true
                    }
                ]
            }, 
            "Type": "one-time", 
            "CreateTime": "2019-02-24T14:55:26.000Z", 
            "SpotPrice": "0.011600"
        }, 
        {
            "Status": {
                "Message": "Your Spot request failed due to bad parameters.", 
                "Code": "bad-parameters", 
                "UpdateTime": "2019-02-24T14:29:24.000Z"
            }, 
            "ActualBlockHourlyPrice": "0.002000", 
            "ValidUntil": "2019-03-03T14:29:23.000Z", 
            "InstanceInterruptionBehavior": "terminate", 
            "Tags": [], 
            "Fault": {
                "Message": "Addressing type must be 'public'", 
                "Code": "InvalidParameterCombination"
            }, 
            "BlockDurationMinutes": 60, 
            "SpotInstanceRequestId": "sir-2jsh5brn", 
            "State": "cancelled", 
            "ProductDescription": "Linux/UNIX", 
            "LaunchedAvailabilityZone": "eu-north-1a", 
            "LaunchSpecification": {
                "Placement": {
                    "Tenancy": "default", 
                    "AvailabilityZone": "eu-north-1a"
                }, 
                "ImageId": "ami-6d27a913", 
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda", 
                        "VirtualName": "root", 
                        "NoDevice": "", 
                        "Ebs": {
                            "Encrypted": false, 
                            "DeleteOnTermination": true, 
                            "VolumeType": "gp2", 
                            "VolumeSize": 8
                        }
                    }
                ], 
                "EbsOptimized": false, 
                "SecurityGroups": [
                    {
                        "GroupName": "default"
                    }
                ], 
                "Monitoring": {
                    "Enabled": false
                }, 
                "InstanceType": "t3.nano", 
                "AddressingType": "", 
                "NetworkInterfaces": [
                    {
                        "DeviceIndex": 0, 
                        "Description": "eth-zero", 
                        "NetworkInterfaceId": "", 
                        "DeleteOnTermination": true, 
                        "SubnetId": "subnet-420ffc2b", 
                        "AssociatePublicIpAddress": true
                    }
                ]
            }, 
            "Type": "one-time", 
            "CreateTime": "2019-02-24T14:29:23.000Z", 
            "SpotPrice": "0.011600"
        }, 
        {
            "Status": {
                "Message": "Your spot request is fulfilled.", 
                "Code": "fulfilled", 
                "UpdateTime": "2019-02-24T15:37:28.000Z"
            }, 
            "ActualBlockHourlyPrice": "0.002000", 
            "ValidUntil": "2019-03-03T15:37:26.000Z", 
            "InstanceInterruptionBehavior": "terminate", 
            "Tags": [], 
            "InstanceId": "i-0a29e9de6d59d433f", 
            "BlockDurationMinutes": 60, 
            "SpotInstanceRequestId": "sir-z1e9591m", 
            "State": "active", 
            "ProductDescription": "Linux/UNIX", 
            "LaunchedAvailabilityZone": "eu-north-1a", 
            "LaunchSpecification": {
                "Placement": {
                    "Tenancy": "default", 
                    "AvailabilityZone": "eu-north-1a"
                }, 
                "ImageId": "ami-6d27a913", 
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda1", 
                        "VirtualName": "root", 
                        "NoDevice": "", 
                        "Ebs": {
                            "Encrypted": false, 
                            "DeleteOnTermination": true, 
                            "VolumeType": "gp2", 
                            "VolumeSize": 8
                        }
                    }
                ], 
                "EbsOptimized": false, 
                "SecurityGroups": [
                    {
                        "GroupName": "default"
                    }
                ], 
                "Monitoring": {
                    "Enabled": false
                }, 
                "InstanceType": "t3.nano", 
                "AddressingType": "public", 
                "NetworkInterfaces": [
                    {
                        "DeviceIndex": 0, 
                        "Description": "eth-zero", 
                        "NetworkInterfaceId": "", 
                        "DeleteOnTermination": true, 
                        "SubnetId": "subnet-420ffc2b", 
                        "AssociatePublicIpAddress": true
                    }
                ]
            }, 
            "Type": "one-time", 
            "CreateTime": "2019-02-24T15:37:26.000Z", 
            "SpotPrice": "0.008000"
        }, 
        {
            "Status": {
                "Message": "Your Spot request failed due to bad parameters.", 
                "Code": "bad-parameters", 
                "UpdateTime": "2019-02-24T14:33:43.000Z"
            }, 
            "ActualBlockHourlyPrice": "0.002000", 
            "ValidUntil": "2019-03-03T14:33:42.000Z", 
            "InstanceInterruptionBehavior": "terminate", 
            "Tags": [], 
            "Fault": {
                "Message": "Invalid device name /dev/sda", 
                "Code": "InvalidBlockDeviceMapping"
            }, 
            "BlockDurationMinutes": 60, 
            "SpotInstanceRequestId": "sir-n7c15y5p", 
            "State": "cancelled", 
            "ProductDescription": "Linux/UNIX", 
            "LaunchedAvailabilityZone": "eu-north-1a", 
            "LaunchSpecification": {
                "Placement": {
                    "Tenancy": "default", 
                    "AvailabilityZone": "eu-north-1a"
                }, 
                "ImageId": "ami-6d27a913", 
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/sda", 
                        "VirtualName": "root", 
                        "NoDevice": "", 
                        "Ebs": {
                            "Encrypted": false, 
                            "DeleteOnTermination": true, 
                            "VolumeType": "gp2", 
                            "VolumeSize": 8
                        }
                    }
                ], 
                "EbsOptimized": false, 
                "SecurityGroups": [
                    {
                        "GroupName": "default"
                    }
                ], 
                "Monitoring": {
                    "Enabled": false
                }, 
                "InstanceType": "t3.nano", 
                "AddressingType": "public", 
                "NetworkInterfaces": [
                    {
                        "DeviceIndex": 0, 
                        "Description": "eth-zero", 
                        "NetworkInterfaceId": "", 
                        "DeleteOnTermination": true, 
                        "SubnetId": "subnet-420ffc2b", 
                        "AssociatePublicIpAddress": true
                    }
                ]
            }, 
            "Type": "one-time", 
            "CreateTime": "2019-02-24T14:33:42.000Z", 
            "SpotPrice": "0.011600"
        }
    ]
}

1
column -tतालिका के साथ हेडर को संरेखित करने की चाल बनाई। धन्यवाद!
दिमित्रिस मोरिटिडिस

आप column -ts $'\t'टैब वर्णों पर विभाजित करने के लिए उपयोग कर सकते हैं, लेकिन रिक्त स्थान नहीं - अन्यथा रिक्त स्थान वाले मानों को कई स्तंभों में विभाजित किया जाएगा। से unix.stackexchange.com/a/57235/140650
alexanderbird

0

यदि मानों में स्थान नहीं हैं, तो यह मददगार हो सकता है:

read -r -a data <<<'name1 value1 name2 value2'

echo "name value"
echo "=========="

for ((i=0; i<${#data[@]}; i+=2)); do
  echo ${data[$i]} ${data[$((i+1))]}
done

उत्पादन

name value
==========
name1 value1
name2 value2

मैं महसूस कर रहा हूं कि मुझे सीधे jq से एक सरणी नहीं मिल सकती है, क्या यह सही है? तो जाने का तरीका यह है कि इससे एक स्ट्रिंग प्राप्त करें (एक व्यावहारिक प्रारूप में) और वहां से जाएं?
रेइन करें

0

उपरोक्त उत्तरों के साथ समस्या यह है कि वे केवल तभी काम करते हैं यदि फ़ील्ड सभी एक ही चौड़ाई के बारे में हैं।

इस समस्या से बचने के लिए, लिनक्स columnकमांड का उपयोग किया जा सकता है:

// input.json
[
  {
    "name": "George",
    "id": "a very very long field",
    "email": "george@domain.com"
  },
  {
    "name": "Jack",
    "id": 18,
    "email": "jack@domain.com"
  },
  {
    "name": "Joe",
    "id": 19,
    "email": "joe@domain.com"
  }
]

फिर:

▶ jq -r '.[] | [.id, .name] | @tsv' input.json | column -ts $'\t'
a very very long field  George
18                      Jack
19                      Joe
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.