Rare android crash from com.android.providers.settings.SettingsProvider.enforceWritePermission - android-settings

Google Play reports the following rare crash:
java.lang.SecurityException:
at android.os.Parcel.createExceptionOrNull (Parcel.java:2373)
at android.os.Parcel.createException (Parcel.java:2357)
at android.os.Parcel.readException (Parcel.java:2340)
at android.database.DatabaseUtils.readExceptionFromParcel (DatabaseUtils.java:190)
at android.database.DatabaseUtils.readExceptionFromParcel (DatabaseUtils.java:142)
at android.content.ContentProviderProxy.call (ContentProviderNative.java:732)
at android.provider.Settings$NameValueCache.putStringForUser (Settings.java:2667)
at android.provider.Settings$Global.putStringForUser (Settings.java:13618)
at android.provider.Settings$Global.putString (Settings.java:13466)
at android.provider.Settings$Global.putInt (Settings.java:13697)
at android.view.View.dispatchPointerEvent (View.java:14612)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent (ViewRootImpl.java:6178)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess (ViewRootImpl.java:5972)
at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:5459)
at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:5516)
at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:5482)
at android.view.ViewRootImpl$AsyncInputStage.forward (ViewRootImpl.java:5634)
at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:5490)
at android.view.ViewRootImpl$AsyncInputStage.apply (ViewRootImpl.java:5691)
at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:5463)
at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:5516)
at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:5482)
at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:5490)
at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:5463)
at android.view.ViewRootImpl.deliverInputEvent (ViewRootImpl.java:8378)
at android.view.ViewRootImpl.doProcessInputEvents (ViewRootImpl.java:8307)
at android.view.ViewRootImpl.enqueueInputEvent (ViewRootImpl.java:8213)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent (ViewRootImpl.java:8513)
at android.view.InputEventReceiver.dispatchInputEvent (InputEventReceiver.java:220)
at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents (Native Method)
at android.view.InputEventReceiver.consumeBatchedInputEvents (InputEventReceiver.java:200)
at android.view.ViewRootImpl.doConsumeBatchedInput (ViewRootImpl.java:8466)
at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run (ViewRootImpl.java:8552)
at android.view.Choreographer$CallbackRecord.run (Choreographer.java:974)
at android.view.Choreographer.doCallbacks (Choreographer.java:797)
at android.view.Choreographer.doFrame (Choreographer.java:725)
at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:959)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:223)
at android.app.ActivityThread.main (ActivityThread.java:7700)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:612)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:997)
Caused by: android.os.RemoteException:
at com.android.providers.settings.SettingsProvider.enforceWritePermission (SettingsProvider.java:2085)
at com.android.providers.settings.SettingsProvider.mutateGlobalSetting (SettingsProvider.java:1289)
at com.android.providers.settings.SettingsProvider.insertGlobalSetting (SettingsProvider.java:1243)
at com.android.providers.settings.SettingsProvider.call (SettingsProvider.java:396)
at android.content.ContentProvider.call (ContentProvider.java:2448)
It does not indicate any code of the app, so I don't know what causes this. It seems related to android.provider.Settings. The app does use it only to read something like the following:
Settings.Secure.getString(getActivity().getContentResolver(), Settings.Secure.ANDROID_ID)
It works fine on all kinds of devices. I want to emphasize this is very rare.
Could anyone offer a clue about the cause?

Related

Equivalent of Platform::IBoxArray in C++/WinRT

I am currently porting an UWP application from C++/CX to C++/WinRT. I encountered a safe_cast<Platform::IBoxArray<byte>^>(data) where data is of type Windows::Foundation::IInspectable ^.
I know that the safe_cast is represented by the as<T> method, and I know there are functions for boxing (winrt::box_value) and unboxing (winrt::unbox_value) in WinRT/C++.
However, I need to know the equivalent of Platform::IBoxArray in order to perform the cast (QueryInterface). According to https://learn.microsoft.com/de-de/cpp/cppcx/platform-iboxarray-interface?view=vs-2017, IBoxArray is the C++/CX equivalent of Windows::Foundation::IReferenceArray, but there is no winrt::Windows::Foundation::IReferenceArray...
Update for nackground: What I am trying to achieve is retrieving the view transform attached by the HoloLens to every Media Foundation sample from its camera. My code is based on https://github.com/Microsoft/HoloLensForCV, and I got really everything working except for this last step. The problem is located around this piece of code:
static const GUID MF_EXTENSION_VIEW_TRANSFORM = {
0x4e251fa4, 0x830f, 0x4770, 0x85, 0x9a, 0x4b, 0x8d, 0x99, 0xaa, 0x80, 0x9b
};
// ...
// In the event handler, which receives const winrt::Windows::Media::Capture::Frames::MediaFrameReader& sender:
auto frame = sender.TryAcquireLatestFrame();
// ...
if (frame.Properties().HasKey(MF_EXTENSION_VIEW_TRANSFORM)) {
auto /* IInspectable */ userData = frame.Properties().Lookup(MF_EXTENSION_VIEW_TRANSFORM);
// Now I would have to do the following:
// auto userBytes = safe_cast<Platform::IBoxArray<Byte> ^>(userData)->Value;
//viewTransform = *reinterpret_cast<float4x4 *>(userBytes.Data);
}
I'm also working on porting some code from HoloLensForCV to C++/WinRT. I came up with the following solution for a very similar case (but not the exact same line of code you ask about):
auto user_data = source.Info().Properties().Lookup(c_MF_MT_USER_DATA); // type documented as 'array of bytes'
auto source_name = user_data.as<Windows::Foundation::IReferenceArray<std::uint8_t>>(); // Trial and error to get the right specialization of IReferenceArray
winrt::com_array<std::uint8_t> arr;
source_name.GetUInt8Array(arr);
winrt::hstring source_name_str{ reinterpret_cast<wchar_t*>(arr.data()) };
Specifically, you can replace the safe_cast with .as<Windows::Foundation::IReferenceArray<std::uint8_t> for a boxed array of bytes. Then, I suspect doing the same cast as me (except to float4x4* instead of wchar_t*) will work for you.
The /ZW flag is not required for my example above.
I can't believe that actually worked, but using information from https://learn.microsoft.com/de-de/windows/uwp/cpp-and-winrt-apis/interop-winrt-cx, I came up with the following solution:
Enable "Consume Windows Runtime Extension" via /ZW and use the following conversion:
auto abi = reinterpret_cast<Platform::Object ^>(winrt::get_abi(userData));
auto userBytes = safe_cast<Platform::IBoxArray<byte> ^>(abi)->Value;
viewTransform = *reinterpret_cast<float4x4 *>(userBytes->Data);
Unfortunately, the solution has the drawback of generating
warning C4447: 'main' signature found without threading model. Consider using 'int main(Platform::Array^ args)'.
But for now, I can live with it ...

Error Magento 2 when edit product in adminpanel

