অ্যামাজন এপিআই গেটওয়ে দ্বারা ফিরিয়ে দেওয়া http স্থিতি কোডগুলি পরিবর্তন করার কোনও উপায় আছে কি?


97

উদাহরণস্বরূপ যদি আমি অবৈধ পরামিতিগুলির জন্য একটি নির্দিষ্ট 400 ত্রুটি বা সম্ভবত একটি 201 ফিরিয়ে দিতে চাই যখন ল্যাম্বদা ফাংশন কলটি তৈরির ফলস্বরূপ।

আমি আলাদা আলাদা HTTP স্থিতি কোড পেতে চাই তবে লিম্বদা ফাংশন ত্রুটি ফিরিয়ে দিলেও এপি গেটওয়ে সর্বদা 200 টি স্ট্যাটাস কোড দেয় বলে মনে হচ্ছে।


4
সুতরাং দেখে মনে হচ্ছে যে সমস্যাটি আমার ছিল তা হ'ল আমি একটি কাস্টম ত্রুটি প্রকারটি ফিরিয়ে দিচ্ছি - যা ত্রুটিমীমাবদ্ধ রেজেক্স সঠিকভাবে কাজ না করে। ল্যাম্বদা থেকে ব্যর্থ প্রতিক্রিয়াতে একটি স্ট্যান্ডার্ড স্ট্রিং ফিরিয়ে দেওয়া নীচের সমাধানটির কাজ করবে - আপনার নিজস্ব কাস্টম ত্রুটি বস্তুটি ফিরিয়ে দেওয়া হবে না, তবে তা করবে না।
MonkeyBonkey

আমার সমাধানটি ছিল সার্ভারলেস সংস্করণ 0.5 থেকে 1.0 এ স্যুইচ করা। এছাড়াও, আমি সার্ভারলেস ডকুমেন্টেশন থেকে প্রতিক্রিয়াটি ব্যবহার করছি, প্রতিক্রিয়া হিসাবে স্ট্যাটাস কোডটি সম্পত্তি হিসাবে উল্লেখ করে spec আশা করি এটি সহায়তা করে
Relu Mesaros

উত্তর:


79

20-9-2016 প্রতি আপডেট

ল্যাম্বদা প্রক্সি ইন্টিগ্রেশন ব্যবহার করে অবশেষে অ্যামাজন এটিকে সহজ করেছে । এটি আপনার ল্যাম্বদা ফাংশনটিকে যথাযথ এইচটিটিপি কোড এবং শিরোনাম ফিরিয়ে দিতে দেয়:

let response = {
    statusCode: '400',
    body: JSON.stringify({ error: 'you messed up!' }),
    headers: {
        'Content-Type': 'application/json',
    }
};

context.succeed(response);

এপিআই গেটওয়েতে বিদায় অনুরোধ / প্রতিক্রিয়া ম্যাপিং বলুন!

বিকল্প 2

অ্যাবস-সার্ভারলেস-এক্সপ্রেস ব্যবহার করে ল্যাম্বদা / এপিআই গেটওয়ের সাথে একটি বিদ্যমান এক্সপ্রেস অ্যাপ সংহত করুন ।


4
আমি এটি একীভূত করতে পারি না, এর অর্থ, আমি 200 স্ট্যাটাস এবং তৈরি প্রতিক্রিয়া (তৈরি হওয়া ত্রুটি) পাই। আমি কিছু অনুপস্থিত করছি ? "এস-ফাংশন.জসন" কেমন দেখাচ্ছে?
রেলু মেসারস

7
যে কেউ ভাবছেন, তাদের জন্য এটি নতুন callbackস্টাইল ব্যবহার করে অর্জন করা যেতে পারে । শুধু কর callback(null, {statusCode: 200, body: 'whatever'})
উইডারশিন

4
@ আঙ্কেলমেট আমারও একই প্রশ্ন রয়েছে। আপনি কি তা বুঝতে পেরেছেন? অজগরে এটি কীভাবে করবেন?
সুশীল

4
@ সুশীল হ্যাঁ, আপনি কেবল উপরের প্রতিক্রিয়া ভেরিয়েবলের মতো জেএসএনকে ফিরিয়ে দিন।
চাচা

