NSURL 쿼리 속성 구문 분석


82

다음과 같은 URL이 있습니다. myApp://action/1?parameter=2&secondparameter=3

속성 쿼리를 사용하면 내 URL

parameter=2&secondparameter=3

A의이을 넣어 쉽게 어떤 방법이 NSDictionary나는 Array?

정말 고마워

답변:


54

그런 것 :

NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
for (NSString *param in [url componentsSeparatedByString:@"&"]) {
  NSArray *elts = [param componentsSeparatedByString:@"="];
  if([elts count] < 2) continue;
  [params setObject:[elts lastObject] forKey:[elts firstObject]];
}

참고 : 이것은 샘플 코드입니다. 모든 오류 사례는 관리되지 않습니다.


2
이 코드는 잘못된 쿼리의 경우 충돌합니다. 아래의 안전한 솔루션을 참조하십시오.
BadPirate 2011 년

2
좋아, 당신은 배열 크기에 대한 확인을 추가합니다! 이 코드는 시작에 불과했습니다 (항상 그렇듯이). 모든 URL을 준수 할 경우, 조각 (끝 # 부분) 치료 이스케이프 문자열에 더 작품을 가지고 ...
브누아

당신을 위해 편집하십시오. 답변이있는 문제에 관심을 끌기 위해 투표 만했습니다. 편집이 완료되면 다시 불러올 수 있습니다.
BadPirate 2011 년

1
이 코드는 특수 문자가없는 가장 단순한 케이스 값을 제외하고는 정확하지 않습니다.
Nick Snyder

대신 마지막 및 첫 번째 개체를 사용해야합니다. [params setObject:[elts lastObject] forKey:[elts firstObject]];더 안전합니다
Laszlo

147

queryItems에서 사용할 수 있습니다 URLComponents.

이 속성의 값을 가져 오면 NSURLComponents 클래스는 쿼리 문자열을 구문 분석하고 NSURLQueryItem 개체의 배열을 반환합니다. 각 개체는 원래 쿼리 문자열에 나타나는 순서대로 단일 키-값 쌍을 나타냅니다.

빠른

let url = "http://example.com?param1=value1&param2=param2"
let queryItems = URLComponents(string: url)?.queryItems
let param1 = queryItems?.filter({$0.name == "param1"}).first
print(param1?.value)

또는 URL에 확장을 추가하여 작업을 더 쉽게 할 수 있습니다.

extension URL {
    var queryParameters: QueryParameters { return QueryParameters(url: self) }
}

class QueryParameters {
    let queryItems: [URLQueryItem]
    init(url: URL?) {
        queryItems = URLComponents(string: url?.absoluteString ?? "")?.queryItems ?? []
        print(queryItems)
    }
    subscript(name: String) -> String? {
        return queryItems.first(where: { $0.name == name })?.value
    }
}

그런 다음 이름으로 매개 변수에 액세스 할 수 있습니다.

let url = "http://example.com?param1=value1&param2=param2"
print(url.queryParameters["param1"])

11
iOS7 이후 쿼리. iOS8 이후의 queryItems.
Onato 2014

이 답변에 감사드립니다. 이 외에도 NSURLComponents에 대해 자세히 알아 보는 데 매우 도움이되는 다음 기사를 발견했습니다. nshipster.com/nsurl
xaphod

훌륭한 답변입니다. 감사!
dpigera

이상하게도 URL에 # 문자가 있으면 NSURLComponents가 작동하지 않습니다. like http://example.com/abc#abc?param1=value1&param2=param2 queryItems는 nil
Pedro

조각 (#abc)이 끝에 속하기 때문입니다.
Onato

55

이 동작에 도움이 될 수있는 확장 기능을 작성해야 할 이유가있었습니다. 먼저 헤더 :

#import <Foundation/Foundation.h>

@interface NSString (XQueryComponents)
- (NSString *)stringByDecodingURLFormat;
- (NSString *)stringByEncodingURLFormat;
- (NSMutableDictionary *)dictionaryFromQueryComponents;
@end

@interface NSURL (XQueryComponents)
- (NSMutableDictionary *)queryComponents;
@end

@interface NSDictionary (XQueryComponents)
- (NSString *)stringFromQueryComponents;
@end

이러한 메서드는 NSString, NSURL 및 NSDictionary를 확장하여 결과를 포함하는 쿼리 구성 요소 문자열 및 사전 개체간에 변환 할 수 있습니다.

이제 관련 .m 코드 :

#import "XQueryComponents.h"

@implementation NSString (XQueryComponents)
- (NSString *)stringByDecodingURLFormat
{
    NSString *result = [self stringByReplacingOccurrencesOfString:@"+" withString:@" "];
    result = [result stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    return result;
}

- (NSString *)stringByEncodingURLFormat
{
    NSString *result = [self stringByReplacingOccurrencesOfString:@" " withString:@"+"];
    result = [result stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    return result;
}

- (NSMutableDictionary *)dictionaryFromQueryComponents
{
    NSMutableDictionary *queryComponents = [NSMutableDictionary dictionary];
    for(NSString *keyValuePairString in [self componentsSeparatedByString:@"&"])
    {
        NSArray *keyValuePairArray = [keyValuePairString componentsSeparatedByString:@"="];
        if ([keyValuePairArray count] < 2) continue; // Verify that there is at least one key, and at least one value.  Ignore extra = signs
        NSString *key = [[keyValuePairArray objectAtIndex:0] stringByDecodingURLFormat];
        NSString *value = [[keyValuePairArray objectAtIndex:1] stringByDecodingURLFormat];
        NSMutableArray *results = [queryComponents objectForKey:key]; // URL spec says that multiple values are allowed per key
        if(!results) // First object
        {
            results = [NSMutableArray arrayWithCapacity:1];
            [queryComponents setObject:results forKey:key];
        }
        [results addObject:value];
    }
    return queryComponents;
}
@end

@implementation NSURL (XQueryComponents)
- (NSMutableDictionary *)queryComponents
{
    return [[self query] dictionaryFromQueryComponents];
}
@end

@implementation NSDictionary (XQueryComponents)
- (NSString *)stringFromQueryComponents
{
    NSString *result = nil;
    for(__strong NSString *key in [self allKeys])
    {
        key = [key stringByEncodingURLFormat];
        NSArray *allValues = [self objectForKey:key];
        if([allValues isKindOfClass:[NSArray class]])
            for(__strong NSString *value in allValues)
            {
                value = [[value description] stringByEncodingURLFormat];
                if(!result)
                    result = [NSString stringWithFormat:@"%@=%@",key,value];
                else 
                    result = [result stringByAppendingFormat:@"&%@=%@",key,value];
            }
        else {
            NSString *value = [[allValues description] stringByEncodingURLFormat];
            if(!result)
                result = [NSString stringWithFormat:@"%@=%@",key,value];
            else 
                result = [result stringByAppendingFormat:@"&%@=%@",key,value];
        }
    }
    return result;
}
@end

두 가지 문제 : 1) 사전에 저장하기 전에 키와 값을 모두 URL 디코딩해야하고 2) URL 규칙에 따라 동일한 키를 여러 번 지정할 수 있습니다. IOW, 단일 값이 아닌 값 배열에 매핑 된 키 여야합니다.
Dave DeLong 2011 년

좋아, 당신은 배열 크기에 대한 확인을 추가합니다 (내 대답에 대한 투표가 필요합니까?)! 이 코드는 시작에 불과했습니다 (항상 그렇듯이). 모든 URL을 준수 할 경우, 조각 (끝 # 부분) 치료 이스케이프 문자열에 더 작품을 가지고 ...
브누아

Dave-좋은 지적입니다. 내 요구에 필요한 것은 아니지만이 일반적인 문제를 방문하는 모든 사람에게 도움이되는 답변을 만들려고하기 때문에 언급 된 기능을 포함 시켰습니다. Benoit-답변으로 문제에주의를 기울이십시오. 편집을 제출했습니다. 아마도 좋은 답변의 사소한 문제에주의를 환기시키기 위해 down을 사용하는 가장 좋은 형태는 아닐 것입니다. 나는 앞으로 그렇게하지 않을 것입니다. 편집이 끝날 때까지 다운 투표를 변경할 수 없습니다. : /
BadPirate

stringByDecodingURLFormat에서 'result'의 유형은 NSString *이어야합니다.
ThomasW

또 다른 문제를 발견했습니다. 키와 값이 섞여 있습니다. 키는 objectAtIndex : 0이고 값은 objectAtIndex : 1이어야합니다.
ThomasW

13

이 시도 ;)!

NSString *query = @"parameter=2&secondparameter=3"; // replace this with [url query];
NSArray *components = [query componentsSeparatedByString:@"&"];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
for (NSString *component in components) {
    NSArray *subcomponents = [component componentsSeparatedByString:@"="];
    [parameters setObject:[[subcomponents objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
                   forKey:[[subcomponents objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}

1
또한 BadPirate가 지적한 충돌 문제 외에 (1) 사전 키 / 값이 반전됩니다. (2) 키 / 값이 여전히 인코딩되어 있으므로 stringByDecodingURLFormat
dpjanes

그것을하는 정말 좋은 방법
Burf2000

9

모든 이전 게시물이 URL 인코딩을 제대로 수행하지 않습니다. 다음 방법을 제안합니다.

+(NSString*)concatenateQuery:(NSDictionary*)parameters {
    if([parameters count]==0) return nil;
    NSMutableString* query = [NSMutableString string];
    for(NSString* parameter in [parameters allKeys])
        [query appendFormat:@"&%@=%@",[parameter stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet],[[parameters objectForKey:parameter] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]];
    return [[query substringFromIndex:1] copy];
}
+(NSDictionary*)splitQuery:(NSString*)query {
    if([query length]==0) return nil;
    NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
    for(NSString* parameter in [query componentsSeparatedByString:@"&"]) {
        NSRange range = [parameter rangeOfString:@"="];
        if(range.location!=NSNotFound)
            [parameters setObject:[[parameter substringFromIndex:range.location+range.length] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] forKey:[[parameter substringToIndex:range.location] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
        else [parameters setObject:[[NSString alloc] init] forKey:[parameter stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    }
    return [parameters copy];
}

if(!query||[query length] == 0)중복됩니다. if([query length] == 0)에서 length를 호출하면 query == nil값이 반환 되는 것처럼 안전하게 확인할 수 있습니다 0.
JRG-Developer

이것이 valueforkey가 아닌 objectForKey를 사용하면 안됩니까?
slf 2013-09-24

좋은 코드. 모든 문자 세트를 지원하기 위해 NSUTF8StringEncodingin splitQuery을 사용 하는 것이 좋습니다. :) 또한 . [string stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]concatenateQuery
William Denniss

불변 인스턴스를 반환하는 것이 좋은 습관이라고 생각하므로 마지막 줄을 [parameters copy]를 반환하도록 변경해야 할 수도 있습니다.
Glenn Howes 2014 년

감사. 귀하의 의견에 따라 코드를 수정했습니다!
Kristian Kraljic 2015 년

7

다음은 신속한 확장입니다.

extension NSURL{
        func queryParams() -> [String:AnyObject] {
            var info : [String:AnyObject] = [String:AnyObject]()
            if let queryString = self.query{
                for parameter in queryString.componentsSeparatedByString("&"){
                    let parts = parameter.componentsSeparatedByString("=")
                    if parts.count > 1{
                        let key = (parts[0] as String).stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
                        let value = (parts[1] as String).stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
                        if key != nil && value != nil{
                            info[key!] = value
                        }
                    }
                }
            }
            return info
        }
    }

7

Onato 의 이미 매우 깨끗한 답변에 따르면 Swift에서 NSURL에 대한 확장을 작성하여 다음과 같은 쿼리 매개 변수를 얻을 수 있습니다.

예를 들어 URL은 param = some_value 쌍을 포함합니다.

let queryItem = url.queryItemForKey("param")
let value = queryItem.value // would get String "someValue"

확장은 다음과 같습니다.

extension NSURL {

  var allQueryItems: [NSURLQueryItem] {
      get {
          let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: false)!
          let allQueryItems = components.queryItems!
          return allQueryItems as [NSURLQueryItem]
      }
  }

  func queryItemForKey(key: String) -> NSURLQueryItem? {

      let predicate = NSPredicate(format: "name=%@", key)!
      return (allQueryItems as NSArray).filteredArrayUsingPredicate(predicate).first as? NSURLQueryItem

  }
}

이것이 최고의 답변입니다! API 문서를 확인하지 않은 이유는 무엇입니까?
야민 장

5

그 사용을 위해 볼트 프레임 워크 당신은 사용할 수 있습니다 :

NSDictionary *parameters = [BFURL URLWithURL:yourURL].inputQueryParameters;

가져 오는 것을 잊지 마십시오 :

#import <Bolts/BFURL.h>

당신이하는 일이 있다면 페이스 북 SDK를 프로젝트에, 당신은 또한이 볼트 . Facebook은이 프레임 워크를 종속성으로 사용하고 있습니다.


Swift with Bolts :BFURL(url: url)?.inputQueryParameters?["myKey"] as? String
JAL

4

URL을 처리하는 데 선호되는 방법은 이제 NSURLComponents입니다. 특히 of params queryItems를 반환하는 속성 NSArray.

에서 매개 변수를 원하는 경우 다음 NSDictionary방법이 있습니다.

+(NSDictionary<NSString *, NSString *>*)queryParamsFromURL:(NSURL*)url
{
    NSURLComponents* urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];

    NSMutableDictionary<NSString *, NSString *>* queryParams = [NSMutableDictionary<NSString *, NSString *> new];
    for (NSURLQueryItem* queryItem in [urlComponents queryItems])
    {
        if (queryItem.value == nil)
        {
            continue;
        }
        [queryParams setObject:queryItem.value forKey:queryItem.name];
    }
    return queryParams;
}

주의 사항 : URL은 반복되는 매개 변수를 가질 수 있지만 사전에는 중복 된 매개 변수의 마지막 값만 포함됩니다. 바람직하지 않은 경우 queryItems어레이를 직접 사용하십시오 .


3

스위프트 2.1

짧막 한 농담:

"p1=v1&p2=v2".componentsSeparatedByString("&").map {
    $0.componentsSeparatedByString("=") 
}.reduce([:]) {
    (var dict: [String:String], p) in
    dict[p[0]] = p[1]
    return dict
}

// ["p1": "v1", "p2": "v2"]

NSURL에서 확장으로 사용 :

extension NSURL {

    /**
     * URL query string as dictionary. Empty dictionary if query string is nil.
     */
    public var queryValues : [String:String] {
        get {
            if let q = self.query {
                return q.componentsSeparatedByString("&").map {
                    $0.componentsSeparatedByString("=") 
                }.reduce([:]) {
                    (var dict: [String:String], p) in
                    dict[p[0]] = p[1]
                    return dict
                }
            } else {
                return [:]
            }
        }
    }

}

예:

let url = NSURL(string: "http://example.com?p1=v1&p2=v2")!
let queryDict = url.queryValues

// ["p1": "v1", "p2": "v2"]

OS X 10.10 또는 iOS 8 (또는 이후 버전)을 사용 NSURLComponents하는 경우 queryItems속성과 속성 을 사용 하고 NSURLQueryItems직접 사전을 만드는 것이 좋습니다 .

다음은 NSURLComponents기반 NSURL확장 솔루션입니다.

extension NSURL {

    /// URL query string as a dictionary. Empty dictionary if query string is nil.
    public var queryValues : [String:String] {
        get {
            guard let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: false) else {
                return [:]
            }

            guard let queryItems = components.queryItems else {
                return [:]
            }

            var result:[String:String] = [:]
            for q in queryItems {
                result[q.name] = q.value
            }
            return result
        }
    }

}

NSURL 확장에 대한 각주는 실제로 Swift에서 속성에 기존 문자열 속성과 동일한 이름을 부여 할 수 있다는 것 query입니다. 시도하기 전까지는 몰랐지만 Swift의 다형성은 반환 유형 만 다를 수 있습니다. 따라서 확장 NSURL 속성이 public var query: [String:String]작동하면 작동합니다. 나는 그것이 약간 미친 것을 알기 때문에 예제에서 이것을 사용하지 않았지만 작동합니다 ...


2

MIT에서 일하는 간단한 수업을 게시했습니다.

https://github.com/anegmawad/URLQueryToCocoa

그것으로 당신은 수집되고 함께 붙인 쿼리에 배열과 객체를 가질 수 있습니다.

예를 들어

users[0][firstName]=Amin&users[0][lastName]=Negm&name=Devs&users[1][lastName]=Kienle&users[1][firstName]=Christian

될 것입니다:

@{
   name : @"Devs",
   users :
   @[
      @{
         firstName = @"Amin",
         lastName = @"Negm"
      },
      @{
         firstName = @"Christian",
         lastName = @"Kienle"
      }
   ]
 }

의 URL 쿼리 대응으로 생각할 수 있습니다 NSJSONSerializer.


잘했습니다. 이것은 유일한 정답 인 것 같습니다 (배열 및 dict 값을 고려하는 것).
안톤 Tropashko

2

다른 iOS 애플리케이션에서 들어오는 데이터를 처리하는 데 사용하고있는 것 같습니다. 그렇다면 이것은 동일한 목적으로 사용하는 것입니다.

초기 호출 (예 : 외부 애플리케이션에서) :

UIApplication *application = [UIApplication sharedApplication];
NSURL *url = [NSURL URLWithString:@"myApp://action/1?parameter=2&secondparameter=3"];
if ([application canOpenURL:url]) {
    [application openURL:url];
    NSLog(@"myApp is installed");
} else {
    NSLog(@"myApp is not installed");
}

NSURL에서 QueryString 데이터를 추출하고 NSDictionary로 저장하는 방법 :

-(NSDictionary *) getNSDictionaryFromQueryString:(NSURL *)url {
   NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
   NSRange needle = [url.absoluteString rangeOfString:@"?" options:NSCaseInsensitiveSearch];
   NSString *data = nil;

   if(needle.location != NSNotFound) {
       NSUInteger start = needle.location + 1;
       NSUInteger end = [url.absoluteString length] - start;
       data = [url.absoluteString substringWithRange:NSMakeRange(start, end)];
   }

   for (NSString *param in [data componentsSeparatedByString:@"&"]) {
       NSArray *keyvalue = [param componentsSeparatedByString:@"="];
       if([keyvalue count] == 2){
           [result setObject:[keyvalue objectAtIndex:1] forKey:[keyvalue objectAtIndex:0]];
       }
   }

  return result;
}

용법:

NSDictionary *result = [self getNSDictionaryFromQueryString:url];

0

이 클래스는 URL 구문 분석을위한 좋은 솔루션입니다.

.h 파일

@interface URLParser : NSObject {
    NSArray *variables;
}

@property (nonatomic, retain) NSArray *variables;

- (id)initWithURLString:(NSString *)url;
- (NSString *)valueForVariable:(NSString *)varName;

@end

.m 파일

#import "URLParser.h"

@implementation URLParser
@synthesize variables;

- (id) initWithURLString:(NSString *)url{
    self = [super init];
    if (self != nil) {
        NSString *string = url;
        NSScanner *scanner = [NSScanner scannerWithString:string];
        [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]];
        NSString *tempString;
        NSMutableArray *vars = [NSMutableArray new];
        [scanner scanUpToString:@"?" intoString:nil];       //ignore the beginning of the string and skip to the vars
        while ([scanner scanUpToString:@"&" intoString:&tempString]) {
            [vars addObject:[tempString copy]];
        }
        self.variables = vars;
    }
    return self;
}

- (NSString *)valueForVariable:(NSString *)varName {
    for (NSString *var in self.variables) {
        if ([var length] > [varName length]+1 && [[var substringWithRange:NSMakeRange(0, [varName length]+1)] isEqualToString:[varName stringByAppendingString:@"="]]) {
            NSString *varValue = [var substringFromIndex:[varName length]+1];
            return varValue;
        }
    }
    return nil;
}

@end

0

Hendrik 은이 질문에서 확장에 대한 좋은 예를 썼지 만, Objective-C 라이브러리 메서드를 사용하지 않도록 다시 작성해야했습니다. NSArray신속하게 사용 하는 것은 올바른 접근 방식이 아닙니다.

결과는 모두 빠르고 안전합니다. 사용 예는 Swift 1.2에서 코드 줄이 줄어들 것입니다.

public extension NSURL {
    /*
    Set an array with all the query items
    */
    var allQueryItems: [NSURLQueryItem] {
        get {
            let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: false)!
            if let allQueryItems = components.queryItems {
                return allQueryItems as [NSURLQueryItem]
            } else {
                return []
            }
        }
    }

    /**
    Get a query item form the URL query

    :param: key The parameter to fetch from the URL query

    :returns: `NSURLQueryItem` the query item
    */
    public func queryItemForKey(key: String) -> NSURLQueryItem? {
        let filteredArray = filter(allQueryItems) { $0.name == key }

        if filteredArray.count > 0 {
            return filteredArray.first
        } else {
            return nil
        }
    }
}

용법:

let queryItem = url.queryItemForKey("myItem")

또는 더 자세한 사용법 :

if let url = NSURL(string: "http://www.domain.com/?myItem=something") {
    if let queryItem = url.queryItemForKey("myItem") {
        if let value = queryItem.value {
            println("The value of 'myItem' is: \(value)")
        }
    }
}

0

이 시도:

-(NSDictionary *)getUrlParameters:(NSString *)url{
    NSArray *justParamsArr = [url componentsSeparatedByString:@"?"];
    url = [justParamsArr lastObject];
    NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
    for (NSString *param in [url componentsSeparatedByString:@"&"]) {
        NSArray *elts = [param componentsSeparatedByString:@"="];
        if([elts count] < 2) continue;
        [params setObject:[elts lastObject] forKey:[elts firstObject]];
    }
    return params;
}

0

상당히 간결한 접근 방식 :

    func stringParamsToDict(query: String) -> [String: String] {
        let params = query.components(separatedBy: "&").map {
            $0.components(separatedBy: "=")
        }.reduce(into: [String: String]()) { dict, pair in
            if pair.count == 2 {
                dict[pair[0]] = pair[1]
            }
        }
        return params
    }

-5

URL을 사용하여 웹 앱에서 전화로 데이터를 전달하고 배열, 숫자, 문자열 등을 전달하려는 경우 가장 강력한 솔루션입니다.

JSON은 PHP에서 객체를 인코딩합니다.

header("Location: myAppAction://".urlencode(json_encode($YOUROBJECT)));

JSON은 iOS에서 결과를 디코딩합니다.

NSData *data = [[[request URL] host] dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *packed = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

1
끔찍한 생각입니다. URL에는 JSON을 직렬화하는 경우 쉽게 초과 될 수있는 길이 제한이 있습니다.
Michael Baldry 2013

그 주변에 2000 자
마이클 Baldry
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.