Magento version 2.2.5, everything was good, then probably I did something (maybe switching to production mode or some url_rewrite manipulations)
but now this strange error, I've never met before. Maybe someone get same error and could help? Nothing like clean cache, reindex, upgrade etc doesn't help..
When I try to edit a product an error message appears:
{"0":"SQLSTATE[42000]: Syntax error or access violation: 1065 Query was empty, query was: ","1":"#0 \/www\/sites\/db\/vendor\/magento\/framework\/DB\/Statement\/Pdo\/Mysql.php(93): Zend_Db_Statement_Pdo->_execute(Array)\n#1 \/www\/sites\/db\/vendor\/magento\/zendframework1\/library\/Zend\/Db\/Statement.php(303): Magento\\Framework\\DB\\Statement\\Pdo\\Mysql->_execute(Array)\n#2 \/www\/sites\/db\/vendor\/magento\/zendframework1\/library\/Zend\/Db\/Adapter\/Abstract.php(480): Zend_Db_Statement->execute(Array)\n#3 \/www\/sites\/db\/vendor\/magento\/zendframework1\/library\/Zend\/Db\/Adapter\/Pdo\/Abstract.php(238): Zend_Db_Adapter_Abstract->query('', Array)\n#4 \/www\/sites\/db\/vendor\/magento\/framework\/DB\/Adapter\/Pdo\/Mysql.php(533): Zend_Db_Adapter_Pdo_Abstract->query('', Array)\n#5 \/www\/sites\/db\/vendor\/magento\/framework\/DB\/Adapter\/Pdo\/Mysql.php(596): Magento\\Framework\\DB\\Adapter\\Pdo\\Mysql->_query('', Array)\n#6 \/www\/sites\/db\/vendor\/magento\/zendframework1\/library\/Zend\/Db\/Adapter\/Abstract.php(737): Magento\\Framework\\DB\\Adapter\\Pdo\\Mysql->query('', Array)\n#7 \/www\/sites\/db\/vendor\/magento\/module-catalog\/Model\/Attribute\/ScopeOverriddenValue.php(153): Zend_Db_Adapter_Abstract->fetchAll('')\n#8 \/www\/sites\/db\/vendor\/magento\/module-catalog\/Model\/Attribute\/ScopeOverriddenValue.php(104): Magento\\Catalog\\Model\\Attribute\\ScopeOverriddenValue->initAttributeValues('Magento\\\\Catalog...', Object(Magento\\Catalog\\Model\\Product\\Interceptor), 0)\n#9 \/www\/sites\/db\/vendor\/magento\/module-catalog\/Model\/AbstractModel.php(328): Magento\\Catalog\\Model\\Attribute\\ScopeOverriddenValue->getDefaultValues('Magento\\\\Catalog...', Object(Magento\\Catalog\\Model\\Product\\Interceptor))\n#10 \/www\/sites\/db\/generated\/code\/Magento\/Catalog\/Model\/Product\/Interceptor.php(2091): Magento\\Catalog\\Model\\AbstractModel->getAttributeDefaultValue('links_title')\n#11 \/www\/sites\/db\/vendor\/magento\/module-downloadable\/Ui\/DataProvider\/Product\/Form\/Modifier\/UsedDefault.php(84): Magento\\Catalog\\Model\\Product\\Interceptor->getAttributeDefaultValue('links_title')\n#12 \/www\/sites\/db\/vendor\/magento\/module-downloadable\/Ui\/DataProvider\/Product\/Form\/Modifier\/UsedDefault.php(66): Magento\\Downloadable\\Ui\\DataProvider\\Product\\Form\\Modifier\\UsedDefault->titleUsedDefault('links_title')\n#13 \/www\/sites\/db\/vendor\/magento\/module-downloadable\/Ui\/DataProvider\/Product\/Form\/Modifier\/Composite.php(81): Magento\\Downloadable\\Ui\\DataProvider\\Product\\Form\\Modifier\\UsedDefault->modifyMeta(Array)\n#14 \/www\/sites\/db\/vendor\/magento\/module-catalog\/Ui\/DataProvider\/Product\/Form\/ProductDataProvider.php(73): Magento\\Downloadable\\Ui\\DataProvider\\Product\\Form\\Modifier\\Composite->modifyMeta(Array)\n#15 \/www\/sites\/db\/vendor\/magento\/framework\/View\/Element\/UiComponentFactory.php(310): Magento\\Catalog\\Ui\\DataProvider\\Product\\Form\\ProductDataProvider->getMeta()\n#16 \/www\/sites\/db\/vendor\/magento\/framework\/View\/Element\/UiComponentFactory.php(216): Magento\\Framework\\View\\Element\\UiComponentFactory->mergeMetadata('product_form', Array, false)\n#17 \/www\/sites\/db\/vendor\/magento\/framework\/View\/Layout\/Generator\/UiComponent.php(135): Magento\\Framework\\View\\Element\\UiComponentFactory->create('product_form', NULL, Array)\n#18 \/www\/sites\/db\/vendor\/magento\/framework\/View\/Layout\/Generator\/UiComponent.php(97): Magento\\Framework\\View\\Layout\\Generator\\UiComponent->generateComponent(Object(Magento\\Framework\\View\\Layout\\Data\\Structure), 'product_form', Array, Object(Magento\\Framework\\View\\Layout\\Interceptor))\n#19 \/www\/sites\/db\/vendor\/magento\/framework\/View\/Layout\/GeneratorPool.php(80): Magento\\Framework\\View\\Layout\\Generator\\UiComponent->process(Object(Magento\\Framework\\View\\Layout\\Reader\\Context), Object(Magento\\Framework\\View\\Layout\\Generator\\Context))\n#20 \/www\/sites\/db\/vendor\/magento\/framework\/View\/Layout.php(344): Magento\\Framework\\View\\Layout\\GeneratorPool->process(Object(Magento\\Framework\\View\\Layout\\Reader\\Context), Object(Magento\\Framework\\View\\Layout\\Generator\\Context))\n#21 \/www\/sites\/db\/generated\/code\/Magento\/Framework\/View\/Layout\/Interceptor.php(89): Magento\\Framework\\View\\Layout->generateElements()\n#22 \/www\/sites\/db\/vendor\/magento\/framework\/View\/Layout\/Builder.php(129): Magento\\Framework\\View\\Layout\\Interceptor->generateElements()\n#23 \/www\/sites\/db\/vendor\/magento\/framework\/View\/Page\/Builder.php(55): Magento\\Framework\\View\\Layout\\Builder->generateLayoutBlocks()\n#24 \/www\/sites\/db\/vendor\/magento\/framework\/View\/Layout\/Builder.php(65): Magento\\Framework\\View\\Page\\Builder->generateLayoutBlocks()\n#25 \/www\/sites\/db\/vendor\/magento\/framework\/View\/Layout.php(254): Magento\\Framework\\View\\Layout\\Builder->build()\n#26 \/www\/sites\/db\/vendor\/magento\/framework\/View\/Layout.php(876): Magento\\Framework\\View\\Layout->build()\n#27 \/www\/sites\/db\/generated\/code\/Magento\/Framework\/View\/Layout\/Interceptor.php(414): Magento\\Framework\\View\\Layout->getBlock('menu')\n#28 \/www\/sites\/db\/vendor\/magento\/module-backend\/Model\/View\/Result\/Page.php(26): Magento\\Framework\\View\\Layout\\Interceptor->getBlock('menu')\n#29 \/www\/sites\/db\/generated\/code\/Magento\/Backend\/Model\/View\/Result\/Page\/Interceptor.php(24): Magento\\Backend\\Model\\View\\Result\\Page->setActiveMenu('Magento_Catalog...')\n#30 \/www\/sites\/db\/vendor\/magento\/module-catalog\/Controller\/Adminhtml\/Product\/Edit.php(69): Magento\\Backend\\Model\\View\\Result\\Page\\Interceptor->setActiveMenu('Magento_Catalog...')\n#31 \/www\/sites\/db\/generated\/code\/Magento\/Catalog\/Controller\/Adminhtml\/Product\/Edit\/Interceptor.php(24): Magento\\Catalog\\Controller\\Adminhtml\\Product\\Edit->execute()\n#32 \/www\/sites\/db\/vendor\/magento\/framework\/App\/Action\/Action.php(107): Magento\\Catalog\\Controller\\Adminhtml\\Product\\Edit\\Interceptor->execute()\n#33 \/www\/sites\/db\/vendor\/magento\/module-backend\/App\/AbstractAction.php(229): Magento\\Framework\\App\\Action\\Action->dispatch(Object(Magento\\Framework\\App\\Request\\Http))\n#34 \/www\/sites\/db\/vendor\/magento\/framework\/Interception\/Interceptor.php(58): Magento\\Backend\\App\\AbstractAction->dispatch(Object(Magento\\Framework\\App\\Request\\Http))\n#35 \/www\/sites\/db\/vendor\/magento\/framework\/Interception\/Interceptor.php(138): Magento\\Catalog\\Controller\\Adminhtml\\Product\\Edit\\Interceptor->___callParent('dispatch', Array)\n#36 \/www\/sites\/db\/vendor\/magento\/module-backend\/App\/Action\/Plugin\/Authentication.php(143): Magento\\Catalog\\Controller\\Adminhtml\\Product\\Edit\\Interceptor->Magento\\Framework\\Interception\\{closure}(Object(Magento\\Framework\\App\\Request\\Http))\n#37 \/www\/sites\/db\/vendor\/magento\/framework\/Interception\/Interceptor.php(135): Magento\\Backend\\App\\Action\\Plugin\\Authentication->aroundDispatch(Object(Magento\\Catalog\\Controller\\Adminhtml\\Product\\Edit\\Interceptor), Object(Closure), Object(Magento\\Framework\\App\\Request\\Http))\n#38 \/www\/sites\/db\/vendor\/magento\/framework\/Interception\/Interceptor.php(153): Magento\\Catalog\\Controller\\Adminhtml\\Product\\Edit\\Interceptor->Magento\\Framework\\Interception\\{closure}(Object(Magento\\Framework\\App\\Request\\Http))\n#39 \/www\/sites\/db\/generated\/code\/Magento\/Catalog\/Controller\/Adminhtml\/Product\/Edit\/Interceptor.php(39): Magento\\Catalog\\Controller\\Adminhtml\\Product\\Edit\\Interceptor->___callPlugins('dispatch', Array, NULL)\n#40 \/www\/sites\/db\/vendor\/magento\/framework\/App\/FrontController.php(55): Magento\\Catalog\\Controller\\Adminhtml\\Product\\Edit\\Interceptor->dispatch(Object(Magento\\Framework\\App\\Request\\Http))\n#41 \/www\/sites\/db\/vendor\/magento\/framework\/Interception\/Interceptor.php(58): Magento\\Framework\\App\\FrontController->dispatch(Object(Magento\\Framework\\App\\Request\\Http))\n#42 \/www\/sites\/db\/vendor\/magento\/framework\/Interception\/Interceptor.php(138): Magento\\Framework\\App\\FrontController\\Interceptor->___callParent('dispatch', Array)\n#43 \/www\/sites\/db\/vendor\/magento\/framework\/Interception\/Interceptor.php(153): Magento\\Framework\\App\\FrontController\\Interceptor->Magento\\Framework\\Interception\\{closure}(Object(Magento\\Framework\\App\\Request\\Http))\n#44 \/www\/sites\/db\/generated\/code\/Magento\/Framework\/App\/FrontController\/Interceptor.php(26): Magento\\Framework\\App\\FrontController\\Interceptor->___callPlugins('dispatch', Array, Array)\n#45 \/www\/sites\/db\/vendor\/magento\/framework\/App\/Http.php(135): Magento\\Framework\\App\\FrontController\\Interceptor->dispatch(Object(Magento\\Framework\\App\\Request\\Http))\n#46 \/www\/sites\/db\/generated\/code\/Magento\/Framework\/App\/Http\/Interceptor.php(24): Magento\\Framework\\App\\Http->launch()\n#47 \/www\/sites\/db\/vendor\/magento\/framework\/App\/Bootstrap.php(256): Magento\\Framework\\App\\Http\\Interceptor->launch()\n#48 \/www\/sites\/db\/index.php(37): Magento\\Framework\\App\\Bootstrap->run(Object(Magento\\Framework\\App\\Http\\Interceptor))\n#49 {main}","url":"\/admin\/catalog\/product\/edit\/id\/481\/key\/2561921a92ab41586d7c2cbd563d2d8cad1ca2d7c57d0edbaece838b19fc68c0\/","script_name":"\/index.php"}
this error basically comes due to DB access issue.
Check DB credentials in app/etc/env.php
clear var/generation or generated folder
clear var/cache
and then try .