8
@ সুশীল আমি ল্যাম্বডাপ্রসী ইন্টিগ্রেশন এবং ফিরে দিয়ে পাইথনে এটি সমাধান করেছিreturn { "isBase64Encoded": True, "statusCode": 200, "headers": { }, "body": "" }
জিতু আর জ্যাকব

74

এখানে কাস্টম এইচটিটিপি স্থিতি কোড এবং একটি কাস্টম ফেরত দেওয়ার দ্রুততম উপায় errorMessage:

এপিআই গেটওয়ে ড্যাশবোর্ডে, নিম্নলিখিতটি করুন:

  1. ইন পদ্ধতি আপনার জন্য রিসোর্স এ ক্লিক করুন পদ্ধতি প্রতিক্রিয়া
  2. ইন HTTP স্থিতি টেবিল, ক্লিক করুন অ্যাড প্রতিক্রিয়া এবং প্রতিটি HTTP স্থিতি কোড আপনি ব্যবহার করতে চান সেটি জুড়ুন।
  3. ইন পদ্ধতি আপনার জন্য রিসোর্স এ ক্লিক করুন ইন্টিগ্রেশন প্রতিক্রিয়া
  4. আপনি আগে তৈরি HTTP স্থিতি কোডগুলির প্রত্যেকটির জন্য ইন্টিগ্রেশন প্রতিক্রিয়া যুক্ত করুন । নিশ্চিত হয়ে নিন যে ইনপুট পাসথ্রুটি পরীক্ষা করা হয়েছে। আপনি যখন ল্যাম্বদা ফাংশন থেকে ত্রুটি বার্তা ফিরবেন তখন কোন স্থিতি কোডটি ব্যবহার করা উচিত তা সনাক্ত করতে ল্যাম্বডা ত্রুটি রিজেক্স ব্যবহার করুন । উদাহরণ স্বরূপ:

    // Return An Error Message String In Your Lambda Function
    
    return context.fail('Bad Request: You submitted invalid input');
    
    // Here is what a Lambda Error Regex should look like.
    // Be sure to include the period and the asterisk so any text
    // after your regex is mapped to that specific HTTP Status Code
    
    Bad Request: .*
    
  5. আপনার এপিআই গেটওয়ে রুটের এটি ফেরত দেওয়া উচিত:

    HTTP Status Code: 400
    JSON Error Response: 
        {
            errorMessage: "Bad Request: You submitted invalid input"
        }
    
  6. আমি এই সেটিংগুলি অনুলিপি করার এবং এটি বিভিন্ন পদ্ধতির জন্য পুনরায় ব্যবহার করার কোনও উপায় দেখতে পাচ্ছি না, তাই করার জন্য আমাদের অনেক বিরক্তিকর রিয়ন্ডল ম্যানুয়াল ইনপুট রয়েছে!

আমার একীকরণের প্রতিক্রিয়াগুলি এর মতো দেখায়:

Aws এপি গেটওয়ে ল্যাম্বডা ত্রুটির প্রতিক্রিয়া হ্যান্ডলিং


4
সুতরাং দেখে মনে হচ্ছে আমার সমস্যাটি হ'ল রেজেক্স ট্রিগার কখনই কাজ করছে না যেহেতু আমি লাম্বদা থেকে কোনও ত্রুটিযুক্ত বস্তুটি কেবল একটি স্ট্রিংয়ের পরিবর্তে ব্যর্থ পদ্ধতিতে ফিরিয়ে দিই। যেমনreturn context.fail(new Error('bad one'))
MonkeyBonkey

7
@ কালিসজোশুয়া আমি সম্প্রতি এপিআই গেটওয়ে / ল্যাম্বডায় ত্রুটি পরিচালনার বিষয়ে একটি মোটামুটি বিস্তারিত পোস্ট প্রকাশ করেছি: jayway.com/2015/11/07/…
কার্ল

9
পাইথন ল্যাম্বদার ক্ষেত্রে প্রসঙ্গের সমতুল্য কি?
রুটবার্ন

4
অজগর জন্য: একটি ব্যতিক্রম উত্থাপন। Docs.aws.amazon.com/lambda/latest/dg/python-exferences.html
6

