CXCallObserver is not working properly and App getting crash when running the app more than one (when includes contacts image data) - ios

I am facing two major problem first one is :
1. I am trying to detect incoming call, outgoing call , dialing call for this i am using this code :
import UIKit
import CoreTelephony
import CallKit
class ViewController: UIViewController,CXCallObserverDelegate {
let callObserver = CXCallObserver()
var seconds = 0
var timer = Timer()
override func viewDidLoad() {
super.viewDidLoad()
callObserver.setDelegate(self, queue: nil)
}
override func viewWillAppear(_ animated: Bool) {
print("viewWillAppear \(seconds)")
}
fileprivate func runTimer(){
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.updateTimer), userInfo: nil, repeats: true)
}
func updateTimer() {
seconds += 1
print("Seconds \(seconds)")
}
#IBAction func callButton(_ sender: UIButton) {
if let url = URL(string: "tel://\(12345879)"){
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) {
if call.hasEnded == true {
print("Disconnected")
seconds = 0
self.timer.invalidate()
}
if call.isOutgoing == true && call.hasConnected == false {
print("Dialing call")
self.runTimer()
}
if call.isOutgoing == false && call.hasConnected == false && call.hasEnded == false {
print("Incoming")
}
if call.hasConnected == true && call.hasEnded == false {
print("Connected")
}
}
}
It working fine when i am dialing a number it shows "Dialling" but when i cut the call then it shows "Disconnected" then again "Dialing" State.
Another problem is when i am fetching all contacts information from the device it works fine when i am not fetching imageData but when i am fetching contacts image it works fine for the very first time . Then if i run it again app become slow . then next it crash shows found nil while unwrapping a value.
i wrote my contact data fetching function in AppDelegate . it is calling when the app start . this is the code :
func fetchContactList(){
let loginInformation = LoginInformation()
var contactModelData: [ContactsModel] = []
var profileImage : UIImage?
let store = CNContactStore()
store.requestAccess(for: .contacts, completionHandler: {
granted, error in
guard granted else {
let alert = UIAlertController(title: "Can't access contact", message: "Please go to Settings -> MyApp to enable contact permission", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
return
}
let keysToFetch = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName),CNContactPhoneNumbersKey, CNContactEmailAddressesKey, CNContactPostalAddressesKey, CNContactImageDataKey, CNContactImageDataAvailableKey,CNContactThumbnailImageDataKey,CNContactThumbnailImageDataKey] as [Any]
let request = CNContactFetchRequest(keysToFetch: keysToFetch as! [CNKeyDescriptor])
var cnContacts = [CNContact]()
do {
try store.enumerateContacts(with: request){
(contact, cursor) -> Void in
cnContacts.append(contact)
}
} catch let error {
NSLog("Fetch contact error: \(error)")
}
for contact in cnContacts {
let fullName = CNContactFormatter.string(from: contact, style: .fullName) ?? "No Name"
var phoneNumberUnclean : String?
var labelofContact : String?
var phoneNumberClean: String?
for phoneNumber in contact.phoneNumbers {
if let number = phoneNumber.value as? CNPhoneNumber,
let label = phoneNumber.label {
let localizedLabel = CNLabeledValue<CNPhoneNumber>.localizedString(forLabel: label)
print("fullname \(fullName), localized \(localizedLabel), number \(number.stringValue)")
phoneNumberUnclean = number.stringValue
labelofContact = localizedLabel
}
}
if let imageData = contact.imageData {
profileImage = UIImage(data: imageData)
print("image \(String(describing: UIImage(data: imageData)))")
} else {
profileImage = UIImage(named: "user")
}
self.contactModelData.append(ContactsModel(contactName: fullName, contactNumber:phoneNumberUnclean!, contactLabel: labelofContact!, contactImage: profileImage!, contactNumberClean: phoneNumberUnclean!))
}
self.loginInformation.saveContactData(allContactData: self.contactModelData)
})
}

I have solved this two problems using this :
for number one when i disconnect a call then if unfortunately it goes to "Dialling" option again i checked the "seconds" variable's value if it greater than 0 in "Dialing" then invalidate the thread.
for number two problem :
I used Dispatch.async.main background thread and take the thumbnail image

Related

play sound based on the number of times listed on a textfield