GNU Octave, how to stop 3d axis from resizing while rotating in the interactive window?

Question: Is there a way to stop octave from trying to auto-fit the axis object into a constant size box and instead leave the viewing scale constant?
I like to show my students lots of 3D plots relating to various math/science topics, and to use the default interactive window (Octave 4.0 through Debian amd64 repositories) to rotate the figure live during class. Problem is the resulting resizing is distracting to the shape of the object/animated-trajectories.
Here is a simple scatter plot animation I am working with but this applies to all 3d plots.
#!/usr/bin/octave-cli
clear all;
close all;
planetx=[-0.1478672, -0.7257694, -0.1756896, 1.3832219;
-0.0381809, -0.7160833, -0.2610456, 1.3850799;
0.0737428, -0.6924100, -0.3444268 , 1.3831345;
0.1793219, -0.6552495, -0.4251856 , 1.3774159;
0.2688712, -0.6053663, -0.5026964, 1.3679664;
0.3311067, -0.5437714, -0.5763614, 1.3548404;
0.3531110, -0.4716991, -0.6456154 , 1.3381034;
0.3219212, -0.3905812, -0.7099307, 1.3178316;
0.2300102, -0.3020162, -0.7688217, 1.2941111;
0.0855329, -0.2077379, -0.8218485, 1.2670372;
-0.0814988, -0.1095802, -0.8686203, 1.2367138;
-0.2318261, -0.0094427, -0.9087983, 1.2032523;
-0.3384457, 0.0907458, -0.9420979, 1.1667714;
-0.3929915, 0.1890627, -0.9682904, 1.1273956;
-0.3988960, 0.2836267, -0.9872039, 1.0852552;
-0.3641642, 0.3726316, -0.9987242, 1.0404850;
-0.2977153, 0.4543788, -1.0027945, 0.9932238;
-0.2081496, 0.5273076, -0.9994152, 0.9436139;
-0.1036023, 0.5900227, -0.9886429, 0.8917999;
0.0079838, 0.6413199, -0.9705888, 0.8379287];
planety=[-0.4466930, -0.0252958, 0.9659716, -0.0238017;
-0.4657149, -0.1263067, 0.9471212, 0.0520870;
-0.4508105, -0.2248822, 0.9208844, 0.1278263;
-0.4013623, -0.3190893, 0.8874673, 0.2032115;
-0.3181219 , -0.4070912, 0.8471345, 0.2780418;
-0.2041932 , -0.4871833, 0.8002063, 0.3521215;
-0.0669533, -0.5578254, 0.7470558, 0.4252601;
0.0789006, -0.6176696, 0.6881051, 0.4972739;
0.2085279, -0.6655848, 0.6238214, 0.5679859;
0.2899490, -0.7006754, 0.5547124, 0.6372265;
0.2993354, -0.7222964, 0.4813220, 0.7048344;
0.2378102, -0.7300623, 0.4042244, 0.7706562;
0.1278686, -0.7238523, 0.3240197, 0.8345477;
-0.0036336, -0.7038105, 0.2413281, 0.8963733;
-0.1357070, -0.6703412, 0.1567847, 0.9560064;
-0.2544710, -0.6241000, 0.0710340, 1.0133298;
-0.3512399, -0.5659813, -0.0152755, 1.0682353;
-0.4205857, -0.4971011, -0.1014962, 1.1206241;
-0.4590497, -0.4187770, -0.1869867, 1.1704064;
-0.4644300, -0.3325042, -0.2711164, 1.2175012];
planetz=[ -2.3139e-02, 4.1378e-02, 2.0503e-04, -3.4412e-02;
-3.4756e-02, 3.9440e-02, 2.0468e-04, -3.2867e-02;
-4.3806e-02, 3.6728e-02, 2.0433e-04, -3.1231e-02;
-4.9452e-02, 3.3297e-02, 2.0398e-04, -2.9511e-02;
-5.0867e-02, 2.9217e-02, 2.0363e-04, -2.7710e-02;
-4.7267e-02, 2.4568e-02, 2.0328e-04, -2.5834e-02;
-3.8071e-02, 1.9444e-02, 2.0292e-04, -2.3890e-02;
-2.3288e-02, 1.3946e-02, 2.0256e-04, -2.1882e-02;
-4.2578e-03, 8.1806e-03, 2.0220e-04, -1.9816e-02;
1.5659e-02, 2.2609e-03, 2.0183e-04, -1.7700e-02;
3.1762e-02, -3.6987e-03, 2.0145e-04, -1.5537e-02;
4.0539e-02, -9.5832e-03, 2.0107e-04, -1.3335e-02;
4.1349e-02, -1.5280e-02, 2.0067e-04, -1.1099e-02;
3.5618e-02, -2.0679e-02, 2.0027e-04, -8.8346e-03;
2.5376e-02, -2.5678e-02, 1.9986e-04, -6.5487e-03;
1.2491e-02, -3.0182e-02, 1.9944e-04, -4.2464e-03;
-1.5080e-03, -3.4104e-02, 1.9901e-04, -1.9337e-03;
-1.5389e-02, -3.7371e-02, 1.9856e-04, 3.8413e-04;
-2.8122e-02, -3.9918e-02, 1.9810e-04, 2.7015e-03;
-3.8798e-02, -4.1699e-02, 1.9762e-04, 5.0131e-03;];
N=size(planetx)
N=N(1,1)
figure('position',[50,50,1000,750]);
h=scatter3(planetx(1,:),planety(1,:),planetz(1,:) , 10*[3,4,5,4],
[3,4,5,4],'filled');
axis([-2,2,-2,2,-1,1],'square');
set(gca,'fontsize',20)
axis('manual')
#box('off')
#axis('off')
view([15,15]);
hold on;
p1=plot3(planetx(1:20,1),planety(1:20,1),planetz(1:20,1),':')
p2=plot3(planetx(1:20,2),planety(1:20,2),planetz(1:20,2),':')
p3=plot3(planetx(1:20,3),planety(1:20,3),planetz(1:20,3),':')
p4=plot3(planetx(1:20,4),planety(1:20,4),planetz(1:20,4),':')
ans=input('loaded, hit enter to start!')
for i=1:N
#[AZ,EL]=view();
set(h, 'xdata', planetx(i,:) , 'ydata', planety(i,:), 'zdata',
planetz(i,:))
title(sprintf('YEAR=%f',2000+i*200/14010 ))
set(p1,'xdata',planetx(1:i,1),'ydata',planety(1:i,1),'zdata', planetz(1:i,1))
set(p2, 'xdata', planetx(1:i,2),'ydata',planety(1:i,2),'zdata',planetz(1:i,2))
set(p3, 'xdata', planetx(1:i,3),'ydata',planety(1:i,3),'zdata',planetz(1:i,3))
set(p4, 'xdata', planetx(1:i,4),'ydata',planety(1:i,4),'zdata',planetz(1:i,4))
pause(1)
endfor;
ans=input('hit to close!')
It seems this may be a bug of older octave versions.
On my system (octave 4.2.1 - linux) it seems to work as you expect it should.
PS. ignore the glitches, they're bugs related to the screen recorder I used
UPDATE: In response to the comment by Cris, it may be that what Robert was referring to was how the camera seems to 'zoom out' slightly in order to accommodate the full 'box' when one rotates.
You can change this behaviour by changing the cameraviewanglemode property from 'auto' to 'manual'. This results in a smoother rotating experience without the camera moving from its place.
>> set(gca, 'cameraviewanglemode', 'manual')
Visual comparison:
'auto mode' vs 'manual mode'
The other 'camera' related properties may be useful to play around with as well. Type get(gca, 'camera') to get a list of relevant properties. (or just have a look at this page in the manual for defaults etc).