4
ত্রুটিবিহীন প্রতিক্রিয়াগুলিতে স্থিতি কোডটি পরিবর্তন করার কোনও উপায় নেই? আমি যদি তৈরি করা অবজেক্টের সাথে "201 তৈরি" পাঠাতে চাইতাম তবে কী হবে?
বেন ডেভিস

18

JSON হিসাবে একটি কাস্টম ত্রুটিযুক্ত বস্তুটি ফিরিয়ে দিতে সক্ষম হতে আপনাকে বেশ কয়েকটি হুপের মধ্য দিয়ে যেতে হবে।

প্রথমত, আপনাকে অবশ্যই ল্যাম্বদা ব্যর্থ করতে হবে এবং এটি একটি স্ট্রিংযুক্ত জেএসওএন বস্তুটি পাস করতে হবে:

exports.handler = function(event, context) {
    var response = {
        status: 400,
        errors: [
            {
              code:   "123",
              source: "/data/attributes/first-name",
              message:  "Value is too short",
              detail: "First name must contain at least three characters."
            },
            {
              code:   "225",
              source: "/data/attributes/password",
              message: "Passwords must contain a letter, number, and punctuation character.",
              detail: "The password provided is missing a punctuation character."
            },
            {
              code:   "226",
              source: "/data/attributes/password",
              message: "Password and password confirmation do not match."
            }
        ]
    }

    context.fail(JSON.stringify(response));
};

এরপরে, আপনি যে স্ট্যাটাস কোডগুলিতে ফিরে আসতে চান তার জন্য আপনি রেজেক্স ম্যাপিং সেটআপ করেন। উপরে বর্ণিত অবজেক্টটি ব্যবহার করে আপনি 400 এর জন্য এই রেজেক্সটি সেটআপ করবেন:

। * "স্থিতি": 400. *

অবশেষে, আপনি লাম্বদা দ্বারা ফিরে আসা ত্রুটিমালা সম্পত্তি থেকে জেএসএন প্রতিক্রিয়াটি সরাতে একটি ম্যাপিং টেম্পলেট সেটআপ করুন। ম্যাপিং টেমপ্লেটটি এর মতো দেখাচ্ছে:

$ ইনপুট.পথ ('error। ত্রুটিমাখা')

আমি এ সম্পর্কিত একটি নিবন্ধ লিখেছি যা আরও বিশদে যায় এবং ল্যাম্বডা থেকে এপিআই গেটওয়েতে এখানে প্রতিক্রিয়া প্রবাহকে ব্যাখ্যা করে: http://kennbrodhagen.net/2016/03/09/how-to-return-a-custom-error-object লাম্বদা সহ-এপিআই-গেটওয়ে-থেকে-এবং-স্থিতি-কোড /


@ একনব্রোডেগন আপনি এপিআই গেটওয়ে এবং জাভা ল্যাম্বডাস সম্পর্কে জানেন? আমি এক ধরণের একই রেগ এক্সপ ব্যবহার করছি এবং এটি আমার পক্ষে কাজ করছে না। আমি ব্যবহার করি। * স্ট্যাটাস কোড ":
422.

@ পেরিমোষ এই নিবন্ধটি পরীক্ষা করে দেখুন যা জাভা ব্যতিক্রমগুলির সাথে এটি কীভাবে করা যায় তা ব্যাখ্যা করে: aws.amazon.com/blogs/compute/…
কেন্নব্রোডাগেন

10

1) API গেটওয়ে সংস্থান সংজ্ঞাটির "ইন্টিগ্রেশন রিকোয়েস্ট" স্ক্রিনে " লাম্বদা প্রক্সি ইন্টিগ্রেশন ব্যবহার করুন " লেবেলটি চেকবক্সটি চেক করে লাম্বদা প্রক্সি ইন্টিগ্রেশন ব্যবহার করতে আপনার এপিআই গেটওয়ে সংস্থানটি কনফিগার করুন । (অথবা এটি আপনার ক্লাউডফর্মেশন / টেরফর্ম / সার্ভারলেস / ইত্যাদি কনফিগারেশনে সংজ্ঞায়িত করুন)