My code below is has a textfield and a sound function. I would like the user to have the sound file be played the number of times the int is in the textfield when the button is pressed.
import UIKit
import AVFoundation
class ViewController: UIViewController {
#IBOutlet var sam : UITextField!
var bombSoundEffect: AVAudioPlayer?
func judo(){
let path = Bundle.main.path(forResource: "example.mp3", ofType:nil)!
let url = URL(fileURLWithPath: path)
do {
bombSoundEffect = try AVAudioPlayer(contentsOf: url)
bombSoundEffect?.play()
} catch {
// couldn't load file :(
}
}
}
Please use numberOfLoops:
"numberOfLoops" is the number of times that the sound will return to the beginning upon reaching the end.
A value of zero means to play the sound just once.
A value of one will result in playing the sound twice, and so on..
Any negative number will loop indefinitely until stopped.
bombSoundEffect.numberOfLoops = 1
You can do this in another way with some delay:
import UIKit
import AVFoundation
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
var player = AVAudioPlayer()
var timer = Timer()
var count: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func playAction(_ sender: Any) {
let alertSound = URL(fileURLWithPath: Bundle.main.path(forResource: "stereo", ofType: "wav")!)
do {
player = try AVAudioPlayer(contentsOf: alertSound)
} catch {
print("No sound found by URL")
}
if let textValue = self.textField.text, let inputNumber = Int(textValue), inputNumber > 0 {
playWith(repeatCount: inputNumber)
} else {
let alert = UIAlertController(title: "Alert", message: "Please enter number.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
func playWith(repeatCount: Int) {
player.play()
self.timer = Timer.scheduledTimer(withTimeInterval: 0.36, repeats: true, block: { (timer) in
self.count += 1
print(self.count)
if self.count != repeatCount {
self.player.play()
} else {
self.count = 0
self.player.stop()
self.timer.invalidate()
}
})
}
}
This is exactly what you want. In this demo, you have to enter input number in the text field and after that sound will play input number times.
If you want that time interval will also dynamic means time interval will also come from textField2 then use this method:
func playWith(repeatCount: Int) {
var timeInterval = 0.36
if let textValue = self.textField2.text, let inputNumber = Double(textValue), inputNumber > 0 {
timeInterval = inputNumber
}
player.play()
self.timer = Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: true, block: { (timer) in
self.count += 1
print(self.count)
if self.count != repeatCount {
self.player.play()
} else {
self.count = 0
self.player.stop()
self.timer.invalidate()
}
})
}

Text message function returns error on device

I am retrieving the phone number from my Firebase database, no matter how I enter it into the database it returns an error on my device:
"Message sent to invalid destination. Please check your number and try again. Msg 2127"
The message comes in as an automatic reply immediately after the text is sent out. I have tried entering it into firebase as 111-111-1111 and 1111111111 (not actually using a number 1 but a real phone number).
The calling function works fine however the same number being texted is not working.
var contact: Int!
#IBAction func textButton(_ sender: Any) {
if canSendText() {
if let contactopt = contact{
var messageVC = MFMessageComposeViewController()
messageVC.recipients = ["tel:\(contactopt)"]
messageVC.messageComposeDelegate = self;
self.present(messageVC, animated: false, completion: nil)}}
else {
let errorAlert = UIAlertView(title: "Cannot Send Text Message", message: "Your device is not able to send text messages.", delegate: self, cancelButtonTitle: "OK")
errorAlert.show()
}
}
func canSendText() -> Bool {
return MFMessageComposeViewController.canSendText()
}
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
controller.dismiss(animated: true, completion: nil)
}
#IBAction func callButton(_ sender: UIButton) {
if let contactopt = contact{
if let url = NSURL(string: "tel://\(contactopt)") {
// UIApplication.shared.openURL(url as URL)
UIApplication.shared.open(url as URL, options: [:], completionHandler: nil)
}
}
}
I had to change
messageVC.recipients = ["tel:(contactopt)"]
messageVC.recipients = [String(contactopt)]

App is performing segue automatically (Swift 2.0, Firebase 3)