Script properties becomes corrupt: Failed to save Project Properties for script

Script properties becomes "corrupt" after a call to "PropertiesService.getScriptProperties().setProperties(properties)" in my script. By "corrupt", I mean I can no longer add or edit existing properties in: "File -> Project properties -> Script properties", and when I first try I receive the error message "Failed to save Project Properties for script." I've tried deleting all properties and re-adding them, I tried deleting all browser cache, and I tried minimizing my Properties calls to ensure(?) I'm not exceeding quotas.
After this error, going to "File -> Project properties" results in in a endlessly spinning busy cursor while it tries to load the "Info" tab. Re-loading the spreadsheet allows "File -> Project properties" to properly load, but any edits made to properties in the "Script properties" tab brings back the error and spinning cursor problem.
I've narrowed down the culprit in my script but I cannot figure out why it's causing this problem. In my "onOpen()" method I am building up ~125 properties, and then I set them with one call to "setProperties()". The properties go into Script Properties okay, and they function as expected, but this programmatic setting of script properties is definitely the cause of the "Failed to save Project Properties for script." error message.
Link to a copy of my Google spreadsheet containing the script causing the problem. The 3 calls causing the problem are commented with "SETPROPS", and the call to set the properties is commented with "BROKE!". This problem, or ones similar, have come up in the past but seem to be "fixed" or no longer occur.
The code sequence is as follows:
I clear all script properties with: PropertiesService.getScriptProperties().deleteAllProperties()
I call three methods, each taking a "properties" argument.
Each of these 3 methods does nearly the same thing. They each add key/value pairs to "properties".
After each of the 3 methods is called, I set the properties with:
if (Object.getOwnPropertyNames(properties).length !== 0)
{
PropertiesService.getScriptProperties().setProperties(properties);
}
Here is one of the 3 methods that adds to the "properties" var (initialize with: var properties = {};). The other 3 methods add to the properties variable in the same manner, but operate on different data.
function setScriptPropertiesShipSizesForFaction(properties, factionName)
{
var dataSheetName = factionName + "Data";
var dataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(dataSheetName);
var shipValues = dataSheet.getRange('B3:D200').getValues();
var index = 0;
while ( (index < shipValues.length) && (shipValues[index][0] != "") )
{
var key = '_shipSize_' + normalize(shipValues[index][0]);
var value = shipValues[index][2];
properties[key] = value;
index++;
}
}
I believe I am not exceeded any Google script quota. I do not get any error messages from the call to "setProperties", and I do not see any errors in Google's Stackdriving Logging. At the bottom of this post I have a list of what I am setting in ScriptProperties. It's logging output, with syntax: key=value.
_shipSize_ArquitensCC=S
_shipSize_ArquitensLC=S
_shipSize_AssaultFrigateMk2A=M
_shipSize_AssaultFrigateMk2B=M
_shipSize_CR90-A=S
_shipSize_CR90-B=S
_shipSize_GR-75CombatRetrofits=S
_shipSize_GR-75MediumTransports=S
_shipSize_Gladiator1=S
_shipSize_Gladiator2=S
_shipSize_GozantiAssault=S
_shipSize_GozantiCruisers=S
_shipSize_HammerheadScout=S
_shipSize_HammerheadTorpedo=S
_shipSize_ISD1=L
_shipSize_ISD2=L
_shipSize_ISDCymoon=L
_shipSize_ISDKuat=L
_shipSize_InterdictorCombat=M
_shipSize_InterdictorSuppression=M
_shipSize_MC30cScout=S
_shipSize_MC30cTorpedo=S
_shipSize_MC75ArmoredCruiser=L
_shipSize_MC75OrdnanceCruiser=L
_shipSize_MC80AssaultCruiser=L
_shipSize_MC80BattleCruiser=L
_shipSize_MC80CommandCruiser=L
_shipSize_MC80StarCruiser=L
_shipSize_Nebulon-BEscort=S
_shipSize_Nebulon-BSupport=S
_shipSize_PeltaAssault=S
_shipSize_PeltaCommand=S
_shipSize_QuasarFire1=M
_shipSize_QuasarFire2=M
_shipSize_Raider1=S
_shipSize_Raider2=S
_shipSize_Victory1=M
_shipSize_Victory2=M
_upgradeKeyPrefix_EmpireDEFENSIVE 2=6.0
_upgradeKeyPrefix_EmpireDEFENSIVE=5.0
_upgradeKeyPrefix_EmpireEXPERIMENTAL 2=8.0
_upgradeKeyPrefix_EmpireEXPERIMENTAL=7.0
_upgradeKeyPrefix_EmpireFLEET COMMAND=9.0
_upgradeKeyPrefix_EmpireFLEET SUPPORT=10.0
_upgradeKeyPrefix_EmpireION CANNONS=11.0
_upgradeKeyPrefix_EmpireOFFENSIVE 2=13.0
_upgradeKeyPrefix_EmpireOFFENSIVE=12.0
_upgradeKeyPrefix_EmpireOFFICER=4.0
_upgradeKeyPrefix_EmpireORDNANCE=14.0
_upgradeKeyPrefix_EmpireSUPPORT TEAM=15.0
_upgradeKeyPrefix_EmpireTITLE=3.0
_upgradeKeyPrefix_EmpireTURBOLASER 2=17.0
_upgradeKeyPrefix_EmpireTURBOLASER=16.0
_upgradeKeyPrefix_EmpireWEAPONS TEAM 2=19.0
_upgradeKeyPrefix_EmpireWEAPONS TEAM=18.0
_upgradeKeyPrefix_RebelDEFENSIVE 2=7.0
_upgradeKeyPrefix_RebelDEFENSIVE=6.0
_upgradeKeyPrefix_RebelFLEET COMMAND=8.0
_upgradeKeyPrefix_RebelFLEET SUPPORT=9.0
_upgradeKeyPrefix_RebelION CANNONS=10.0
_upgradeKeyPrefix_RebelOFFENSIVE=11.0
_upgradeKeyPrefix_RebelOFFICER 2=5.0
_upgradeKeyPrefix_RebelOFFICER=4.0
_upgradeKeyPrefix_RebelORDNANCE 2=13.0
_upgradeKeyPrefix_RebelORDNANCE=12.0
_upgradeKeyPrefix_RebelSUPPORT TEAM=14.0
_upgradeKeyPrefix_RebelTITLE=3.0
_upgradeKeyPrefix_RebelTURBOLASER 2=16.0
_upgradeKeyPrefix_RebelTURBOLASER=15.0
_upgradeKeyPrefix_RebelWEAPONS TEAM=17.0
_upgradeSize_BailOrgana=ML
_upgradeSize_DisposableCapacitors=SM
_upgradeSize_GovernorPryce=ML
_upgradeSize_HardenedBulkheads=L
_upgradeSize_StrategicAdviser=L calculatedDataSheetName=Calculated Data cellCommander=E2 colEmpirePlayerNames=1 colRebelPlayerNames=8
colShipNames=2 colSquadNames=2 colUpgradesStart=3
colVariableUpgradesEndEmpire=19 colVariableUpgradesEndRebel=17
colVariableUpgradesStartEmpire=5 colVariableUpgradesStartRebel=6
disabledBgColor=#999999 enabledBgColor=#93c47d
factionNameEmpire=Empire factionNameRebel=Rebel
indexFleetSheetsStart=3
multipleIconUpgrade_BoardingEngineers=OFFENSIVE,WEAPONS TEAM
multipleIconUpgrade_BoardingTroopers=OFFENSIVE,WEAPONS TEAM
multipleIconUpgrade_ChamSyndulla=OFFENSIVE,WEAPONS TEAM
multipleIconUpgrade_DarthVader=OFFENSIVE,WEAPONS TEAM
multipleIconUpgrade_JynErso=OFFENSIVE,WEAPONS TEAM playersPerTeam=3
rowPlayerNamesStart=7 rowShipsEnd=17 rowShipsStart=6
rowSquadNamesEnd=44 rowSquadNamesStart=21 rowUpgradeNames=5
sheetNameSystemTracking=Systems Tracking sheetNameTeamStatus=Team
Status upgradeKeyPrefix=_upgradeKeyPrefix_
upgradeKeyPrefixEmpireDEFENSIVE 2=6.0
upgradeKeyPrefixEmpireDEFENSIVE=5.0
upgradeKeyPrefixEmpireEXPERIMENTAL 2=8.0
upgradeKeyPrefixEmpireEXPERIMENTAL=7.0 upgradeKeyPrefixEmpireFLEET
COMMAND=9.0 upgradeKeyPrefixEmpireFLEET SUPPORT=10.0
upgradeKeyPrefixEmpireION CANNONS=11.0
upgradeKeyPrefixEmpireOFFENSIVE 2=13.0
upgradeKeyPrefixEmpireOFFENSIVE=12.0
upgradeKeyPrefixEmpireOFFICER=4.0 upgradeKeyPrefixEmpireORDNANCE=14.0
upgradeKeyPrefixEmpireSUPPORT TEAM=15.0
upgradeKeyPrefixEmpireTITLE=3.0 upgradeKeyPrefixEmpireTURBOLASER
2=17.0 upgradeKeyPrefixEmpireTURBOLASER=16.0
upgradeKeyPrefixEmpireWEAPONS TEAM 2=19.0
upgradeKeyPrefixEmpireWEAPONS TEAM=18.0
upgradeKeyPrefixRebelDEFENSIVE 2=7.0
upgradeKeyPrefixRebelDEFENSIVE=6.0 upgradeKeyPrefixRebelFLEET
COMMAND=8.0 upgradeKeyPrefixRebelFLEET SUPPORT=9.0
upgradeKeyPrefixRebelION CANNONS=10.0
upgradeKeyPrefixRebelOFFENSIVE=11.0 upgradeKeyPrefixRebelOFFICER
2=5.0 upgradeKeyPrefixRebelOFFICER=4.0 upgradeKeyPrefixRebelORDNANCE
2=13.0 upgradeKeyPrefixRebelORDNANCE=12.0
upgradeKeyPrefixRebelSUPPORT TEAM=14.0 upgradeKeyPrefixRebelTITLE=3.0
upgradeKeyPrefixRebelTURBOLASER 2=16.0
upgradeKeyPrefixRebelTURBOLASER=15.0 upgradeKeyPrefixRebelWEAPONS
TEAM=17.0 upgradeRegex_DEFENSIVE 2=MC80\s+Assault
upgradeRegex_DEFENSIVE=Arquitens|ISD\s+(2|Kuat)|Assault\s+Frigate|CR90|MC30|MC75|MC80\s+(Assault|Command)
upgradeRegex_EXPERIMENTAL 2=Suppression
upgradeRegex_EXPERIMENTAL=Interdictor upgradeRegex_FLEET
COMMAND=Pelta|ISD\s+Cymoon upgradeRegex_FLEET SUPPORT=Gozanti|GR\-75
upgradeRegex_ION
CANNONS=CR90\-B|ISD\s+(2|Kuat|1)|Interdictor|MC75\s+Armored|MC80|Raider\s+2|Victory\s+2
upgradeRegex_OFFENSIVE 2=ISD\s+1|Quasar\s+Fire\s+1
upgradeRegex_OFFENSIVE=Gozanti|ISD|Interdictor|Quasar|Raider|Victory|Assault\s+Frigate|GR\-75|Hammerhead|MC75|MC80\s+Command|Pelta\s+Command
upgradeRegex_ORDNANCE 2=MC75\s+Ordnance
upgradeRegex_ORDNANCE=Hammerhead\s+Torpedo|Gladiator|ISD\s+Kuat|MC30|MC75|Raider\s+1|Victory\s+1|Pelta\s+Assault
upgradeRegex_SUPPORT
TEAM=Arquitens\s+CC|CR90|Gladiator|Interdictor|MC80|Pelta|Nebulon
upgradeRegex_TURBOLASER 2=ISD\s+Cymoon|MC80\s+(Star|Battle)
upgradeRegex_TURBOLASER=Arquitens|Assault\s+Frigate|CR90\-A|Hammerhead\s+Scout|ISD\s+(2|Cymoon|1)|MC30|MC75\s+Armored|MC80|Nebulon|Victory
upgradeRegex_WEAPONS TEAM 2=Quasar\s+Fire\s+2 upgradeRegex_WEAPONS
TEAM=Assault\s+Frigate|Hammerhead|Gladiator|ISD|MC30|MC75|MC80\s+(Battle|Star)|Quasar|Raider|Victory
For what it's worth, I'm experiencing much the same problem too. There's an older version of this Google Apps Script running and it's got around the same number of Properties. Going via the GAS interface I can't delete any of the properties. I've only just come across this problem so I haven't yet delved into a solution. The property I'm storing is a token for each user for a Service Account to utilise, so I'm hoping a programmatic purge of the tokens every x days will suffice. I'll post updates here.
In my case i couldn't save any file because an old linked library was deleted.