2) আপনার ল্যাম্বদা কোডটি 2 উপায়ে পরিবর্তন করুন

  • আগত event(1 ম ফাংশন যুক্তি) যথাযথভাবে প্রক্রিয়া করুন । এটি এখন কেবল খালি পেডলোড নয়, এটি শিরোনাম, ক্যোয়ারী স্ট্রিং, এবং বডি সহ পুরো এইচটিটিপি অনুরোধকে উপস্থাপন করে। নীচে নমুনা। মূল বিষয় হ'ল জেএসওএন সংস্থাগুলি স্পষ্ট JSON.parse(event.body)কলের জন্য স্ট্রিংগুলি হবে (এটি ভুলে যাবেন না try/catch)। উদাহরণ নীচে।
  • তারপর নাল একটি প্রতিক্রিয়া বস্তু সহ HTTP- র বিস্তারিত সঙ্গে কলব্যাক কল করে প্রতিক্রিয়া statusCode, bodyএবং headers
    • bodyএকটি স্ট্রিং হওয়া উচিত, সুতরাং JSON.stringify(payload)প্রয়োজন হিসাবে করুন
    • statusCode একটি সংখ্যা হতে পারে
    • headers মানগুলিতে শিরোনামের নামগুলির একটি অবজেক্ট

প্রক্সি ইন্টিগ্রেশনের জন্য নমুনা লাম্বদা ইভেন্ট আর্গুমেন্ট

{
    "resource": "/example-path",
    "path": "/example-path",
    "httpMethod": "POST",
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "CloudFront-Forwarded-Proto": "https",
        "CloudFront-Is-Desktop-Viewer": "true",
        "CloudFront-Is-Mobile-Viewer": "false",
        "CloudFront-Is-SmartTV-Viewer": "false",
        "CloudFront-Is-Tablet-Viewer": "false",
        "CloudFront-Viewer-Country": "US",
        "Content-Type": "application/json",
        "Host": "exampleapiid.execute-api.us-west-2.amazonaws.com",
        "User-Agent": "insomnia/4.0.12",
        "Via": "1.1 9438b4fa578cbce283b48cf092373802.cloudfront.net (CloudFront)",
        "X-Amz-Cf-Id": "oCflC0BzaPQpTF9qVddpN_-v0X57Dnu6oXTbzObgV-uU-PKP5egkFQ==",
        "X-Forwarded-For": "73.217.16.234, 216.137.42.129",
        "X-Forwarded-Port": "443",
        "X-Forwarded-Proto": "https"
    },
    "queryStringParameters": {
        "bar": "BarValue",
        "foo": "FooValue"
    },
    "pathParameters": null,
    "stageVariables": null,
    "requestContext": {
        "accountId": "666",
        "resourceId": "xyz",
        "stage": "dev",
        "requestId": "5944789f-ce00-11e6-b2a2-dfdbdba4a4ee",
        "identity": {
            "cognitoIdentityPoolId": null,
            "accountId": null,
            "cognitoIdentityId": null,
            "caller": null,
            "apiKey": null,
            "sourceIp": "73.217.16.234",
            "accessKey": null,
            "cognitoAuthenticationType": null,
            "cognitoAuthenticationProvider": null,
            "userArn": null,
            "userAgent": "insomnia/4.0.12",
            "user": null
        },
        "resourcePath": "/example-path",
        "httpMethod": "POST",
        "apiId": "exampleapiid"
    },
    "body": "{\n  \"foo\": \"FOO\",\n  \"bar\": \"BAR\",\n  \"baz\": \"BAZ\"\n}\n",
    "isBase64Encoded": false
}

নমুনা কলব্যাক প্রতিক্রিয়া আকার

callback(null, {
  statusCode: 409,
  body: JSON.stringify(bodyObject),
  headers: {
    'Content-Type': 'application/json'
  }
})

নোট - আমি বিশ্বাস করি উপর পদ্ধতি contextযেমন context.succeed()অসমর্থিত হয়েছে। তারা এখনও ডকুমেন্টেড হয় না যদিও তারা এখনও কাজ করে বলে মনে হচ্ছে। আমি মনে করি কলব্যাক এপিআই তে কোডিং হ'ল এগিয়ে যাওয়া সঠিক জিনিস।


4
এটা কাজ করে না. আমি এখনও এই পুরো প্রতিক্রিয়া আউটপুট সঙ্গে 200 স্থিতি ফিরে পেতে। এপিআইকে প্রকৃতপক্ষে 409 স্থিতি ফেরানোর জন্য সেট করা যায় না
অ্যান্ডি এন