Been smashing my face against the wall all day trying to upgrade my app to the Firebase 3.x code.
I was having a ton of trouble with updating my original userAuth code and decided to just start from scratch. I haven't really been able to test it though because when I run the app it is calling the segue immediately upon loading the initial VC. Obviously I don't want it to do this and I don't know what is causing it.
I've tried deleting the app from the simulator and when I load it back up I get the same result.
Here is my code for the VC:
import UIKit
import FirebaseAuth
class SignInViewController: UIViewController {
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
override func viewDidAppear(animated: Bool) {
if let user = FIRAuth.auth()?.currentUser {
self.signedIn(user)
}
}
#IBAction func didTapSignIn(sender: AnyObject) {
// Sign In with credentials.
let email = emailField.text
let password = passwordField.text
FIRAuth.auth()?.signInWithEmail(email!, password: password!) { (user, error) in
if let error = error {
print(error.localizedDescription)
return
}
self.signedIn(user!)
}
}
#IBAction func didTapSignUp(sender: AnyObject) {
let email = emailField.text
let password = passwordField.text
FIRAuth.auth()?.createUserWithEmail(email!, password: password!) { (user, error) in
if let error = error {
print(error.localizedDescription)
return
}
self.setDisplayName(user!)
}
}
func setDisplayName(user: FIRUser) {
let changeRequest = user.profileChangeRequest()
changeRequest.displayName = user.email!.componentsSeparatedByString("#")[0]
changeRequest.commitChangesWithCompletion(){ (error) in
if let error = error {
print(error.localizedDescription)
return
}
self.signedIn(FIRAuth.auth()?.currentUser)
}
}
#IBAction func didRequestPasswordReset(sender: AnyObject) {
let prompt = UIAlertController.init(title: nil, message: "Email:", preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction.init(title: "OK", style: UIAlertActionStyle.Default) { (action) in
let userInput = prompt.textFields![0].text
if (userInput!.isEmpty) {
return
}
FIRAuth.auth()?.sendPasswordResetWithEmail(userInput!) { (error) in
if let error = error {
print(error.localizedDescription)
return
}
}
}
prompt.addTextFieldWithConfigurationHandler(nil)
prompt.addAction(okAction)
presentViewController(prompt, animated: true, completion: nil);
}
func signedIn(user: FIRUser?) {
MeasurementHelper.sendLoginEvent()
AppState.sharedInstance.displayName = user?.displayName ?? user?.email
AppState.sharedInstance.photoUrl = user?.photoURL
AppState.sharedInstance.signedIn = true
NSNotificationCenter.defaultCenter().postNotificationName(Constants.NotificationKeys.SignedIn, object: nil, userInfo: nil)
performSegueWithIdentifier(Constants.Segues.SignInToFp, sender: nil)
}
}
Can someone please help? Thank you in advance.

Unexpected quirky behavior from socket.io in Swift