Difficulty unpacking JSON tuple string

I figured out how to use rebar. I'm trying to use jsx (jiffy doesn't work properly on Windows) to parse json that I obtained using the openexchangerates.org API, but I can't even figure out how to correctly utilize Erlang's extensive binary functionality in order to unpack the JSON tuple obtained. Using the following code snippet, I managed to get a tuple that has all the data I need:
-module(currency).
-export([start/0]).
start() ->
URL = "http://openexchangerates.org",
Endpoint = "/api/latest.json?app_id=<myprivateid>",
X = string:concat(URL, Endpoint),
% io:format("~p~n",[X]).
inets:start(),
{ok, Req} = httpc:request(X),
Req.
Here is the obtained response:
9> currency:start().
{{"HTTP/1.1",200,"OK"},
[{"cache-control","public"},
{"connection","close"},
{"date","Fri, 15 Aug 2014 01:28:06 GMT"},
{"etag","\"d9ad180d4af1caaedab6e622ec0a8a70\""},
{"server","Apache"},
{"content-length","4370"},
{"content-type","application/json; charset=utf-8"},
{"last-modified","Fri, 15 Aug 2014 01:00:56 GMT"},
{"access-control-allow-origin","*"}],
"{\n \"disclaimer\": \"Exchange rates are provided for informational purposes only, and do not constitute financial advice of any kind. Although every attempt is made to ensure quality, NO guarantees are given whatsoever of accuracy, validity, availability, or fitness for any purpose - please use at your own risk. All usage is subject to your acceptance of the Terms and Conditions of Service, available at: https://openexchangerates.org/terms/\",\n \"license\": \"Data sourced from various providers with public-facing APIs; copyright may apply; resale is prohibited; no warranties given of any kind. Bitcoin data provided by http://coindesk.com. All usage is subject to your acceptance of the License Agreement available at: https://openexchangerates.org/license/\",\n \"timestamp\": 1408064456,\n \"base\": \"USD\",\n \"rates\": {\n \"AED\": 3.673128,\n \"AFN\": 56.479925,\n \"ALL\": 104.147599,\n \"AMD\": 413.859001,\n \"ANG\": 1.789,\n \"AOA\": 97.913074,\n \"ARS\": 8.274908,\n \"AUD\": 1.073302,\n \"AWG\": 1.79005,\n \"AZN\": 0.783933,\n \"BAM\": 1.46437,\n \"BBD\": 2,\n \"BDT\": 77.478631,\n \"BGN\": 1.464338,\n \"BHD\": 0.377041,\n \"BIF\": 1546.956667,\n \"BMD\": 1,\n \"BND\": 1.247024,\n \"BOB\": 6.91391,\n \"BRL\": 2.269422,\n \"BSD\": 1,\n \"BTC\": 0.0019571961,\n \"BTN\": 60.843812,\n \"BWP\": 8.833083,\n \"BYR\": 10385.016667,\n \"BZD\": 1.99597,\n \"CAD\": 1.0906,\n \"CDF\": 924.311667,\n \"CHF\": 0.906799,\n \"CLF\": 0.02399,\n \"CLP\": 577.521099,\n \"CNY\": 6.153677,\n \"COP\": 1880.690016,\n \"CRC\": 540.082202,\n \"CUP\": 1.000688,\n \"CVE\": 82.102201,\n \"CZK\": 20.81766,\n \"DJF\": 178.76812,\n \"DKK\": 5.579046,\n \"DOP\": 43.43789,\n \"DZD\": 79.8973,\n \"EEK\": 11.70595,\n \"EGP\": 7.151305,\n \"ERN\": 15.062575,\n \"ETB\": 19.83205,\n \"EUR\": 0.748385,\n \"FJD\": 1.85028,\n \"FKP\": 0.599315,\n \"GBP\": 0.599315,\n \"GEL\": 1.74167,\n \"GGP\": 0.599315,\n \"GHS\": 3.735499,\n \"GIP\": 0.599315,\n \"GMD\": 39.73668,\n \"GNF\": 6995.309935,\n \"GTQ\": 7.839405,\n \"GYD\": 205.351249,\n \"HKD\": 7.750863,\n \"HNL\": 21.04854,\n \"HRK\": 5.708371,\n \"HTG\": 44.66625,\n \"HUF\": 233.847801,\n \"IDR\": 11682.083333,\n \"ILS\": 3.471749,\n \"IMP\": 0.599315,\n \"INR\": 60.81923,\n \"IQD\": 1178.211753,\n \"IRR\": 26354,\n \"ISK\": 115.976,\n \"JEP\": 0.599315,\n \"JMD\": 112.604801,\n \"JOD\": 0.707578,\n \"JPY\": 102.501401,\n \"KES\": 88.106539,\n \"KGS\": 51.96,\n \"KHR\": 4056.578416,\n \"KMF\": 368.149,\n \"KPW\": 900,\n \"KRW\": 1021.166657,\n \"KWD\": 0.283537,\n \"KYD\": 0.826373,\n \"KZT\": 182.076001,\n \"LAK\": 8049.834935,\n \"LBP\": 1509.068333,\n \"LKR\": 130.184301,\n \"LRD\": 91.49085,\n \"LSL\": 10.56165,\n \"LTL\": 2.583284,\n \"LVL\": 0.521303,\n \"LYD\": 1.244127,\n \"MAD\": 8.372529,\n \"MDL\": 13.7178,\n \"MGA\": 2495.605,\n \"MKD\": 45.99967,\n \"MMK\": 972.1784,\n \"MNT\": 1884.666667,\n \"MOP\": 7.986251,\n \"MRO\": 292.0081,\n \"MTL\": 0.683602,\n \"MUR\": 30.61708,\n \"MVR\": 15.37833,\n \"MWK\": 392.9201,\n \"MXN\": 13.07888,\n \"MYR\": 3.175156,\n \"MZN\": 30.3522,\n \"NAD\": 10.56145,\n \"NGN\": 162.303701,\n \"NIO\": 26.07651,\n \"NOK\": 6.157432,\n \"NPR\": 97.66846,\n \"NZD\": 1.179688,\n \"OMR\": 0.38501,\n \"PAB\": 1,\n \"PEN\": 2.795018,\n \"PGK\": 2.464545,\n \"PHP\": 43.66429,\n \"PKR\": 99.5662,\n \"PLN\": 3.126223,\n \"PYG\": 4272.421673,\n \"QAR\": 3.641137,\n \"RON\": 3.320192,\n \"RSD\": 87.82784,\n \"RUB\": 36.00216,\n \"RWF\": 690.269,\n \"SAR\": 3.750523,\n \"SBD\": 7.269337,\n \"SCR\": 12.40801,\n \"SDG\": 5.699103,\n \"SEK\": 6.86018,\n \"SGD\": 1.246263,\n \"SHP\": 0.599315,\n \"SLL\": 4372.166667,\n \"SOS\": 841.5678,\n \"SRD\": 3.275,\n \"STD\": 18316.816667,\n \"SVC\": 8.745567,\n \"SYP\": 150.751249,\n \"SZL\": 10.56279,\n \"THB\": 31.86192,\n \"TJS\": 4.9856,\n \"TMT\": 2.8501,\n \"TND\": 1.719658,\n \"TOP\": 1.8861,\n \"TRY\": 2.15338,\n \"TTD\": 6.343484,\n \"TWD\": 30.00481,\n \"TZS\": 1661.865,\n \"UAH\": 13.02466,\n \"UGX\": 2614.28,\n \"USD\": 1,\n \"UYU\": 23.70693,\n \"UZS\": 2337.106637,\n \"VEF\": 6.295009,\n \"VND\": 21191.15,\n \"VUV\": 94.6,\n \"WST\": 2.301222,\n \"XAF\": 491.286739,\n \"XAG\": 0.05031657,\n \"XAU\": 0.00076203,\n \"XCD\": 2.70154,\n \"XDR\": 0.654135,\n \"XOF\": 491.394602,\n \"XPF\": 89.414091,\n \"YER\": 214.985901,\n \"ZAR\": 10.55678,\n \"ZMK\": 5253.075255,\n \"ZMW\": 6.169833,\n \"ZWL\": 322.355006\n }\n}"}
I don't understand why this code oesn't work:
X = "Arthur".
B = <<X>>.
JSX allows a lot of parsing functionality but only if I have a binary as my representation of JSON, and this JSON I'm getting from the currency API is a string in a tuple... I'm a bit lost as to where to start to research. Unpacking a tuple using pattern matching is supposedly quite simple (I've done some Prolog programming and I can see that erlang has similar behavior) but is there a another, better, Erlang-appropriate way to grab the "rates" part of the JSON I'm receiving as a response?
Thank you! I'm working on a cool web app to learn erlang and this is a good first step. I have three Erlang books and I'm reading through them diligently but the problem is that I want as much practical exposure as early on as possible. I love this language but I want to get a solid grounding as fast as possible.
Thank you!
get_currencies() ->
URL = "http://openexchangerates.org",
Endpoint = "/api/latest.json?app_id=<myprivateid>",
X = string:concat(URL, Endpoint),
% io:format("~p~n",[X]).
inets:start(),
{ok, {_,_,R}} = httpc:request(X),
E = jsx:decode(lists_to_binary(R)),
Base = proplists:get_value(<<"base">>,E),
Sec = proplists:get_value(<<"timestamp">>,E),
{Days,Time} = calendar:seconds_to_daystime(Sec),
Date = calendar:gregorian_days_to_date(Days+719528),
Currencies = proplists:get_value(<<"rates">>,E),
fun(C) -> V = proplists:get_value(C,Currencies),
{change,Date,Time,Base,C,V}
end.
and somewhere in your code:
GC = get_currencies(), %% you can store GC in an ets, a server state...
%% but don't forget to refresh it :o)
and use it later
{change,D,T,B,C,V} = GC(<<"ZWL">>),
%% should return {change,{2014,8,15},{2,0,12},<<"USD">>,<<"ZWL">>,322.355006}
[edit]
When I use an external application such as jsx (using rebar itself), I use also rebar and its dependency mechanism to create my own application, in my opinion it is the most convenient way. (In other cases, I use also rebar :o)
Then I build my application using the OTP behaviors (application, supervisor, gen_server...). It is a lot of modules to write, but some of them are very very short (application and supervisors) and they facilitate the application structure (see What is OTP if you are not familiar with this).
In your case, my first idea is to have a gen server that build and store the GC anonymous function in its state, each time it get a cast message such as update_currencies, and provide the answer each time it get a call message such as {get_change,Cur} (and maybe refresh GC if it is undefined or out dated).
You will also have to decide where the errors will be managed - it may be nowhere: if the gen_server does nothing else but answer to this currency query: if something wrong appears it will crash and be restarted by its supervisor - because this code has many interfaces with the out world and so subject to numerous failures (no Internet access, structure of answer change from site, bad currency request from user...)
I figured out my problem.
So first of all, I wasn't thinking of how simple it is to simply count how many elements there are in the tuple. That being said, I realized there were only three.
So the line I needed was
{A,B,C} = Req.
After that, I only wanted to look at the last one (C, the JSON payload), which was a string.
I found out through another source (not to disregard what you told me, Kay!) that you need to use the list functions, since strings and just lists of integers within an ASCII range (I think), in this case list_to_binary.
Once I used this line:
D = list_to_binary(C), and subsequently
E = jsx:decode(D), I got this output:
[{<<"disclaimer">>,
<<"Exchange rates are provided for infor
attempt is made to ensure quality, NO gua
se - please use at your own risk. All usag
s://openexchangerates.org/terms/">>},
{<<"license">>,
<<"Data sourced from various providers w
any kind. Bitcoin data provided by http://
t: https://openexchangerates.org/license/"
{<<"timestamp">>,1408068012},
{<<"base">>,<<"USD">>},
{<<"rates">>,
[{<<"AED">>,3.673128},
{<<"AFN">>,56.479925},
{<<"ALL">>,104.1526},
{<<"AMD">>,413.859001},
{<<"ANG">>,1.789},
{<<"AOA">>,97.913949},
{<<"ARS">>,8.274608},
{<<"AUD">>,1.073236},
{<<"AWG">>,1.79005},
{<<"AZN">>,0.783933},
{<<"BAM">>,1.46437},
{<<"BBD">>,2},
{<<"BDT">>,77.478631},
{<<"BGN">>,1.464358},
{<<"BHD">>,0.377041},
{<<"BIF">>,1546.956667},
{<<"BMD">>,1},
{<<"BND">>,1.246774},
{<<"BOB">>,6.91391},
{<<"BRL">>,2.269462},
{<<"BSD">>,1},
{<<"BTC">>,0.0019393375},
{<<"BTN">>,60.843812},
{<<"BWP">>,8.833083},
{<<"BYR">>,10385.016667},
{<<"BZD">>,1.99597},
{<<"CAD">>,1.090486},
{<<"CDF">>,924.311667},
{<<"CHF">>,0.906833},
{<<"CLF">>,0.02399},
{<<"CLP">>,577.521099},
{<<"CNY">>,6.151637},
{<<"COP">>,1880.690016},
{<<"CRC">>,540.082202},
{<<"CUP">>,1.000688},
{<<"CVE">>,82.049699},
{<<"CZK">>,20.818},
{<<"DJF">>,179.084119},
{<<"DKK">>,5.579049},
{<<"DOP">>,43.43789},
{<<"DZD">>,79.8641},
{<<"EEK">>,11.7064},
{<<"EGP">>,7.150475},
{<<"ERN">>,15.062575},
{<<"ETB">>,19.83205},
{<<"EUR">>,0.748419},
{<<"FJD">>,1.850441},
{<<"FKP">>,0.599402},
{<<"GBP">>,0.599402},
{<<"GEL">>,1.74167},
{<<"GGP">>,0.599402},
{<<"GHS">>,3.735499},
{<<"GIP">>,0.599402},
{<<"GMD">>,39.73668},
{<<"GNF">>,6995.309935},
{<<"GTQ">>,7.839405},
{<<"GYD">>,205.351249},
{<<"HKD">>,7.750754},
{<<"HNL">>,21.04854},
{<<"HRK">>,5.708511},
{<<"HTG">>,44.66625},
{<<"HUF">>,233.8448},
{<<"IDR">>,11685.75},
{<<"ILS">>,3.471469},
{<<"IMP">>,0.599402},
{<<"INR">>,60.82523},
{<<"IQD">>,1178.211753},
{<<"IRR">>,26355.666667},
{<<"ISK">>,115.96},
{<<"JEP">>,0.599402},
{<<"JMD">>,112.604801},
{<<"JOD">>,0.707778},
{<<"JPY">>,102.495401},
{<<"KES">>,88.107639},
{<<"KGS">>,51.991},
{<<"KHR">>,4056.578416},
{<<"KMF">>,368.142141},
{<<"KPW">>,900},
{<<"KRW">>,1021.353328},
{<<"KWD">>,0.283537},
{<<"KYD">>,0.826373},
{<<"KZT">>,182.076001},
{<<"LAK">>,8049.834935},
{<<"LBP">>,1509.068333},
{<<"LKR">>,130.184301},
{<<"LRD">>,91.49085},
{<<"LSL">>,10.56165},
{<<"LTL">>,2.583364},
{<<"LVL">>,0.521328},
{<<"LYD">>,1.244147},
{<<"MAD">>,8.372619},
{<<"MDL">>,13.7178},
{<<"MGA">>,2495.605},
{<<"MKD">>,46.00037},
{<<"MMK">>,972.1784},
{<<"MNT">>,1885},
{<<"MOP">>,7.986291},
{<<"MRO">>,292.0081},
{<<"MTL">>,0.683738},
{<<"MUR">>,30.61748},
{<<"MVR">>,15.37833},
{<<"MWK">>,392.9201},
{<<"MXN">>,13.07883},
{<<"MYR">>,3.175406},
{<<"MZN">>,30.3272},
{<<"NAD">>,10.56145},
{<<"NGN">>,162.303701},
{<<"NIO">>,26.07651},
{<<"NOK">>,6.156902},
{<<"NPR">>,97.66846},
{<<"NZD">>,1.179692},
{<<"OMR">>,0.38501},
{<<"PAB">>,1},
{<<"PEN">>,2.795018},
{<<"PGK">>,2.464545},
{<<"PHP">>,43.68439},
{<<"PKR">>,99.5642},
{<<"PLN">>,3.126203},
{<<"PYG">>,4272.421673},
{<<"QAR">>,3.641297},
{<<"RON">>,3.319212},
{<<"RSD">>,87.8205},
{<<"RUB">>,36.00206},
{<<"RWF">>,690.088},
{<<"SAR">>,3.750583},
{<<"SBD">>,7.258136},
{<<"SCR">>,12.40829},
{<<"SDG">>,5.697837},
{<<"SEK">>,6.857347},
{<<"SGD">>,1.246447},
{<<"SHP">>,0.599402},
{<<"SLL">>,4360},
{<<"SOS">>,841.5678},
{<<"SRD">>,3.275},
{<<"STD">>,18322.733333},
{<<"SVC">>,8.745567},
{<<"SYP">>,150.793749},
{<<"SZL">>,10.56279},
{<<"THB">>,31.87122},
{<<"TJS">>,4.985575},
{<<"TMT">>,2.8501},
{<<"TND">>,1.719698},
{<<"TOP">>,1.889033},
{<<"TRY">>,2.15342},
{<<"TTD">>,6.343484},
{<<"TWD">>,29.99281},
{<<"TZS">>,1661.865},
{<<"UAH">>,13.02466},
{<<"UGX">>,2614.28},
{<<"USD">>,1},
{<<"UYU">>,23.70693},
{<<"UZS">>,2337.773304},
{<<"VEF">>,6.295009},
{<<"VND">>,21191.15},
{<<"VUV">>,94.4875},
{<<"WST">>,2.301222},
{<<"XAF">>,491.283058},
{<<"XAG">>,0.05031404},
{<<"XAU">>,7.6211e-4},
{<<"XCD">>,2.70154},
{<<"XDR">>,0.654135},
{<<"XOF">>,491.394602},
{<<"XPF">>,89.416091},
{<<"YER">>,214.985901},
{<<"ZAR">>,10.55649},
{<<"ZMK">>,5252.024745},
{<<"ZMW">>,6.169833},
{<<"ZWL">>,322.355006}]}]
ok
So this is closer to what I want, but how do I extract a specific currency easily? Like ZWL, for example.