7

আমি ল্যাম্বডা থেকে ত্রুটিটি যথাযথ 500 ত্রুটি হতে চেয়েছিলাম, অনেক গবেষণা করার পরে নীচে নিয়ে এসেছিল, যা কাজ করে:

এলএএমবিডিএ-তে

একটি ভাল প্রতিক্রিয়া জন্য, আমি নীচের মত ফিরে আসছি:

exports.handler = (event, context, callback) => {
    // ..

    var someData1 =  {
        data: {
            httpStatusCode: 200,
            details: [
                {
                    prodId: "123",
                    prodName: "Product 1"
                },
                {
                    "more": "213",
                    "moreDetails": "Product 2"
                }
            ]
        }
    };
    return callback(null, someData1);
}

একটি খারাপ প্রতিক্রিয়া জন্য, নীচের মত ফিরে

exports.handler = (event, context, callback) => {
    // ..

    var someError1 = {
        error: {
            httpStatusCode: 500,
            details: [
                {
                    code: "ProductNotFound",
                    message: "Product not found in Cart",
                    description: "Product should be present after checkout, but not found in Cart",
                    source: "/data/attributes/product"
                },
                {
                    code: "PasswordConfirmPasswordDoesntMatch",
                    message: "Password and password confirmation do not match.",
                    description: "Password and password confirmation must match for registration to succeed.",
                    source: "/data/attributes/password",
                }
            ]
        }
    };

    return callback(new Error(JSON.stringify(someError1)));
}

এপিআই গেটওয়েতে

একটি গেট মেথডের জন্য, / রেজি 1 / পরিষেবা 1 এর জিইটি বলুন:

Through Method Response > Add Response, added 3 responses:
- 200
- 300
- 400

তারপরে,

Through 'Integration Response' > 'Add integration response', create a Regex for 400 errors (client error):

Lambda Error Regex    .*"httpStatusCode":.*4.*

'Body Mapping Templates' > Add mapping template as:  
    Content-Type                 application/json  
    Template text box*           $input.path('$.errorMessage')  


Similarly, create a Regex for 500 errors (server error):

Lambda Error Regex    .*"httpStatusCode":.*5.*

'Body Mapping Templates' > Add mapping template as:  
    Content-Type                 application/json  
    Template text box*           $input.path('$.errorMessage')  

এখন, প্রকাশ করুন / রেস 1 / পরিষেবা 1, প্রকাশিত ইউআরএল হিট করুন, যা উপরে লাম্বদার সাথে সংযুক্ত

ব্যবহৃত অ্যাডভান্সড আরইএসটি ক্লায়েন্ট (বা পোস্টম্যান) ক্রোম প্লাগইন, আপনি সার্ভার ত্রুটি (500) বা 400 এর মতো যথাযথ http কোডগুলি দেখতে পাবেন যেখানে "httpstatusCode" তে দেওয়া হয়েছিল এমন সমস্ত অনুরোধের জন্য 200 HTTP প্রতিক্রিয়া কোডের পরিবর্তে।

এপিআই এর 'ড্যাশবোর্ড' থেকে, এপিআই গেটওয়েতে, আমরা নীচের মতো HTTP স্থিতি কোডগুলি দেখতে পারি:

400 এবং 500 ত্রুটি


7

এটি করার সহজতম উপায় হ'ল ল্যাম্বডিএডিএআরএক্সএক্সআরএকটি ইন্টিগ্রেশন ব্যবহার করা । এই পদ্ধতিটি ব্যবহার করে, আপনাকে এপিআই গেটওয়ে পাইপলাইনে সেট করার জন্য কোনও বিশেষ রূপান্তর দরকার নেই।

আপনার রিটার্ন অবজেক্টটি নীচের স্নিপেটের মতো হতে হবে:

module.exports.lambdaHandler = (event, context, done) => {
    // ...
    let response = {
        statusCode: 200, // or any other HTTP code
        headers: {       // optional
             "any-http-header" : "my custom header value"
        },
        body: JSON.stringify(payload) // data returned by the API Gateway endpoint
    };
    done(null, response); // always return as a success
};