As per title, I'm having some trouble dealing with socket.io. It connects really well and accordingly in the first view controller but weird things happen when it comes to second controller.
Here's the code:
First Controller: I have declared some global variable for connection purposes between both view controller.
import UIKit
import SocketIOClientSwift
import SwiftyJSON
import CoreData
//declare some global variable
var patientCoreData = [NSManagedObject]()
var numberOfUsersExisting:Int = 0 //assign to 0 by default
var appUserData: Patient? //for specific user
var pSample: Array<Patient> = [] //for all user
//initiate socket globally
let socket = SocketIOClient(socketURL: "localhost:3000", options: [
"reconnects": true
])
func reportStatus(){
socket.on("connect") {data, ack in
print("Report status: View Controller connected")
socket.emit("click", "Client app connected")
}
}
func readDataFromSocket(completion: (data:AnyObject)-> ()){
socket.on("reply") {data, ack in
print("database replied")
completion(data: data)
}//socket
}//readDataFromSOCKET
func importData(){
reportStatus()
socket.connect()
readDataFromSocket(){ data in
let json = JSON(data)
let nou = json[0].count
if nou > 0 {
print("Test(1st VC): grabbing data from database")
for var i=0; i<nou; ++i{
numberOfUsersExisting = nou
pSample += [Patient(id: json[0][i]["ID"].intValue, name: json[0][i]["Name"].stringValue, gender: json[0][i]["Gender"].stringValue, mileage: json[0][i]["Mileage"].doubleValue)]
pSample.sortInPlace({$0.globalPatientMileAge < $1.globalPatientMileAge})
}
print("Successfully grabbed data")
}else{
print("No user in the database")
numberOfUsersExisting = 0
}
}//readDataFromSocket
}
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout{
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
print("First view appeared")
let prefs = NSUserDefaults.standardUserDefaults()
//if an user has logged in
let isLoggedIn = prefs.integerForKey("ISLOGGEDIN") as Int
if (isLoggedIn != 1){
print("No user currently, so heading to login screen")
socket.disconnect()
self.performSegueWithIdentifier("gotoLogin", sender: self)
}else{
print("ViewDidAppear: An user has been logged in")
let permissionToLoadData = prefs.integerForKey("ISLOGGEDIN")
if (permissionToLoadData != 1) {
print("Please grant permission to get data")
}else{
print("First view: connecting to database")
importData()
}//permission to load data
}
}//end of viewDidAppear
}
Second Controller:
import UIKit
import SocketIOClientSwift
import SwiftyJSON
import CoreData
var nou:Int?
class LoginViewController: UIViewController {
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
let registeredUserID = NSUserDefaults.standardUserDefaults().stringForKey("registerPatientID")
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
func displayAlertMessage(userMessage:String){
let alert = UIAlertController(title: "Alert", message: userMessage, preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil)
alert.addAction(okAction)
self.presentViewController(alert, animated: true, completion: nil)
}
func successMessage(userMessage:String){
let alert = UIAlertController(title: "Welcome Back", message: userMessage, preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil)
alert.addAction(okAction)
self.presentViewController(alert, animated: true, completion: nil)
}
#IBOutlet weak var loginPatientID: UITextField!
#IBAction func LoginButton(sender: AnyObject) {
let logInUserID = loginPatientID.text
if (logInUserID!.isEmpty){
displayAlertMessage("Please enter your Patient ID!")
return
}else{
print("Test: requesting login permission from database")
socket.emit("loginRequest", logInUserID!)
print("Test: requested")
socket.on("loginReply") {data, ack in
let jsonLogin = JSON(data)
if jsonLogin[0].intValue == 1{
print("Test: ID Matched, putting up ViewController")
self.prefs.setObject(logInUserID, forKey: "AppUserID")
self.prefs.setInteger(1, forKey: "ISLOGGEDIN")
self.prefs.synchronize()
let permissionToLoadData = self.prefs.integerForKey("ISLOGGEDIN")
if (permissionToLoadData != 1) {
print("Please grant permission to get data")
}else{
print("First view: connecting to database")
importData()
print("Did you import?")
}//permission to load data
self.loginPatientID.resignFirstResponder()
self.dismissViewControllerAnimated(true, completion: nil)
}else if jsonLogin[0].intValue == 0{
self.displayAlertMessage("Sorry, you are not assigned to this program")
}else if jsonLogin[0].intValue == 3{
print("Test: Query problem")
}else{
print("Test: not getting anything from ID database")
}
}//socket.on
}//else
}//login button
override func viewDidLoad() {
super.viewDidLoad()
print("Login View Controller loaded")
}
override func viewDidAppear(animated: Bool) {
socket.connect()
print("LoginVC: establishing connection")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
You may have noticed that in First view controller, when the viewDidAppear() is launched, the app will checks if user is login or not. If somebody has already logged in, it's fine. If there is nobody logging in, it will perform a segue(modally segue) to Second view controller.
A login form will be presented in second view controller and once user hits the login button, you might wanna look at the code.
Let's assume that everything goes right until it comes to importData(), the function isn't launched at all but the app just goes on, why?
Here's a screenshot of the console, pay attention to "Did you import?", if the function is launched, the app should return some additional message from 1st view controller.
After struggling for a few days, I think I may have found the correct answer.
Eventually I defined 2 different socket handlers connection as such:
let loginSocket = SocketIOClient(socketURL: "localhost:3000")
let socket = SocketIOClient(socketURL: "localhost:3000", options: [
"reconnects": true
])
for both view controller.
If there is a conclusion I can draw from this conundrum is that we can't use single socket handler for socket methods from different view controller.

WatchConnectivity send message of watch with the launch of a timer on the iphone

I created a timer app that runs on the iphone.
I wish we could control it iPhone and Watch
The controls (Play, Stop, Restart) with the iPhone works fine, my meter is displayed on the Watch.
Watch on the Stop works well, for against the Start does not work, the meter does not turn on iPhone or the Watch.
Restart the works too.
My Label on the iPhone is very slow to change if the information comes from the Watch, but works well in the other direction, toward the iPhone Watch
Have you noticed this problem, it is a problem related to WatchConnectivity
Thanks for your help
Below is my code:
ViewController.swift
import UIKit
import WatchConnectivity
class ViewController: UIViewController, WCSessionDelegate {
#IBOutlet weak var timerLabel: UILabel!
#IBOutlet weak var watchLabel: UILabel!
var session: WCSession!
var timerCount = 0
var timerRunning = false
var timer = NSTimer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if (WCSession.isSupported()) {
let session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
if session.paired != true {
print("Apple Watch is not paired")
}
if session.watchAppInstalled != true {
print("WatchKit app is not installed")
}
} else {
print("WatchConnectivity is not supported on this device")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func startButton(sender: UIButton) {
startPlay()
}
#IBAction func stopButton(sender: UIButton) {
stopPlay()
}
#IBAction func restartButton(sender: UIButton) {
restartPlay()
}
//Receive messages from watch
func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
var replyValues = Dictionary<String, AnyObject>()
//let viewController = self.window!.rootViewController as! ViewController
switch message["command"] as! String {
case "start" :
startPlay()
replyValues["status"] = "Playing"
case "stop" :
stopPlay()
replyValues["status"] = "Stopped"
case "restart" :
restartPlay()
replyValues["status"] = "Stopped"
default:
break
}
replyHandler(replyValues)
}
//Counter Timer
func counting(timer:NSTimer) {
self.timerCount++
self.timerLabel.text = String(timerCount)
let requestValues = ["timer" : String(timerCount)]
let session = WCSession.defaultSession()
session.sendMessage(requestValues, replyHandler: nil, errorHandler: { error in print("error: \(error)")})
}
//Fonction Play
func startPlay() {
if timerRunning == false {
self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("counting:"), userInfo: nil, repeats: true)
self.timerRunning = true
self.watchLabel.text = "START"
}
}
//Fonction Stop
func stopPlay() {
if timerRunning == true {
self.timer.invalidate()
self.timerRunning = false
self.watchLabel.text = "STOP"
}
}
//Fonction Restart
func restartPlay() {
self.timerCount = 0
self.timerLabel.text = "0";
let requestValues = ["timer" : "0"]
let session = WCSession.defaultSession()
session.sendMessage(requestValues, replyHandler: nil, errorHandler: { error in print("error: \(error)")})
}
}
InterfaceController.swift
import WatchKit
import Foundation
import WatchConnectivity
class InterfaceController: WKInterfaceController, WCSessionDelegate {
#IBOutlet var watchLabel: WKInterfaceLabel!
#IBOutlet var statusLabel: WKInterfaceLabel!
//Receiving message from iphone
func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {
self.watchLabel.setText(message["timer"]! as? String)
// self.statusLabel.setText(message["command"]! as? String)
}
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
// Configure interface objects here.
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
if (WCSession.isSupported()) {
let session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
}
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
#IBAction func startButtonWatch() {
if WCSession.defaultSession().reachable == true {
let requestValues = ["command" : "start"]
let session = WCSession.defaultSession()
session.sendMessage(requestValues, replyHandler: { reply in
self.statusLabel.setText(reply["status"] as? String)
}, errorHandler: { error in
print("error: \(error)")
})
}
}
#IBAction func stopButtonWatch() {
if WCSession.defaultSession().reachable == true {
let requestValues = ["command" : "stop"]
let session = WCSession.defaultSession()
session.sendMessage(requestValues, replyHandler: { reply in
self.statusLabel.setText(reply["status"] as? String)
}, errorHandler: { error in
print("error: \(error)")
})
}
}
#IBAction func restartButtonWatch() {
if WCSession.defaultSession().reachable == true {
let requestValues = ["command" : "restart"]
let session = WCSession.defaultSession()
session.sendMessage(requestValues, replyHandler: { reply in
self.statusLabel.setText(reply["status"] as? String)
}, errorHandler: { error in
print("error: \(error)")
})
}
}
}
You should use this:
func startPlay() {
if timerRunning == false {
//self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("counting:"), userInfo: nil, repeats: true)
self.timer = NSTimer(timeInterval: 1, target: self, selector: "counting:", userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(self.timer, forMode: NSRunLoopCommonModes)
self.timerRunning = true
self.watchLabel.text = "Start"
}
}
I cant explain you why we need use NSRunLoop explicitly. I stuck with same timer issue when develop an app with data transfer. Some answers you can find in google by query "nstimer run loop" or here.
And i pref use this for restart:
func restartPlay() {
self.timerCount = 0
self.timerLabel.text = "0";
stopPlay()
startPlay()
self.watchLabel.text = "Restarted"
}
Cheers.
This functional and optimized code :
//Fonction Play
func startPlay() {
if timerRunning == false {
self.mytimer = NSTimer(timeInterval: 1, target: self, selector: "counting:", userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(self.mytimer, forMode: NSRunLoopCommonModes)
timerRunning = true
dispatch_async(dispatch_get_main_queue()) {
self.watchLabel.text = "PLAYING"
}
}
}

Resources