এতে কয়েকটি ত্রুটি রয়েছে: ত্রুটি পরিচালনার বিষয়ে বিশেষভাবে যত্নবান হওয়া এবং আপনার ল্যাম্বডা ফাংশনটি এপিআই গেটওয়ে শেষ পয়েন্টে সংযুক্ত করার জন্য; এটি বলেছিল, আপনি যদি সত্যিই এটি অন্য কোথাও ব্যবহার না করে থাকেন তবে সমস্যাটি খুব বেশি নয়।


6

যারা এই প্রশ্নটিতে সমস্ত কিছু রেখেছেন এবং এই কাজটি করতে (আমার মতো) করতে পারেননি তাদের জন্য, এই পোস্টে দেবদেবকিট মন্তব্যটি পরীক্ষা করুন (আমার দিনটি রক্ষা করলেন):

https://forums.aws.amazon.com/thread.jspa?threadID=192918

এটি সম্পূর্ণ নীচে পুনরুত্পাদন:

আমার নিজেই এ নিয়ে সমস্যা ছিল এবং আমি বিশ্বাস করি যে নতুন লাইন চরিত্রগুলিই অপরাধী।

foo। * "foo" এর সাথে মিলিত হবে তারপরে কোনও অক্ষর ছাড়াই নিউলাইন। সাধারণত এটি '/ s' পতাকা যুক্ত করে সমাধান করা হয়, অর্থাত "foo। * / S", তবে লাম্বডা ত্রুটি রেজেক্স এটি সম্মান করে বলে মনে হয় না।

বিকল্প হিসাবে আপনি কিছু ব্যবহার করতে পারেন: foo (। | \ N) *


আশ্চর্যজনক সন্ধান! এটি আমার মাথা ধাক্কা দেওয়ার কয়েক ঘন্টা বাঁচিয়েছে! এবং এটি সুস্পষ্ট থেকে অনেক দূরে।
মিরকো ভুকুসিć

মিরকো, আমি আপনাকে খুশি করে আনন্দিত!
কার্লোস ব্যলক

2

যদি এপিআই গেটওয়ে ব্যবহার করা হয় তবে এটি কোনও এডাব্লুএস কম্পিউট ব্লগে সুপারিশ করা হয়। সরাসরি ল্যাম্বডো আহ্বানের সাথে একীকরণ কাজ করে কিনা তা পরীক্ষা করা হচ্ছে।

var myErrorObj = {
    errorType : "InternalServerError",
    httpStatus : 500,
    requestId : context.awsRequestId,
    message : "An unknown error has occurred. Please try again."
}
callback(JSON.stringify(myErrorObj));

সরাসরি লাম্বদা আমন্ত্রণের জন্য, এটি ক্লায়েন্ট-সাইডে পার্সিংয়ের সেরা সমাধান বলে মনে হয়।


যদি উদাহরণটি ল্যাম্বডা কল করতে লাম্বদা হয়। এই কি এখনও বলা ল্যাম্বদা ফিরে আসবে? এবং কলিং ল্যাম্বডায় আমি কীভাবে এই httpstatus পড়তে পারি।
রড

1

আমি সার্ভারলেস 0.5 ব্যবহার করছি। এটি আমার কেসের জন্য এটি কাজ করে

s- ফাংশন.জসন:

{
  "name": "temp-err-test",
  "description": "Deployed",
  "runtime": "nodejs4.3",
  "handler": "path/to/handler.handler",
  "timeout": 6,
  "memorySize": 1024,
  "endpoints": [
    {
      "path": "test-error-handling",
      "method": "GET",
      "type": "AWS_PROXY",
      "responses": {
        "default": {
          "statusCode": "200"
        }
      }
    }
  ]
}

হ্যান্ডেল.জেএস:

'use strict';
function serveRequest(event, context, cb) {
  let response = {
    statusCode: '400',
    body: JSON.stringify({ event, context }),
    headers: {
      'Content-Type': 'application/json',
    }
  };
  cb(null, response);
}
module.exports.handler = serveRequest;

1

আপনি যদি প্রক্সি ব্যবহার করতে না চান তবে আপনি এই টেমপ্লেটটি ব্যবহার করতে পারেন:

#set($context.responseOverride.status =  $input.path('$.statusCode'))
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.